mirror of
https://github.com/Cccc-owo/CheckInApp.git
synced 2026-06-17 05:56:29 +00:00
feat(webui): totally convert to new webui
This commit is contained in:
@@ -75,9 +75,10 @@ CheckIn App V2 采用用户-任务分离架构,一个用户可管理多个打
|
||||
### 前端
|
||||
|
||||
- **Vue 3**: Composition API
|
||||
- **Ant Design Vue**: UI 组件库
|
||||
- **Pinia**: 状态管理
|
||||
- **Axios**: HTTP 客户端,拦截器处理 Token
|
||||
- **TypeScript**: 前端类型约束
|
||||
- **shadcn-vue**: 共享 UI primitive
|
||||
- **Tailwind CSS**: 设计令牌和布局表达
|
||||
- **fetch + local API helpers**: 请求封装和 Token 处理
|
||||
|
||||
## 认证流程
|
||||
|
||||
@@ -166,11 +167,11 @@ apps/backend/
|
||||
```
|
||||
apps/frontend/src/
|
||||
├── api/ # API 调用封装
|
||||
├── app/ # 认证、路由、主题
|
||||
├── views/ # 页面组件
|
||||
├── components/ # 可复用组件
|
||||
├── stores/ # Pinia 状态
|
||||
├── router/ # 路由配置
|
||||
└── composables/ # 组合式函数
|
||||
├── components/ # 可复用组件和 shadcn primitives
|
||||
├── utils/ # 格式化与显示 helper
|
||||
└── style.css # 全局 token 和语义样式
|
||||
```
|
||||
|
||||
## 扩展性
|
||||
|
||||
+6
-3
@@ -7,7 +7,8 @@
|
||||
- Ubuntu 20.04+ / CentOS 7+ / Windows Server
|
||||
- Python 3.9+
|
||||
- uv
|
||||
- Node.js 16+
|
||||
- Node.js 20+
|
||||
- pnpm
|
||||
- Chrome / Chromium
|
||||
- 2GB+ RAM
|
||||
|
||||
@@ -17,10 +18,12 @@
|
||||
# Ubuntu
|
||||
sudo apt update
|
||||
sudo apt install -y python3 nodejs npm chromium-browser
|
||||
npm install -g pnpm
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
|
||||
# CentOS
|
||||
sudo yum install -y python3 nodejs npm chromium
|
||||
npm install -g pnpm
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
```
|
||||
|
||||
@@ -52,10 +55,10 @@ vim .env # 修改环境变量
|
||||
cd apps/frontend
|
||||
|
||||
# 安装依赖
|
||||
npm install
|
||||
pnpm install --frozen-lockfile
|
||||
|
||||
# 构建生产版本
|
||||
npm run build
|
||||
pnpm build
|
||||
|
||||
# 输出在 dist/ 目录
|
||||
```
|
||||
|
||||
+68
-80
@@ -21,14 +21,14 @@ uv run python main.py backend
|
||||
cd apps/frontend
|
||||
|
||||
# 安装依赖
|
||||
npm install
|
||||
pnpm install
|
||||
|
||||
# 启动开发服务器
|
||||
npm run dev
|
||||
pnpm dev
|
||||
|
||||
# 代码格式化
|
||||
npm run lint
|
||||
npm run format
|
||||
# 代码检查和格式化
|
||||
pnpm lint:check
|
||||
pnpm format:check
|
||||
```
|
||||
|
||||
## 项目结构
|
||||
@@ -82,12 +82,18 @@ apps/backend/
|
||||
|
||||
```
|
||||
apps/frontend/src/
|
||||
├── main.js # Vue 应用入口
|
||||
├── main.ts # Vue 应用入口
|
||||
├── App.vue # 根组件
|
||||
│
|
||||
├── api/ # API 封装
|
||||
│ ├── client.js # Axios 实例、拦截器
|
||||
│ └── index.js # API 模块(auth, user, task 等)
|
||||
│ ├── client.ts # fetch 客户端、鉴权存储、错误归一化
|
||||
│ ├── index.ts # API 模块(auth, user, task 等)
|
||||
│ └── types.ts # API 类型
|
||||
│
|
||||
├── app/ # 应用级状态和路由
|
||||
│ ├── auth.ts # 认证状态
|
||||
│ ├── router.ts # Vue Router 配置、导航守卫
|
||||
│ └── theme.ts # 主题模式
|
||||
│
|
||||
├── views/ # 页面组件
|
||||
│ ├── LoginView.vue
|
||||
@@ -97,21 +103,14 @@ apps/frontend/src/
|
||||
│ └── admin/ # 管理员页面
|
||||
│
|
||||
├── components/ # 可复用组件
|
||||
│ ├── TaskCard.vue
|
||||
│ ├── RecordTable.vue
|
||||
│ └── ...
|
||||
│ ├── AppLayout.vue
|
||||
│ ├── StateBlock.vue
|
||||
│ ├── templates/ # 模板结构化编辑器
|
||||
│ └── ui/ # shadcn-vue primitive
|
||||
│
|
||||
├── stores/ # Pinia 状态管理
|
||||
│ ├── auth.js # 认证状态
|
||||
│ ├── user.js # 用户信息
|
||||
│ └── task.js # 任务列表
|
||||
│
|
||||
├── router/ # Vue Router
|
||||
│ └── index.js # 路由配置、导航守卫
|
||||
│
|
||||
└── composables/ # 组合式函数
|
||||
├── useAuth.js
|
||||
└── useTask.js
|
||||
├── components/ui.ts # 本地共享样式 helper
|
||||
├── style.css # Tailwind v4 + shadcn token
|
||||
└── utils/ # 格式化和显示 helper
|
||||
```
|
||||
|
||||
## 开发流程
|
||||
@@ -163,38 +162,27 @@ app.include_router(tags.router, prefix="/api")
|
||||
|
||||
**步骤**:
|
||||
|
||||
1. 在 `api/index.js` 添加 API 调用
|
||||
2. 在 `stores/` 创建或更新状态
|
||||
3. 创建或更新 Vue 组件
|
||||
1. 在 `apps/frontend/src/api/index.ts` 添加 API 调用和类型引用
|
||||
2. 在 `apps/frontend/src/app/` 更新认证、路由或主题状态(如需要)
|
||||
3. 创建或更新 Vue 组件,优先复用现有 shadcn-vue primitive 和 `src/components/ui.ts`
|
||||
4. 配置路由(如需要)
|
||||
|
||||
**示例**: 添加标签管理页面
|
||||
|
||||
```javascript
|
||||
// api/index.js
|
||||
```typescript
|
||||
// apps/frontend/src/api/index.ts
|
||||
export const tagApi = {
|
||||
addTag: (taskId, data) => client.post(`/tasks/${taskId}/tags`, data),
|
||||
getTags: (taskId) => client.get(`/tasks/${taskId}/tags`)
|
||||
}
|
||||
|
||||
// stores/tag.js
|
||||
export const useTagStore = defineStore('tag', {
|
||||
state: () => ({
|
||||
tags: []
|
||||
}),
|
||||
actions: {
|
||||
async fetchTags(taskId) {
|
||||
const { data } = await tagApi.getTags(taskId)
|
||||
this.tags = data
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// components/TagManager.vue
|
||||
// apps/frontend/src/components/TagManager.vue
|
||||
<template>
|
||||
<div>
|
||||
<a-tag v-for="tag in tags" :key="tag.id">{{ tag.tag_name }}</a-tag>
|
||||
<a-button @click="addTag">添加标签</a-button>
|
||||
<div class="grid gap-2">
|
||||
<span v-for="tag in tags" :key="tag.id" :class="toneClass('neutral')">
|
||||
{{ tag.tag_name }}
|
||||
</span>
|
||||
<Button type="button" @click="addTag">添加标签</Button>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
@@ -229,20 +217,12 @@ uv run pytest tests/
|
||||
|
||||
#### 前端测试
|
||||
|
||||
```javascript
|
||||
// tests/TaskCard.spec.js
|
||||
import { mount } from '@vue/test-utils'
|
||||
import TaskCard from '@/components/TaskCard.vue'
|
||||
```bash
|
||||
cd apps/frontend
|
||||
|
||||
test('displays task name', () => {
|
||||
const wrapper = mount(TaskCard, {
|
||||
props: { task: { name: 'Test Task' } }
|
||||
})
|
||||
expect(wrapper.text()).toContain('Test Task')
|
||||
})
|
||||
|
||||
// 运行测试
|
||||
npm run test
|
||||
pnpm test
|
||||
pnpm lint:check
|
||||
pnpm build
|
||||
```
|
||||
|
||||
## 代码规范
|
||||
@@ -273,23 +253,47 @@ async def create_task(
|
||||
- 使用 ESLint + Prettier
|
||||
- 组件使用 Composition API
|
||||
- 使用 `<script setup>` 语法
|
||||
- Props 添加类型验证
|
||||
- 统一使用 Ant Design Vue 组件
|
||||
- 使用 TypeScript 类型定义 Props 和 API 数据
|
||||
- 优先使用 shadcn-vue primitive、lucide 图标、Tailwind token 和 `src/components/ui.ts` 共享样式
|
||||
- 保留页面局部 Tailwind 来表达独有布局,不为一次性结构强行抽象
|
||||
|
||||
```vue
|
||||
<!-- 好的示例 -->
|
||||
<script setup>
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
const props = defineProps<{
|
||||
task: {
|
||||
type: Object,
|
||||
required: true
|
||||
name: string
|
||||
is_active: boolean
|
||||
}
|
||||
})
|
||||
}>()
|
||||
|
||||
const isActive = computed(() => props.task.is_active)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<article class="rounded-lg border border-border bg-card p-4">
|
||||
{{ task.name }}
|
||||
</article>
|
||||
</template>
|
||||
```
|
||||
|
||||
### 前端调试
|
||||
|
||||
```typescript
|
||||
// 使用 Vue Devtools
|
||||
// Chrome 扩展安装
|
||||
|
||||
// console 输出
|
||||
console.log('Task data:', task.value)
|
||||
|
||||
// 调试 API 请求
|
||||
const response = await fetch('/api/tasks', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## 调试技巧
|
||||
@@ -311,22 +315,6 @@ logging.basicConfig()
|
||||
logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)
|
||||
```
|
||||
|
||||
### 前端调试
|
||||
|
||||
```javascript
|
||||
// 使用 Vue Devtools
|
||||
// Chrome 扩展安装
|
||||
|
||||
// console 输出
|
||||
console.log('Task data:', task.value)
|
||||
|
||||
// 调试 API 请求
|
||||
axios.interceptors.request.use(request => {
|
||||
console.log('Request:', request)
|
||||
return request
|
||||
})
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
|
||||
### CORS 错误
|
||||
|
||||
Reference in New Issue
Block a user