Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0cc35e6351 |
@@ -29,34 +29,28 @@ k8s:deployment:create # K8S-部署-创建
|
|||||||
|
|
||||||
### 前端示例
|
### 前端示例
|
||||||
```typescript
|
```typescript
|
||||||
// 在需要使用日志的文件中直接引入debug
|
// src/client/utils/logger.ts
|
||||||
import debug from 'debug';
|
import debug from 'debug';
|
||||||
|
|
||||||
// 按需定义命名空间
|
export const logger = {
|
||||||
const errorLogger = debug('frontend:error');
|
error: debug('frontend:error'),
|
||||||
const apiLogger = debug('frontend:api');
|
api: debug('frontend:api'),
|
||||||
const authLogger = debug('frontend:auth');
|
auth: debug('frontend:auth'),
|
||||||
const uiLogger = debug('frontend:ui');
|
ui: debug('frontend:ui')
|
||||||
|
};
|
||||||
// 使用示例
|
|
||||||
errorLogger('用户登录失败: %s', error.message);
|
|
||||||
apiLogger('API请求: %s', url);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 后端示例
|
### 后端示例
|
||||||
```typescript
|
```typescript
|
||||||
// 在需要使用日志的文件中直接引入debug
|
// src/server/utils/logger.ts
|
||||||
import debug from 'debug';
|
import debug from 'debug';
|
||||||
|
|
||||||
// 按需定义命名空间
|
export const logger = {
|
||||||
const errorLogger = debug('backend:error');
|
error: debug('backend:error'),
|
||||||
const apiLogger = debug('backend:api');
|
api: debug('backend:api'),
|
||||||
const dbLogger = debug('backend:db');
|
db: debug('backend:db'),
|
||||||
const middlewareLogger = debug('backend:middleware');
|
middleware: debug('backend:middleware')
|
||||||
|
};
|
||||||
// 使用示例
|
|
||||||
errorLogger('数据库连接失败: %s', error.message);
|
|
||||||
dbLogger('查询执行: %s', sql);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 5. 最佳实践
|
## 5. 最佳实践
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
||||||
import { z } from '@hono/zod-openapi';
|
import { z } from 'zod';
|
||||||
|
|
||||||
@Entity('table_name') // 使用小写下划线命名表名
|
@Entity('table_name') // 使用小写下划线命名表名
|
||||||
export class EntityName {
|
export class EntityName {
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
"start": "export NODE_ENV='production' && node dist-server/index.js"
|
"start": "export NODE_ENV='production' && node dist-server/index.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/icons": "^6.0.0",
|
|
||||||
"@emotion/react": "^11.14.0",
|
"@emotion/react": "^11.14.0",
|
||||||
"@heroicons/react": "^2.2.0",
|
"@heroicons/react": "^2.2.0",
|
||||||
"@hono/node-server": "^1.14.3",
|
"@hono/node-server": "^1.14.3",
|
||||||
|
|||||||
1767
pnpm-lock.yaml
generated
1767
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,17 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useRouteError, useNavigate } from 'react-router';
|
import { useRouteError, useNavigate } from 'react-router';
|
||||||
import { Alert, Button } from 'antd';
|
import { Alert, Button } from 'antd';
|
||||||
|
import { useTheme } from '../hooks/ThemeProvider';
|
||||||
|
|
||||||
export const ErrorPage = () => {
|
export const ErrorPage = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const { isDark } = useTheme();
|
||||||
const error = useRouteError() as any;
|
const error = useRouteError() as any;
|
||||||
const errorMessage = error?.statusText || error?.message || '未知错误';
|
const errorMessage = error?.statusText || error?.message || '未知错误';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col items-center justify-center flex-grow p-4"
|
<div className="flex flex-col items-center justify-center flex-grow p-4"
|
||||||
|
style={{ color: isDark ? '#fff' : 'inherit' }}
|
||||||
>
|
>
|
||||||
<div className="max-w-3xl w-full">
|
<div className="max-w-3xl w-full">
|
||||||
<h1 className="text-2xl font-bold mb-4">发生错误</h1>
|
<h1 className="text-2xl font-bold mb-4">发生错误</h1>
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useNavigate } from 'react-router';
|
import { useNavigate } from 'react-router';
|
||||||
import { Button } from 'antd';
|
import { Button } from 'antd';
|
||||||
|
import { useTheme } from '../hooks/ThemeProvider';
|
||||||
|
|
||||||
export const NotFoundPage = () => {
|
export const NotFoundPage = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const { isDark } = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col items-center justify-center flex-grow p-4">
|
<div className="flex flex-col items-center justify-center flex-grow p-4"
|
||||||
|
style={{ color: isDark ? '#fff' : 'inherit' }}
|
||||||
|
>
|
||||||
<div className="max-w-3xl w-full">
|
<div className="max-w-3xl w-full">
|
||||||
<h1 className="text-2xl font-bold mb-4">404 - 页面未找到</h1>
|
<h1 className="text-2xl font-bold mb-4">404 - 页面未找到</h1>
|
||||||
<p className="mb-6 text-gray-600 dark:text-gray-300">
|
<p className="mb-6 text-gray-600 dark:text-gray-300">
|
||||||
|
|||||||
@@ -108,13 +108,12 @@ export const MainLayout = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout style={{ minHeight: '100vh' }}>
|
<Layout style={{ minHeight: '100vh' }}>
|
||||||
<Sider
|
<Sider
|
||||||
trigger={null}
|
trigger={null}
|
||||||
collapsible
|
collapsible
|
||||||
collapsed={collapsed}
|
collapsed={collapsed}
|
||||||
width={240}
|
width={240}
|
||||||
className="custom-sider"
|
className="custom-sider"
|
||||||
theme='light'
|
|
||||||
style={{
|
style={{
|
||||||
overflow: 'auto',
|
overflow: 'auto',
|
||||||
height: '100vh',
|
height: '100vh',
|
||||||
@@ -123,8 +122,6 @@ export const MainLayout = () => {
|
|||||||
top: 0,
|
top: 0,
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
zIndex: 100,
|
zIndex: 100,
|
||||||
transition: 'all 0.2s ease',
|
|
||||||
boxShadow: '2px 0 8px 0 rgba(29, 35, 41, 0.05)',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="p-4">
|
<div className="p-4">
|
||||||
@@ -159,9 +156,12 @@ export const MainLayout = () => {
|
|||||||
</Sider>
|
</Sider>
|
||||||
|
|
||||||
<Layout style={{ marginLeft: collapsed ? 80 : 240, transition: 'margin-left 0.2s' }}>
|
<Layout style={{ marginLeft: collapsed ? 80 : 240, transition: 'margin-left 0.2s' }}>
|
||||||
<div className="sticky top-0 z-50 bg-white shadow-sm transition-all duration-200 h-16 flex items-center justify-between pl-2"
|
<Header className="p-0 flex justify-between items-center"
|
||||||
style={{
|
style={{
|
||||||
boxShadow: '0 1px 4px rgba(0,21,41,0.08)'
|
position: 'sticky',
|
||||||
|
top: 0,
|
||||||
|
zIndex: 99,
|
||||||
|
boxShadow: '0 1px 4px rgba(0,21,41,0.08)',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
@@ -191,10 +191,10 @@ export const MainLayout = () => {
|
|||||||
</Space>
|
</Space>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</Space>
|
</Space>
|
||||||
</div>
|
</Header>
|
||||||
|
|
||||||
<Content className="m-6" style={{ overflow: 'initial', transition: 'all 0.2s ease' }}>
|
<Content className="m-6" style={{ overflow: 'initial' }}>
|
||||||
<div className="site-layout-content p-6 rounded-lg bg-white shadow-sm">
|
<div className="site-layout-content p-6 rounded-lg">
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
Input,
|
Input,
|
||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
App,
|
message,
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import {
|
import {
|
||||||
UserOutlined,
|
UserOutlined,
|
||||||
@@ -17,7 +17,6 @@ import {
|
|||||||
|
|
||||||
// 登录页面
|
// 登录页面
|
||||||
export const LoginPage = () => {
|
export const LoginPage = () => {
|
||||||
const { message } = App.useApp();
|
|
||||||
const { login } = useAuth();
|
const { login } = useAuth();
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
@@ -47,7 +46,7 @@ export const LoginPage = () => {
|
|||||||
// 登录成功后跳转到管理后台首页
|
// 登录成功后跳转到管理后台首页
|
||||||
navigate('/admin/dashboard');
|
navigate('/admin/dashboard');
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
message.error(error instanceof Error ? error.message : '登录失败');
|
message.error(error.response?.data?.error || '登录失败');
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { Link } from 'react-router-dom'
|
||||||
import { createRoot } from 'react-dom/client'
|
import { createRoot } from 'react-dom/client'
|
||||||
import { getGlobalConfig } from '../utils/utils'
|
import { getGlobalConfig } from '../utils/utils'
|
||||||
|
|
||||||
@@ -21,20 +22,20 @@ const Home = () => {
|
|||||||
|
|
||||||
{/* 管理入口按钮 */}
|
{/* 管理入口按钮 */}
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<a
|
<Link
|
||||||
href="/admin"
|
to="/admin"
|
||||||
className="w-full flex justify-center py-3 px-4 border border-transparent rounded-md shadow-sm text-lg font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
className="w-full flex justify-center py-3 px-4 border border-transparent rounded-md shadow-sm text-lg font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||||
>
|
>
|
||||||
进入管理后台
|
进入管理后台
|
||||||
</a>
|
</Link>
|
||||||
|
|
||||||
{/* 移动端入口按钮 */}
|
{/* 移动端入口按钮 */}
|
||||||
<a
|
<Link
|
||||||
href="/mobile"
|
to="/mobile"
|
||||||
className="w-full flex justify-center py-3 px-4 border border-blue-600 rounded-md shadow-sm text-lg font-medium text-blue-600 bg-white hover:bg-blue-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
className="w-full flex justify-center py-3 px-4 border border-blue-600 rounded-md shadow-sm text-lg font-medium text-blue-600 bg-white hover:bg-blue-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||||
>
|
>
|
||||||
进入移动端
|
进入移动端
|
||||||
</a>
|
</Link>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createRoute, OpenAPIHono } from '@hono/zod-openapi'
|
import { createRoute, OpenAPIHono } from '@hono/zod-openapi'
|
||||||
import { AuthService } from '../../../modules/auth/auth.service'
|
import { AuthService } from '../../../modules/auth/auth.service'
|
||||||
import { UserService } from '../../../modules/users/user.service'
|
import { UserService } from '../../../modules/users/user.service'
|
||||||
import { z } from '@hono/zod-openapi'
|
import { z } from 'zod'
|
||||||
import { ErrorSchema } from '../../../utils/errorHandler'
|
import { ErrorSchema } from '../../../utils/errorHandler'
|
||||||
import { AppDataSource } from '../../../data-source'
|
import { AppDataSource } from '../../../data-source'
|
||||||
import { AuthContext } from '../../../types/context'
|
import { AuthContext } from '../../../types/context'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
|
import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
|
||||||
import { z } from '@hono/zod-openapi'
|
import { z } from 'zod'
|
||||||
import { AuthContext } from '@/server/types/context';
|
import { AuthContext } from '@/server/types/context';
|
||||||
import { authMiddleware } from '@/server/middleware/auth.middleware';
|
import { authMiddleware } from '@/server/middleware/auth.middleware';
|
||||||
import { AppDataSource } from '@/server/data-source';
|
import { AppDataSource } from '@/server/data-source';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createRoute, OpenAPIHono } from '@hono/zod-openapi'
|
import { createRoute, OpenAPIHono } from '@hono/zod-openapi'
|
||||||
import { AuthService } from '../../../modules/auth/auth.service'
|
import { AuthService } from '../../../modules/auth/auth.service'
|
||||||
import { UserService } from '../../../modules/users/user.service'
|
import { UserService } from '../../../modules/users/user.service'
|
||||||
import { z } from '@hono/zod-openapi'
|
import { z } from 'zod'
|
||||||
import { AppDataSource } from '../../../data-source'
|
import { AppDataSource } from '../../../data-source'
|
||||||
import { ErrorSchema } from '../../../utils/errorHandler'
|
import { ErrorSchema } from '../../../utils/errorHandler'
|
||||||
import { AuthContext } from '../../../types/context'
|
import { AuthContext } from '../../../types/context'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
|
import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
|
||||||
import { UserService } from '@/server/modules/users/user.service';
|
import { UserService } from '@/server/modules/users/user.service';
|
||||||
import { z } from '@hono/zod-openapi';
|
import { z } from 'zod';
|
||||||
import { authMiddleware } from '@/server/middleware/auth.middleware';
|
import { authMiddleware } from '@/server/middleware/auth.middleware';
|
||||||
import { ErrorSchema } from '@/server/utils/errorHandler';
|
import { ErrorSchema } from '@/server/utils/errorHandler';
|
||||||
import { AppDataSource } from '@/server/data-source';
|
import { AppDataSource } from '@/server/data-source';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
|
import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
|
||||||
import { UserService } from '@/server/modules/users/user.service';
|
import { UserService } from '@/server/modules/users/user.service';
|
||||||
import { z } from '@hono/zod-openapi';
|
import { z } from 'zod';
|
||||||
import { authMiddleware } from '@/server/middleware/auth.middleware';
|
import { authMiddleware } from '@/server/middleware/auth.middleware';
|
||||||
import { ErrorSchema } from '@/server/utils/errorHandler';
|
import { ErrorSchema } from '@/server/utils/errorHandler';
|
||||||
import { AppDataSource } from '@/server/data-source';
|
import { AppDataSource } from '@/server/data-source';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
|
import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
|
||||||
import { UserService } from '@/server/modules/users/user.service';
|
import { UserService } from '@/server/modules/users/user.service';
|
||||||
import { z } from '@hono/zod-openapi';
|
import { z } from 'zod';
|
||||||
import { authMiddleware } from '@/server/middleware/auth.middleware';
|
import { authMiddleware } from '@/server/middleware/auth.middleware';
|
||||||
import { ErrorSchema } from '@/server/utils/errorHandler';
|
import { ErrorSchema } from '@/server/utils/errorHandler';
|
||||||
import { AppDataSource } from '@/server/data-source';
|
import { AppDataSource } from '@/server/data-source';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
|
import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
|
||||||
import { UserService } from '../../modules/users/user.service';
|
import { UserService } from '../../modules/users/user.service';
|
||||||
import { z } from '@hono/zod-openapi';
|
import { z } from 'zod';
|
||||||
import { authMiddleware } from '../../middleware/auth.middleware';
|
import { authMiddleware } from '../../middleware/auth.middleware';
|
||||||
import { ErrorSchema } from '../../utils/errorHandler';
|
import { ErrorSchema } from '../../utils/errorHandler';
|
||||||
import { AppDataSource } from '../../data-source';
|
import { AppDataSource } from '../../data-source';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
|
import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
|
||||||
import { UserService } from '../../modules/users/user.service';
|
import { UserService } from '../../modules/users/user.service';
|
||||||
import { z } from '@hono/zod-openapi';
|
import { z } from 'zod';
|
||||||
import { authMiddleware } from '../../middleware/auth.middleware';
|
import { authMiddleware } from '../../middleware/auth.middleware';
|
||||||
import { ErrorSchema } from '../../utils/errorHandler';
|
import { ErrorSchema } from '../../utils/errorHandler';
|
||||||
import { AppDataSource } from '../../data-source';
|
import { AppDataSource } from '../../data-source';
|
||||||
|
|||||||
@@ -17,6 +17,6 @@ export const AppDataSource = new DataSource({
|
|||||||
User, Role
|
User, Role
|
||||||
],
|
],
|
||||||
migrations: [],
|
migrations: [],
|
||||||
synchronize: process.env.DB_SYNCHRONIZE !== "false",
|
synchronize: process.env.DB_SYNCHRONIZE === "true",
|
||||||
logging: process.env.DB_LOGGING === "true",
|
logging: process.env.DB_LOGGING === "true",
|
||||||
});
|
});
|
||||||
@@ -1,13 +1,8 @@
|
|||||||
import jwt from 'jsonwebtoken';
|
import jwt from 'jsonwebtoken';
|
||||||
import { UserService } from '../users/user.service';
|
import { UserService } from '../users/user.service';
|
||||||
import { UserEntity as User } from '../users/user.entity';
|
import { UserEntity as User } from '../users/user.entity';
|
||||||
|
import { logger } from '@/server/utils/logger';
|
||||||
import { DisabledStatus } from '@/share/types';
|
import { DisabledStatus } from '@/share/types';
|
||||||
import debug from 'debug';
|
|
||||||
|
|
||||||
const logger = {
|
|
||||||
info: debug('backend:auth:info'),
|
|
||||||
error: debug('backend:auth:error')
|
|
||||||
}
|
|
||||||
|
|
||||||
const JWT_SECRET = 'your-secret-key'; // 生产环境应使用环境变量
|
const JWT_SECRET = 'your-secret-key'; // 生产环境应使用环境变量
|
||||||
const JWT_EXPIRES_IN = '7d'; // 7天有效期
|
const JWT_EXPIRES_IN = '7d'; // 7天有效期
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
||||||
import { z } from '@hono/zod-openapi';
|
import { z } from 'zod';
|
||||||
|
|
||||||
export type Permission = string;
|
export type Permission = string;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Context } from 'hono'
|
import { Context } from 'hono'
|
||||||
import { z } from '@hono/zod-openapi'
|
import { z } from 'zod'
|
||||||
import { HTTPException } from 'hono/http-exception'
|
import { HTTPException } from 'hono/http-exception'
|
||||||
|
|
||||||
export const ErrorSchema = z.object({
|
export const ErrorSchema = z.object({
|
||||||
|
|||||||
@@ -5,4 +5,5 @@ export const logger = {
|
|||||||
api: debug('backend:api'),
|
api: debug('backend:api'),
|
||||||
db: debug('backend:db'),
|
db: debug('backend:db'),
|
||||||
middleware: debug('backend:middleware'),
|
middleware: debug('backend:middleware'),
|
||||||
|
info: debug('backend:info'),
|
||||||
};
|
};
|
||||||
@@ -1,55 +1 @@
|
|||||||
@import 'tailwindcss';
|
@import 'tailwindcss';
|
||||||
|
|
||||||
/* 全局滚动条样式 */
|
|
||||||
::-webkit-scrollbar {
|
|
||||||
width: 6px;
|
|
||||||
height: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar-track {
|
|
||||||
background: #f1f1f1;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb {
|
|
||||||
background: #c1c1c1;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb:hover {
|
|
||||||
background: #a8a8a8;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 响应式断点 */
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.custom-sider {
|
|
||||||
width: 100% !important;
|
|
||||||
max-width: 100% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.site-layout-content {
|
|
||||||
padding: 1rem !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 全局过渡效果 */
|
|
||||||
.transition-all {
|
|
||||||
transition-property: all;
|
|
||||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
transition-duration: 150ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 内容区域阴影优化 */
|
|
||||||
.shadow-sm {
|
|
||||||
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 按钮悬停效果 */
|
|
||||||
.ant-btn:hover {
|
|
||||||
transform: translateY(-1px);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 卡片样式优化 */
|
|
||||||
.ant-card {
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,12 @@
|
|||||||
import reactStack from 'hono-vite-react-stack-node'
|
import reactStack from 'hono-vite-react-stack-node'
|
||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from 'vite'
|
||||||
|
import i18nextLoader from 'vite-plugin-i18next-loader'
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [
|
plugins: [
|
||||||
|
i18nextLoader({
|
||||||
|
paths: ['src/client/i18n/locales']
|
||||||
|
}),
|
||||||
reactStack({
|
reactStack({
|
||||||
minify: false,
|
minify: false,
|
||||||
port: 8080
|
port: 8080
|
||||||
|
|||||||
Reference in New Issue
Block a user