3 Commits
Author SHA1 Message Date
Claude 43750b306c chore: 移除额外的README文档文件
- 移除FILE_MANAGEMENT_README.md
- 移除PHASE7_README.md
- 移除TRANSFER_RECOVERY_README.md
- 只保留根目录README.md

Co-Authored-By: Claude Sonnet <claude@anthropic.com>
2026-01-25 00:37:37 +08:00
Claude 28aa8b5f62 chore: 清理仓库,移除无用文件
- 更新.gitignore文件
- 移除所有.md文档文件(保留README.md)
- 移除测试文件和临时文件
- 移除PHASE和交付报告文件
- 优化仓库结构,只保留源代码和必要配置

Co-Authored-By: Claude Sonnet <claude@anthropic.com>
2026-01-25 00:36:46 +08:00
ClaudeandClaude Sonnet 4.5 e71181f0a3 fix: 修复多个关键问题
- 修复前端路由守卫:未登录时不显示提示,直接跳转登录页
- 修复API拦截器:401错误不显示提示,直接跳转
- 增强验证码显示:图片尺寸从120x40增加到200x80
- 增大验证码字体:从28号增加到48号
- 优化验证码字符:排除易混淆的0和1
- 减少干扰线:从5条减少到3条,添加背景色优化
- 增强登录API日志:添加详细的调试日志
- 增强验证码生成和验证日志
- 优化异常处理和错误追踪

影响文件:
- src/router/index.ts
- src/api/request.ts
- app/services/auth_service.py
- app/api/v1/auth.py
- app/schemas/user.py

