feat: 完成工具菜单所有功能

- 后端ToolController实现6个工具API
- 前端创建6个工具页面
- 修改pages.json注册页面
- 修改api.js添加工具API
- 修改tools.vue添加跳转逻辑
This commit is contained in:
H1d3rOne committed 2026-03-08 01:06:24 +08:00
1 parent c85c819008
commit e021ce5bc9
10 files changed
+2292 -14

No files matched your search

@@ -0,0 +1,402 @@
package xuan.controller;
import com.nlf.calendar.Lunar;
import com.nlf.calendar.Solar;
import com.nlf.calendar.LunarYear;
import com.nlf.calendar.LunarMonth;
import org.springframework.web.bind.annotation.*;
import xuan.core.bazi.BaZi;
import xuan.core.bazi.settings.BaZiJiChuSetting;
import java.util.*;
@RestController
@RequestMapping("/api/tools")
public class ToolController {
@PostMapping("/lunar")
public Map<String, Object> lunarQuery(@RequestBody Map<String, Object> params) {
Map<String, Object> result = new HashMap<>();
try {
String date = params.get("date").toString();
int type = params.containsKey("type") ? Integer.parseInt(params.get("type").toString()) : 0;
Map<String, Object> data = new HashMap<>();
if (type == 0) {
Solar solar = Solar.fromYmdHms(
Integer.parseInt(date.substring(0, 4)),
Integer.parseInt(date.substring(5, 7)),
Integer.parseInt(date.substring(8, 10)),
params.containsKey("hour") ? Integer.parseInt(params.get("hour").toString()) : 0,
params.containsKey("minute") ? Integer.parseInt(params.get("minute").toString()) : 0,
0
);
Lunar lunar = solar.getLunar();
data.put("solar", solar.toString());
data.put("lunar", lunar.toString());
data.put("lunarYear", lunar.getYearInGanZhi());
data.put("lunarMonth", lunar.getMonthInGanZhi());
data.put("lunarDay", lunar.getDayInGanZhi());
data.put("lunarYearName", lunar.getYearShengXiao() + "年");
data.put("lunarMonthName", lunar.getMonthName());
data.put("lunarDayName", lunar.getDayName());
data.put("festival", lunar.getFestivals());
data.put("jieQi", lunar.getJieQi());
data.put("week", solar.getWeekInChinese());
data.put("constellation", solar.getXingZuo());
} else {
int year = Integer.parseInt(params.get("lunarYear").toString());
int month = Integer.parseInt(params.get("lunarMonth").toString());
int day = Integer.parseInt(params.get("lunarDay").toString());
boolean isLeap = params.containsKey("isLeap") && Boolean.parseBoolean(params.get("isLeap").toString());
Lunar lunar = Lunar.fromYmd(year, month, day, isLeap ? 1 : 0);
Solar solar = lunar.getSolar();
data.put("lunar", lunar.toString());
data.put("solar", solar.toString());
data.put("solarYear", solar.getYear());
data.put("solarMonth", solar.getMonth());
data.put("solarDay", solar.getDay());
}
result.put("success", true);
result.put("data", data);
} catch (Exception e) {
result.put("success", false);
result.put("error", e.getMessage());
}
return result;
}
@PostMapping("/ganzhi")
public Map<String, Object> ganZhiQuery(@RequestBody Map<String, Object> params) {
Map<String, Object> result = new HashMap<>();
try {
String date = params.get("date").toString();
int hour = params.containsKey("hour") ? Integer.parseInt(params.get("hour").toString()) : 0;
Solar solar = Solar.fromYmdHms(
Integer.parseInt(date.substring(0, 4)),
Integer.parseInt(date.substring(5, 7)),
Integer.parseInt(date.substring(8, 10)),
hour, 0, 0
);
Lunar lunar = solar.getLunar();
Map<String, Object> data = new HashMap<>();
data.put("yearGanZhi", lunar.getYearInGanZhi());
data.put("monthGanZhi", lunar.getMonthInGanZhi());
data.put("dayGanZhi", lunar.getDayInGanZhi());
data.put("hourGanZhi", lunar.getTimeInGanZhi());
data.put("yearGan", lunar.getYearGan());
data.put("yearZhi", lunar.getYearZhi());
data.put("monthGan", lunar.getMonthGan());
data.put("monthZhi", lunar.getMonthZhi());
data.put("dayGan", lunar.getDayGan());
data.put("dayZhi", lunar.getDayZhi());
data.put("hourGan", lunar.getTimeGan());
data.put("hourZhi", lunar.getTimeZhi());
result.put("success", true);
result.put("data", data);
} catch (Exception e) {
result.put("success", false);
result.put("error", e.getMessage());
}
return result;
}
@PostMapping("/shengxiao")
public Map<String, Object> shengXiaoQuery(@RequestBody Map<String, Object> params) {
Map<String, Object> result = new HashMap<>();
try {
int year = Integer.parseInt(params.get("year").toString());
Solar solar = Solar.fromYmd(year, 1, 1);
Lunar lunar = solar.getLunar();
String shengXiao = lunar.getYearShengXiao();
Map<String, Object> data = new HashMap<>();
data.put("year", year);
data.put("shengXiao", shengXiao);
String[] shengXiaoOrder = {"鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪"};
Map<String, String> shengXiaoInfo = new HashMap<>();
shengXiaoInfo.put("鼠", "子鼠,五行属水,聪明机智,适应力强");
shengXiaoInfo.put("牛", "丑牛,五行属土,勤劳踏实,责任心强");
shengXiaoInfo.put("虎", "寅虎,五行属木,勇敢自信,领导力强");
shengXiaoInfo.put("兔", "卯兔,五行属木,温柔善良,心思细腻");
shengXiaoInfo.put("龙", "辰龙,五行属土,气宇轩昂,有远大理想");
shengXiaoInfo.put("蛇", "巳蛇,五行属火,智慧深沉,洞察力强");
shengXiaoInfo.put("马", "午马,五行属火,热情奔放,行动力强");
shengXiaoInfo.put("羊", "未羊,五行属土,温文尔雅,富有同情心");
shengXiaoInfo.put("猴", "申猴,五行属金,聪明伶俐,多才多艺");
shengXiaoInfo.put("鸡", "酉鸡,五行属金,精明能干,善于表达");
shengXiaoInfo.put("狗", "戌狗,五行属土,忠诚可靠,正义感强");
shengXiaoInfo.put("猪", "亥猪,五行属水,善良宽厚,乐观豁达");
data.put("info", shengXiaoInfo.getOrDefault(shengXiao, "未知生肖"));
String ganZhi = lunar.getYearInGanZhi();
data.put("ganZhi", ganZhi);
result.put("success", true);
result.put("data", data);
} catch (Exception e) {
result.put("success", false);
result.put("error", e.getMessage());
}
return result;
}
@PostMapping("/xingzuo")
public Map<String, Object> xingZuoQuery(@RequestBody Map<String, Object> params) {
Map<String, Object> result = new HashMap<>();
try {
int month = Integer.parseInt(params.get("month").toString());
int day = Integer.parseInt(params.get("day").toString());
Solar solar = Solar.fromYmd(2000, month, day);
String xingZuo = solar.getXingZuo();
Map<String, Object> data = new HashMap<>();
data.put("month", month);
data.put("day", day);
data.put("xingZuo", xingZuo);
Map<String, Map<String, String>> xingZuoInfo = new HashMap<>();
xingZuoInfo.put("白羊座", Map.of(
"dateRange", "3月21日-4月19日",
"element", "火象星座",
"character", "热情、冲动、自信",
"desc", "白羊座是黄道十二宫的第一宫,代表着新的开始和生命力。白羊座的人充满活力,勇于冒险,具有领导才能。"
));
xingZuoInfo.put("金牛座", Map.of(
"dateRange", "4月20日-5月20日",
"element", "土象星座",
"character", "稳重、务实、固执",
"desc", "金牛座是黄道十二宫的第二宫,代表着物质和财富。金牛座的人踏实可靠,追求稳定,有很强的耐心。"
));
xingZuoInfo.put("双子座", Map.of(
"dateRange", "5月21日-6月21日",
"element", "风象星座",
"character", "聪明、善变、好奇",
"desc", "双子座是黄道十二宫的第三宫,代表着沟通和交流。双子座的人思维敏捷,善于表达,兴趣广泛。"
));
xingZuoInfo.put("巨蟹座", Map.of(
"dateRange", "6月22日-7月22日",
"element", "水象星座",
"character", "敏感、顾家、情绪化",
"desc", "巨蟹座是黄道十二宫的第四宫,代表着家庭和情感。巨蟹座的人重视家庭,情感丰富,有很强的保护欲。"
));
xingZuoInfo.put("狮子座", Map.of(
"dateRange", "7月23日-8月22日",
"element", "火象星座",
"character", "自信、慷慨、霸道",
"desc", "狮子座是黄道十二宫的第五宫,代表着创造力和自我表达。狮子座的人自信大方,有领导才能,喜欢成为焦点。"
));
xingZuoInfo.put("处女座", Map.of(
"dateRange", "8月23日-9月22日",
"element", "土象星座",
"character", "细心、完美主义、挑剔",
"desc", "处女座是黄道十二宫的第六宫,代表着分析和服务。处女座的人注重细节,追求完美,有很强的分析能力。"
));
xingZuoInfo.put("天秤座", Map.of(
"dateRange", "9月23日-10月23日",
"element", "风象星座",
"character", "优雅、公正、犹豫",
"desc", "天秤座是黄道十二宫的第七宫,代表着平衡和和谐。天秤座的人追求公正,善于社交,有很强的审美能力。"
));
xingZuoInfo.put("天蝎座", Map.of(
"dateRange", "10月24日-11月22日",
"element", "水象星座",
"character", "神秘、执着、多疑",
"desc", "天蝎座是黄道十二宫的第八宫,代表着转化和重生。天蝎座的人意志坚定,洞察力强,有很强的直觉。"
));
xingZuoInfo.put("射手座", Map.of(
"dateRange", "11月23日-12月21日",
"element", "火象星座",
"character", "乐观、自由、粗心",
"desc", "射手座是黄道十二宫的第九宫,代表着探索和哲学。射手座的人热爱自由,乐观开朗,有很强的冒险精神。"
));
xingZuoInfo.put("摩羯座", Map.of(
"dateRange", "12月22日-1月19日",
"element", "土象星座",
"character", "务实、有责任感、悲观",
"desc", "摩羯座是黄道十二宫的第十宫,代表着成就和责任。摩羯座的人有很强的责任感,追求成功,脚踏实地。"
));
xingZuoInfo.put("水瓶座", Map.of(
"dateRange", "1月20日-2月18日",
"element", "风象星座",
"character", "独立、创新、叛逆",
"desc", "水瓶座是黄道十二宫的第十一宫,代表着创新和人道主义。水瓶座的人思想前卫,独立自主,有很强的创造力。"
));
xingZuoInfo.put("双鱼座", Map.of(
"dateRange", "2月19日-3月20日",
"element", "水象星座",
"character", "浪漫、敏感、优柔寡断",
"desc", "双鱼座是黄道十二宫的最后一宫,代表着灵性和直觉。双鱼座的人富有想象力,感情丰富,有很强的同理心。"
));
Map<String, String> info = xingZuoInfo.getOrDefault(xingZuo, Map.of("desc", "未知星座"));
data.put("dateRange", info.get("dateRange"));
data.put("element", info.get("element"));
data.put("character", info.get("character"));
data.put("desc", info.get("desc"));
result.put("success", true);
result.put("data", data);
} catch (Exception e) {
result.put("success", false);
result.put("error", e.getMessage());
}
return result;
}
@PostMapping("/wuxing")
public Map<String, Object> wuXingQuery(@RequestBody Map<String, Object> params) {
Map<String, Object> result = new HashMap<>();
try {
String date = params.get("date").toString();
int hour = params.containsKey("hour") ? Integer.parseInt(params.get("hour").toString()) : 0;
Solar solar = Solar.fromYmdHms(
Integer.parseInt(date.substring(0, 4)),
Integer.parseInt(date.substring(5, 7)),
Integer.parseInt(date.substring(8, 10)),
hour, 0, 0
);
Lunar lunar = solar.getLunar();
String yearGan = lunar.getYearGan();
String monthGan = lunar.getMonthGan();
String dayGan = lunar.getDayGan();
String hourGan = lunar.getTimeGan();
Map<String, String> ganWuXing = new HashMap<>();
ganWuXing.put("甲", "木"); ganWuXing.put("乙", "木");
ganWuXing.put("丙", "火"); ganWuXing.put("丁", "火");
ganWuXing.put("戊", "土"); ganWuXing.put("己", "土");
ganWuXing.put("庚", "金"); ganWuXing.put("辛", "金");
ganWuXing.put("壬", "水"); ganWuXing.put("癸", "水");
Map<String, Object> data = new HashMap<>();
data.put("yearGan", yearGan);
data.put("yearWuXing", ganWuXing.get(yearGan));
data.put("monthGan", monthGan);
data.put("monthWuXing", ganWuXing.get(monthGan));
data.put("dayGan", dayGan);
data.put("dayWuXing", ganWuXing.get(dayGan));
data.put("hourGan", hourGan);
data.put("hourWuXing", ganWuXing.get(hourGan));
Map<String, Integer> wuXingCount = new HashMap<>();
wuXingCount.put("金", 0);
wuXingCount.put("木", 0);
wuXingCount.put("水", 0);
wuXingCount.put("火", 0);
wuXingCount.put("土", 0);
for (String gan : Arrays.asList(yearGan, monthGan, dayGan, hourGan)) {
String wx = ganWuXing.get(gan);
wuXingCount.put(wx, wuXingCount.get(wx) + 1);
}
String[] zhiList = {lunar.getYearZhi(), lunar.getMonthZhi(), lunar.getDayZhi(), lunar.getTimeZhi()};
Map<String, String> zhiWuXing = new HashMap<>();
zhiWuXing.put("子", "水"); zhiWuXing.put("丑", "土");
zhiWuXing.put("寅", "木"); zhiWuXing.put("卯", "木");
zhiWuXing.put("辰", "土"); zhiWuXing.put("巳", "火");
zhiWuXing.put("午", "火"); zhiWuXing.put("未", "土");
zhiWuXing.put("申", "金"); zhiWuXing.put("酉", "金");
zhiWuXing.put("戌", "土"); zhiWuXing.put("亥", "水");
for (String zhi : zhiList) {
String wx = zhiWuXing.get(zhi);
wuXingCount.put(wx, wuXingCount.get(wx) + 1);
}
data.put("wuXingCount", wuXingCount);
List<String> missing = new ArrayList<>();
for (Map.Entry<String, Integer> entry : wuXingCount.entrySet()) {
if (entry.getValue() == 0) {
missing.add(entry.getKey());
}
}
data.put("missing", missing);
Map<String, String> wuXingInfo = new HashMap<>();
wuXingInfo.put("金", "金主义,其性刚,其情烈。金盛之人骨肉相称,面方白净,眉高眼深。");
wuXingInfo.put("木", "木主仁,其性直,其情和。木盛之人丰姿秀丽,骨骼修长,手足细腻。");
wuXingInfo.put("水", "水主智,其性聪,其情善。水盛之人面黑有采,语言清和,为人深思熟虑。");
wuXingInfo.put("火", "火主礼,其性急,其情恭。火盛之人头小脚长,上尖下阔,浓眉小耳。");
wuXingInfo.put("土", "土主信,其性重,其情厚。土盛之人圆腰廓鼻,眉清目秀,口才声重。");
data.put("wuXingInfo", wuXingInfo);
result.put("success", true);
result.put("data", data);
} catch (Exception e) {
result.put("success", false);
result.put("error", e.getMessage());
}
return result;
}
@PostMapping("/jiri")
public Map<String, Object> jiRiQuery(@RequestBody Map<String, Object> params) {
Map<String, Object> result = new HashMap<>();
try {
String date = params.get("date").toString();
Solar solar = Solar.fromYmd(
Integer.parseInt(date.substring(0, 4)),
Integer.parseInt(date.substring(5, 7)),
Integer.parseInt(date.substring(8, 10))
);
Lunar lunar = solar.getLunar();
Map<String, Object> data = new HashMap<>();
data.put("solar", solar.toString());
data.put("lunar", lunar.toString());
data.put("ganZhi", lunar.getDayInGanZhi());
data.put("xingZuo", solar.getXingZuo());
data.put("week", solar.getWeekInChinese());
List<String> yi = lunar.getDayYi();
List<String> ji = lunar.getDayJi();
data.put("yi", yi);
data.put("ji", ji);
String[] chong = lunar.getDayChong().split(" ");
data.put("chong", chong.length > 0 ? chong[0] : "");
data.put("chongGan", lunar.getDayChongGan());
data.put("chongZhi", lunar.getDayChongZhi());
data.put("sha", lunar.getDaySha());
String jieQi = lunar.getJieQi();
data.put("jieQi", jieQi != null ? jieQi : "无");
List<String> festivals = lunar.getFestivals();
data.put("festivals", festivals);
List<String> solarFestivals = solar.getFestivals();
data.put("solarFestivals", solarFestivals);
boolean isGoodDay = yi.size() > ji.size();
data.put("isGoodDay", isGoodDay);
data.put("suggestion", isGoodDay ? "今日宜多行善事,适合办理重要事务" : "今日宜静不宜动,适合修身养性");
result.put("success", true);
result.put("data", data);
} catch (Exception e) {
result.put("success", false);
result.put("error", e.getMessage());
}
return result;
}
}
+48
View File
@@ -160,6 +160,54 @@
"navigationBarBackgroundColor": "#8B5CF6",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/tool-lunar/tool-lunar",
"style": {
"navigationBarTitleText": "农历查询",
"navigationBarBackgroundColor": "#3B82F6",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/tool-ganzhi/tool-ganzhi",
"style": {
"navigationBarTitleText": "干支查询",
"navigationBarBackgroundColor": "#10B981",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/tool-shengxiao/tool-shengxiao",
"style": {
"navigationBarTitleText": "生肖查询",
"navigationBarBackgroundColor": "#F59E0B",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/tool-xingzuo/tool-xingzuo",
"style": {
"navigationBarTitleText": "星座查询",
"navigationBarBackgroundColor": "#8B5CF6",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/tool-wuxing/tool-wuxing",
"style": {
"navigationBarTitleText": "五行查询",
"navigationBarBackgroundColor": "#EF4444",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/tool-jiri/tool-jiri",
"style": {
"navigationBarTitleText": "吉日查询",
"navigationBarBackgroundColor": "#EC4899",
"navigationBarTextStyle": "white"
}
}
],
"globalStyle": {
@@ -0,0 +1,284 @@
<template>
<view class="container">
<view class="header-card">
<text class="header-title">🕐 干支查询</text>
<text class="header-subtitle">年月日时干支</text>
</view>
<view class="form-card">
<view class="form-item">
<text class="form-label">日期</text>
<picker mode="date" :value="date" @change="onDateChange">
<view class="picker-value">{{ date }}</view>
</picker>
</view>
<view class="form-item">
<text class="form-label">时辰</text>
<picker mode="selector" :range="hours" :value="hourIndex" @change="onHourChange">
<view class="picker-value">{{ hours[hourIndex] }}</view>
</picker>
</view>
<button class="submit-btn" @click="query" :disabled="loading">
<text class="btn-text">{{ loading ? '查询中...' : '开始查询' }}</text>
</button>
</view>
<view class="result-card" v-if="result">
<view class="result-header">
<text class="result-title">查询结果</text>
</view>
<view class="result-content">
<view class="result-item">
<text class="item-label">年柱</text>
<text class="item-value highlight">{{ result.yearGanZhi }}</text>
</view>
<view class="result-item">
<text class="item-label">月柱</text>
<text class="item-value highlight">{{ result.monthGanZhi }}</text>
</view>
<view class="result-item">
<text class="item-label">日柱</text>
<text class="item-value highlight">{{ result.dayGanZhi }}</text>
</view>
<view class="result-item">
<text class="item-label">时柱</text>
<text class="item-value highlight">{{ result.hourGanZhi }}</text>
</view>
</view>
<view class="detail-card">
<text class="detail-title">四柱详解</text>
<view class="detail-item">
<text class="detail-label">年干:</text>
<text class="detail-value">{{ result.yearGan }} ({{ result.yearGan }}干)</text>
</view>
<view class="detail-item">
<text class="detail-label">年支:</text>
<text class="detail-value">{{ result.yearZhi }} ({{ result.yearZhi }}支)</text>
</view>
<view class="detail-item">
<text class="detail-label">月干:</text>
<text class="detail-value">{{ result.monthGan }}</text>
</view>
<view class="detail-item">
<text class="detail-label">月支:</text>
<text class="detail-value">{{ result.monthZhi }}</text>
</view>
<view class="detail-item">
<text class="detail-label">日干:</text>
<text class="detail-value">{{ result.dayGan }}</text>
</view>
<view class="detail-item">
<text class="detail-label">日支:</text>
<text class="detail-value">{{ result.dayZhi }}</text>
</view>
<view class="detail-item">
<text class="detail-label">时干:</text>
<text class="detail-value">{{ result.hourGan }}</text>
</view>
<view class="detail-item">
<text class="detail-label">时支:</text>
<text class="detail-value">{{ result.hourZhi }}</text>
</view>
</view>
</view>
</view>
</template>
<script>
import api from '@/utils/api.js'
export default {
data() {
return {
date: '2000-01-01',
hourIndex: 0,
hours: ['子时(23-1点)', '丑时(1-3点)', '寅时(3-5点)', '卯时(5-7点)', '辰时(7-9点)', '巳时(9-11点)', '午时(11-13点)', '未时(13-15点)', '申时(15-17点)', '酉时(17-19点)', '戌时(19-21点)', '亥时(21-23点)'],
hourValues: [23, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21],
loading: false,
result: null
}
},
methods: {
onDateChange(e) {
this.date = e.detail.value
},
onHourChange(e) {
this.hourIndex = e.detail.value
},
async query() {
this.loading = true
try {
const res = await api.toolApi.ganzhi({
date: this.date,
hour: this.hourValues[this.hourIndex]
})
if (res.success) {
this.result = res.data
} else {
uni.showToast({ title: res.error || '查询失败', icon: 'none' })
}
} catch (e) {
uni.showToast({ title: '查询失败', icon: 'none' })
} finally {
this.loading = false
}
}
}
}
</script>
<style>
page {
background: linear-gradient(180deg, #ECFDF5 0%, #D1FAE5 50%, #A7F3D0 100%);
min-height: 100vh;
}
.container {
padding: 32rpx;
}
.header-card {
background: linear-gradient(135deg, #10B981 0%, #059669 100%);
border-radius: 32rpx;
padding: 48rpx 32rpx;
text-align: center;
margin-bottom: 32rpx;
box-shadow: 0 16rpx 48rpx rgba(16, 185, 129, 0.25);
}
.header-title {
font-size: 44rpx;
font-weight: 700;
color: #ffffff;
display: block;
margin-bottom: 12rpx;
}
.header-subtitle {
font-size: 26rpx;
color: rgba(255, 255, 255, 0.8);
}
.form-card {
background: rgba(255, 255, 255, 0.95);
border-radius: 32rpx;
padding: 32rpx;
margin-bottom: 32rpx;
box-shadow: 0 8rpx 32rpx rgba(16, 185, 129, 0.08);
}
.form-item {
margin-bottom: 28rpx;
}
.form-label {
font-size: 28rpx;
color: #374151;
font-weight: 500;
display: block;
margin-bottom: 16rpx;
}
.picker-value {
padding: 24rpx;
background: #F9FAFB;
border-radius: 16rpx;
font-size: 28rpx;
color: #1F2937;
}
.submit-btn {
background: linear-gradient(135deg, #10B981 0%, #059669 100%);
border-radius: 24rpx;
padding: 32rpx;
text-align: center;
margin-top: 32rpx;
border: none;
}
.btn-text {
font-size: 32rpx;
font-weight: 600;
color: #ffffff;
}
.result-card {
background: rgba(255, 255, 255, 0.95);
border-radius: 32rpx;
padding: 32rpx;
box-shadow: 0 8rpx 32rpx rgba(16, 185, 129, 0.08);
}
.result-header {
margin-bottom: 24rpx;
}
.result-title {
font-size: 32rpx;
font-weight: 600;
color: #1F2937;
}
.result-content {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.result-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16rpx 0;
border-bottom: 1rpx solid #F3F4F6;
}
.item-label {
font-size: 28rpx;
color: #6B7280;
}
.item-value {
font-size: 28rpx;
color: #1F2937;
font-weight: 500;
}
.item-value.highlight {
font-size: 36rpx;
color: #059669;
font-weight: 700;
}
.detail-card {
margin-top: 32rpx;
padding-top: 24rpx;
border-top: 1rpx solid #E5E7EB;
}
.detail-title {
font-size: 28rpx;
font-weight: 600;
color: #374151;
display: block;
margin-bottom: 16rpx;
}
.detail-item {
display: flex;
margin-bottom: 12rpx;
}
.detail-label {
font-size: 26rpx;
color: #6B7280;
width: 100rpx;
}
.detail-value {
font-size: 26rpx;
color: #1F2937;
}
</style>
@@ -0,0 +1,370 @@
<template>
<view class="container">
<view class="header-card">
<text class="header-title">📆 吉日查询</text>
<text class="header-subtitle">黄道吉日查询</text>
</view>
<view class="form-card">
<view class="form-item">
<text class="form-label">查询日期</text>
<picker mode="date" :value="date" @change="onDateChange">
<view class="picker-value">{{ date }}</view>
</picker>
</view>
<button class="submit-btn" @click="query" :disabled="loading">
<text class="btn-text">{{ loading ? '查询中...' : '开始查询' }}</text>
</button>
</view>
<view class="result-card" v-if="result">
<view class="result-header">
<text class="result-title">{{ result.solar }}</text>
<text class="result-subtitle">{{ result.lunar }}</text>
</view>
<view class="day-status" :class="{ good: result.isGoodDay }">
<text class="status-icon">{{ result.isGoodDay ? '✨' : '🌙' }}</text>
<text class="status-text">{{ result.isGoodDay ? '吉日' : '平日' }}</text>
</view>
<view class="info-grid">
<view class="info-item">
<text class="info-label">干支</text>
<text class="info-value">{{ result.ganZhi }}</text>
</view>
<view class="info-item">
<text class="info-label">星期</text>
<text class="info-value">{{ result.week }}</text>
</view>
<view class="info-item">
<text class="info-label">星座</text>
<text class="info-value">{{ result.xingZuo }}</text>
</view>
<view class="info-item" v-if="result.jieQi">
<text class="info-label">节气</text>
<text class="info-value">{{ result.jieQi }}</text>
</view>
</view>
<view class="yi-ji-section">
<view class="yi-card">
<text class="card-title">宜</text>
<view class="tag-list">
<text class="tag yi" v-for="(item, index) in result.yi" :key="index">{{ item }}</text>
</view>
</view>
<view class="ji-card">
<text class="card-title">忌</text>
<view class="tag-list">
<text class="tag ji" v-for="(item, index) in result.ji" :key="index">{{ item }}</text>
</view>
</view>
</view>
<view class="chong-section">
<text class="section-title">冲煞</text>
<view class="chong-info">
<text class="chong-text">冲{{ result.chong }} ({{ result.chongGan }}{{ result.chongZhi }})</text>
<text class="sha-text">煞{{ result.sha }}</text>
</view>
</view>
<view class="festival-section" v-if="result.festivals && result.festivals.length > 0">
<text class="section-title">节日</text>
<text class="festival-text">{{ result.festivals.join('、') }}</text>
</view>
<view class="suggestion-section">
<text class="suggestion-text">{{ result.suggestion }}</text>
</view>
</view>
</view>
</template>
<script>
import api from '@/utils/api.js'
export default {
data() {
return {
date: new Date().toISOString().split('T')[0],
loading: false,
result: null
}
},
methods: {
onDateChange(e) {
this.date = e.detail.value
},
async query() {
this.loading = true
try {
const res = await api.toolApi.jiri({
date: this.date
})
if (res.success) {
this.result = res.data
} else {
uni.showToast({ title: res.error || '查询失败', icon: 'none' })
}
} catch (e) {
uni.showToast({ title: '查询失败', icon: 'none' })
} finally {
this.loading = false
}
}
}
}
</script>
<style>
page {
background: linear-gradient(180deg, #FDF2F8 0%, #FCE7F3 50%, #FBCFE8 100%);
min-height: 100vh;
}
.container {
padding: 32rpx;
}
.header-card {
background: linear-gradient(135deg, #EC4899 0%, #DB2777 100%);
border-radius: 32rpx;
padding: 48rpx 32rpx;
text-align: center;
margin-bottom: 32rpx;
box-shadow: 0 16rpx 48rpx rgba(236, 72, 153, 0.25);
}
.header-title {
font-size: 44rpx;
font-weight: 700;
color: #ffffff;
display: block;
margin-bottom: 12rpx;
}
.header-subtitle {
font-size: 26rpx;
color: rgba(255, 255, 255, 0.8);
}
.form-card {
background: rgba(255, 255, 255, 0.95);
border-radius: 32rpx;
padding: 32rpx;
margin-bottom: 32rpx;
box-shadow: 0 8rpx 32rpx rgba(236, 72, 153, 0.08);
}
.form-item {
margin-bottom: 28rpx;
}
.form-label {
font-size: 28rpx;
color: #374151;
font-weight: 500;
display: block;
margin-bottom: 16rpx;
}
.picker-value {
padding: 24rpx;
background: #F9FAFB;
border-radius: 16rpx;
font-size: 28rpx;
color: #1F2937;
}
.submit-btn {
background: linear-gradient(135deg, #EC4899 0%, #DB2777 100%);
border-radius: 24rpx;
padding: 32rpx;
text-align: center;
margin-top: 32rpx;
border: none;
}
.btn-text {
font-size: 32rpx;
font-weight: 600;
color: #ffffff;
}
.result-card {
background: rgba(255, 255, 255, 0.95);
border-radius: 32rpx;
padding: 32rpx;
box-shadow: 0 8rpx 32rpx rgba(236, 72, 153, 0.08);
}
.result-header {
text-align: center;
margin-bottom: 24rpx;
}
.result-title {
font-size: 36rpx;
font-weight: 700;
color: #1F2937;
display: block;
margin-bottom: 8rpx;
}
.result-subtitle {
font-size: 26rpx;
color: #6B7280;
}
.day-status {
display: flex;
flex-direction: column;
align-items: center;
padding: 24rpx;
background: #F3F4F6;
border-radius: 16rpx;
margin-bottom: 24rpx;
}
.day-status.good {
background: linear-gradient(135deg, #FEF3C7 0%, #FDE68A 100%);
}
.status-icon {
font-size: 48rpx;
margin-bottom: 8rpx;
}
.status-text {
font-size: 28rpx;
font-weight: 600;
color: #92400E;
}
.info-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16rpx;
margin-bottom: 24rpx;
}
.info-item {
display: flex;
justify-content: space-between;
padding: 16rpx;
background: #F9FAFB;
border-radius: 12rpx;
}
.info-label {
font-size: 26rpx;
color: #6B7280;
}
.info-value {
font-size: 26rpx;
color: #1F2937;
font-weight: 500;
}
.yi-ji-section {
display: flex;
gap: 16rpx;
margin-bottom: 24rpx;
}
.yi-card, .ji-card {
flex: 1;
padding: 20rpx;
border-radius: 16rpx;
}
.yi-card {
background: #ECFDF5;
}
.ji-card {
background: #FEF2F2;
}
.card-title {
font-size: 28rpx;
font-weight: 600;
display: block;
margin-bottom: 12rpx;
}
.yi-card .card-title {
color: #059669;
}
.ji-card .card-title {
color: #DC2626;
}
.tag-list {
display: flex;
flex-wrap: wrap;
gap: 8rpx;
}
.tag {
padding: 4rpx 12rpx;
border-radius: 8rpx;
font-size: 22rpx;
}
.tag.yi {
background: #D1FAE5;
color: #065F46;
}
.tag.ji {
background: #FECACA;
color: #991B1B;
}
.section-title {
font-size: 28rpx;
font-weight: 600;
color: #374151;
display: block;
margin-bottom: 12rpx;
}
.chong-section, .festival-section {
margin-bottom: 24rpx;
padding-top: 24rpx;
border-top: 1rpx solid #F3F4F6;
}
.chong-info {
display: flex;
gap: 24rpx;
}
.chong-text, .sha-text {
font-size: 26rpx;
color: #6B7280;
}
.festival-text {
font-size: 26rpx;
color: #DB2777;
}
.suggestion-section {
padding: 20rpx;
background: #FDF2F8;
border-radius: 16rpx;
}
.suggestion-text {
font-size: 26rpx;
color: #9D174D;
text-align: center;
}
</style>
@@ -0,0 +1,338 @@
<template>
<view class="container">
<view class="header-card">
<text class="header-title">📅 农历查询</text>
<text class="header-subtitle">公历农历互转</text>
</view>
<view class="form-card">
<view class="form-item">
<text class="form-label">查询方式</text>
<view class="type-tabs">
<view class="type-tab" :class="{ active: queryType === 0 }" @click="queryType = 0">
<text>公历转农历</text>
</view>
<view class="type-tab" :class="{ active: queryType === 1 }" @click="queryType = 1">
<text>农历转公历</text>
</view>
</view>
</view>
<view v-if="queryType === 0">
<view class="form-item">
<text class="form-label">公历日期</text>
<picker mode="date" :value="solarDate" @change="onDateChange">
<view class="picker-value">{{ solarDate }}</view>
</picker>
</view>
<view class="form-item">
<text class="form-label">时辰</text>
<picker mode="selector" :range="hours" :value="hourIndex" @change="onHourChange">
<view class="picker-value">{{ hours[hourIndex] }}</view>
</picker>
</view>
</view>
<view v-if="queryType === 1">
<view class="form-item">
<text class="form-label">农历年份</text>
<picker mode="selector" :range="years" :value="yearIndex" @change="onYearChange">
<view class="picker-value">{{ years[yearIndex] }}</view>
</picker>
</view>
<view class="form-item">
<text class="form-label">农历月份</text>
<picker mode="selector" :range="months" :value="monthIndex" @change="onMonthChange">
<view class="picker-value">{{ months[monthIndex] }}</view>
</picker>
</view>
<view class="form-item">
<text class="form-label">农历日期</text>
<picker mode="selector" :range="days" :value="dayIndex" @change="onDayChange">
<view class="picker-value">{{ days[dayIndex] }}</view>
</picker>
</view>
<view class="form-item">
<view class="checkbox-item" @click="isLeap = !isLeap">
<view class="checkbox" :class="{ checked: isLeap }"></view>
<text class="checkbox-label">闰月</text>
</view>
</view>
</view>
<button class="submit-btn" @click="query" :disabled="loading">
<text class="btn-text">{{ loading ? '查询中...' : '开始查询' }}</text>
</button>
</view>
<view class="result-card" v-if="result">
<view class="result-header">
<text class="result-title">查询结果</text>
</view>
<view class="result-content">
<view class="result-item">
<text class="item-label">公历</text>
<text class="item-value">{{ result.solar }}</text>
</view>
<view class="result-item">
<text class="item-label">农历</text>
<text class="item-value">{{ result.lunar }}</text>
</view>
<view class="result-item">
<text class="item-label">干支</text>
<text class="item-value">{{ result.lunarYear }}年 {{ result.lunarMonth }}月 {{ result.lunarDay }}日</text>
</view>
<view class="result-item">
<text class="item-label">生肖</text>
<text class="item-value">{{ result.lunarYearName }}</text>
</view>
<view class="result-item" v-if="result.week">
<text class="item-label">星期</text>
<text class="item-value">{{ result.week }}</text>
</view>
<view class="result-item" v-if="result.constellation">
<text class="item-label">星座</text>
<text class="item-value">{{ result.constellation }}</text>
</view>
<view class="result-item" v-if="result.jieQi">
<text class="item-label">节气</text>
<text class="item-value">{{ result.jieQi }}</text>
</view>
</view>
</view>
</view>
</template>
<script>
import api from '@/utils/api.js'
export default {
data() {
return {
queryType: 0,
solarDate: '2000-01-01',
hourIndex: 0,
hours: ['子时(23-1点)', '丑时(1-3点)', '寅时(3-5点)', '卯时(5-7点)', '辰时(7-9点)', '巳时(9-11点)', '午时(11-13点)', '未时(13-15点)', '申时(15-17点)', '酉时(17-19点)', '戌时(19-21点)', '亥时(21-23点)'],
hourValues: [23, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21],
yearIndex: 50,
years: [],
monthIndex: 0,
months: ['正月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '冬月', '腊月'],
dayIndex: 0,
days: ['初一', '初二', '初三', '初四', '初五', '初六', '初七', '初八', '初九', '初十', '十一', '十二', '十三', '十四', '十五', '十六', '十七', '十八', '十九', '二十', '廿一', '廿二', '廿三', '廿四', '廿五', '廿六', '廿七', '廿八', '廿九', '三十'],
isLeap: false,
loading: false,
result: null
}
},
created() {
for (let i = 1900; i <= 2100; i++) {
this.years.push(i + '年')
}
this.yearIndex = this.years.indexOf(new Date().getFullYear() + '年')
},
methods: {
onDateChange(e) {
this.solarDate = e.detail.value
},
onHourChange(e) {
this.hourIndex = e.detail.value
},
onYearChange(e) {
this.yearIndex = e.detail.value
},
onMonthChange(e) {
this.monthIndex = e.detail.value
},
onDayChange(e) {
this.dayIndex = e.detail.value
},
async query() {
this.loading = true
try {
let params = { type: this.queryType }
if (this.queryType === 0) {
params.date = this.solarDate
params.hour = this.hourValues[this.hourIndex]
} else {
params.lunarYear = this.years[this.yearIndex].replace('年', '')
params.lunarMonth = this.monthIndex + 1
params.lunarDay = this.dayIndex + 1
params.isLeap = this.isLeap
}
const res = await api.toolApi.lunar(params)
if (res.success) {
this.result = res.data
} else {
uni.showToast({ title: res.error || '查询失败', icon: 'none' })
}
} catch (e) {
uni.showToast({ title: '查询失败', icon: 'none' })
} finally {
this.loading = false
}
}
}
}
</script>
<style>
page {
background: linear-gradient(180deg, #EFF6FF 0%, #DBEAFE 50%, #BFDBFE 100%);
min-height: 100vh;
}
.container {
padding: 32rpx;
}
.header-card {
background: linear-gradient(135deg, #3B82F6 0%, #1D4ED8 100%);
border-radius: 32rpx;
padding: 48rpx 32rpx;
text-align: center;
margin-bottom: 32rpx;
box-shadow: 0 16rpx 48rpx rgba(59, 130, 246, 0.25);
}
.header-title {
font-size: 44rpx;
font-weight: 700;
color: #ffffff;
display: block;
margin-bottom: 12rpx;
}
.header-subtitle {
font-size: 26rpx;
color: rgba(255, 255, 255, 0.8);
}
.form-card {
background: rgba(255, 255, 255, 0.95);
border-radius: 32rpx;
padding: 32rpx;
margin-bottom: 32rpx;
box-shadow: 0 8rpx 32rpx rgba(59, 130, 246, 0.08);
}
.form-item {
margin-bottom: 28rpx;
}
.form-label {
font-size: 28rpx;
color: #374151;
font-weight: 500;
display: block;
margin-bottom: 16rpx;
}
.type-tabs {
display: flex;
gap: 16rpx;
}
.type-tab {
flex: 1;
text-align: center;
padding: 20rpx;
background: #F3F4F6;
border-radius: 16rpx;
font-size: 26rpx;
color: #6B7280;
}
.type-tab.active {
background: linear-gradient(135deg, #3B82F6 0%, #1D4ED8 100%);
color: #ffffff;
}
.picker-value {
padding: 24rpx;
background: #F9FAFB;
border-radius: 16rpx;
font-size: 28rpx;
color: #1F2937;
}
.checkbox-item {
display: flex;
align-items: center;
gap: 16rpx;
}
.checkbox {
width: 40rpx;
height: 40rpx;
border: 4rpx solid #D1D5DB;
border-radius: 8rpx;
}
.checkbox.checked {
background: #3B82F6;
border-color: #3B82F6;
}
.checkbox-label {
font-size: 28rpx;
color: #374151;
}
.submit-btn {
background: linear-gradient(135deg, #3B82F6 0%, #1D4ED8 100%);
border-radius: 24rpx;
padding: 32rpx;
text-align: center;
margin-top: 32rpx;
border: none;
}
.btn-text {
font-size: 32rpx;
font-weight: 600;
color: #ffffff;
}
.result-card {
background: rgba(255, 255, 255, 0.95);
border-radius: 32rpx;
padding: 32rpx;
box-shadow: 0 8rpx 32rpx rgba(59, 130, 246, 0.08);
}
.result-header {
margin-bottom: 24rpx;
}
.result-title {
font-size: 32rpx;
font-weight: 600;
color: #1F2937;
}
.result-content {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.result-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16rpx 0;
border-bottom: 1rpx solid #F3F4F6;
}
.item-label {
font-size: 28rpx;
color: #6B7280;
}
.item-value {
font-size: 28rpx;
color: #1F2937;
font-weight: 500;
}
</style>
@@ -0,0 +1,219 @@
<template>
<view class="container">
<view class="header-card">
<text class="header-title">🐉 生肖查询</text>
<text class="header-subtitle">十二生肖属性</text>
</view>
<view class="form-card">
<view class="form-item">
<text class="form-label">出生年份</text>
<picker mode="selector" :range="years" :value="yearIndex" @change="onYearChange">
<view class="picker-value">{{ years[yearIndex] }}</view>
</picker>
</view>
<button class="submit-btn" @click="query" :disabled="loading">
<text class="btn-text">{{ loading ? '查询中...' : '开始查询' }}</text>
</button>
</view>
<view class="result-card" v-if="result">
<view class="result-header">
<text class="result-title">查询结果</text>
</view>
<view class="result-content">
<view class="shengxiao-display">
<text class="shengxiao-icon">{{ getShengXiaoIcon(result.shengXiao) }}</text>
<text class="shengxiao-name">{{ result.shengXiao }}</text>
<text class="shengxiao-ganzhi">{{ result.ganZhi }}年</text>
</view>
<view class="info-card">
<text class="info-text">{{ result.info }}</text>
</view>
</view>
</view>
</view>
</template>
<script>
import api from '@/utils/api.js'
export default {
data() {
return {
yearIndex: 50,
years: [],
loading: false,
result: null
}
},
created() {
for (let i = 1900; i <= 2100; i++) {
this.years.push(i + '年')
}
this.yearIndex = this.years.indexOf(new Date().getFullYear() + '年')
},
methods: {
onYearChange(e) {
this.yearIndex = e.detail.value
},
getShengXiaoIcon(name) {
const icons = {
'鼠': '🐭', '牛': '🐮', '虎': '🐯', '兔': '🐰',
'龙': '🐲', '蛇': '🐍', '马': '🐴', '羊': '🐑',
'猴': '🐵', '鸡': '🐔', '狗': '🐶', '猪': '🐷'
}
return icons[name] || '🐉'
},
async query() {
this.loading = true
try {
const res = await api.toolApi.shengxiao({
year: this.years[this.yearIndex].replace('年', '')
})
if (res.success) {
this.result = res.data
} else {
uni.showToast({ title: res.error || '查询失败', icon: 'none' })
}
} catch (e) {
uni.showToast({ title: '查询失败', icon: 'none' })
} finally {
this.loading = false
}
}
}
}
</script>
<style>
page {
background: linear-gradient(180deg, #FFFBEB 0%, #FEF3C7 50%, #FDE68A 100%);
min-height: 100vh;
}
.container {
padding: 32rpx;
}
.header-card {
background: linear-gradient(135deg, #F59E0B 0%, #D97706 100%);
border-radius: 32rpx;
padding: 48rpx 32rpx;
text-align: center;
margin-bottom: 32rpx;
box-shadow: 0 16rpx 48rpx rgba(245, 158, 11, 0.25);
}
.header-title {
font-size: 44rpx;
font-weight: 700;
color: #ffffff;
display: block;
margin-bottom: 12rpx;
}
.header-subtitle {
font-size: 26rpx;
color: rgba(255, 255, 255, 0.8);
}
.form-card {
background: rgba(255, 255, 255, 0.95);
border-radius: 32rpx;
padding: 32rpx;
margin-bottom: 32rpx;
box-shadow: 0 8rpx 32rpx rgba(245, 158, 11, 0.08);
}
.form-item {
margin-bottom: 28rpx;
}
.form-label {
font-size: 28rpx;
color: #374151;
font-weight: 500;
display: block;
margin-bottom: 16rpx;
}
.picker-value {
padding: 24rpx;
background: #F9FAFB;
border-radius: 16rpx;
font-size: 28rpx;
color: #1F2937;
}
.submit-btn {
background: linear-gradient(135deg, #F59E0B 0%, #D97706 100%);
border-radius: 24rpx;
padding: 32rpx;
text-align: center;
margin-top: 32rpx;
border: none;
}
.btn-text {
font-size: 32rpx;
font-weight: 600;
color: #ffffff;
}
.result-card {
background: rgba(255, 255, 255, 0.95);
border-radius: 32rpx;
padding: 32rpx;
box-shadow: 0 8rpx 32rpx rgba(245, 158, 11, 0.08);
}
.result-header {
margin-bottom: 24rpx;
}
.result-title {
font-size: 32rpx;
font-weight: 600;
color: #1F2937;
}
.shengxiao-display {
display: flex;
flex-direction: column;
align-items: center;
padding: 40rpx 0;
}
.shengxiao-icon {
font-size: 120rpx;
margin-bottom: 20rpx;
}
.shengxiao-name {
font-size: 48rpx;
font-weight: 700;
color: #D97706;
margin-bottom: 12rpx;
}
.shengxiao-ganzhi {
font-size: 28rpx;
color: #6B7280;
}
.info-card {
background: #FFFBEB;
border-radius: 16rpx;
padding: 24rpx;
margin-top: 24rpx;
}
.info-text {
font-size: 26rpx;
color: #92400E;
line-height: 1.6;
}
</style>
@@ -0,0 +1,312 @@
<template>
<view class="container">
<view class="header-card">
<text class="header-title">🔥 五行查询</text>
<text class="header-subtitle">五行属性分析</text>
</view>
<view class="form-card">
<view class="form-item">
<text class="form-label">出生日期</text>
<picker mode="date" :value="date" @change="onDateChange">
<view class="picker-value">{{ date }}</view>
</picker>
</view>
<view class="form-item">
<text class="form-label">出生时辰</text>
<picker mode="selector" :range="hours" :value="hourIndex" @change="onHourChange">
<view class="picker-value">{{ hours[hourIndex] }}</view>
</picker>
</view>
<button class="submit-btn" @click="query" :disabled="loading">
<text class="btn-text">{{ loading ? '查询中...' : '开始查询' }}</text>
</button>
</view>
<view class="result-card" v-if="result">
<view class="result-header">
<text class="result-title">五行分析</text>
</view>
<view class="wuxing-chart">
<view class="wuxing-item" v-for="(count, name) in result.wuXingCount" :key="name">
<view class="wuxing-bar" :style="{ height: (count * 20) + 'rpx', background: getWuXingColor(name) }"></view>
<text class="wuxing-name">{{ name }}</text>
<text class="wuxing-count">{{ count }}</text>
</view>
</view>
<view class="detail-section">
<text class="section-title">四柱五行</text>
<view class="detail-item">
<text class="detail-label">年柱:</text>
<text class="detail-value">{{ result.yearGan }}({{ result.yearWuXing }})</text>
</view>
<view class="detail-item">
<text class="detail-label">月柱:</text>
<text class="detail-value">{{ result.monthGan }}({{ result.monthWuXing }})</text>
</view>
<view class="detail-item">
<text class="detail-label">日柱:</text>
<text class="detail-value">{{ result.dayGan }}({{ result.dayWuXing }})</text>
</view>
<view class="detail-item">
<text class="detail-label">时柱:</text>
<text class="detail-value">{{ result.hourGan }}({{ result.hourWuXing }})</text>
</view>
</view>
<view class="missing-section" v-if="result.missing && result.missing.length > 0">
<text class="section-title">五行缺失</text>
<view class="missing-tags">
<text class="missing-tag" v-for="item in result.missing" :key="item" :style="{ background: getWuXingColor(item) }">{{ item }}</text>
</view>
</view>
<view class="info-section">
<text class="section-title">五行释义</text>
<view class="info-item" v-for="(info, name) in result.wuXingInfo" :key="name">
<text class="info-name" :style="{ color: getWuXingColor(name) }">{{ name }}</text>
<text class="info-desc">{{ info }}</text>
</view>
</view>
</view>
</view>
</template>
<script>
import api from '@/utils/api.js'
export default {
data() {
return {
date: '2000-01-01',
hourIndex: 0,
hours: ['子时(23-1点)', '丑时(1-3点)', '寅时(3-5点)', '卯时(5-7点)', '辰时(7-9点)', '巳时(9-11点)', '午时(11-13点)', '未时(13-15点)', '申时(15-17点)', '酉时(17-19点)', '戌时(19-21点)', '亥时(21-23点)'],
hourValues: [23, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21],
loading: false,
result: null
}
},
methods: {
onDateChange(e) {
this.date = e.detail.value
},
onHourChange(e) {
this.hourIndex = e.detail.value
},
getWuXingColor(name) {
const colors = {
'金': 'linear-gradient(135deg, #F59E0B 0%, #D97706 100%)',
'木': 'linear-gradient(135deg, #10B981 0%, #059669 100%)',
'水': 'linear-gradient(135deg, #3B82F6 0%, #1D4ED8 100%)',
'火': 'linear-gradient(135deg, #EF4444 0%, #DC2626 100%)',
'土': 'linear-gradient(135deg, #A78BFA 0%, #7C3AED 100%)'
}
return colors[name] || '#6B7280'
},
async query() {
this.loading = true
try {
const res = await api.toolApi.wuxing({
date: this.date,
hour: this.hourValues[this.hourIndex]
})
if (res.success) {
this.result = res.data
} else {
uni.showToast({ title: res.error || '查询失败', icon: 'none' })
}
} catch (e) {
uni.showToast({ title: '查询失败', icon: 'none' })
} finally {
this.loading = false
}
}
}
}
</script>
<style>
page {
background: linear-gradient(180deg, #FEF2F2 0%, #FECACA 50%, #FCA5A5 100%);
min-height: 100vh;
}
.container {
padding: 32rpx;
}
.header-card {
background: linear-gradient(135deg, #EF4444 0%, #DC2626 100%);
border-radius: 32rpx;
padding: 48rpx 32rpx;
text-align: center;
margin-bottom: 32rpx;
box-shadow: 0 16rpx 48rpx rgba(239, 68, 68, 0.25);
}
.header-title {
font-size: 44rpx;
font-weight: 700;
color: #ffffff;
display: block;
margin-bottom: 12rpx;
}
.header-subtitle {
font-size: 26rpx;
color: rgba(255, 255, 255, 0.8);
}
.form-card {
background: rgba(255, 255, 255, 0.95);
border-radius: 32rpx;
padding: 32rpx;
margin-bottom: 32rpx;
box-shadow: 0 8rpx 32rpx rgba(239, 68, 68, 0.08);
}
.form-item {
margin-bottom: 28rpx;
}
.form-label {
font-size: 28rpx;
color: #374151;
font-weight: 500;
display: block;
margin-bottom: 16rpx;
}
.picker-value {
padding: 24rpx;
background: #F9FAFB;
border-radius: 16rpx;
font-size: 28rpx;
color: #1F2937;
}
.submit-btn {
background: linear-gradient(135deg, #EF4444 0%, #DC2626 100%);
border-radius: 24rpx;
padding: 32rpx;
text-align: center;
margin-top: 32rpx;
border: none;
}
.btn-text {
font-size: 32rpx;
font-weight: 600;
color: #ffffff;
}
.result-card {
background: rgba(255, 255, 255, 0.95);
border-radius: 32rpx;
padding: 32rpx;
box-shadow: 0 8rpx 32rpx rgba(239, 68, 68, 0.08);
}
.result-header {
margin-bottom: 24rpx;
}
.result-title {
font-size: 32rpx;
font-weight: 600;
color: #1F2937;
}
.wuxing-chart {
display: flex;
justify-content: space-around;
align-items: flex-end;
height: 200rpx;
padding: 20rpx 0;
border-bottom: 1rpx solid #F3F4F6;
}
.wuxing-item {
display: flex;
flex-direction: column;
align-items: center;
}
.wuxing-bar {
width: 40rpx;
border-radius: 8rpx 8rpx 0 0;
min-height: 20rpx;
}
.wuxing-name {
font-size: 24rpx;
color: #6B7280;
margin-top: 8rpx;
}
.wuxing-count {
font-size: 20rpx;
color: #9CA3AF;
}
.section-title {
font-size: 28rpx;
font-weight: 600;
color: #374151;
display: block;
margin-bottom: 16rpx;
}
.detail-section, .missing-section, .info-section {
margin-top: 24rpx;
padding-top: 24rpx;
border-top: 1rpx solid #F3F4F6;
}
.detail-item {
display: flex;
margin-bottom: 12rpx;
}
.detail-label {
font-size: 26rpx;
color: #6B7280;
width: 100rpx;
}
.detail-value {
font-size: 26rpx;
color: #1F2937;
}
.missing-tags {
display: flex;
gap: 16rpx;
}
.missing-tag {
padding: 8rpx 24rpx;
border-radius: 20rpx;
font-size: 26rpx;
color: #ffffff;
}
.info-item {
margin-bottom: 16rpx;
}
.info-name {
font-size: 26rpx;
font-weight: 600;
margin-right: 8rpx;
}
.info-desc {
font-size: 24rpx;
color: #6B7280;
line-height: 1.5;
}
</style>
@@ -0,0 +1,263 @@
<template>
<view class="container">
<view class="header-card">
<text class="header-title">⭐ 星座查询</text>
<text class="header-subtitle">十二星座运势</text>
</view>
<view class="form-card">
<view class="form-item">
<text class="form-label">出生月份</text>
<picker mode="selector" :range="months" :value="monthIndex" @change="onMonthChange">
<view class="picker-value">{{ months[monthIndex] }}</view>
</picker>
</view>
<view class="form-item">
<text class="form-label">出生日期</text>
<picker mode="selector" :range="days" :value="dayIndex" @change="onDayChange">
<view class="picker-value">{{ days[dayIndex] }}</view>
</picker>
</view>
<button class="submit-btn" @click="query" :disabled="loading">
<text class="btn-text">{{ loading ? '查询中...' : '开始查询' }}</text>
</button>
</view>
<view class="result-card" v-if="result">
<view class="result-header">
<text class="result-title">查询结果</text>
</view>
<view class="result-content">
<view class="xingzuo-display">
<text class="xingzuo-icon">{{ getXingZuoIcon(result.xingZuo) }}</text>
<text class="xingzuo-name">{{ result.xingZuo }}</text>
<text class="xingzuo-date">{{ result.dateRange }}</text>
</view>
<view class="info-list">
<view class="info-item">
<text class="info-label">元素</text>
<text class="info-value">{{ result.element }}</text>
</view>
<view class="info-item">
<text class="info-label">性格</text>
<text class="info-value">{{ result.character }}</text>
</view>
</view>
<view class="desc-card">
<text class="desc-text">{{ result.desc }}</text>
</view>
</view>
</view>
</view>
</template>
<script>
import api from '@/utils/api.js'
export default {
data() {
return {
monthIndex: 0,
months: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
dayIndex: 0,
days: [],
loading: false,
result: null
}
},
created() {
for (let i = 1; i <= 31; i++) {
this.days.push(i + '日')
}
},
methods: {
onMonthChange(e) {
this.monthIndex = e.detail.value
},
onDayChange(e) {
this.dayIndex = e.detail.value
},
getXingZuoIcon(name) {
const icons = {
'白羊座': '♈', '金牛座': '♉', '双子座': '♊', '巨蟹座': '♋',
'狮子座': '♌', '处女座': '♍', '天秤座': '♎', '天蝎座': '♏',
'射手座': '♐', '摩羯座': '♑', '水瓶座': '♒', '双鱼座': '♓'
}
return icons[name] || '⭐'
},
async query() {
this.loading = true
try {
const res = await api.toolApi.xingzuo({
month: this.monthIndex + 1,
day: this.dayIndex + 1
})
if (res.success) {
this.result = res.data
} else {
uni.showToast({ title: res.error || '查询失败', icon: 'none' })
}
} catch (e) {
uni.showToast({ title: '查询失败', icon: 'none' })
} finally {
this.loading = false
}
}
}
}
</script>
<style>
page {
background: linear-gradient(180deg, #F5F3FF 0%, #EDE9FE 50%, #DDD6FE 100%);
min-height: 100vh;
}
.container {
padding: 32rpx;
}
.header-card {
background: linear-gradient(135deg, #8B5CF6 0%, #7C3AED 100%);
border-radius: 32rpx;
padding: 48rpx 32rpx;
text-align: center;
margin-bottom: 32rpx;
box-shadow: 0 16rpx 48rpx rgba(139, 92, 246, 0.25);
}
.header-title {
font-size: 44rpx;
font-weight: 700;
color: #ffffff;
display: block;
margin-bottom: 12rpx;
}
.header-subtitle {
font-size: 26rpx;
color: rgba(255, 255, 255, 0.8);
}
.form-card {
background: rgba(255, 255, 255, 0.95);
border-radius: 32rpx;
padding: 32rpx;
margin-bottom: 32rpx;
box-shadow: 0 8rpx 32rpx rgba(139, 92, 246, 0.08);
}
.form-item {
margin-bottom: 28rpx;
}
.form-label {
font-size: 28rpx;
color: #374151;
font-weight: 500;
display: block;
margin-bottom: 16rpx;
}
.picker-value {
padding: 24rpx;
background: #F9FAFB;
border-radius: 16rpx;
font-size: 28rpx;
color: #1F2937;
}
.submit-btn {
background: linear-gradient(135deg, #8B5CF6 0%, #7C3AED 100%);
border-radius: 24rpx;
padding: 32rpx;
text-align: center;
margin-top: 32rpx;
border: none;
}
.btn-text {
font-size: 32rpx;
font-weight: 600;
color: #ffffff;
}
.result-card {
background: rgba(255, 255, 255, 0.95);
border-radius: 32rpx;
padding: 32rpx;
box-shadow: 0 8rpx 32rpx rgba(139, 92, 246, 0.08);
}
.result-header {
margin-bottom: 24rpx;
}
.result-title {
font-size: 32rpx;
font-weight: 600;
color: #1F2937;
}
.xingzuo-display {
display: flex;
flex-direction: column;
align-items: center;
padding: 40rpx 0;
}
.xingzuo-icon {
font-size: 120rpx;
margin-bottom: 20rpx;
}
.xingzuo-name {
font-size: 48rpx;
font-weight: 700;
color: #7C3AED;
margin-bottom: 12rpx;
}
.xingzuo-date {
font-size: 28rpx;
color: #6B7280;
}
.info-list {
margin-top: 24rpx;
}
.info-item {
display: flex;
justify-content: space-between;
padding: 16rpx 0;
border-bottom: 1rpx solid #F3F4F6;
}
.info-label {
font-size: 28rpx;
color: #6B7280;
}
.info-value {
font-size: 28rpx;
color: #1F2937;
font-weight: 500;
}
.desc-card {
background: #F5F3FF;
border-radius: 16rpx;
padding: 24rpx;
margin-top: 24rpx;
}
.desc-text {
font-size: 26rpx;
color: #5B21B6;
line-height: 1.6;
}
</style>
+8 -9
View File
@@ -37,20 +37,19 @@ export default {
data() {
return {
tools: [
{ name: '农历查询', desc: '公历农历互转', icon: '📅', color: 'linear-gradient(135deg, #3B82F6 0%, #1D4ED8 100%)' },
{ name: '干支查询', desc: '年月日时干支', icon: '🕐', color: 'linear-gradient(135deg, #10B981 0%, #059669 100%)' },
{ name: '生肖查询', desc: '十二生肖属性', icon: '🐉', color: 'linear-gradient(135deg, #F59E0B 0%, #D97706 100%)' },
{ name: '星座查询', desc: '十二星座运势', icon: '⭐', color: 'linear-gradient(135deg, #8B5CF6 0%, #7C3AED 100%)' },
{ name: '五行查询', desc: '五行属性分析', icon: '🔥', color: 'linear-gradient(135deg, #EF4444 0%, #DC2626 100%)' },
{ name: '吉日查询', desc: '黄道吉日查询', icon: '📆', color: 'linear-gradient(135deg, #EC4899 0%, #DB2777 100%)' }
{ name: '农历查询', desc: '公历农历互转', icon: '📅', color: 'linear-gradient(135deg, #3B82F6 0%, #1D4ED8 100%)', path: '/pages/tool-lunar/tool-lunar' },
{ name: '干支查询', desc: '年月日时干支', icon: '🕐', color: 'linear-gradient(135deg, #10B981 0%, #059669 100%)', path: '/pages/tool-ganzhi/tool-ganzhi' },
{ name: '生肖查询', desc: '十二生肖属性', icon: '🐉', color: 'linear-gradient(135deg, #F59E0B 0%, #D97706 100%)', path: '/pages/tool-shengxiao/tool-shengxiao' },
{ name: '星座查询', desc: '十二星座运势', icon: '⭐', color: 'linear-gradient(135deg, #8B5CF6 0%, #7C3AED 100%)', path: '/pages/tool-xingzuo/tool-xingzuo' },
{ name: '五行查询', desc: '五行属性分析', icon: '🔥', color: 'linear-gradient(135deg, #EF4444 0%, #DC2626 100%)', path: '/pages/tool-wuxing/tool-wuxing' },
{ name: '吉日查询', desc: '黄道吉日查询', icon: '📆', color: 'linear-gradient(135deg, #EC4899 0%, #DB2777 100%)', path: '/pages/tool-jiri/tool-jiri' }
]
}
},
methods: {
openTool(item) {
uni.showToast({
title: `${item.name}功能开发中`,
icon: 'none'
uni.navigateTo({
url: item.path
})
}
}
+48 -5
View File
@@ -13,11 +13,7 @@ const request = (options) => {
timeout: 30000,
success: (res) => {
if (res.statusCode === 200) {
if (res.data.success) {
resolve(res.data.data)
} else {
reject(new Error(res.data.error || '请求失败'))
}
resolve(res.data)
} else {
reject(new Error('网络请求失败: ' + res.statusCode))
}
@@ -35,6 +31,7 @@ const baziApi = {
url: '/bazi/paipan',
method: 'POST',
data: {
userId: data.userId || 'default_user',
name: data.name || '某人',
sex: data.sex || 1,
date: data.date,
@@ -224,6 +221,51 @@ const recordApi = {
}
}
const toolApi = {
lunar: (data) => {
return request({
url: '/tools/lunar',
method: 'POST',
data: data
})
},
ganzhi: (data) => {
return request({
url: '/tools/ganzhi',
method: 'POST',
data: data
})
},
shengxiao: (data) => {
return request({
url: '/tools/shengxiao',
method: 'POST',
data: data
})
},
xingzuo: (data) => {
return request({
url: '/tools/xingzuo',
method: 'POST',
data: data
})
},
wuxing: (data) => {
return request({
url: '/tools/wuxing',
method: 'POST',
data: data
})
},
jiri: (data) => {
return request({
url: '/tools/jiri',
method: 'POST',
data: data
})
}
}
export default {
baziApi,
liuyaoApi,
@@ -233,5 +275,6 @@ export default {
zhanxingApi,
taLuoApi,
recordApi,
toolApi,
request
}