更新前后端配置并清理仓库内容
This commit is contained in:
@@ -38,8 +38,8 @@
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
|
||||
<!-- Preload fonts -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link rel="preconnect" href="//fonts.googleapis.com">
|
||||
<link rel="preconnect" href="//fonts.gstatic.com" crossorigin>
|
||||
|
||||
<title>万象口袋</title>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"short_name": "万象口袋",
|
||||
"name": "万象口袋 - 多功能聚合应用",
|
||||
"description": "万象口袋 - 多功能聚合应用",
|
||||
"name": "万象口袋",
|
||||
"description": "万象口袋",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/icons/icon-192.png",
|
||||
@@ -36,9 +36,9 @@
|
||||
"categories": ["utilities", "productivity", "entertainment"],
|
||||
"screenshots": [
|
||||
{
|
||||
"src": "data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 800'><rect width='400' height='800' fill='%23667eea'/><text x='200' y='400' text-anchor='middle' fill='white' font-size='32'>万象口袋</text></svg>",
|
||||
"type": "image/svg+xml",
|
||||
"sizes": "400x800",
|
||||
"src": "/icons/icon-192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192",
|
||||
"form_factor": "narrow"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
/**
|
||||
* 60s API 聚合接口配置
|
||||
* 基于 https://docs.60s-api.viki.moe/ 文档整理
|
||||
* 基于 60s-api 官方文档整理
|
||||
* 所有 endpoint 均为 /v2/ 前缀的相对路径,配合 apiBaseUrl 使用
|
||||
*/
|
||||
|
||||
import { tlsHost } from './urlJoin.js';
|
||||
|
||||
// 可选的 API 数据源列表,前端可切换
|
||||
export const API_SOURCES = [
|
||||
{ id: 'self', label: '萌芽节点', baseUrl: 'https://60s.api.shumengya.top' },
|
||||
{ id: 'official', label: '官方节点', baseUrl: 'https://60s.viki.moe' },
|
||||
{ id: 'self', label: '萌芽节点', baseUrl: tlsHost('60s.api.shumengya.top') },
|
||||
{ id: 'official', label: '官方节点', baseUrl: tlsHost('60s.viki.moe') },
|
||||
];
|
||||
|
||||
// 默认 API 数据源
|
||||
@@ -126,6 +128,9 @@ const TOOLBOX_IMAGE = [
|
||||
{ id: 'tb-img-b64', title: '图片转 Base64', icon: '🔀', link: '/toolbox/图片处理/图片转Base64编码/index.html', desc: '编码转换', offlineOk: true },
|
||||
{ id: 'tb-img-gif-split', title: 'GIF拆帧', icon: '🎞️', link: '/toolbox/图片处理/GIF拆帧/index.html', desc: 'GIF帧提取', offlineOk: true },
|
||||
{ id: 'tb-img-webp', title: '图片转 WebP', icon: '🌐', link: '/toolbox/图片处理/图片转webp格式/index.html', desc: 'WebP格式转换', offlineOk: true },
|
||||
{ id: 'tb-img-watermark', title: '图片加文字水印', icon: '✏️', link: '/toolbox/图片处理/图片加文字水印/图片加文字水印.html', desc: '为图片添加文字水印', offlineOk: true },
|
||||
{ id: 'tb-img-compress', title: '图片压缩', icon: '🗜️', link: '/toolbox/图片处理/图片压缩处理/图片压缩处理.html', desc: '压缩图片体积', offlineOk: true },
|
||||
{ id: 'tb-img-png-jpg', title: 'PNG / JPG 互转', icon: '🔁', link: '/toolbox/图片处理/png和jpg格式互转/png和jpg相互转化.html', desc: 'PNG 与 JPG 格式转换', offlineOk: true },
|
||||
];
|
||||
|
||||
const TOOLBOX_UTIL = [
|
||||
@@ -135,6 +140,7 @@ const TOOLBOX_UTIL = [
|
||||
{ id: 'tb-json', title: 'JSON 编辑器', icon: '📑', link: '/toolbox/实用工具/Json编辑器/index.html', desc: '格式化与校验', offlineOk: true },
|
||||
{ id: 'tb-markdown', title: 'Markdown', icon: '⌨️', link: '/toolbox/实用工具/Markdown解析器/index.html', desc: '实时预览', offlineOk: true },
|
||||
{ id: 'tb-js', title: 'JavaScript', icon: '🟩', link: '/toolbox/实用工具/JavaScript编译器/index.html', desc: '本地运行脚本', offlineOk: true },
|
||||
{ id: 'tb-c-lang', title: 'C 语言编译器', icon: '⚙️', link: '/toolbox/实用工具/C语言编译器/网页C语言编译器.html', desc: '网页端编写与运行 C', offlineOk: true },
|
||||
{ id: 'tb-random-num', title: '随机数', icon: '🎲', link: '/toolbox/实用工具/随机数生成器/index.html', desc: '自定义范围', offlineOk: true },
|
||||
{ id: 'tb-wheel', title: '做决定转盘', icon: '🎡', link: '/toolbox/实用工具/做决定转盘/index.html', desc: '随机选择', offlineOk: true },
|
||||
{ id: 'tb-calc', title: '计算器', icon: '🔢', link: '/toolbox/实用工具/计算器/index.html', desc: '基础运算', offlineOk: true },
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import { tlsHost, loopbackPort } from './urlJoin.js';
|
||||
|
||||
const resolveApiUrl = () => {
|
||||
const mode = import.meta.env.MODE;
|
||||
const envApiUrl = import.meta.env.VITE_API_URL;
|
||||
|
||||
if (mode === 'production') {
|
||||
if (envApiUrl && envApiUrl.trim() !== '') return envApiUrl;
|
||||
return 'https://infogenie.api.shumengya.top';
|
||||
return tlsHost('infogenie.api.shumengya.top');
|
||||
}
|
||||
|
||||
if (envApiUrl && envApiUrl.trim() !== '') return envApiUrl;
|
||||
return 'http://127.0.0.1:5002';
|
||||
return loopbackPort('127.0.0.1', '5002');
|
||||
};
|
||||
|
||||
const resolveAuthUrl = () => {
|
||||
@@ -17,11 +19,11 @@ const resolveAuthUrl = () => {
|
||||
|
||||
if (mode === 'production') {
|
||||
if (envAuthUrl && envAuthUrl.trim() !== '') return envAuthUrl;
|
||||
return 'https://auth.shumengya.top';
|
||||
return tlsHost('auth.shumengya.top');
|
||||
}
|
||||
|
||||
if (envAuthUrl && envAuthUrl.trim() !== '') return envAuthUrl;
|
||||
return 'https://auth.shumengya.top';
|
||||
return tlsHost('auth.shumengya.top');
|
||||
};
|
||||
|
||||
const resolveAuthApiUrl = () => {
|
||||
@@ -30,11 +32,11 @@ const resolveAuthApiUrl = () => {
|
||||
|
||||
if (mode === 'production') {
|
||||
if (envAuthApiUrl && envAuthApiUrl.trim() !== '') return envAuthApiUrl;
|
||||
return 'https://auth.api.shumengya.top';
|
||||
return tlsHost('auth.api.shumengya.top');
|
||||
}
|
||||
|
||||
if (envAuthApiUrl && envAuthApiUrl.trim() !== '') return envAuthApiUrl;
|
||||
return 'https://auth.api.shumengya.top';
|
||||
return tlsHost('auth.api.shumengya.top');
|
||||
};
|
||||
|
||||
const config = {
|
||||
|
||||
12
InfoGenie-frontend/src/config/urlJoin.js
Normal file
12
InfoGenie-frontend/src/config/urlJoin.js
Normal file
@@ -0,0 +1,12 @@
|
||||
/** 避免源码中出现 https/http 连续字符,否则 Tailwind 扫描会误生成无效任意属性类 */
|
||||
const c = String.fromCharCode(58);
|
||||
const tlsScheme = String.fromCharCode(104, 116, 116, 112, 115);
|
||||
const plainScheme = String.fromCharCode(104, 116, 116, 112);
|
||||
|
||||
export function tlsHost(host) {
|
||||
return `${tlsScheme}${c}//${host}`;
|
||||
}
|
||||
|
||||
export function loopbackPort(host, port) {
|
||||
return `${plainScheme}${c}//${host}${c}${port}`;
|
||||
}
|
||||
@@ -11,6 +11,10 @@ import { ENV_CONFIG } from '../config/env';
|
||||
import { API_CATEGORIES, TOOLBOX_ITEMS, API_SOURCES } from '../config/Api60sConfig';
|
||||
import { AI_MODEL_APPS } from '../config/StaticPageConfig';
|
||||
|
||||
const gridOverviewStats = { gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))' };
|
||||
const gridQuickActions = { gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))' };
|
||||
const gridAdminItems = { gridTemplateColumns: 'repeat(auto-fill, minmax(210px, 1fr))' };
|
||||
|
||||
const InfoCard = ({ children }) => (
|
||||
<div className="bg-white/95 rounded-[14px] p-6 shadow-[0_4px_12px_rgba(0,0,0,0.08)] mb-6">{children}</div>
|
||||
);
|
||||
@@ -458,7 +462,7 @@ const AdminPage = () => {
|
||||
|
||||
{adminSection === 'overview' && (
|
||||
<>
|
||||
<div className="grid grid-cols-[repeat(auto-fit,minmax(200px,1fr))] gap-3 mb-6">
|
||||
<div className="grid gap-3 mb-6" style={gridOverviewStats}>
|
||||
{[
|
||||
{ icon: FiGrid, bg: 'linear-gradient(135deg,#4ade80,#22c55e)', label: '60sAPI', value: apiCount },
|
||||
{ icon: FiBox, bg: 'linear-gradient(135deg,#60a5fa,#3b82f6)', label: '休闲游戏', value: gameCount },
|
||||
@@ -496,7 +500,7 @@ const AdminPage = () => {
|
||||
</InfoCard>
|
||||
|
||||
<h3 className="text-base text-white mb-3 mt-2 [text-shadow:0_1px_4px_rgba(0,0,0,0.12)]">快捷操作</h3>
|
||||
<div className="grid grid-cols-[repeat(auto-fit,minmax(180px,1fr))] gap-3 mb-2">
|
||||
<div className="grid gap-3 mb-2" style={gridQuickActions}>
|
||||
<ActionBtn onClick={fetchSysInfo} disabled={loading}><FiRefreshCw size={16} /> 刷新后端状态</ActionBtn>
|
||||
<ActionBtn onClick={handleClearBuildCache}><FiMonitor size={16} /> 清除 SW 缓存</ActionBtn>
|
||||
<ActionBtn onClick={handleClearLocalStorage}><FiBox size={16} /> 清理本地存储</ActionBtn>
|
||||
@@ -733,7 +737,7 @@ const AdminPage = () => {
|
||||
) : (
|
||||
<>
|
||||
{[
|
||||
{ id: 'ai-base', label: 'API Base URL', type: 'text', value: aiBase, onChange: setAiBase, placeholder: 'https://api.deepseek.com' },
|
||||
{ id: 'ai-base', label: 'API Base URL', type: 'text', value: aiBase, onChange: setAiBase, placeholder: '例如 api.deepseek.com' },
|
||||
{ id: 'ai-key', label: `API Key${aiKeySet ? `(已配置:${aiKeyHint})` : ''}`, type: 'password', value: aiKey, onChange: setAiKey, placeholder: aiKeySet ? '留空保留原密钥;填写则覆盖' : '必填,保存后仅显示脱敏尾号', autoComplete: 'new-password' },
|
||||
{ id: 'ai-model', label: '默认模型 ID', type: 'text', value: aiModel, onChange: setAiModel, placeholder: 'deepseek-chat' },
|
||||
].map(({ id, label, type, value, onChange, placeholder, autoComplete }) => (
|
||||
@@ -756,11 +760,11 @@ const AdminPage = () => {
|
||||
<p className="text-sm text-gray-500 leading-[1.55] mb-3">
|
||||
选择 60s 类接口的<strong>上游根地址</strong>(与 <code className="text-xs bg-gray-100 px-1.5 py-0.5 rounded text-gray-700">Api60sConfig.API_SOURCES</code> 对齐)。
|
||||
</p>
|
||||
<div className="grid grid-cols-[repeat(auto-fill,minmax(210px,1fr))] gap-[8px_14px] max-w-[520px]">
|
||||
<div className="grid gap-[8px_14px] max-w-[520px]" style={gridAdminItems}>
|
||||
{API_SOURCES.map((s) => (
|
||||
<SixtyItem key={s.id} htmlFor={`admin-sixty-${s.id}`}>
|
||||
<input type="radio" id={`admin-sixty-${s.id}`} name="admin_sixty_src" checked={sixtySrcId === s.id} onChange={() => setSixtySrcId(s.id)} />
|
||||
<span>{s.label} <span className="text-gray-400 text-[11px] font-medium">({s.baseUrl.replace(/^https?:\/\//, '')})</span></span>
|
||||
<span>{s.label} <span className="text-gray-400 text-[11px] font-medium">({s.baseUrl.replace(/^[^/]+\/\//, '')})</span></span>
|
||||
</SixtyItem>
|
||||
))}
|
||||
</div>
|
||||
@@ -783,7 +787,7 @@ const AdminPage = () => {
|
||||
{API_CATEGORIES.map((cat) => (
|
||||
<div key={cat.id}>
|
||||
<h3 className="text-[15px] text-[#166534] mt-[18px] mb-2.5 first:mt-1">{cat.icon} {cat.title}</h3>
|
||||
<div className="grid grid-cols-[repeat(auto-fill,minmax(210px,1fr))] gap-[8px_14px]">
|
||||
<div className="grid gap-[8px_14px]" style={gridAdminItems}>
|
||||
{cat.items.map((item) => (
|
||||
<SixtyItem key={item.id}>
|
||||
<input type="checkbox" checked={!disabled60sSet.has(item.id)} onChange={(e) => setItemVisible(item.id, e.target.checked)} />
|
||||
@@ -811,7 +815,7 @@ const AdminPage = () => {
|
||||
<p className="text-sm text-gray-500">正在加载配置…</p>
|
||||
) : (
|
||||
<>
|
||||
<div className="grid grid-cols-[repeat(auto-fill,minmax(210px,1fr))] gap-[8px_14px]">
|
||||
<div className="grid gap-[8px_14px]" style={gridAdminItems}>
|
||||
{AI_MODEL_APPS.map((app) => (
|
||||
<SixtyItem key={app.id}>
|
||||
<input type="checkbox" checked={!disabledAIModelsSet.has(app.id)} onChange={(e) => setAIModelVisible(app.id, e.target.checked)} />
|
||||
|
||||
@@ -187,9 +187,9 @@ export function accentFromGradient(gradient) {
|
||||
export const ModuleGrid = ({ children, className = '' }) => (
|
||||
<div
|
||||
className={clsx(
|
||||
'grid grid-cols-1 min-[520px]:grid-cols-2',
|
||||
'gap-3 min-[520px]:gap-3.5',
|
||||
'max-w-[900px] mx-auto px-3 min-[520px]:px-4',
|
||||
'grid grid-cols-1 sm:grid-cols-2',
|
||||
'gap-3 sm:gap-3.5',
|
||||
'max-w-[900px] mx-auto px-3 sm:px-4',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -7,6 +7,8 @@ import { fileURLToPath } from 'url';
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
export default defineConfig({
|
||||
// 若为 true,esbuild 会对 Tailwind 误生成的 gri 等无效规则告警;可改回 true 并接受提示
|
||||
build: { cssMinify: false },
|
||||
plugins: [
|
||||
// Allow JSX in .js files (all files under src/)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user