This commit is contained in:
linfeng 2025-03-06 19:58:07 +08:00
commit 8850795f58
20 changed files with 4462 additions and 0 deletions

73
.gitignore vendored Executable file
View File

@ -0,0 +1,73 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
backup
# dependencies
**/node_modules/
volumes
web-dist
/.pnp
.pnp.js
*.tar
# testing
**/coverage/
.env
docker-compose.yml
packages/common/prisma/migrations
packages/common/src/generated
# production
**/build/
**/dist/
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# 快速刷新错误记录
.expo/web/cache/development/
# Expo
**/.expo/
**/.expo-shared/
# Android
*.apk
*.aar
*.jks
!apps/mobile/android/app/release.jks
**/android/.gradle/
**/android/app/build/
**/android/app/release/
**/android/react-native-jsc/build/
**/android/react/build/
**/android/*/google-services.json
**/android/app/src/debug/res/xml/react_native_debug.xml
**/android/app/src/dev19/res/xml/react_native_debug.xml
**/android/app/src/dev20/res/xml/react_native_debug.xml
**/android/app/src/main/assets/shell-app.bundle
**/android/app/src/main/res/raw/shell_app_bundle
**/android/app/src/release/res/xml/react_native_debug.xml
# iOS
**/ios/Pods/
/ios/*.xcworkspace
**/ios/DerivedData/
**/ios/build/
**/ios/Podfile.lock
# Yarn Plug'n'Play
.pnp.*
.yarn/cache/
.yarn/unplugged/
.yarn/build-state.yml
.yarn/install-state.gz
# Ignore .idea files in the Expo monorepo
**/.idea/
uploads
packages/mind-elixir-core
config/nginx/conf.d/web.conf

54
README.md Normal file
View File

@ -0,0 +1,54 @@
# React + TypeScript + Vite
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
Currently, two official plugins are available:
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
## Expanding the ESLint configuration
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
```js
export default tseslint.config({
extends: [
// Remove ...tseslint.configs.recommended and replace with this
...tseslint.configs.recommendedTypeChecked,
// Alternatively, use this for stricter rules
...tseslint.configs.strictTypeChecked,
// Optionally, add this for stylistic rules
...tseslint.configs.stylisticTypeChecked,
],
languageOptions: {
// other options...
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
},
})
```
You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
```js
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'
export default tseslint.config({
plugins: {
// Add the react-x and react-dom plugins
'react-x': reactX,
'react-dom': reactDom,
},
rules: {
// other rules...
// Enable its recommended typescript rules
...reactX.configs['recommended-typescript'].rules,
...reactDom.configs.recommended.rules,
},
})
```

28
eslint.config.js Normal file
View File

@ -0,0 +1,28 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'
export default tseslint.config(
{ ignores: ['dist'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
},
)

13
index.html Normal file
View File

@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

41
package.json Normal file
View File

@ -0,0 +1,41 @@
{
"name": "my-todolist",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"@ant-design/icons": "^5.6.1",
"@ant-design/pro-table": "^3.18.6",
"@prisma/client": "^6.4.1",
"@tailwindcss/vite": "^4.0.9",
"antd": "^5.24.2",
"echarts": "^5.6.0",
"echarts-for-react": "^3.0.3",
"pg": "^8.13.3",
"prisma": "^6.4.1",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-router-dom": "^7.2.0",
"tailwindcss": "^4.0.9"
},
"devDependencies": {
"@eslint/js": "^9.21.0",
"@types/echarts": "^5.0.0",
"@types/react": "^19.0.10",
"@types/react-dom": "^19.0.4",
"@vitejs/plugin-react": "^4.3.4",
"eslint": "^9.21.0",
"eslint-plugin-react-hooks": "^5.1.0",
"eslint-plugin-react-refresh": "^0.4.19",
"globals": "^15.15.0",
"typescript": "~5.7.2",
"typescript-eslint": "^8.24.1",
"vite": "^6.2.0"
}
}

