mirror of
https://github.com/patdelphi/suanming.git
synced 2026-02-27 21:23:12 +08:00
feat: 优化首页布局和Docker配置
- 调整首页四个模块为4个一排的响应式布局 - 优化立即体验按钮高度对齐,使用flex布局确保视觉统一 - 升级Dockerfile支持Node 20和Puppeteer,优化构建性能 - 修复AI解读404错误处理,支持奇门遁甲类型 - 优化奇门盘移动端显示,解决重叠问题 - 完善Docker配置文件,提升部署成功率
This commit is contained in:
@@ -46,9 +46,8 @@ tests/
|
|||||||
# Development tools
|
# Development tools
|
||||||
.eslintrc*
|
.eslintrc*
|
||||||
.prettierrc*
|
.prettierrc*
|
||||||
tailwind.config.js
|
|
||||||
vite.config.ts
|
|
||||||
tsconfig*.json
|
|
||||||
components.json
|
components.json
|
||||||
|
|
||||||
# Logs
|
# Logs
|
||||||
|
|||||||
27
Dockerfile
27
Dockerfile
@@ -1,12 +1,33 @@
|
|||||||
# 使用官方Node.js运行时作为基础镜像
|
# 使用官方Node.js运行时作为基础镜像
|
||||||
FROM node:18-alpine
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
# 更换Alpine镜像源为清华大学
|
||||||
|
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories
|
||||||
|
|
||||||
|
# Install python and build tools for native modules
|
||||||
|
RUN apk add --no-cache python3 make g++
|
||||||
|
|
||||||
# 设置工作目录
|
# 设置工作目录
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
# --- Puppeteer 相关的配置和安装 ---
|
||||||
|
# 阻止 puppeteer 自动下载 Chromium
|
||||||
|
ENV PUPPETEER_SKIP_DOWNLOAD=true
|
||||||
|
# 安装 Chromium 浏览器
|
||||||
|
RUN apk add --no-cache chromium
|
||||||
|
# 设置 puppeteer 查找浏览器的路径
|
||||||
|
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
|
||||||
|
# --- Puppeteer 相关的配置和安装 ---
|
||||||
|
|
||||||
# 复制package.json和package-lock.json
|
# 复制package.json和package-lock.json
|
||||||
COPY package.json package-lock.json ./
|
COPY package.json package-lock.json ./
|
||||||
|
|
||||||
|
# 设置npm镜像源
|
||||||
|
RUN npm config set registry https://registry.npmmirror.com
|
||||||
|
|
||||||
|
# 强制清理npm缓存
|
||||||
|
RUN npm cache clean --force
|
||||||
|
|
||||||
# 安装所有依赖(包括开发依赖用于构建前端)
|
# 安装所有依赖(包括开发依赖用于构建前端)
|
||||||
RUN npm ci
|
RUN npm ci
|
||||||
|
|
||||||
@@ -14,10 +35,10 @@ RUN npm ci
|
|||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# 构建前端
|
# 构建前端
|
||||||
RUN npm run build
|
RUN npm run build:prod
|
||||||
|
|
||||||
# 清理开发依赖,只保留生产依赖
|
# 清理开发依赖,只保留生产依赖
|
||||||
RUN npm ci --only=production
|
RUN npm ci --omit=dev
|
||||||
|
|
||||||
# 创建数据目录用于SQLite数据库
|
# 创建数据目录用于SQLite数据库
|
||||||
RUN mkdir -p /app/data
|
RUN mkdir -p /app/data
|
||||||
|
|||||||
1434
docs/qimen_theory.md
Normal file
1434
docs/qimen_theory.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -292,7 +292,7 @@ const CompleteQimenAnalysis: React.FC<QimenAnalysisProps> = ({ analysis, classNa
|
|||||||
return String(value);
|
return String(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 渲染奇门盘九宫格(参考传统样式)
|
// 渲染专业奇门盘九宫格(参考传统专业样式)
|
||||||
const renderQimenPan = () => {
|
const renderQimenPan = () => {
|
||||||
if (!qimenPan || !qimenPan.dipan) return null;
|
if (!qimenPan || !qimenPan.dipan) return null;
|
||||||
|
|
||||||
@@ -304,80 +304,164 @@ const CompleteQimenAnalysis: React.FC<QimenAnalysisProps> = ({ analysis, classNa
|
|||||||
];
|
];
|
||||||
|
|
||||||
const palaceNames = ['坎', '坤', '震', '巽', '中', '乾', '兑', '艮', '离'];
|
const palaceNames = ['坎', '坤', '震', '巽', '中', '乾', '兑', '艮', '离'];
|
||||||
const palacePositions = ['一', '二', '三', '四', '五', '六', '七', '八', '九'];
|
const palaceNumbers = ['一', '二', '三', '四', '五', '六', '七', '八', '九'];
|
||||||
|
const palaceElements = ['水', '土', '木', '木', '土', '金', '金', '土', '火'];
|
||||||
|
|
||||||
|
// 地支对应
|
||||||
|
const palaceZhi = ['子', '未', '卯', '辰', '戊', '戌', '酉', '丑', '午'];
|
||||||
|
|
||||||
|
// 获取宫位颜色
|
||||||
|
const getPalaceColor = (palaceIndex: number, palace: any) => {
|
||||||
|
const isCenter = palaceIndex === 4;
|
||||||
|
if (isCenter) return 'bg-yellow-100 border-yellow-400';
|
||||||
|
|
||||||
|
// 根据九星设置颜色
|
||||||
|
const starColors = {
|
||||||
|
'天蓬': 'bg-blue-50 border-blue-300',
|
||||||
|
'天任': 'bg-green-50 border-green-300',
|
||||||
|
'天冲': 'bg-red-50 border-red-300',
|
||||||
|
'天辅': 'bg-purple-50 border-purple-300',
|
||||||
|
'天英': 'bg-orange-50 border-orange-300',
|
||||||
|
'天芮': 'bg-gray-50 border-gray-300',
|
||||||
|
'天柱': 'bg-indigo-50 border-indigo-300',
|
||||||
|
'天心': 'bg-pink-50 border-pink-300',
|
||||||
|
'天禽': 'bg-yellow-50 border-yellow-300'
|
||||||
|
};
|
||||||
|
|
||||||
|
return starColors[palace?.star] || 'bg-gray-50 border-gray-300';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取门的颜色
|
||||||
|
const getDoorColor = (door: string) => {
|
||||||
|
const doorColors = {
|
||||||
|
'休门': 'text-blue-600',
|
||||||
|
'生门': 'text-green-600',
|
||||||
|
'伤门': 'text-red-600',
|
||||||
|
'杜门': 'text-gray-600',
|
||||||
|
'景门': 'text-orange-600',
|
||||||
|
'死门': 'text-black',
|
||||||
|
'惊门': 'text-purple-600',
|
||||||
|
'开门': 'text-yellow-600'
|
||||||
|
};
|
||||||
|
return doorColors[door] || 'text-gray-600';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取神的颜色
|
||||||
|
const getGodColor = (god: string) => {
|
||||||
|
const godColors = {
|
||||||
|
'值符': 'text-red-700',
|
||||||
|
'腾蛇': 'text-red-500',
|
||||||
|
'太阴': 'text-blue-700',
|
||||||
|
'六合': 'text-green-700',
|
||||||
|
'白虎': 'text-gray-700',
|
||||||
|
'玄武': 'text-black',
|
||||||
|
'九地': 'text-yellow-700',
|
||||||
|
'九天': 'text-purple-700'
|
||||||
|
};
|
||||||
|
return godColors[god] || 'text-gray-600';
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
{/* 四柱信息 */}
|
{/* 四柱信息和基本信息 */}
|
||||||
{timeInfo?.ganzhi && (
|
{timeInfo?.ganzhi && (
|
||||||
<div className="text-center mb-6">
|
<div className="bg-gradient-to-r from-red-50 to-yellow-50 p-4 rounded-lg border border-red-200">
|
||||||
<div className="text-lg font-bold text-red-800 mb-2">
|
<div className="text-center space-y-2">
|
||||||
四柱:{timeInfo.ganzhi.year?.gan}{timeInfo.ganzhi.year?.zhi} {timeInfo.ganzhi.month?.gan}{timeInfo.ganzhi.month?.zhi} {timeInfo.ganzhi.day?.gan}{timeInfo.ganzhi.day?.zhi} {timeInfo.ganzhi.hour?.gan}{timeInfo.ganzhi.hour?.zhi}
|
<div className="text-lg font-bold text-red-800">
|
||||||
|
四柱:{timeInfo.ganzhi.year?.gan}{timeInfo.ganzhi.year?.zhi}年 {timeInfo.ganzhi.month?.gan}{timeInfo.ganzhi.month?.zhi}月 {timeInfo.ganzhi.day?.gan}{timeInfo.ganzhi.day?.zhi}日 {timeInfo.ganzhi.hour?.gan}{timeInfo.ganzhi.hour?.zhi}时
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-2 text-sm text-red-700">
|
||||||
|
<div>节气:{timeInfo.jieqi || '未知'}</div>
|
||||||
|
<div>元运:{timeInfo.yuan || '未知'}</div>
|
||||||
|
<div>局数:{qimenPan?.yindun ? '阴遁' : '阳遁'}{qimenPan?.jushu || ''}局</div>
|
||||||
|
<div>旬首:甲戌旬</div>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-2 md:grid-cols-3 gap-2 text-sm text-red-700">
|
||||||
|
<div>值符:{timeInfo.zhifu || '未知'}</div>
|
||||||
|
<div>值使:{timeInfo.zhishi || '未知'}</div>
|
||||||
|
<div>空亡:申酉</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm text-red-700 space-y-1">
|
|
||||||
<div>节气:{timeInfo.jieqi || '未知'} ~ {timeInfo.yuan || '未知'} {qimenPan?.yindun ? '阴遁' : '阳遁'}{qimenPan?.jushu || ''}局</div>
|
|
||||||
<div>值符:{timeInfo.zhifu || '未知'} 值使:{timeInfo.zhishi || '未知'}</div>
|
|
||||||
<div>旬首:甲戌旬 空亡:申酉 马星:寅</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* 传统九宫格布局 */}
|
{/* 专业九宫格奇门盘 */}
|
||||||
<div className="max-w-lg mx-auto">
|
<div className="w-full max-w-sm mx-auto p-4">
|
||||||
<div className="grid grid-cols-3 gap-0 border-2 border-black">
|
<div className="grid grid-cols-3 gap-3 w-full">
|
||||||
{gridPositions.map((row, rowIndex) =>
|
{gridPositions.map((row, rowIndex) =>
|
||||||
row.map((palaceIndex, colIndex) => {
|
row.map((palaceIndex, colIndex) => {
|
||||||
const palace = qimenPan.dipan[palaceIndex];
|
const palace = qimenPan.dipan[palaceIndex];
|
||||||
const isCenter = rowIndex === 1 && colIndex === 1;
|
const isCenter = palaceIndex === 4;
|
||||||
|
const colorClass = getPalaceColor(palaceIndex, palace);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={`${rowIndex}-${colIndex}`}
|
key={`${rowIndex}-${colIndex}`}
|
||||||
className={cn(
|
className={cn(
|
||||||
'aspect-square border border-black p-2 text-xs bg-yellow-50 relative',
|
'aspect-square border-2 relative flex flex-col justify-between p-1',
|
||||||
isCenter && 'bg-yellow-100'
|
'min-h-[80px] min-w-[80px]',
|
||||||
|
colorClass,
|
||||||
|
isCenter && 'border-4 border-yellow-500 bg-yellow-200'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{/* 宫位标识 */}
|
{/* 顶部行:宫位信息 */}
|
||||||
<div className="absolute top-0 left-0 text-xs text-gray-600 font-bold">
|
<div className="flex justify-between items-start text-xs leading-none">
|
||||||
{palaceNames[palaceIndex]}
|
<div className="text-red-800 font-bold">
|
||||||
|
<div>{palaceNames[palaceIndex]}</div>
|
||||||
|
<div className="text-gray-600">{palaceNumbers[palaceIndex]}</div>
|
||||||
|
</div>
|
||||||
|
<div className="text-center">
|
||||||
|
<div className="text-blue-700 font-medium">{palaceElements[palaceIndex]}</div>
|
||||||
|
<div className="text-gray-700">{palaceZhi[palaceIndex]}</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 宫位内容 */}
|
{/* 中心区域:主要信息 */}
|
||||||
<div className="h-full flex flex-col justify-center items-center space-y-1">
|
<div className="flex-1 flex flex-col justify-center items-center">
|
||||||
{/* 天干 */}
|
{/* 天干 - 最大最显眼 */}
|
||||||
{palace?.gan && (
|
{palace?.gan && (
|
||||||
<div className="text-black font-bold text-lg">
|
<div className="text-black font-bold text-lg sm:text-xl md:text-2xl">
|
||||||
{palace.gan}
|
{palace.gan}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* 九星 */}
|
{/* 九星 */}
|
||||||
{palace?.star && (
|
{palace?.star && (
|
||||||
<div className="text-blue-700 font-medium text-sm">
|
<div className="text-blue-700 font-bold text-xs">
|
||||||
{palace.star}
|
{palace.star}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* 八门 */}
|
{/* 底部行:门神信息 */}
|
||||||
|
<div className="flex justify-between items-end text-xs font-bold">
|
||||||
|
{/* 左下角:八门 */}
|
||||||
|
<div>
|
||||||
{palace?.door && (
|
{palace?.door && (
|
||||||
<div className="text-green-700 font-medium text-sm">
|
<div className={getDoorColor(palace.door)}>
|
||||||
{palace.door}
|
{palace.door}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* 八神 */}
|
{/* 右下角:八神 */}
|
||||||
|
<div>
|
||||||
{palace?.god && (
|
{palace?.god && (
|
||||||
<div className="text-purple-700 font-medium text-sm">
|
<div className={getGodColor(palace.god)}>
|
||||||
{palace.god}
|
{palace.god}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 宫位编号 */}
|
|
||||||
<div className="absolute bottom-0 right-0 text-xs text-gray-600">
|
|
||||||
{palacePositions[palaceIndex]}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* 特殊标记 */}
|
||||||
|
{palace?.special && (
|
||||||
|
<div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2">
|
||||||
|
<div className="w-4 h-4 rounded-full bg-red-500 text-white text-xs flex items-center justify-center font-bold">
|
||||||
|
{palace.special}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
@@ -385,36 +469,64 @@ const CompleteQimenAnalysis: React.FC<QimenAnalysisProps> = ({ analysis, classNa
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 四害颜色说明 */}
|
{/* 颜色和符号说明 */}
|
||||||
<div className="text-center text-sm text-red-700">
|
<div className="bg-white p-4 rounded-lg border border-gray-200">
|
||||||
四害颜色:<span className="text-red-600">刑</span><span className="text-green-600">墓</span><span className="text-purple-600">迫</span> <span className="text-red-600">【刑墓】</span> <span className="text-gray-600">空○</span>
|
<h4 className="font-bold text-red-800 mb-3 text-center">奇门盘要素说明</h4>
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 奇门盘构成要素详解 */}
|
|
||||||
<div className="bg-white p-4 rounded-lg border-l-4 border-indigo-500">
|
|
||||||
<h4 className="font-bold text-red-800 mb-3">奇门盘构成要素详解</h4>
|
|
||||||
<div className="grid md:grid-cols-2 gap-4 text-sm">
|
<div className="grid md:grid-cols-2 gap-4 text-sm">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<div className="flex items-center">
|
<div className="font-semibold text-red-700 mb-2">九星(天时):</div>
|
||||||
<span className="w-3 h-3 bg-blue-500 rounded mr-2"></span>
|
<div className="grid grid-cols-2 gap-1 text-xs">
|
||||||
<span className="text-red-700"><strong>九星:</strong>天蓬、天任、天冲、天辅、天英、天芮、天柱、天心、天禽,代表天时因素</span>
|
<div className="flex items-center"><span className="w-3 h-3 bg-blue-200 rounded mr-1"></span>天蓬(水)</div>
|
||||||
</div>
|
<div className="flex items-center"><span className="w-3 h-3 bg-green-200 rounded mr-1"></span>天任(土)</div>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center"><span className="w-3 h-3 bg-red-200 rounded mr-1"></span>天冲(木)</div>
|
||||||
<span className="w-3 h-3 bg-green-500 rounded mr-2"></span>
|
<div className="flex items-center"><span className="w-3 h-3 bg-purple-200 rounded mr-1"></span>天辅(木)</div>
|
||||||
<span className="text-red-700"><strong>八门:</strong>休、生、伤、杜、景、死、惊、开,代表人事因素</span>
|
<div className="flex items-center"><span className="w-3 h-3 bg-orange-200 rounded mr-1"></span>天英(火)</div>
|
||||||
|
<div className="flex items-center"><span className="w-3 h-3 bg-gray-200 rounded mr-1"></span>天芮(土)</div>
|
||||||
|
<div className="flex items-center"><span className="w-3 h-3 bg-indigo-200 rounded mr-1"></span>天柱(金)</div>
|
||||||
|
<div className="flex items-center"><span className="w-3 h-3 bg-pink-200 rounded mr-1"></span>天心(金)</div>
|
||||||
|
<div className="flex items-center"><span className="w-3 h-3 bg-yellow-200 rounded mr-1"></span>天禽(土)</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<div className="flex items-center">
|
<div className="font-semibold text-red-700 mb-2">八门(人事):</div>
|
||||||
<span className="w-3 h-3 bg-purple-500 rounded mr-2"></span>
|
<div className="grid grid-cols-2 gap-1 text-xs">
|
||||||
<span className="text-red-700"><strong>八神:</strong>值符、腾蛇、太阴、六合、白虎、玄武、九地、九天,代表神煞因素</span>
|
<div className="text-blue-600">休门(水)</div>
|
||||||
</div>
|
<div className="text-green-600">生门(土)</div>
|
||||||
<div className="flex items-center">
|
<div className="text-red-600">伤门(木)</div>
|
||||||
<span className="w-3 h-3 bg-orange-500 rounded mr-2"></span>
|
<div className="text-gray-600">杜门(木)</div>
|
||||||
<span className="text-red-700"><strong>天干:</strong>甲乙丙丁戊己庚辛壬癸,代表地利因素</span>
|
<div className="text-orange-600">景门(火)</div>
|
||||||
|
<div className="text-black">死门(土)</div>
|
||||||
|
<div className="text-purple-600">惊门(金)</div>
|
||||||
|
<div className="text-yellow-600">开门(金)</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mt-4 pt-4 border-t border-gray-200">
|
||||||
|
<div className="font-semibold text-red-700 mb-2">八神(神煞):</div>
|
||||||
|
<div className="grid grid-cols-4 gap-2 text-xs">
|
||||||
|
<div className="text-red-700">值符</div>
|
||||||
|
<div className="text-red-500">腾蛇</div>
|
||||||
|
<div className="text-blue-700">太阴</div>
|
||||||
|
<div className="text-green-700">六合</div>
|
||||||
|
<div className="text-gray-700">白虎</div>
|
||||||
|
<div className="text-black">玄武</div>
|
||||||
|
<div className="text-yellow-700">九地</div>
|
||||||
|
<div className="text-purple-700">九天</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 奇门盘解读要点 */}
|
||||||
|
<div className="bg-gradient-to-r from-blue-50 to-purple-50 p-4 rounded-lg border border-blue-200">
|
||||||
|
<h4 className="font-bold text-red-800 mb-3">奇门盘解读要点</h4>
|
||||||
|
<div className="text-sm text-red-700 space-y-2">
|
||||||
|
<div>• <strong>天干:</strong>位于宫位中央,代表事物的本质和核心</div>
|
||||||
|
<div>• <strong>九星:</strong>位于天干下方,代表天时和自然规律</div>
|
||||||
|
<div>• <strong>八门:</strong>位于左下角,代表人事活动和行动方式</div>
|
||||||
|
<div>• <strong>八神:</strong>位于右下角,代表神煞和隐性因素</div>
|
||||||
|
<div>• <strong>宫位:</strong>九宫代表不同的方位和领域</div>
|
||||||
|
<div>• <strong>颜色:</strong>不同颜色代表不同的五行属性和吉凶性质</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import { toast } from 'sonner';
|
|||||||
interface AIInterpretationButtonProps {
|
interface AIInterpretationButtonProps {
|
||||||
analysisData?: any; // 分析数据对象(可选)
|
analysisData?: any; // 分析数据对象(可选)
|
||||||
analysisMarkdown?: string; // 直接传递的MD内容(可选)
|
analysisMarkdown?: string; // 直接传递的MD内容(可选)
|
||||||
analysisType: 'bazi' | 'ziwei' | 'yijing';
|
analysisType: 'bazi' | 'ziwei' | 'yijing' | 'qimen';
|
||||||
recordId?: number; // 分析记录ID,用于AI解读
|
recordId?: number; // 分析记录ID,用于AI解读
|
||||||
className?: string;
|
className?: string;
|
||||||
variant?: 'default' | 'outline' | 'ghost';
|
variant?: 'default' | 'outline' | 'ghost';
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ const HomePage: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Features Section */}
|
{/* Features Section */}
|
||||||
<div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-4 md:gap-6 relative max-w-6xl mx-auto px-4">
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 md:gap-6 relative max-w-7xl mx-auto px-4">
|
||||||
{/* 装饰元素 - 仅在大屏幕显示 */}
|
{/* 装饰元素 - 仅在大屏幕显示 */}
|
||||||
<div className="absolute -left-12 top-1/4 w-16 h-16 opacity-15 pointer-events-none hidden xl:block">
|
<div className="absolute -left-12 top-1/4 w-16 h-16 opacity-15 pointer-events-none hidden xl:block">
|
||||||
<img
|
<img
|
||||||
@@ -185,15 +185,15 @@ const HomePage: React.FC = () => {
|
|||||||
{features.map((feature, index) => {
|
{features.map((feature, index) => {
|
||||||
const Icon = feature.icon;
|
const Icon = feature.icon;
|
||||||
return (
|
return (
|
||||||
<ChineseCard key={index} variant="elevated" className="text-center sm:col-span-1 lg:col-span-1 last:sm:col-span-2 last:lg:col-span-1">
|
<ChineseCard key={index} variant="elevated" className="text-center h-full flex flex-col">
|
||||||
<ChineseCardHeader>
|
<ChineseCardHeader>
|
||||||
<div className="w-12 h-12 md:w-14 md:h-14 bg-gradient-to-br from-yellow-400 to-yellow-600 rounded-full flex items-center justify-center mx-auto mb-3 md:mb-4 shadow-lg border-2 border-red-600">
|
<div className="w-12 h-12 md:w-14 md:h-14 bg-gradient-to-br from-yellow-400 to-yellow-600 rounded-full flex items-center justify-center mx-auto mb-3 md:mb-4 shadow-lg border-2 border-red-600">
|
||||||
<Icon className="h-6 w-6 md:h-7 md:w-7 text-red-800" />
|
<Icon className="h-6 w-6 md:h-7 md:w-7 text-red-800" />
|
||||||
</div>
|
</div>
|
||||||
<ChineseCardTitle className="text-red-600 text-heading-md font-bold font-chinese">{feature.title}</ChineseCardTitle>
|
<ChineseCardTitle className="text-red-600 text-heading-md font-bold font-chinese">{feature.title}</ChineseCardTitle>
|
||||||
</ChineseCardHeader>
|
</ChineseCardHeader>
|
||||||
<ChineseCardContent>
|
<ChineseCardContent className="flex-1 flex flex-col">
|
||||||
<p className="text-gray-700 leading-relaxed font-chinese mb-4 text-body-md">{feature.description}</p>
|
<p className="text-gray-700 leading-relaxed font-chinese mb-4 text-body-md flex-1">{feature.description}</p>
|
||||||
{user && (
|
{user && (
|
||||||
<Link to={feature.link}>
|
<Link to={feature.link}>
|
||||||
<ChineseButton variant="secondary" className="w-full">
|
<ChineseButton variant="secondary" className="w-full">
|
||||||
|
|||||||
@@ -1052,6 +1052,9 @@ export const getAIInterpretation = async (readingId: number): Promise<AIInterpre
|
|||||||
tokensUsed: data.data.tokens_used
|
tokensUsed: data.data.tokens_used
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
} else if (response.status === 404) {
|
||||||
|
// 404是正常情况,表示还没有AI解读记录
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user