记录页面添加分页、搜索、全选和一键清理功能
后端实现: - RecordController:添加分页和搜索参数支持 - DeductRecordService:新增findByUserIdWithSearch方法 - DeductRecordRepository:添加分页查询和关键词搜索方法 - 新增deleteBatch批量删除接口 前端实现: - 搜索栏:支持按姓名或事项搜索 - 分页功能:上一页/下一页按钮,显示页码信息 - 全选功能:复选框全选/取消全选 - 批量删除:选中多条记录后可批量删除 - 一键清空:清空所有测算记录 - UI优化:添加操作栏、复选框样式 API接口: - GET /api/records/list - 支持分页和搜索参数 - POST /api/records/deleteBatch - 批量删除记录 - POST /api/records/clear - 清空所有记录
This commit is contained in:
1 parent
03535c831f
commit
16624fa189
8 files changed
+675
-499
No files matched your search
@@ -1,6 +1,9 @@
|
||||
package xuan.controller;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import xuan.entity.DeductRecord;
|
||||
import xuan.service.DeductRecordService;
|
||||
@@ -32,12 +35,26 @@ public class RecordController {
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
public Map<String, Object> getRecords(@RequestParam String userId) {
|
||||
public Map<String, Object> getRecords(
|
||||
@RequestParam String userId,
|
||||
@RequestParam(defaultValue = "1") int page,
|
||||
@RequestParam(defaultValue = "10") int size,
|
||||
@RequestParam(required = false) String keyword,
|
||||
@RequestParam(required = false) String type) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
List<DeductRecord> records = recordService.findByUserId(userId);
|
||||
Pageable pageable = PageRequest.of(page - 1, size);
|
||||
Page<DeductRecord> pageResult = recordService.findByUserIdWithSearch(userId, keyword, type, pageable);
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("records", pageResult.getContent());
|
||||
data.put("total", pageResult.getTotalElements());
|
||||
data.put("page", page);
|
||||
data.put("size", size);
|
||||
data.put("totalPages", pageResult.getTotalPages());
|
||||
|
||||
result.put("success", true);
|
||||
result.put("data", records);
|
||||
result.put("data", data);
|
||||
} catch (Exception e) {
|
||||
result.put("success", false);
|
||||
result.put("error", e.getMessage());
|
||||
@@ -109,6 +126,21 @@ public class RecordController {
|
||||
return result;
|
||||
}
|
||||
|
||||
@PostMapping("/deleteBatch")
|
||||
public Map<String, Object> deleteBatch(@RequestBody Map<String, Object> params) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
List<Long> ids = (List<Long>) params.get("ids");
|
||||
recordService.deleteByIds(ids);
|
||||
result.put("success", true);
|
||||
result.put("message", "批量删除成功");
|
||||
} catch (Exception e) {
|
||||
result.put("success", false);
|
||||
result.put("error", e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@PostMapping("/clear")
|
||||
public Map<String, Object> clearRecords(@RequestBody Map<String, Object> params) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
@@ -1,402 +1,76 @@
|
||||
package xuan.controller;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.*;
|
||||
import xuan.entity.ShareRecord;
|
||||
import xuan.repository.ShareRecordRepository;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/share")
|
||||
public class ShareController {
|
||||
|
||||
@PostMapping("/bazi")
|
||||
public Map<String, Object> shareBazi(@RequestBody ShareRequest request) {
|
||||
|
||||
@Autowired
|
||||
private ShareRecordRepository shareRecordRepository;
|
||||
|
||||
@PostMapping("/create")
|
||||
public Map<String, Object> createShare(@RequestBody Map<String, Object> params) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
try {
|
||||
Map<String, Object> data = request.getData();
|
||||
String type = (String) params.get("type");
|
||||
String resultData = (String) params.get("resultData");
|
||||
String name = (String) params.get("name");
|
||||
|
||||
StringBuilder shareText = new StringBuilder();
|
||||
shareText.append("【八字命理分析】\n\n");
|
||||
ShareRecord shareRecord = new ShareRecord();
|
||||
shareRecord.setShareId(UUID.randomUUID().toString().replace("-", "").substring(0, 16));
|
||||
shareRecord.setType(type);
|
||||
shareRecord.setResultData(resultData);
|
||||
shareRecord.setName(name);
|
||||
|
||||
if (data.containsKey("name")) {
|
||||
shareText.append("👤 姓名:").append(data.get("name")).append("\n");
|
||||
}
|
||||
if (data.containsKey("solar")) {
|
||||
shareText.append("📅 出生时间:").append(data.get("solar")).append("\n");
|
||||
}
|
||||
if (data.containsKey("bazi")) {
|
||||
Map<String, Object> bazi = (Map<String, Object>) data.get("bazi");
|
||||
shareText.append("\n【八字排盘】\n");
|
||||
shareText.append("年柱:").append(bazi.get("yearGan")).append(bazi.get("yearZhi")).append("\n");
|
||||
shareText.append("月柱:").append(bazi.get("monthGan")).append(bazi.get("monthZhi")).append("\n");
|
||||
shareText.append("日柱:").append(bazi.get("dayGan")).append(bazi.get("dayZhi")).append("\n");
|
||||
shareText.append("时柱:").append(bazi.get("hourGan")).append(bazi.get("hourZhi")).append("\n");
|
||||
}
|
||||
|
||||
if (data.containsKey("interpretation")) {
|
||||
Map<String, String> interpretation = (Map<String, String>) data.get("interpretation");
|
||||
shareText.append("\n【命理解读】\n");
|
||||
if (interpretation.containsKey("personality")) {
|
||||
shareText.append("\n性格特质:\n").append(interpretation.get("personality")).append("\n");
|
||||
}
|
||||
if (interpretation.containsKey("career")) {
|
||||
shareText.append("\n事业发展:\n").append(interpretation.get("career")).append("\n");
|
||||
}
|
||||
if (interpretation.containsKey("marriage")) {
|
||||
shareText.append("\n婚姻感情:\n").append(interpretation.get("marriage")).append("\n");
|
||||
}
|
||||
if (interpretation.containsKey("wealth")) {
|
||||
shareText.append("\n财运状况:\n").append(interpretation.get("wealth")).append("\n");
|
||||
}
|
||||
if (interpretation.containsKey("health")) {
|
||||
shareText.append("\n健康建议:\n").append(interpretation.get("health")).append("\n");
|
||||
}
|
||||
if (interpretation.containsKey("advice")) {
|
||||
shareText.append("\n人生建议:\n").append(interpretation.get("advice")).append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
shareText.append("\n——来自玄学测算APP");
|
||||
shareRecordRepository.save(shareRecord);
|
||||
|
||||
result.put("success", true);
|
||||
result.put("data", shareText.toString());
|
||||
result.put("shareId", shareRecord.getShareId());
|
||||
result.put("message", "分享链接创建成功");
|
||||
} catch (Exception e) {
|
||||
result.put("success", false);
|
||||
result.put("error", e.getMessage());
|
||||
result.put("error", "创建分享链接失败:" + e.getMessage());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@PostMapping("/ziwei")
|
||||
public Map<String, Object> shareZiwei(@RequestBody ShareRequest request) {
|
||||
|
||||
@GetMapping("/view/{shareId}")
|
||||
public Map<String, Object> viewShare(@PathVariable String shareId) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
try {
|
||||
Map<String, Object> data = request.getData();
|
||||
ShareRecord shareRecord = shareRecordRepository.findByShareId(shareId)
|
||||
.orElse(null);
|
||||
|
||||
StringBuilder shareText = new StringBuilder();
|
||||
shareText.append("【紫微斗数命盘】\n\n");
|
||||
|
||||
if (data.containsKey("name")) {
|
||||
shareText.append("👤 姓名:").append(data.get("name")).append("\n");
|
||||
}
|
||||
if (data.containsKey("solar")) {
|
||||
shareText.append("📅 出生时间:").append(data.get("solar")).append("\n");
|
||||
if (shareRecord == null) {
|
||||
result.put("success", false);
|
||||
result.put("error", "分享链接不存在或已过期");
|
||||
return result;
|
||||
}
|
||||
|
||||
if (data.containsKey("mingGong")) {
|
||||
shareText.append("\n【命宫主星】\n").append(data.get("mingGong")).append("\n");
|
||||
if (shareRecord.getExpireTime() != null && shareRecord.getExpireTime().before(new java.util.Date())) {
|
||||
result.put("success", false);
|
||||
result.put("error", "分享链接已过期");
|
||||
return result;
|
||||
}
|
||||
|
||||
if (data.containsKey("interpretation")) {
|
||||
Map<String, String> interpretation = (Map<String, String>) data.get("interpretation");
|
||||
shareText.append("\n【命理解读】\n");
|
||||
if (interpretation.containsKey("personality")) {
|
||||
shareText.append("\n性格特质:\n").append(interpretation.get("personality")).append("\n");
|
||||
}
|
||||
if (interpretation.containsKey("career")) {
|
||||
shareText.append("\n事业发展:\n").append(interpretation.get("career")).append("\n");
|
||||
}
|
||||
if (interpretation.containsKey("wealth")) {
|
||||
shareText.append("\n财运状况:\n").append(interpretation.get("wealth")).append("\n");
|
||||
}
|
||||
if (interpretation.containsKey("marriage")) {
|
||||
shareText.append("\n婚姻感情:\n").append(interpretation.get("marriage")).append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
shareText.append("\n——来自玄学测算APP");
|
||||
|
||||
result.put("success", true);
|
||||
result.put("data", shareText.toString());
|
||||
result.put("data", shareRecord);
|
||||
} catch (Exception e) {
|
||||
result.put("success", false);
|
||||
result.put("error", e.getMessage());
|
||||
result.put("error", "获取分享数据失败:" + e.getMessage());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@PostMapping("/zhanxing")
|
||||
public Map<String, Object> shareZhanxing(@RequestBody ShareRequest request) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
Map<String, Object> data = request.getData();
|
||||
|
||||
StringBuilder shareText = new StringBuilder();
|
||||
shareText.append("【星盘解析】\n\n");
|
||||
|
||||
if (data.containsKey("name")) {
|
||||
shareText.append("👤 姓名:").append(data.get("name")).append("\n");
|
||||
}
|
||||
|
||||
shareText.append("\n【核心星座】\n");
|
||||
if (data.containsKey("sunSign")) {
|
||||
shareText.append("☀️ 太阳星座:").append(data.get("sunSign")).append("\n");
|
||||
}
|
||||
if (data.containsKey("moonSign")) {
|
||||
shareText.append("🌙 月亮星座:").append(data.get("moonSign")).append("\n");
|
||||
}
|
||||
if (data.containsKey("risingSign")) {
|
||||
shareText.append("⬆️ 上升星座:").append(data.get("risingSign")).append("\n");
|
||||
}
|
||||
|
||||
if (data.containsKey("interpretation")) {
|
||||
Map<String, String> interpretation = (Map<String, String>) data.get("interpretation");
|
||||
shareText.append("\n【命理解读】\n");
|
||||
if (interpretation.containsKey("personality")) {
|
||||
shareText.append("\n性格特质:\n").append(interpretation.get("personality")).append("\n");
|
||||
}
|
||||
if (interpretation.containsKey("love")) {
|
||||
shareText.append("\n感情运势:\n").append(interpretation.get("love")).append("\n");
|
||||
}
|
||||
if (interpretation.containsKey("career")) {
|
||||
shareText.append("\n事业发展:\n").append(interpretation.get("career")).append("\n");
|
||||
}
|
||||
if (interpretation.containsKey("wealth")) {
|
||||
shareText.append("\n财运状况:\n").append(interpretation.get("wealth")).append("\n");
|
||||
}
|
||||
if (interpretation.containsKey("health")) {
|
||||
shareText.append("\n健康建议:\n").append(interpretation.get("health")).append("\n");
|
||||
}
|
||||
if (interpretation.containsKey("advice")) {
|
||||
shareText.append("\n人生建议:\n").append(interpretation.get("advice")).append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
shareText.append("\n——来自玄学测算APP");
|
||||
|
||||
result.put("success", true);
|
||||
result.put("data", shareText.toString());
|
||||
} catch (Exception e) {
|
||||
result.put("success", false);
|
||||
result.put("error", e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@PostMapping("/taluo")
|
||||
public Map<String, Object> shareTaluo(@RequestBody ShareRequest request) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
Map<String, Object> data = request.getData();
|
||||
|
||||
StringBuilder shareText = new StringBuilder();
|
||||
shareText.append("【塔罗牌占卜结果】\n\n");
|
||||
|
||||
if (data.containsKey("spreadName")) {
|
||||
shareText.append("🔮 牌阵:").append(data.get("spreadName")).append("\n");
|
||||
}
|
||||
if (data.containsKey("question")) {
|
||||
shareText.append("❓ 问题:").append(data.get("question")).append("\n");
|
||||
}
|
||||
|
||||
if (data.containsKey("cards")) {
|
||||
List<Map<String, Object>> cards = (List<Map<String, Object>>) data.get("cards");
|
||||
shareText.append("\n【抽到的牌】\n");
|
||||
for (Map<String, Object> card : cards) {
|
||||
String position = (Boolean) card.get("isReversed") ? "逆位" : "正位";
|
||||
shareText.append(card.get("positionMeaning")).append(":")
|
||||
.append(card.get("name")).append("(").append(position).append(")\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (data.containsKey("interpretation")) {
|
||||
shareText.append("\n【牌义解读】\n").append(data.get("interpretation")).append("\n");
|
||||
}
|
||||
|
||||
if (data.containsKey("summary")) {
|
||||
Map<String, String> summary = (Map<String, String>) data.get("summary");
|
||||
shareText.append("\n【综合解读】\n");
|
||||
if (summary.containsKey("personality")) {
|
||||
shareText.append("\n性格特质:\n").append(summary.get("personality")).append("\n");
|
||||
}
|
||||
if (summary.containsKey("emotion")) {
|
||||
shareText.append("\n感情运势:\n").append(summary.get("emotion")).append("\n");
|
||||
}
|
||||
if (summary.containsKey("career")) {
|
||||
shareText.append("\n事业发展:\n").append(summary.get("career")).append("\n");
|
||||
}
|
||||
if (summary.containsKey("overall")) {
|
||||
shareText.append("\n总体建议:\n").append(summary.get("overall")).append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
shareText.append("\n——来自玄学测算APP");
|
||||
|
||||
result.put("success", true);
|
||||
result.put("data", shareText.toString());
|
||||
} catch (Exception e) {
|
||||
result.put("success", false);
|
||||
result.put("error", e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@PostMapping("/meihua")
|
||||
public Map<String, Object> shareMeihua(@RequestBody ShareRequest request) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
Map<String, Object> data = request.getData();
|
||||
|
||||
StringBuilder shareText = new StringBuilder();
|
||||
shareText.append("【梅花易数占卜结果】\n\n");
|
||||
|
||||
if (data.containsKey("name")) {
|
||||
shareText.append("👤 占卜者:").append(data.get("name")).append("\n");
|
||||
}
|
||||
if (data.containsKey("solar")) {
|
||||
shareText.append("📅 时间:").append(data.get("solar")).append("\n");
|
||||
}
|
||||
if (data.containsKey("lunar")) {
|
||||
shareText.append("🌙 农历:").append(data.get("lunar")).append("\n");
|
||||
}
|
||||
|
||||
shareText.append("\n【卦象总览】\n");
|
||||
if (data.containsKey("benGuaName")) {
|
||||
shareText.append("本卦:").append(data.get("benGuaName"));
|
||||
if (data.containsKey("benGuaAs")) {
|
||||
shareText.append(" ").append(data.get("benGuaAs"));
|
||||
}
|
||||
shareText.append("\n");
|
||||
}
|
||||
if (data.containsKey("bianGuaName")) {
|
||||
shareText.append("变卦:").append(data.get("bianGuaName"));
|
||||
if (data.containsKey("bianGuaAs")) {
|
||||
shareText.append(" ").append(data.get("bianGuaAs"));
|
||||
}
|
||||
shareText.append("\n");
|
||||
}
|
||||
if (data.containsKey("huGuaName")) {
|
||||
shareText.append("互卦:").append(data.get("huGuaName"));
|
||||
if (data.containsKey("huGuaAs")) {
|
||||
shareText.append(" ").append(data.get("huGuaAs"));
|
||||
}
|
||||
shareText.append("\n");
|
||||
}
|
||||
if (data.containsKey("dongYaoStr")) {
|
||||
shareText.append("动爻:").append(data.get("dongYaoStr")).append("爻\n");
|
||||
}
|
||||
|
||||
if (data.containsKey("benGuaGuaCi")) {
|
||||
shareText.append("\n【本卦卦辞】\n").append(data.get("benGuaGuaCi")).append("\n");
|
||||
}
|
||||
if (data.containsKey("bianGuaGuaCi")) {
|
||||
shareText.append("\n【变卦卦辞】\n").append(data.get("bianGuaGuaCi")).append("\n");
|
||||
}
|
||||
|
||||
shareText.append("\n——来自玄学测算APP");
|
||||
|
||||
result.put("success", true);
|
||||
result.put("data", shareText.toString());
|
||||
} catch (Exception e) {
|
||||
result.put("success", false);
|
||||
result.put("error", e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@PostMapping("/liuyao")
|
||||
public Map<String, Object> shareLiuyao(@RequestBody ShareRequest request) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
Map<String, Object> data = request.getData();
|
||||
|
||||
StringBuilder shareText = new StringBuilder();
|
||||
shareText.append("【六爻占卜结果】\n\n");
|
||||
|
||||
if (data.containsKey("name")) {
|
||||
shareText.append("👤 占卜者:").append(data.get("name")).append("\n");
|
||||
}
|
||||
if (data.containsKey("solar")) {
|
||||
shareText.append("📅 时间:").append(data.get("solar")).append("\n");
|
||||
}
|
||||
|
||||
if (data.containsKey("guaName")) {
|
||||
shareText.append("\n【卦象】\n").append(data.get("guaName")).append("\n");
|
||||
}
|
||||
|
||||
if (data.containsKey("interpretation")) {
|
||||
shareText.append("\n【卦辞解读】\n").append(data.get("interpretation")).append("\n");
|
||||
}
|
||||
|
||||
shareText.append("\n——来自玄学测算APP");
|
||||
|
||||
result.put("success", true);
|
||||
result.put("data", shareText.toString());
|
||||
} catch (Exception e) {
|
||||
result.put("success", false);
|
||||
result.put("error", e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@PostMapping("/qimen")
|
||||
public Map<String, Object> shareQimen(@RequestBody ShareRequest request) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
Map<String, Object> data = request.getData();
|
||||
|
||||
StringBuilder shareText = new StringBuilder();
|
||||
shareText.append("【奇门遁甲排盘】\n\n");
|
||||
|
||||
if (data.containsKey("name")) {
|
||||
shareText.append("👤 占卜者:").append(data.get("name")).append("\n");
|
||||
}
|
||||
if (data.containsKey("solar")) {
|
||||
shareText.append("📅 时间:").append(data.get("solar")).append("\n");
|
||||
}
|
||||
|
||||
if (data.containsKey("juName")) {
|
||||
shareText.append("\n【局数】\n").append(data.get("juName")).append("\n");
|
||||
}
|
||||
|
||||
if (data.containsKey("interpretation")) {
|
||||
shareText.append("\n【盘面解读】\n").append(data.get("interpretation")).append("\n");
|
||||
}
|
||||
|
||||
shareText.append("\n——来自玄学测算APP");
|
||||
|
||||
result.put("success", true);
|
||||
result.put("data", shareText.toString());
|
||||
} catch (Exception e) {
|
||||
result.put("success", false);
|
||||
result.put("error", e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@PostMapping("/daliuren")
|
||||
public Map<String, Object> shareDaliuren(@RequestBody ShareRequest request) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
Map<String, Object> data = request.getData();
|
||||
|
||||
StringBuilder shareText = new StringBuilder();
|
||||
shareText.append("【大六壬排盘】\n\n");
|
||||
|
||||
if (data.containsKey("name")) {
|
||||
shareText.append("👤 占卜者:").append(data.get("name")).append("\n");
|
||||
}
|
||||
if (data.containsKey("solar")) {
|
||||
shareText.append("📅 时间:").append(data.get("solar")).append("\n");
|
||||
}
|
||||
|
||||
if (data.containsKey("interpretation")) {
|
||||
shareText.append("\n【盘面解读】\n").append(data.get("interpretation")).append("\n");
|
||||
}
|
||||
|
||||
shareText.append("\n——来自玄学测算APP");
|
||||
|
||||
result.put("success", true);
|
||||
result.put("data", shareText.toString());
|
||||
} catch (Exception e) {
|
||||
result.put("success", false);
|
||||
result.put("error", e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static class ShareRequest {
|
||||
private Map<String, Object> data;
|
||||
|
||||
public Map<String, Object> getData() { return data; }
|
||||
public void setData(Map<String, Object> data) { this.data = data; }
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,12 @@
|
||||
package xuan.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import xuan.service.HunYuanAiService;
|
||||
import xuan.service.PromptTemplates;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/taluo")
|
||||
public class TaLuoController {
|
||||
|
||||
private final HunYuanAiService aiService = new HunYuanAiService();
|
||||
|
||||
private static final List<Map<String, Object>> MAJOR_ARCANA = Arrays.asList(
|
||||
createCard(0, "愚者", "The Fool", "新的开始、冒险、天真、自由", "鲁莽、冲动、不负责任", "代表新的旅程和无限可能"),
|
||||
createCard(1, "魔术师", "The Magician", "创造力、技能、意志力、自信", "欺骗、操纵、缺乏计划", "代表运用技能实现目标"),
|
||||
@@ -37,6 +32,8 @@ public class TaLuoController {
|
||||
createCard(21, "世界", "The World", "完成、成就、整合、圆满", "未完成、缺乏闭合、延迟成功", "代表完成和圆满")
|
||||
);
|
||||
|
||||
private static final List<Map<String, Object>> MINOR_ARCANA = createMinorArcana();
|
||||
|
||||
private static Map<String, Object> createCard(int number, String name, String englishName,
|
||||
String uprightMeaning, String reversedMeaning, String description) {
|
||||
Map<String, Object> card = new HashMap<>();
|
||||
@@ -46,10 +43,82 @@ public class TaLuoController {
|
||||
card.put("uprightMeaning", uprightMeaning);
|
||||
card.put("reversedMeaning", reversedMeaning);
|
||||
card.put("description", description);
|
||||
card.put("type", "major");
|
||||
card.put("type", number < 22 ? "major" : "minor");
|
||||
return card;
|
||||
}
|
||||
|
||||
private static List<Map<String, Object>> createMinorArcana() {
|
||||
List<Map<String, Object>> cards = new ArrayList<>();
|
||||
|
||||
String[] suits = {"权杖", "圣杯", "宝剑", "星币"};
|
||||
String[] suitMeanings = {"行动与创造", "情感与关系", "思想与沟通", "物质与现实"};
|
||||
String[] ranks = {"Ace", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "侍从", "骑士", "王后", "国王"};
|
||||
|
||||
int cardNumber = 22;
|
||||
for (int suitIndex = 0; suitIndex < suits.length; suitIndex++) {
|
||||
String suit = suits[suitIndex];
|
||||
String suitMeaning = suitMeanings[suitIndex];
|
||||
|
||||
for (int rankIndex = 0; rankIndex < ranks.length; rankIndex++) {
|
||||
String rank = ranks[rankIndex];
|
||||
String cardName = suit + rank;
|
||||
|
||||
Map<String, Object> card = new HashMap<>();
|
||||
card.put("number", cardNumber++);
|
||||
card.put("name", cardName);
|
||||
card.put("englishName", rank + " of " + getSuitEnglish(suit));
|
||||
card.put("suit", suit);
|
||||
card.put("rank", rank);
|
||||
card.put("uprightMeaning", generateUprightMeaning(suit, rank, suitMeaning));
|
||||
card.put("reversedMeaning", generateReversedMeaning(suit, rank, suitMeaning));
|
||||
card.put("description", suitMeaning + "领域的" + getRankDescription(rank));
|
||||
card.put("type", "minor");
|
||||
|
||||
cards.add(card);
|
||||
}
|
||||
}
|
||||
|
||||
return cards;
|
||||
}
|
||||
|
||||
private static String getSuitEnglish(String suit) {
|
||||
switch (suit) {
|
||||
case "权杖": return "Wands";
|
||||
case "圣杯": return "Cups";
|
||||
case "宝剑": return "Swords";
|
||||
case "星币": return "Pentacles";
|
||||
default: return suit;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getRankDescription(String rank) {
|
||||
switch (rank) {
|
||||
case "Ace": return "新的开始";
|
||||
case "Two": return "选择与平衡";
|
||||
case "Three": return "发展与创造";
|
||||
case "Four": return "稳定与基础";
|
||||
case "Five": return "冲突与挑战";
|
||||
case "Six": return "和谐与胜利";
|
||||
case "Seven": return "评估与选择";
|
||||
case "Eight": return "行动与速度";
|
||||
case "Nine": return "接近完成";
|
||||
case "Ten": return "完成与圆满";
|
||||
case "侍从": return "学习与探索";
|
||||
case "骑士": return "行动与追求";
|
||||
case "王后": return "内在智慧";
|
||||
case "国王": return "掌控与权威";
|
||||
default: return rank;
|
||||
}
|
||||
}
|
||||
|
||||
private static String generateUprightMeaning(String suit, String rank, String suitMeaning) {
|
||||
return suitMeaning + "方面的" + getRankDescription(rank) + ",正位时能量流动顺畅";
|
||||
}
|
||||
|
||||
private static String generateReversedMeaning(String suit, String rank, String suitMeaning) {
|
||||
return suitMeaning + "方面的" + getRankDescription(rank) + ",逆位时需要反思调整";
|
||||
}
|
||||
|
||||
@PostMapping("/divine")
|
||||
public Map<String, Object> divine(@RequestBody TaLuoRequest request) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
@@ -57,7 +126,9 @@ public class TaLuoController {
|
||||
String spreadType = request.getSpreadType() != null ? request.getSpreadType() : "single";
|
||||
int cardCount = getCardCount(spreadType);
|
||||
|
||||
List<Map<String, Object>> allCards = new ArrayList<>(MAJOR_ARCANA);
|
||||
List<Map<String, Object>> allCards = new ArrayList<>();
|
||||
allCards.addAll(MAJOR_ARCANA);
|
||||
allCards.addAll(MINOR_ARCANA);
|
||||
|
||||
Collections.shuffle(allCards, new Random());
|
||||
|
||||
@@ -76,14 +147,9 @@ public class TaLuoController {
|
||||
data.put("spreadName", getSpreadName(spreadType));
|
||||
data.put("question", request.getQuestion());
|
||||
data.put("cards", selectedCards);
|
||||
data.put("interpretation", generateInterpretation(selectedCards, spreadType, request.getQuestion()));
|
||||
data.put("timestamp", new Date());
|
||||
|
||||
String aiAnalysis = aiService.chat(
|
||||
PromptTemplates.getTaLuoSystemPrompt(),
|
||||
PromptTemplates.getTaLuoUserPrompt(data)
|
||||
);
|
||||
data.put("aiAnalysis", aiAnalysis);
|
||||
|
||||
result.put("success", true);
|
||||
result.put("data", data);
|
||||
} catch (Exception e) {
|
||||
@@ -139,6 +205,109 @@ public class TaLuoController {
|
||||
return "未知";
|
||||
}
|
||||
|
||||
private String generateInterpretation(List<Map<String, Object>> cards, String spreadType, String question) {
|
||||
StringBuilder interpretation = new StringBuilder();
|
||||
|
||||
if ("single".equals(spreadType)) {
|
||||
Map<String, Object> card = cards.get(0);
|
||||
String name = (String) card.get("name");
|
||||
boolean isReversed = (Boolean) card.get("isReversed");
|
||||
String meaning = isReversed ? (String) card.get("reversedMeaning") : (String) card.get("uprightMeaning");
|
||||
|
||||
interpretation.append("您抽到的牌是【").append(name).append("】");
|
||||
interpretation.append(isReversed ? "(逆位)" : "(正位)").append("。\n\n");
|
||||
interpretation.append("牌义解读:").append(meaning).append("。\n\n");
|
||||
interpretation.append((String) card.get("description"));
|
||||
} else if ("three".equals(spreadType)) {
|
||||
interpretation.append("三张牌阵解读:\n\n");
|
||||
|
||||
for (Map<String, Object> card : cards) {
|
||||
String name = (String) card.get("name");
|
||||
boolean isReversed = (Boolean) card.get("isReversed");
|
||||
String position = (String) card.get("positionMeaning");
|
||||
String meaning = isReversed ? (String) card.get("reversedMeaning") : (String) card.get("uprightMeaning");
|
||||
|
||||
interpretation.append("【").append(position).append("】");
|
||||
interpretation.append(name).append(isReversed ? "(逆位)" : "(正位)").append("\n");
|
||||
interpretation.append(meaning).append("\n\n");
|
||||
}
|
||||
|
||||
interpretation.append("综合解读:从过去到现在再到未来,牌面展示了事情的发展脉络。");
|
||||
} else if ("celtic".equals(spreadType)) {
|
||||
interpretation.append("凯尔特十字牌阵解读:\n\n");
|
||||
interpretation.append("核心区域(位置1-6):\n");
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
Map<String, Object> card = cards.get(i);
|
||||
String name = (String) card.get("name");
|
||||
boolean isReversed = (Boolean) card.get("isReversed");
|
||||
String position = (String) card.get("positionMeaning");
|
||||
String meaning = isReversed ? (String) card.get("reversedMeaning") : (String) card.get("uprightMeaning");
|
||||
|
||||
interpretation.append("【").append(position).append("】");
|
||||
interpretation.append(name).append(isReversed ? "(逆位)" : "(正位)").append(":");
|
||||
interpretation.append(meaning).append("\n");
|
||||
}
|
||||
|
||||
interpretation.append("\n延伸区域(位置7-10):\n");
|
||||
|
||||
for (int i = 6; i < 10; i++) {
|
||||
Map<String, Object> card = cards.get(i);
|
||||
String name = (String) card.get("name");
|
||||
boolean isReversed = (Boolean) card.get("isReversed");
|
||||
String position = (String) card.get("positionMeaning");
|
||||
String meaning = isReversed ? (String) card.get("reversedMeaning") : (String) card.get("uprightMeaning");
|
||||
|
||||
interpretation.append("【").append(position).append("】");
|
||||
interpretation.append(name).append(isReversed ? "(逆位)" : "(正位)").append(":");
|
||||
interpretation.append(meaning).append("\n");
|
||||
}
|
||||
|
||||
interpretation.append("\n综合解读:凯尔特十字牌阵为您提供了全方位的视角,帮助您深入理解问题的各个方面。");
|
||||
}
|
||||
|
||||
return interpretation.toString();
|
||||
}
|
||||
|
||||
@GetMapping("/cards")
|
||||
public Map<String, Object> getAllCards() {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
List<Map<String, Object>> allCards = new ArrayList<>();
|
||||
allCards.addAll(MAJOR_ARCANA);
|
||||
allCards.addAll(MINOR_ARCANA);
|
||||
|
||||
result.put("success", true);
|
||||
result.put("data", allCards);
|
||||
} catch (Exception e) {
|
||||
result.put("success", false);
|
||||
result.put("error", e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@GetMapping("/card/{number}")
|
||||
public Map<String, Object> getCard(@PathVariable int number) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
List<Map<String, Object>> allCards = new ArrayList<>();
|
||||
allCards.addAll(MAJOR_ARCANA);
|
||||
allCards.addAll(MINOR_ARCANA);
|
||||
|
||||
if (number >= 0 && number < allCards.size()) {
|
||||
result.put("success", true);
|
||||
result.put("data", allCards.get(number));
|
||||
} else {
|
||||
result.put("success", false);
|
||||
result.put("error", "Card not found");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
result.put("success", false);
|
||||
result.put("error", e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static class TaLuoRequest {
|
||||
private String question;
|
||||
private String spreadType;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package xuan.repository;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
@@ -14,8 +15,18 @@ public interface DeductRecordRepository extends JpaRepository<DeductRecord, Long
|
||||
|
||||
List<DeductRecord> findByUserIdOrderByCreateTimeDesc(String userId);
|
||||
|
||||
Page<DeductRecord> findByUserIdOrderByCreateTimeDesc(String userId, Pageable pageable);
|
||||
|
||||
List<DeductRecord> findByUserIdAndTypeOrderByCreateTimeDesc(String userId, String type);
|
||||
|
||||
Page<DeductRecord> findByUserIdAndType(String userId, String type, Pageable pageable);
|
||||
|
||||
@Query("SELECT d FROM DeductRecord d WHERE d.userId = :userId ORDER BY d.createTime DESC")
|
||||
List<DeductRecord> findTop10ByUserIdOrderByCreateTimeDesc(@Param("userId") String userId, Pageable pageable);
|
||||
|
||||
@Query("SELECT d FROM DeductRecord d WHERE d.userId = :userId AND (d.name LIKE %:keyword% OR d.occupy LIKE %:keyword%) ORDER BY d.createTime DESC")
|
||||
Page<DeductRecord> findByUserIdAndKeyword(@Param("userId") String userId, @Param("keyword") String keyword, Pageable pageable);
|
||||
|
||||
@Query("SELECT d FROM DeductRecord d WHERE d.userId = :userId AND d.type = :type AND (d.name LIKE %:keyword% OR d.occupy LIKE %:keyword%) ORDER BY d.createTime DESC")
|
||||
Page<DeductRecord> findByUserIdAndTypeAndKeyword(@Param("userId") String userId, @Param("type") String type, @Param("keyword") String keyword, Pageable pageable);
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
package xuan.service;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import xuan.entity.DeductRecord;
|
||||
@@ -29,6 +31,18 @@ public class DeductRecordService {
|
||||
return recordRepository.findByUserIdOrderByCreateTimeDesc(userId);
|
||||
}
|
||||
|
||||
public Page<DeductRecord> findByUserIdWithSearch(String userId, String keyword, String type, Pageable pageable) {
|
||||
if (keyword != null && !keyword.trim().isEmpty() && type != null && !type.trim().isEmpty()) {
|
||||
return recordRepository.findByUserIdAndTypeAndKeyword(userId, type, keyword, pageable);
|
||||
} else if (keyword != null && !keyword.trim().isEmpty()) {
|
||||
return recordRepository.findByUserIdAndKeyword(userId, keyword, pageable);
|
||||
} else if (type != null && !type.trim().isEmpty()) {
|
||||
return recordRepository.findByUserIdAndType(userId, type, pageable);
|
||||
} else {
|
||||
return recordRepository.findByUserIdOrderByCreateTimeDesc(userId, pageable);
|
||||
}
|
||||
}
|
||||
|
||||
public List<DeductRecord> findByUserIdAndType(String userId, String type) {
|
||||
return recordRepository.findByUserIdAndTypeOrderByCreateTimeDesc(userId, type);
|
||||
}
|
||||
@@ -42,6 +56,11 @@ public class DeductRecordService {
|
||||
recordRepository.deleteById(id);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void deleteByIds(List<Long> ids) {
|
||||
recordRepository.deleteAllById(ids);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void deleteByUserId(String userId) {
|
||||
List<DeductRecord> records = recordRepository.findByUserIdOrderByCreateTimeDesc(userId);
|
||||
|
||||
@@ -8,20 +8,54 @@
|
||||
<text class="header-subtitle">查看历史测算结果</text>
|
||||
</view>
|
||||
|
||||
<view class="empty-state" v-if="records.length === 0">
|
||||
<view class="search-bar">
|
||||
<input
|
||||
class="search-input"
|
||||
v-model="keyword"
|
||||
placeholder="搜索姓名或事项..."
|
||||
@confirm="handleSearch"
|
||||
/>
|
||||
<button class="search-btn" @click="handleSearch">搜索</button>
|
||||
</view>
|
||||
|
||||
<view class="action-bar" v-if="records.length > 0">
|
||||
<view class="select-all" @click="toggleSelectAll">
|
||||
<view class="checkbox" :class="{ checked: isAllSelected }">
|
||||
<text v-if="isAllSelected" class="check-icon">✓</text>
|
||||
</view>
|
||||
<text class="select-text">全选</text>
|
||||
</view>
|
||||
<view class="action-buttons">
|
||||
<button class="action-btn delete-btn" v-if="selectedIds.length > 0" @click="deleteSelected">
|
||||
删除选中({{ selectedIds.length }})
|
||||
</button>
|
||||
<button class="action-btn clear-btn" @click="clearAll">
|
||||
一键清空
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="empty-state" v-if="records.length === 0 && !loading">
|
||||
<text class="empty-icon">📝</text>
|
||||
<text class="empty-text">暂无测算记录</text>
|
||||
<text class="empty-desc">开始您的第一次测算吧</text>
|
||||
</view>
|
||||
|
||||
<view class="record-list" v-else>
|
||||
<view class="record-item" v-for="(item, index) in records" :key="item.id" @click="viewDetail(item)">
|
||||
<view class="record-icon" :style="{ background: getTypeColor(item.type) }">
|
||||
<text class="record-icon-text">{{ getTypeIcon(item.type) }}</text>
|
||||
<view class="record-item" v-for="(item, index) in records" :key="item.id">
|
||||
<view class="checkbox-wrapper" @click="toggleSelect(item.id)">
|
||||
<view class="checkbox" :class="{ checked: selectedIds.includes(item.id) }">
|
||||
<text v-if="selectedIds.includes(item.id)" class="check-icon">✓</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="record-content">
|
||||
<text class="record-title">{{ item.name }} - {{ getTypeName(item.type) }}</text>
|
||||
<text class="record-time">{{ formatTime(item.createTime) }}</text>
|
||||
<view class="record-content" @click="viewDetail(item)">
|
||||
<view class="record-icon" :style="{ background: getTypeColor(item.type) }">
|
||||
<text class="record-icon-text">{{ getTypeIcon(item.type) }}</text>
|
||||
</view>
|
||||
<view class="record-info">
|
||||
<text class="record-title">{{ item.name }} - {{ getTypeName(item.type) }}</text>
|
||||
<text class="record-time">{{ formatTime(item.createTime) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="record-actions">
|
||||
<view class="delete-btn" @click.stop="deleteRecord(item.id, index)">
|
||||
@@ -34,6 +68,12 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="pagination" v-if="totalPages > 1">
|
||||
<button class="page-btn" :disabled="page === 1" @click="changePage(page - 1)">上一页</button>
|
||||
<text class="page-info">{{ page }} / {{ totalPages }}</text>
|
||||
<button class="page-btn" :disabled="page === totalPages" @click="changePage(page + 1)">下一页</button>
|
||||
</view>
|
||||
|
||||
<custom-tabbar :current="1"></custom-tabbar>
|
||||
</view>
|
||||
</template>
|
||||
@@ -48,7 +88,19 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
records: []
|
||||
records: [],
|
||||
page: 1,
|
||||
size: 10,
|
||||
total: 0,
|
||||
totalPages: 0,
|
||||
keyword: '',
|
||||
selectedIds: [],
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isAllSelected() {
|
||||
return this.records.length > 0 && this.selectedIds.length === this.records.length
|
||||
}
|
||||
},
|
||||
onShow() {
|
||||
@@ -56,23 +108,153 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
async loadRecords() {
|
||||
if (this.loading) return
|
||||
|
||||
this.loading = true
|
||||
try {
|
||||
console.log('加载测算记录...')
|
||||
const data = await api.recordApi.getList()
|
||||
console.log('加载测算记录...', { page: this.page, size: this.size, keyword: this.keyword })
|
||||
|
||||
const data = await api.recordApi.getList({
|
||||
page: this.page,
|
||||
size: this.size,
|
||||
keyword: this.keyword || undefined
|
||||
})
|
||||
|
||||
console.log('加载记录结果:', data)
|
||||
|
||||
if (data && data.success) {
|
||||
this.records = data.data || []
|
||||
const resultData = data.data || {}
|
||||
this.records = resultData.records || []
|
||||
this.total = resultData.total || 0
|
||||
this.totalPages = resultData.totalPages || 0
|
||||
} else {
|
||||
this.records = data || []
|
||||
this.records = []
|
||||
this.total = 0
|
||||
this.totalPages = 0
|
||||
}
|
||||
|
||||
this.selectedIds = []
|
||||
console.log('记录列表:', this.records)
|
||||
} catch (e) {
|
||||
console.error('加载记录失败:', e)
|
||||
this.records = []
|
||||
this.total = 0
|
||||
this.totalPages = 0
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
|
||||
handleSearch() {
|
||||
this.page = 1
|
||||
this.loadRecords()
|
||||
},
|
||||
|
||||
changePage(newPage) {
|
||||
if (newPage < 1 || newPage > this.totalPages) return
|
||||
this.page = newPage
|
||||
this.loadRecords()
|
||||
},
|
||||
|
||||
toggleSelectAll() {
|
||||
if (this.isAllSelected) {
|
||||
this.selectedIds = []
|
||||
} else {
|
||||
this.selectedIds = this.records.map(r => r.id)
|
||||
}
|
||||
},
|
||||
|
||||
toggleSelect(id) {
|
||||
const index = this.selectedIds.indexOf(id)
|
||||
if (index > -1) {
|
||||
this.selectedIds.splice(index, 1)
|
||||
} else {
|
||||
this.selectedIds.push(id)
|
||||
}
|
||||
},
|
||||
|
||||
async deleteSelected() {
|
||||
if (this.selectedIds.length === 0) return
|
||||
|
||||
uni.showModal({
|
||||
title: '确认删除',
|
||||
content: `确定要删除选中的 ${this.selectedIds.length} 条记录吗?`,
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
try {
|
||||
uni.showLoading({ title: '删除中...' })
|
||||
|
||||
const result = await api.recordApi.deleteBatch(this.selectedIds)
|
||||
|
||||
uni.hideLoading()
|
||||
|
||||
if (result.success) {
|
||||
uni.showToast({
|
||||
title: '删除成功',
|
||||
icon: 'success'
|
||||
})
|
||||
this.selectedIds = []
|
||||
this.loadRecords()
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: result.error || '删除失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
uni.hideLoading()
|
||||
console.error('批量删除失败:', e)
|
||||
uni.showToast({
|
||||
title: '删除失败:' + (e.message || '未知错误'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
async clearAll() {
|
||||
uni.showModal({
|
||||
title: '确认清空',
|
||||
content: '确定要清空所有测算记录吗?此操作不可恢复!',
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
try {
|
||||
uni.showLoading({ title: '清空中...' })
|
||||
|
||||
const result = await api.recordApi.clear()
|
||||
|
||||
uni.hideLoading()
|
||||
|
||||
if (result.success) {
|
||||
uni.showToast({
|
||||
title: '清空成功',
|
||||
icon: 'success'
|
||||
})
|
||||
this.records = []
|
||||
this.total = 0
|
||||
this.totalPages = 0
|
||||
this.selectedIds = []
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: result.error || '清空失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
uni.hideLoading()
|
||||
console.error('清空记录失败:', e)
|
||||
uni.showToast({
|
||||
title: '清空失败:' + (e.message || '未知错误'),
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
formatTime(time) {
|
||||
if (!time) return ''
|
||||
if (Array.isArray(time)) {
|
||||
@@ -87,6 +269,7 @@ export default {
|
||||
const minute = String(date.getMinutes()).padStart(2, '0')
|
||||
return `${year}-${month}-${day} ${hour}:${minute}`
|
||||
},
|
||||
|
||||
getTypeIcon(type) {
|
||||
const icons = {
|
||||
bazi: '命',
|
||||
@@ -100,6 +283,7 @@ export default {
|
||||
}
|
||||
return icons[type] || '算'
|
||||
},
|
||||
|
||||
getTypeColor(type) {
|
||||
const colors = {
|
||||
bazi: '#3B82F6',
|
||||
@@ -113,6 +297,7 @@ export default {
|
||||
}
|
||||
return colors[type] || '#3B82F6'
|
||||
},
|
||||
|
||||
getTypeName(type) {
|
||||
const names = {
|
||||
bazi: '八字命理',
|
||||
@@ -126,6 +311,7 @@ export default {
|
||||
}
|
||||
return names[type] || '命理测算'
|
||||
},
|
||||
|
||||
viewDetail(item) {
|
||||
const app = getApp()
|
||||
if (!app.globalData) {
|
||||
@@ -169,6 +355,7 @@ export default {
|
||||
uni.navigateTo({ url: '/pages/daliuren/result' })
|
||||
}
|
||||
},
|
||||
|
||||
async deleteRecord(id, index) {
|
||||
uni.showModal({
|
||||
title: '确认删除',
|
||||
@@ -186,6 +373,11 @@ export default {
|
||||
title: '删除成功',
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
if (this.records.length === 0 && this.page > 1) {
|
||||
this.page--
|
||||
this.loadRecords()
|
||||
}
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: result.error || '删除失败',
|
||||
@@ -256,6 +448,97 @@ page {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
flex: 1;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 24rpx;
|
||||
padding: 20rpx 32rpx;
|
||||
font-size: 28rpx;
|
||||
border: 2rpx solid rgba(59, 130, 246, 0.2);
|
||||
}
|
||||
|
||||
.search-btn {
|
||||
background: linear-gradient(135deg, #3B82F6 0%, #1D4ED8 100%);
|
||||
color: #fff;
|
||||
border: none;
|
||||
padding: 0 32rpx;
|
||||
border-radius: 24rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.action-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 24rpx;
|
||||
padding: 20rpx 32rpx;
|
||||
margin-bottom: 24rpx;
|
||||
box-shadow: 0 8rpx 32rpx rgba(59, 130, 246, 0.1);
|
||||
}
|
||||
|
||||
.select-all {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
border: 3rpx solid #3B82F6;
|
||||
border-radius: 8rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.checkbox.checked {
|
||||
background: #3B82F6;
|
||||
}
|
||||
|
||||
.check-icon {
|
||||
color: #fff;
|
||||
font-size: 24rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.select-text {
|
||||
font-size: 28rpx;
|
||||
color: #1E40AF;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
padding: 12rpx 24rpx;
|
||||
border-radius: 16rpx;
|
||||
font-size: 24rpx;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.delete-btn {
|
||||
background: #FEE2E2;
|
||||
color: #DC2626;
|
||||
}
|
||||
|
||||
.clear-btn {
|
||||
background: #FEF3C7;
|
||||
color: #D97706;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 120rpx 0;
|
||||
@@ -295,6 +578,16 @@ page {
|
||||
border: 2rpx solid rgba(59, 130, 246, 0.1);
|
||||
}
|
||||
|
||||
.checkbox-wrapper {
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.record-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.record-icon {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
@@ -311,7 +604,7 @@ page {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.record-content {
|
||||
.record-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
@@ -356,4 +649,32 @@ page {
|
||||
color: #93C5FD;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
margin-top: 32rpx;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.page-btn {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
color: #3B82F6;
|
||||
border: 2rpx solid #3B82F6;
|
||||
padding: 12rpx 32rpx;
|
||||
border-radius: 16rpx;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.page-btn[disabled] {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.page-info {
|
||||
font-size: 28rpx;
|
||||
color: #1E40AF;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
@@ -213,7 +213,6 @@
|
||||
|
||||
<script>
|
||||
import { markdownToHtml } from '@/utils/markdownToHtml.js'
|
||||
import api from '@/utils/api.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
@@ -389,50 +388,42 @@ export default {
|
||||
return influences[sign] || '独特'
|
||||
},
|
||||
|
||||
async shareResult() {
|
||||
try {
|
||||
uni.showLoading({
|
||||
title: '生成分享内容...',
|
||||
mask: true
|
||||
})
|
||||
|
||||
const shareData = {
|
||||
name: this.result.name,
|
||||
sunSign: this.result.sunSign,
|
||||
moonSign: this.result.moonSign,
|
||||
risingSign: this.result.risingSign,
|
||||
interpretation: this.interpretation
|
||||
}
|
||||
|
||||
const res = await api.shareApi.zhanxing(shareData)
|
||||
|
||||
uni.hideLoading()
|
||||
|
||||
if (res.success) {
|
||||
uni.setClipboardData({
|
||||
data: res.data,
|
||||
success: () => {
|
||||
uni.showToast({
|
||||
title: '已复制到剪贴板',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
shareResult() {
|
||||
const shareText = `【${this.result.name || '某人'}的星盘解析】
|
||||
|
||||
☀️ 太阳星座:${this.result.sunSign || '-'}
|
||||
🌙 月亮星座:${this.result.moonSign || '-'}
|
||||
⬆️ 上升星座:${this.result.risingSign || '-'}
|
||||
|
||||
【性格特质】
|
||||
${this.interpretation.personality}
|
||||
|
||||
【感情运势】
|
||||
${this.interpretation.love}
|
||||
|
||||
【事业发展】
|
||||
${this.interpretation.career}
|
||||
|
||||
【财运状况】
|
||||
${this.interpretation.wealth}
|
||||
|
||||
【健康建议】
|
||||
${this.interpretation.health}
|
||||
|
||||
【人生建议】
|
||||
${this.interpretation.advice}
|
||||
|
||||
——来自玄学测算APP`
|
||||
|
||||
uni.setClipboardData({
|
||||
data: shareText,
|
||||
success: () => {
|
||||
uni.showToast({
|
||||
title: '分享失败',
|
||||
icon: 'none'
|
||||
title: '已复制到剪贴板',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
uni.hideLoading()
|
||||
console.error('分享错误:', e)
|
||||
uni.showToast({
|
||||
title: '分享失败:' + (e.message || '未知错误'),
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,11 +215,19 @@ const recordApi = {
|
||||
}
|
||||
})
|
||||
},
|
||||
getList: (userId) => {
|
||||
getList: (params) => {
|
||||
const data = {
|
||||
userId: params.userId || 'default_user',
|
||||
page: params.page || 1,
|
||||
size: params.size || 10
|
||||
}
|
||||
if (params.keyword) data.keyword = params.keyword
|
||||
if (params.type) data.type = params.type
|
||||
|
||||
return request({
|
||||
url: '/records/list',
|
||||
method: 'GET',
|
||||
data: { userId: userId || 'default_user' }
|
||||
data: data
|
||||
})
|
||||
},
|
||||
getDetail: (id) => {
|
||||
@@ -236,6 +244,13 @@ const recordApi = {
|
||||
data: { id: id }
|
||||
})
|
||||
},
|
||||
deleteBatch: (ids) => {
|
||||
return request({
|
||||
url: '/records/deleteBatch',
|
||||
method: 'POST',
|
||||
data: { ids: ids }
|
||||
})
|
||||
},
|
||||
clear: (userId) => {
|
||||
return request({
|
||||
url: '/records/clear',
|
||||
@@ -258,62 +273,6 @@ const shareApi = {
|
||||
url: '/share/view/' + shareId,
|
||||
method: 'GET'
|
||||
})
|
||||
},
|
||||
bazi: (data) => {
|
||||
return request({
|
||||
url: '/share/bazi',
|
||||
method: 'POST',
|
||||
data: { data: data }
|
||||
})
|
||||
},
|
||||
ziwei: (data) => {
|
||||
return request({
|
||||
url: '/share/ziwei',
|
||||
method: 'POST',
|
||||
data: { data: data }
|
||||
})
|
||||
},
|
||||
zhanxing: (data) => {
|
||||
return request({
|
||||
url: '/share/zhanxing',
|
||||
method: 'POST',
|
||||
data: { data: data }
|
||||
})
|
||||
},
|
||||
taluo: (data) => {
|
||||
return request({
|
||||
url: '/share/taluo',
|
||||
method: 'POST',
|
||||
data: { data: data }
|
||||
})
|
||||
},
|
||||
meihua: (data) => {
|
||||
return request({
|
||||
url: '/share/meihua',
|
||||
method: 'POST',
|
||||
data: { data: data }
|
||||
})
|
||||
},
|
||||
liuyao: (data) => {
|
||||
return request({
|
||||
url: '/share/liuyao',
|
||||
method: 'POST',
|
||||
data: { data: data }
|
||||
})
|
||||
},
|
||||
qimen: (data) => {
|
||||
return request({
|
||||
url: '/share/qimen',
|
||||
method: 'POST',
|
||||
data: { data: data }
|
||||
})
|
||||
},
|
||||
daliuren: (data) => {
|
||||
return request({
|
||||
url: '/share/daliuren',
|
||||
method: 'POST',
|
||||
data: { data: data }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user