3813
pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,10 @@
-- CreateTable
CREATE TABLE "Todo" (
"id" TEXT NOT NULL,
"completed" BOOLEAN NOT NULL DEFAULT false,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"content" TEXT NOT NULL,
CONSTRAINT "Todo_pkey" PRIMARY KEY ("id")
);

View File

@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "postgresql"

22
prisma/schema.prisma Normal file
View File

@ -0,0 +1,22 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Todo{
id String @id @default(uuid())
completed Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
content String
}

1
public/vite.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

1
src/index.css Normal file
View File

@ -0,0 +1 @@
@import "tailwindcss"

11
src/main.tsx Normal file
View File

@ -0,0 +1,11 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { RouterProvider } from 'react-router-dom'
import { router } from './router/router.tsx'
// import Dashboard from './test.tsx'
createRoot(document.getElementById('root')!).render(
<StrictMode>
<RouterProvider router={router}></RouterProvider>
</StrictMode>,
)

132
src/page/App.tsx Normal file
View File

@ -0,0 +1,132 @@
import { Button, Form, Input, Select } from "antd"
import "../index.css"
import { useState } from "react"
import form from "antd/es/form"
import { Avatar } from "antd" // 新增Avatar组件
function App() {
const [status, setStatus] = useState("未提交")
const [loading, setLoading] = useState(false)
const [form] = Form.useForm()
const handleReset = () => {
setStatus("未提交")
form.resetFields()
}
return (
<div className="min-h-screen flex bg-slate-900"> {/* 改为flex布局 */}
{/* 新增导航栏 */}
<div className="w-96 flex flex-col border-r border-sky-400/30 bg-gradient-to-b from-gray-800/70 to-gray-900/70 shadow-[0_0_30px_rgba(14,165,235,0.1)]">
{/* 头像区域 */}
<div className="p-4 border-b border-sky-400/20 hover:bg-gray-700/30 transition-colors cursor-pointer"
onClick={() => {/* 基本信息设置逻辑 */ }}>
<div className="w-16 h-16 mx-auto rounded-full bg-gradient-to-r from-sky-400 to-cyan-500 shadow-lg cursor-pointer overflow-hidden">
{/* 替换为实际头像 */}
<div className="w-full h-full bg-gray-700" />
</div>
</div>
{/* 导航菜单 */}
<div className="flex-1 space-y-2 p-4">
{[1, 2, 3].map((item) => (
<div
key={item}
className="px-4 py-3 rounded-lg text-sky-300/90 hover:text-cyan-400
bg-gray-700/30 hover:bg-gray-700/50 cursor-pointer transition-all
hover:shadow-[0_0_10px_rgba(14,165,235,0.3)] border border-sky-400/20"
>
{item}
</div>
))}
</div>
</div>
{/* 原有内容容器 */}
<div className="flex-1 flex flex-col">
{/* 头部科技感改造 */}
<div className="bg-gradient-to-r from-sky-500 to-cyan-600 mx-auto px-4 w-full max-w-3xl rounded-b-xl shadow-lg shadow-cyan-500/20">
<h1 className="text-center text-2xl md:text-3xl font-bold p-4 md:p-6 bg-gradient-to-r from-sky-400 to-cyan-400 bg-clip-text text-transparent">
TodoList
</h1>
</div>
{/* 表单容器暗黑改造 */}
<div className="relative mt-4 md:mt-6 mx-auto px-4 w-full max-w-3xl bg-gray-800 rounded-xl shadow-[0_0_30px_rgba(14,165,235,0.2)] border border-sky-400/50 py-6">
<Form
form={form}
onFinish={(e) => {
setLoading(true)
setTimeout(() => {
setStatus("已提交")
setLoading(false)
}, 1000)
console.log(e)
}}
layout="vertical"
className="space-y-6 px-4"
>
<Form.Item
label="代办事项:"
name="todo"
className="font-bold text-lg text-sky-200" // 修改文字颜色
labelCol={{ style: { color: '#bae6fd' } }} // 新增亮色
>
<Input
placeholder="请输入代办事项"
size="large"
className="w-full bg-gray-700/50 border-sky-400 hover:border-sky-300 focus:border-sky-500 text-gray-100 placeholder-gray-400" // 暗黑风格
/>
</Form.Item>
<Form.Item
label="状态:"
name="status"
labelCol={{ style: { color: '#bae6fd' } }}
className="font-bold text-lg text-sky-200"
>
<Select
placeholder="请选择状态"
size="large"
className="w-full [&>.ant-select-selector]:bg-gray-700/50 [&>.ant-select-selector]:border-sky-400 [&>.ant-select-selection-item]:text-gray-100"
dropdownClassName="bg-gray-700 [&>.ant-select-item-option-active]:bg-gray-600"
options={[
{
value: "优先",
label: "优先",
},
{
value: "一般",
label: "一般",
},
]}
onChange={(e) => { console.log(e) }}
>
</Select>
</Form.Item>
{/* 按钮组响应式优化 */}
<div className="flex flex-col md:flex-row gap-3 md:gap-4 justify-center">
<Button
type="primary"
htmlType="submit"
className="h-10 px-6 text-lg w-full md:w-auto
bg-gradient-to-r from-sky-400 to-cyan-400 hover:from-sky-500 hover:to-cyan-500 shadow-lg shadow-sky-500/20"
disabled={status === "已提交"}
loading={loading}
>
{status === "未提交" ? "提交" : "已提交"}
</Button>
<Button
type="default"
className="h-10 px-6 text-lg w-full md:w-auto
border-sky-400 text-sky-400 hover:border-cyan-400 hover:text-cyan-400"
onClick={() => handleReset()}
>
</Button>
</div>
</Form>
</div>
</div>
</div>
)
}
export default App