测试状态:
- 前端构建通过
- 后端语法检查通过
- 验证码显示效果优化完成

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-25 00:26:21 +08:00
505 changed files with 412 additions and 82963 deletions
-31
View File
@@ -1,31 +0,0 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
# Matches multiple files with brace expansion notation
[*.{js,jsx,ts,tsx,vue}]
indent_style = space
indent_size = 2
# Matches multiple files with brace expansion notation
[*.{json,md,yml,yaml}]
indent_style = space
indent_size = 2
# Matches multiple files with brace expansion notation
[*.scss]
indent_style = space
indent_size = 2
# The above files are for code, but for config files we want no indentation
[{package.json,.eslintrc.cjs,.prettierrc}]
indent_style = space
indent_size = 2
-3
View File
@@ -1,3 +0,0 @@
# 开发环境配置
VITE_API_BASE_URL=http://localhost:8000/api/v1
VITE_APP_TITLE=资产管理系统
+35 -3
View File
@@ -1,3 +1,35 @@
# 生产环境配置 APP_NAME=资产管理系统
VITE_API_BASE_URL=https://zc.workyai.cn/api/v1 APP_VERSION=1.0.0
VITE_APP_TITLE=资产管理系统 APP_ENVIRONMENT=production
DEBUG=False
HOST=0.0.0.0
PORT=8001
API_V1_PREFIX=/api/v1
# 数据库配置(从服务器获取)
DATABASE_URL=postgresql+asyncpg://asset_user:PASSWORD@118.145.218.2:5433/asset_management
DATABASE_ECHO=False
# Redis配置
REDIS_URL=redis://:PASSWORD@118.145.218.2:6380/0
REDIS_MAX_CONNECTIONS=50
# JWT配置
SECRET_KEY=请生成强密钥
ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=15
REFRESH_TOKEN_EXPIRE_DAYS=7
# CORS配置
CORS_ORIGINS=["https://zc.workyai.cn"]
CORS_ALLOW_CREDENTIALS=True
CORS_ALLOW_METHODS=["GET","POST","PUT","DELETE","PATCH"]
CORS_ALLOW_HEADERS=["*"]
# 文件上传配置
UPLOAD_DIR=uploads
MAX_UPLOAD_SIZE=104857600
# 日志配置
LOG_LEVEL=INFO
LOG_FILE=logs/app.log
-312
View File
@@ -1,312 +0,0 @@
{
"globals": {
"Component": true,
"ComponentPublicInstance": true,
"ComputedRef": true,
"DirectiveBinding": true,
"EffectScope": true,
"ExtractDefaultPropTypes": true,
"ExtractPropTypes": true,
"ExtractPublicPropTypes": true,
"InjectionKey": true,
"MaybeRef": true,
"MaybeRefOrGetter": true,
"PropType": true,
"Ref": true,
"VNode": true,
"WritableComputedRef": true,
"acceptHMRUpdate": true,
"asyncComputed": true,
"autoResetRef": true,
"computed": true,
"computedAsync": true,
"computedEager": true,
"computedInject": true,
"computedWithControl": true,
"controlledComputed": true,
"controlledRef": true,
"createApp": true,
"createEventHook": true,
"createGlobalState": true,
"createInjectionState": true,
"createPinia": true,
"createReactiveFn": true,
"createReusableTemplate": true,
"createSharedComposable": true,
"createTemplatePromise": true,
"createUnrefFn": true,
"customRef": true,
"debouncedRef": true,
"debouncedWatch": true,
"defineAsyncComponent": true,
"defineComponent": true,
"defineStore": true,
"eagerComputed": true,
"effectScope": true,
"extendRef": true,
"getActivePinia": true,
"getCurrentInstance": true,
"getCurrentScope": true,
"h": true,
"ignorableWatch": true,
"inject": true,
"injectLocal": true,
"isDefined": true,
"isProxy": true,
"isReactive": true,
"isReadonly": true,
"isRef": true,
"makeDestructurable": true,
"mapActions": true,
"mapGetters": true,
"mapState": true,
"mapStores": true,
"mapWritableState": true,
"markRaw": true,
"nextTick": true,
"onActivated": true,
"onBeforeMount": true,
"onBeforeRouteLeave": true,
"onBeforeRouteUpdate": true,
"onBeforeUnmount": true,
"onBeforeUpdate": true,
"onClickOutside": true,
"onDeactivated": true,
"onErrorCaptured": true,
"onKeyStroke": true,
"onLongPress": true,
"onMounted": true,
"onRenderTracked": true,
"onRenderTriggered": true,
"onScopeDispose": true,
"onServerPrefetch": true,
"onStartTyping": true,
"onUnmounted": true,
"onUpdated": true,
"onWatcherCleanup": true,
"pausableWatch": true,
"provide": true,
"provideLocal": true,
"reactify": true,
"reactifyObject": true,
"reactive": true,
"reactiveComputed": true,
"reactiveOmit": true,
"reactivePick": true,
"readonly": true,
"ref": true,
"refAutoReset": true,
"refDebounced": true,
"refDefault": true,
"refThrottled": true,
"refWithControl": true,
"resolveComponent": true,
"resolveRef": true,
"resolveUnref": true,
"setActivePinia": true,
"setMapStoreSuffix": true,
"shallowReactive": true,
"shallowReadonly": true,
"shallowRef": true,
"storeToRefs": true,
"syncRef": true,
"syncRefs": true,
"templateRef": true,
"throttledRef": true,
"throttledWatch": true,
"toRaw": true,
"toReactive": true,
"toRef": true,
"toRefs": true,
"toValue": true,
"triggerRef": true,
"tryOnBeforeMount": true,
"tryOnBeforeUnmount": true,
"tryOnMounted": true,
"tryOnScopeDispose": true,
"tryOnUnmounted": true,
"unref": true,
"unrefElement": true,
"until": true,
"useActiveElement": true,
"useAnimate": true,
"useArrayDifference": true,
"useArrayEvery": true,
"useArrayFilter": true,
"useArrayFind": true,
"useArrayFindIndex": true,
"useArrayFindLast": true,
"useArrayIncludes": true,
"useArrayJoin": true,
"useArrayMap": true,
"useArrayReduce": true,
"useArraySome": true,
"useArrayUnique": true,
"useAsyncQueue": true,
"useAsyncState": true,
"useAttrs": true,
"useBase64": true,
"useBattery": true,
"useBluetooth": true,
"useBreakpoints": true,
"useBroadcastChannel": true,
"useBrowserLocation": true,
"useCached": true,
"useClipboard": true,
"useClipboardItems": true,
"useCloned": true,
"useColorMode": true,
"useConfirmDialog": true,
"useCounter": true,
"useCssModule": true,
"useCssVar": true,
"useCssVars": true,
"useCurrentElement": true,
"useCycleList": true,
"useDark": true,
"useDateFormat": true,
"useDebounce": true,
"useDebounceFn": true,
"useDebouncedRefHistory": true,
"useDeviceMotion": true,
"useDeviceOrientation": true,
"useDevicePixelRatio": true,
"useDevicesList": true,
"useDisplayMedia": true,
"useDocumentVisibility": true,
"useDraggable": true,
"useDropZone": true,
"useElementBounding": true,
"useElementByPoint": true,
"useElementHover": true,
"useElementSize": true,
"useElementVisibility": true,
"useEventBus": true,
"useEventListener": true,
"useEventSource": true,
"useEyeDropper": true,
"useFavicon": true,
"useFetch": true,
"useFileDialog": true,
"useFileSystemAccess": true,
"useFocus": true,
"useFocusWithin": true,
"useFps": true,
"useFullscreen": true,
"useGamepad": true,
"useGeolocation": true,
"useId": true,
"useIdle": true,
"useImage": true,
"useInfiniteScroll": true,
"useIntersectionObserver": true,
"useInterval": true,
"useIntervalFn": true,
"useKeyModifier": true,
"useLastChanged": true,
"useLink": true,
"useLocalStorage": true,
"useMagicKeys": true,
"useManualRefHistory": true,
"useMediaControls": true,
"useMediaQuery": true,
"useMemoize": true,
"useMemory": true,
"useModel": true,
"useMounted": true,
"useMouse": true,
"useMouseInElement": true,
"useMousePressed": true,
"useMutationObserver": true,
"useNavigatorLanguage": true,
"useNetwork": true,
"useNow": true,
"useObjectUrl": true,
"useOffsetPagination": true,
"useOnline": true,
"usePageLeave": true,
"useParallax": true,
"useParentElement": true,
"usePerformanceObserver": true,
"usePermission": true,
"usePointer": true,
"usePointerLock": true,
"usePointerSwipe": true,
"usePreferredColorScheme": true,
"usePreferredContrast": true,
"usePreferredDark": true,
"usePreferredLanguages": true,
"usePreferredReducedMotion": true,
"usePrevious": true,
"useRafFn": true,
"useRefHistory": true,
"useResizeObserver": true,
"useRoute": true,
"useRouter": true,
"useScreenOrientation": true,
"useScreenSafeArea": true,
"useScriptTag": true,
"useScroll": true,
"useScrollLock": true,
"useSessionStorage": true,
"useShare": true,
"useSlots": true,
"useSorted": true,
"useSpeechRecognition": true,
"useSpeechSynthesis": true,
"useStepper": true,
"useStorage": true,
"useStorageAsync": true,
"useStyleTag": true,
"useSupported": true,
"useSwipe": true,
"useTemplateRef": true,
"useTemplateRefsList": true,
"useTextDirection": true,
"useTextSelection": true,
"useTextareaAutosize": true,
"useThrottle": true,
"useThrottleFn": true,
"useThrottledRefHistory": true,
"useTimeAgo": true,
"useTimeout": true,
"useTimeoutFn": true,
"useTimeoutPoll": true,
"useTimestamp": true,
"useTitle": true,
"useToNumber": true,
"useToString": true,
"useToggle": true,
"useTransition": true,
"useUrlSearchParams": true,
"useUserMedia": true,
"useVModel": true,
"useVModels": true,
"useVibrate": true,
"useVirtualList": true,
"useWakeLock": true,
"useWebNotification": true,
"useWebSocket": true,
"useWebWorker": true,
"useWebWorkerFn": true,
"useWindowFocus": true,
"useWindowScroll": true,
"useWindowSize": true,
"watch": true,
"watchArray": true,
"watchAtMost": true,
"watchDebounced": true,
"watchDeep": true,
"watchEffect": true,
"watchIgnorable": true,
"watchImmediate": true,
"watchOnce": true,
"watchPausable": true,
"watchPostEffect": true,
"watchSyncEffect": true,
"watchThrottled": true,
"watchTriggerable": true,
"watchWithFilter": true,
"whenever": true
}
}
-41
View File
@@ -1,41 +0,0 @@
module.exports = {
root: true,
env: {
browser: true,
es2021: true,
node: true
},
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:vue/vue3-recommended'
],
parser: 'vue-eslint-parser',
parserOptions: {
ecmaVersion: 'latest',
parser: '@typescript-eslint/parser',
sourceType: 'module'
},
plugins: ['@typescript-eslint', 'vue'],
rules: {
// Vue 规则
'vue/multi-word-component-names': 'off',
'vue/no-v-html': 'off',
// TypeScript 规则
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-unused-vars': ['error', {
argsIgnorePattern: '^_',
varsIgnorePattern: '^_'
}],
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
// 通用规则
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'prefer-const': 'error',
'no-var': 'error'
}
}
+102 -33
View File
@@ -1,38 +1,107 @@
# Logs # Byte-compiled / optimized / DLL files
logs __pycache__/
*.log *.py[cod]
npm-debug.log* *$py.class
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules # C extensions
dist *.so
dist-ssr
*.local
# Editor directories and files # Distribution / packaging
.vscode/* .Python
!.vscode/extensions.json build/
.idea develop-eggs/
.DS_Store dist/
*.suo downloads/
*.ntvs* eggs/
*.njsproj .eggs/
*.sln lib/
*.sw? lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# Environment variables # PyInstaller
*.manifest
.spec
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
tests/.pytest_cache/
tests/*.png
# Environments
.env .env
.env.local .env.local
.env.development.local .env.production
.env.test.local .venv
.env.production.local env/
venv/
ENV/
env.bak/
venv.bak/
# IDE
.idea/
.vscode/
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db
# Logs
logs/
*.log
# Database
*.db
*.sqlite
*.sqlite3
# Uploads
uploads/*
!uploads/.gitkeep
# Alembic
alembic/versions/*.py
!alembic/versions/__init__.py
# MyPy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre
.pyre/
# Jupyter
.ipynb_checkpoints
# PyCharm
.idea/
# VSCode
.vscode/
# Testing # Testing
coverage test_*.py
.nyc_output/ *_test.py
tests/
# Documentation # Documentation
*.md *.md
@@ -41,7 +110,6 @@ PHASE*.md
DELIVERY*.md DELIVERY*.md
SUMMARY*.md SUMMARY*.md
!README.md !README.md
!src/components/charts/README.md
# Temporary files # Temporary files
*.tmp *.tmp
@@ -49,7 +117,8 @@ SUMMARY*.md
*.bak *.bak
*.backup *.backup
# Lock files # Docker
package-lock.json .dockerignore
yarn.lock
pnpm-lock.yaml # Test reports
test_reports/
-9
View File
@@ -1,9 +0,0 @@
{
"semi": false,
"singleQuote": true,
"printWidth": 100,
"tabWidth": 2,
"trailingComma": "none",
"arrowParens": "avoid",
"endOfLine": "auto"
}
-64
View File
@@ -1,64 +0,0 @@
图表组件库文件清单
===================
核心组件
--------
src/components/charts/BaseChart.vue
src/components/charts/PieChart.vue
src/components/charts/BarChart.vue
src/components/charts/LineChart.vue
src/components/charts/GaugeChart.vue
src/components/charts/FunnelChart.vue
业务图表组件
------------
src/components/charts/business/AssetStatusChart.vue
src/components/charts/business/AssetDistributionChart.vue
src/components/charts/business/AssetValueTrendChart.vue
src/components/charts/business/AssetUtilizationChart.vue
统计卡片组件
------------
src/components/statistics/StatCard.vue
src/components/statistics/StatCardGroup.vue
Composables
-----------
src/composables/useECharts.ts
src/composables/useChartData.ts
工具函数
--------
src/utils/echarts.ts
src/utils/echarts/performance.ts
类型定义
--------
src/types/charts.ts
src/components/charts/charts.d.ts
组件导出
--------
src/components/charts/index.ts
src/components/charts/README.md
src/components/statistics/index.ts
文档
----
CHARTS_README.md - 完整使用文档
CHARTS_DELIVERY.md - 交付文档
CHARTS_QUICKSTART.md - 快速开始指南
CHARTS_SUMMARY.md - 项目总结
CHARTS_FILES.txt - 本文件
示例和测试
----------
src/views/examples/ChartsExample.vue
tests/unit/components/PieChart.test.ts
tests/unit/composables/useECharts.test.ts
路由配置
--------
src/router/index.ts (已添加示例页面路由)
总计:25 个文件
+21 -7
View File
@@ -1,12 +1,26 @@
FROM nginx:alpine FROM python:3.10-slim
# 复制构建产物 WORKDIR /app
COPY dist /usr/share/nginx/html
# 复制Nginx配置 # 安装系统依赖
COPY nginx.conf /etc/nginx/conf.d/default.conf RUN apt-get update && apt-get install -y \
gcc \
postgresql-client \
curl \
&& rm -rf /var/lib/apt/lists/*
# 复制依赖文件
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 复制应用代码
COPY . .
# 创建必要的目录
RUN mkdir -p logs uploads uploads/qrcodes
# 暴露端口 # 暴露端口
EXPOSE 3000 EXPOSE 8001
CMD ["nginx", "-g", "daemon off;"] # 启动命令
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8001"]
View File
+236 -169
View File
@@ -1,217 +1,284 @@
# 资产管理系统前端 # 资产管理系统 - 后端API
> 基于 Vue 3 + TypeScript + Element Plus 构建的现代化资产管理系统前端应用 基于 FastAPI + SQLAlchemy + PostgreSQL 的企业级资产管理系统后端API
## 技术栈 ## 技术栈
- **框架**: Vue 3.4+ (Composition API + `<script setup>`) - **框架**: FastAPI 0.104+
- **语言**: TypeScript 5.0+ - **ORM**: SQLAlchemy 2.0+ (异步模式)
- **构建工具**: Vite 5 - **数据库**: PostgreSQL 14+
- **UI组件库**: Element Plus - **缓存**: Redis
- **状态管理**: Pinia - **认证**: JWT (python-jose)
- **路由**: Vue Router 4 - **密码加密**: bcrypt
- **HTTP客户端**: Axios - **数据验证**: Pydantic v2
- **表单验证**: VeeValidate + Yup - **数据库迁移**: Alembic
- **图表**: ECharts - **测试**: pytest
- **工具库**: dayjs, lodash-es, qrcode - **ASGI服务器**: Uvicorn
- **组合式函数**: @vueuse/core
- **代码规范**: ESLint + Prettier
- **测试**: Vitest
## 功能特性 ## 项目结构
### Phase 1: 项目基础搭建 ✅
- [x] Vite + Vue 3项目初始化
- [x] TypeScript配置
- [x] ESLint + Prettier配置
- [x] 路由配置(Vue Router 4
- [x] 状态管理(Pinia
- [x] Axios请求封装
- [x] UI主题配置(青灰配色 #475569
### Phase 2: 认证与布局 ✅
- [x] 登录页面(Login.vue
- [x] 主应用布局(MainLayout.vue
- [x] 侧边菜单组件
- [x] 顶部导航栏
- [x] 认证状态管理
- [x] 路由守卫
### Phase 3: 后台管理模块(开发中)
- [ ] 用户管理页面
- [ ] 角色权限页面
- [ ] 设备类型管理页面
- [ ] 动态表单设计器
- [ ] 机构网点管理页面
### Phase 4: 资产管理模块(部分完成)
- [x] 资产列表页面
- [x] 资产详情对话框
- [x] 资产入库页面
- [x] 资产编辑对话框
- [ ] 批量导入组件
- [ ] 批量导出组件
- [ ] 扫码查询页面
- [ ] 二维码对话框
- [ ] 资产状态追踪组件
### Phase 5: 资产分配模块(待开发)
- [ ] 分配单列表页面
- [ ] 创建分配单对话框
- [ ] 审批对话框
- [ ] 资产选择器
### Phase 6: 维修与统计(待开发)
- [ ] 维修管理页面
- [ ] 统计报表页面
- [ ] ECharts图表集成
### Phase 7: 系统管理(待开发)
- [ ] 系统配置页面
- [ ] 操作日志页面
- [ ] 消息通知组件
- [ ] 个人中心页面
## 目录结构
``` ```
src/ asset_management_backend/
├── api/ # API接口 ├── app/
│ ├── request.ts # Axios封装 │ ├── api/ # API路由
├── auth.ts # 认证接口 │ └── v1/
├── assets.ts # 资产接口 │ ├── auth.py # 认证相关API
├── users.ts # 用户接口 │ └── __init__.py
── index.ts # 统一导出 ── core/ # 核心模块
├── assets/ # 静态资源 ├── config.py # 配置管理
└── styles/ # 全局样式 │ ├── security.py # 安全相关
├── variables.scss # 主题变量 ├── deps.py # 依赖注入
── index.scss # 全局样式 ── exceptions.py # 自定义异常
├── components/ # 通用组件 │ │ └── response.py # 统一响应
├── composables/ # 组合式函数 ├── crud/ # 数据库CRUD操作
│ ├── usePagination.ts # 分页 │ ├── user.py # 用户CRUD
│ └── useTable.ts # 表格 │ └── ...
├── layouts/ # 布局组件 │ ├── db/ # 数据库相关
└── MainLayout.vue # 主布局 │ ├── base.py # 模型基类
├── router/ # 路由配置 └── session.py # 会话管理
── index.ts ── models/ # SQLAlchemy模型
├── stores/ # Pinia状态管理 ├── user.py # 用户模型
├── modules/ │ └── ...
│ ├── user.ts # 用户状态 │ ├── schemas/ # Pydantic Schema
│ │ ── app.ts # 应用状态 │ │ ── user.py # 用户Schema
│ └── index.ts │ └── ...
├── types/ # TypeScript类型定义 │ ├── services/ # 业务逻辑层
└── index.ts │ ├── auth_service.py # 认证服务
├── utils/ # 工具函数 │ │ └── ...
── auth.ts # 认证工具 ── utils/ # 工具函数
├── format.ts # 格式化工具 └── ...
├── validate.ts # 验证工具 ├── alembic/ # 数据库迁移
│ └── constants.ts # 常量定义 │ └── versions/
├── views/ # 页面组件 ├── tests/ # 测试
│ ├── auth/ # 认证相关 ├── logs/ # 日志文件
│ │ └── Login.vue ├── uploads/ # 上传文件
│ ├── admin/ # 后台管理 ├── .env.example # 环境变量示例
│ │ ├── UserManagement.vue ├── requirements.txt # 依赖包
│ │ ├── RoleManagement.vue ├── run.py # 开发服务器启动脚本
│ │ ├── DeviceTypeManagement.vue └── README.md # 项目说明
│ │ └── OrganizationManagement.vue
│ ├── assets/ # 资产管理
│ │ ├── AssetList.vue
│ │ ├── AssetCreate.vue
│ │ ├── AssetAllocation.vue
│ │ ├── AssetScan.vue
│ │ ├── MaintenanceManagement.vue
│ │ ├── StatisticsDashboard.vue
│ │ └── components/ # 资产相关组件
│ │ ├── AssetDetailDialog.vue
│ │ ├── AssetEditDialog.vue
│ │ └── QrcodeDialog.vue
│ └── error/ # 错误页面
│ └── 404.vue
├── App.vue # 根组件
└── main.ts # 应用入口
``` ```
## 开发指南 ## 快速开始
### 安装依赖 ### 1. 环境准备
确保已安装:
- Python 3.10+
- PostgreSQL 14+
- Redis
### 2. 安装依赖
```bash ```bash
npm install # 创建虚拟环境
python -m venv venv
# 激活虚拟环境
# Windows:
venv\Scripts\activate
# Linux/Mac:
source venv/bin/activate
# 安装依赖包
pip install -r requirements.txt
``` ```
### 启动开发服务器 ### 3. 配置环境变量
```bash ```bash
npm run dev # 复制环境变量示例文件
cp .env.example .env
# 编辑 .env 文件,配置数据库等信息
``` ```
访问 `http://localhost:3000` ### 4. 初始化数据库
### 构建生产版本
```bash ```bash
npm run build # 创建数据库
createdb asset_management
# 运行数据库迁移
alembic upgrade head
# 或在开发环境直接初始化(会自动创建表)
# 修改 app/main.py 中的 lifespan 函数,取消注释 init_db()
``` ```
### 代码检查 ### 5. 启动服务
```bash ```bash
npm run lint # 开发模式(支持热重载)
python run.py
# 或使用 uvicorn
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
``` ```
### 代码格式化 ### 6. 访问API文档
```bash 启动成功后,访问以下地址:
npm run format
```
### 运行测试 - Swagger UI: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc
- OpenAPI JSON: http://localhost:8000/openapi.json
```bash ## API端点
npm run test
```
## 环境配置 ### 认证模块
### 开发环境 (.env.development) - `POST /api/v1/auth/login` - 用户登录
``` - `POST /api/v1/auth/refresh` - 刷新令牌
VITE_API_BASE_URL=http://localhost:8000/api/v1 - `POST /api/v1/auth/logout` - 用户登出
VITE_APP_TITLE=资产管理系统 - `PUT /api/v1/auth/change-password` - 修改密码
``` - `GET /api/v1/auth/captcha` - 获取验证码
### 生产环境 (.env.production) ### 用户管理
```
VITE_API_BASE_URL=https://api.yourcompany.com/api/v1
VITE_APP_TITLE=资产管理系统
```
## 主题定制 - `GET /api/v1/users` - 用户列表
- `POST /api/v1/users` - 创建用户
- `GET /api/v1/users/{user_id}` - 获取用户详情
- `PUT /api/v1/users/{user_id}` - 更新用户
- `DELETE /api/v1/users/{user_id}` - 删除用户
- `POST /api/v1/users/{user_id}/reset-password` - 重置密码
- `GET /api/v1/users/me` - 获取当前用户信息
主题色采用青灰配色方案 (#475569),在 `src/assets/styles/variables.scss` 中可以自定义主题变量。 ### 角色权限
## API接口规范 - `GET /api/v1/roles` - 角色列表
- `POST /api/v1/roles` - 创建角色
- `GET /api/v1/roles/{role_id}` - 获取角色详情
- `PUT /api/v1/roles/{role_id}` - 更新角色
- `DELETE /api/v1/roles/{role_id}` - 删除角色
- `GET /api/v1/permissions/tree` - 权限树列表
详见 `complete_api_reference.md` 文档。 更多API请查看Swagger文档。
## 开发规范 ## 开发规范
详见 `development_standards_guide.md` 请参考 `development_standards_guide.md`
## 页面原型 ### 代码风格
详见 `frontend_page_prototypes.md` 文档。 - 遵循 PEP 8 规范
- 使用 Black 进行代码格式化
- 使用 isort 管理导入
- 使用 flake8 进行代码检查
- 使用 mypy 进行类型检查
## 浏览器支持 ### 提交规范
- Chrome >= 90 遵循 Conventional Commits 规范:
- Firefox >= 88
- Safari >= 14
- Edge >= 90
## 作者 ```
feat: 新功能
fix: Bug修复
docs: 文档更新
style: 代码格式
refactor: 重构
perf: 性能优化
test: 测试
chore: 构建/工具
```
老王 示例:
```bash
git commit -m "feat(auth): 实现用户登录功能"
git commit -m "fix(asset): 修复资产状态转换问题"
```
## 测试
```bash
# 运行所有测试
pytest
# 运行特定测试文件
pytest tests/api/test_auth.py
# 生成覆盖率报告
pytest --cov=app --cov-report=html
# 查看覆盖率报告
open htmlcov/index.html
```
## 数据库迁移
```bash
# 创建新的迁移
alembic revision --autogenerate -m "描述信息"
# 执行迁移
alembic upgrade head
# 回滚迁移
alembic downgrade -1
# 查看迁移历史
alembic history
# 查看当前版本
alembic current
```
## 生产部署
### 使用 Docker
```bash
# 构建镜像
docker build -t asset-management-backend .
# 运行容器
docker run -d \
--name asset-backend \
-p 8000:8000 \
--env-file .env \
asset-management-backend
```
### 使用 Gunicorn + Uvicorn
```bash
pip install gunicorn
gunicorn app.main:app \
--workers 4 \
--worker-class uvicorn.workers.UvicornWorker \
--bind 0.0.0.0:8000 \
--access-logfile - \
--error-logfile -
```
## 常见问题
### 数据库连接失败
检查 `DATABASE_URL` 是否正确配置,确保PostgreSQL服务正在运行。
### Redis连接失败
检查 `REDIS_URL` 是否正确配置,确保Redis服务正在运行。
### Token验证失败
确保 `SECRET_KEY` 配置正确,并检查Token是否过期。
## 贡献指南
1. Fork 本仓库
2. 创建功能分支 (`git checkout -b feature/AmazingFeature`)
3. 提交更改 (`git commit -m 'feat: Add some AmazingFeature'`)
4. 推送到分支 (`git push origin feature/AmazingFeature`)
5. 创建 Pull Request
## 许可证 ## 许可证
MIT 本项目采用 MIT 许可证。
## 联系方式
- 项目负责人: 老王
- 创建时间: 2025-01-24
- 版本: v1.0.0
View File
@@ -207,6 +207,9 @@ class AuthService:
Returns: Returns:
包含captcha_key和captcha_base64的字典 包含captcha_key和captcha_base64的字典
""" """
import logging
logger = logging.getLogger(__name__)
from app.utils.redis_client import redis_client from app.utils.redis_client import redis_client
import random import random
import string import string
@@ -214,8 +217,10 @@ class AuthService:
from io import BytesIO from io import BytesIO
from PIL import Image, ImageDraw, ImageFont from PIL import Image, ImageDraw, ImageFont
try:
# 生成4位随机验证码,使用更清晰的字符组合(排除易混淆的字符) # 生成4位随机验证码,使用更清晰的字符组合(排除易混淆的字符)
captcha_text = ''.join(random.choices('23456789', k=4)) # 排除0、1 captcha_text = ''.join(random.choices('23456789', k=4)) # 排除0、1
logger.info(f"生成验证码: {captcha_text}")
# 生成验证码图片 # 生成验证码图片
width, height = 200, 80 # 增大图片尺寸 width, height = 200, 80 # 增大图片尺寸
@@ -260,6 +265,7 @@ class AuthService:
# 生成captcha_key # 生成captcha_key
captcha_key = ''.join(random.choices(string.ascii_letters + string.digits, k=32)) captcha_key = ''.join(random.choices(string.ascii_letters + string.digits, k=32))
logger.info(f"生成验证码Key: {captcha_key}")
# 存储到Redis5分钟过期 # 存储到Redis5分钟过期
await redis_client.setex( await redis_client.setex(
@@ -267,11 +273,15 @@ class AuthService:
300, 300,
captcha_text captcha_text
) )
logger.info(f"验证码已存储到Redis: captcha:{captcha_key}, 值: {captcha_text}")
return { return {
"captcha_key": captcha_key, "captcha_key": captcha_key,
"captcha_base64": f"data:image/png;base64,{image_base64}" "captcha_base64": f"data:image/png;base64,{image_base64}"
} }
except Exception as e:
logger.error(f"生成验证码失败: {str(e)}", exc_info=True)
raise
async def _verify_captcha(self, captcha_key: str, captcha: str) -> bool: async def _verify_captcha(self, captcha_key: str, captcha: str) -> bool:
""" """

Some files were not shown because too many files have changed in this diff Show More