74
src/page/login.tsx Normal file
View File

@ -0,0 +1,74 @@
import { Button, FloatButton, Form, Input } from "antd"
import { useNavigate } from "react-router-dom"
export default function Login() {
const navigate = useNavigate()
// 修正函数名拼写错误 (handeLogin → handleLogin)
const handleLogin = () => {
navigate("/path")
}
return (
<div className="min-h-screen flex flex-col bg-slate-900">
<FloatButton></FloatButton>
<div className="bg-gradient-to-r from-sky-500 to-cyan-600 w-full">
<div className="mx-auto px-4 max-w-3xl rounded-b-xl shadow-lg shadow-cyan-500/20">
<h1 className="text-center text-2xl md:text-3xl font-bold p-4 md:p-6 bg-gradient-to-r from-sky-400 to-cyan-400 bg-clip-text text-transparent">
</h1>
</div>
</div>
<div className="flex-1 ">
{/* 添加响应式边距和最大宽度 */}
<div className="relative mx-4 md:mx-[50vh] mt-16 md:mt-[20vh] max-w-[90%] md:max-w-full bg-gray-800 rounded-xl shadow-[0_0_30px_rgba(14,165,235,0.2)] border border-sky-400/50 py-6">
<Form
className="space-y-6 px-4"
onFinish={handleLogin}
layout="vertical"
>
{/* 添加响应式字体大小 */}
<h2 className="text-transparent bg-clip-text bg-gradient-to-r from-sky-400 to-cyan-300 text-xl md:text-3xl font-bold text-center mb-8">
</h2>
<div className="space-y-8 flex-1">
<Form.Item
label="用户名"
name="username"
className="font-bold text-lg text-sky-200"
labelCol={{ style: { color: '#bae6fd' } }}
>
<Input
className="w-full bg-gray-700/50 border-sky-400 hover:border-sky-300 focus:border-sky-500 rounded-lg text-gray-100 placeholder-gray-400 h-12 text-lg px-4" // 移除max-width限制
/>
</Form.Item>
<Form.Item
label="密码"
name="password"
className="font-bold text-lg text-sky-200"
labelCol={{ style: { color: '#bae6fd' } }}
>
<Input.Password
className="w-full bg-gray-700/50 border-sky-400 hover:border-sky-300 focus:border-sky-500 rounded-lg [&>input]:text-gray-100 h-12 text-lg px-4" // 移除max-width限制
/>
</Form.Item>
</div>
<div className="flex justify-center mt-8">
<Button
type="primary"
htmlType="submit"
className="w-full md:w-2/3 bg-gradient-to-r from-sky-400 to-cyan-400 hover:from-sky-500 hover:to-cyan-500 h-12 text-lg font-bold rounded-xl transition-all duration-300 shadow-lg shadow-sky-500/20"
>
</Button>
</div>
</Form>
</div>
</div>
</div>
)
}

104
src/page/test.tsx Normal file
View File

@ -0,0 +1,104 @@
import React from 'react';
import { Card, Row, Col, Spin } from 'antd';
import ReactECharts from 'echarts-for-react';
// 在顶部import区域添加类型引用
import type { EChartsOption } from 'echarts';
const Dashboard = () => {
// 模拟静态数据结构
const mockChartData = {
// API标记处需要从/getChartData接口获取
xAxis: ['周一', '周二', '周三', '周四', '周五'],
series: [120, 200, 150, 80, 70] // 示例数据
};
// 修复类型定义:添加类型断言和正确配置格式
const chartOption: EChartsOption = {
grid: { top: 20, right: 40, left: 40, bottom: 20 },
xAxis: {
type: 'category',
data: mockChartData.xAxis,
axisLine: { lineStyle: { color: '#1890ff' } }
},
yAxis: { type: 'value' },
series: [{
data: mockChartData.series,
type: 'line',
smooth: true,
areaStyle: { color: '#1890ff22' },
lineStyle: {
color: '#1890ff',
width: 2
},
// 添加必要字段
name: '数据趋势',
symbol: 'none' // 移除数据点标记
}]
} as EChartsOption;
return (
<Row gutter={16} style={{ padding: 24 }}>
{/* 数据趋势模块 */}
<Col span={16}>
<Card title="数据趋势分析" bordered={false}>
<ReactECharts
option={chartOption}
style={{ height: 400 }}
showLoading={true}
/>
{/* API使
<ReactECharts
option={chartData}
loading={isLoading}
/> */}
</Card>
</Col>
{/* 数据表格模块 */}
<Col span={8}>
<Card title="最新记录" bordered={false}>
<Spin spinning={false} /* API标记处设置loading状态 */>
<table className="mock-table">
<thead>
<tr>
<th>ID</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
{/* API标记处需要从/getRecords接口获取 */}
<tr>
<td colSpan={3} style={{ textAlign: 'center' }}>
...
</td>
</tr>
</tbody>
</table>
</Spin>
</Card>
</Col>
</Row>
);
};
// 简易表格样式
const mockTableStyle = `
.mock-table {
width: 100%;
border-collapse: collapse;
margin-top: 12px;
}
.mock-table th {
background: #fafafa;
padding: 8px;
text-align: left;
}
.mock-table td {
padding: 8px;
border-bottom: 1px solid #f0f0f0;
}
`;
export default Dashboard;

14
src/router/router.tsx Normal file
View File

@ -0,0 +1,14 @@
import {createBrowserRouter} from "react-router-dom";
import Login from "../page/login";
import App from "../page/App";
export const router = createBrowserRouter([
{
path: "/",
element: <Login />,
},
{
path: "/path",
element: <App></App>
}
])

26
tsconfig.app.json Normal file
View File

@ -0,0 +1,26 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["src"]
}

7
tsconfig.json Normal file
View File

@ -0,0 +1,7 @@
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}

24
tsconfig.node.json Normal file
View File

@ -0,0 +1,24 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2022",
"lib": ["ES2023"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
}

11
vite.config.ts Normal file
View File

@ -0,0 +1,11 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'
// https://vite.dev/config/
export default defineConfig({
plugins: [
react(),
tailwindcss(),
],
})