From 8e856d13446b52a8d5b9a0db0ad15bc21a70c58a Mon Sep 17 00:00:00 2001 From: yuan <964343743@qq.com> Date: Mon, 8 Sep 2025 16:42:47 +0800 Subject: [PATCH 1/6] =?UTF-8?q?refactor(role):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E9=AA=8C=E8=AF=81=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/api/v1/module_system/role/schema.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/backend/app/api/v1/module_system/role/schema.py b/backend/app/api/v1/module_system/role/schema.py index 8f0c9c53..828d0362 100644 --- a/backend/app/api/v1/module_system/role/schema.py +++ b/backend/app/api/v1/module_system/role/schema.py @@ -26,11 +26,10 @@ class RolePermissionSettingSchema(BaseModel): menu_ids: List[int] = Field(default_factory=list, description='菜单ID列表') dept_ids: List[int] = Field(default_factory=list, description='部门ID列表') - @classmethod @model_validator(mode='after') - def validate_fields(cls, data): + def validate_fields(self): """验证权限配置字段""" - return role_permission_request_validator(data) + return role_permission_request_validator(self) class RoleUpdateSchema(RoleCreateSchema): From a1dc54a662af49cfc27570100efcd55e7d5b0016 Mon Sep 17 00:00:00 2001 From: yuan <964343743@qq.com> Date: Mon, 8 Sep 2025 16:47:30 +0800 Subject: [PATCH 2/6] =?UTF-8?q?fix(menu):=20=E4=BF=AE=E5=A4=8D=E8=8F=9C?= =?UTF-8?q?=E5=8D=95=E7=9A=84=E9=AA=8C=E8=AF=81=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/api/v1/module_system/menu/schema.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/backend/app/api/v1/module_system/menu/schema.py b/backend/app/api/v1/module_system/menu/schema.py index fbd3c176..2b9a019f 100644 --- a/backend/app/api/v1/module_system/menu/schema.py +++ b/backend/app/api/v1/module_system/menu/schema.py @@ -28,10 +28,9 @@ class MenuCreateSchema(BaseModel): parent_id: Optional[int] = Field(default=None, ge=1, description="父菜单ID") description: Optional[str] = Field(default=None, max_length=500, description="备注说明") - @classmethod @model_validator(mode='after') - def validate_fields(cls, data): - return menu_request_validator(data) + def validate_fields(self): + return menu_request_validator(self) class MenuUpdateSchema(MenuCreateSchema): From 255f9ef245462b9e66d382260901883b4c8c5e09 Mon Sep 17 00:00:00 2001 From: yuan <964343743@qq.com> Date: Mon, 8 Sep 2025 16:50:27 +0800 Subject: [PATCH 3/6] =?UTF-8?q?refactor(auth):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E8=AE=A4=E8=AF=81=E7=9A=84=E4=BB=A3=E7=A0=81=E9=A3=8E=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/api/v1/module_system/auth/schema.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/app/api/v1/module_system/auth/schema.py b/backend/app/api/v1/module_system/auth/schema.py index 9f96d84b..ceccde0f 100644 --- a/backend/app/api/v1/module_system/auth/schema.py +++ b/backend/app/api/v1/module_system/auth/schema.py @@ -2,7 +2,7 @@ from typing import Optional, Union from datetime import datetime -from pydantic import ConfigDict, Field, BaseModel, field_validator, model_validator +from pydantic import ConfigDict, Field, BaseModel, model_validator from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import Session @@ -25,10 +25,10 @@ class JWTPayloadSchema(BaseModel): exp: Union[datetime, int] = Field(..., description='过期时间') @model_validator(mode='after') - def validate_fields(cls, data): - if not data.sub or len(data.sub.strip()) == 0: + def validate_fields(self): + if not self.sub or len(self.sub.strip()) == 0: raise ValueError("会话编号不能为空") - return data + return self class JWTOutSchema(BaseModel): From 372bce54e68c2183b3d181aaf7d7d9b29ab81e27 Mon Sep 17 00:00:00 2001 From: yuan <964343743@qq.com> Date: Mon, 8 Sep 2025 18:06:31 +0800 Subject: [PATCH 4/6] =?UTF-8?q?fix(user):=20=E4=BF=AE=E5=A4=8D=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E7=94=A8=E6=88=B7=E6=98=AF=E5=BF=85=E4=BC=A0password?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/api/v1/module_system/user/schema.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/app/api/v1/module_system/user/schema.py b/backend/app/api/v1/module_system/user/schema.py index f477eea2..5eb17b09 100644 --- a/backend/app/api/v1/module_system/user/schema.py +++ b/backend/app/api/v1/module_system/user/schema.py @@ -78,7 +78,9 @@ class UserCreateSchema(CurrentUserUpdateSchema): class UserUpdateSchema(UserCreateSchema): """更新""" - model_config = ConfigDict(from_attributes=True, exclude={"password"}) + model_config = ConfigDict(from_attributes=True) + + password: Optional[str] = Field(default=None, max_length=128, description="密码哈希值") class UserOutSchema(UserCreateSchema, BaseSchema): From d0f0ff3ad1d102fcf446b427f3da195fb438d184 Mon Sep 17 00:00:00 2001 From: zhangtao <9480807882@qq.com> Date: Mon, 8 Sep 2025 20:49:46 +0800 Subject: [PATCH 5/6] =?UTF-8?q?docs(readme):=20=E6=9B=B4=E6=96=B0=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E4=BB=8B=E7=BB=8D=E5=A2=9E=E5=8A=A0wot-design-uni?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改README.md中的项目介绍,新增wot-design-uni依赖说明 - 调整auto-imports.d.ts,删除大量与主题相关的接口定义 - 移除关于主题、颜色、渐变等相关工具函数的声明 - 清理无用的主题组合式函数和工具方法的导入声明 - 保持全局类型声明更简洁,减少主题相关的导入依赖 - 保留核心api和工具函数的全局类型声明,确保正常使用 --- fastapp/README.md | 2 +- fastapp/src/types/auto-imports.d.ts | 30 ----------------------------- 2 files changed, 1 insertion(+), 31 deletions(-) diff --git a/fastapp/README.md b/fastapp/README.md index c8febeed..413237cd 100644 --- a/fastapp/README.md +++ b/fastapp/README.md @@ -1,6 +1,6 @@ # 项目介绍 -基于 uni-app + Vue 3 + TypeScript 移动端跨平台开发模板,集成了 ESLint、Prettier、Stylelint、Husky 和 Commitlint 等工具,确保代码规范与质量。 +基于 uni-app + wot-design-uni + Vue 3 + TypeScript 移动端跨平台开发模板,集成了 ESLint、Prettier、Stylelint、Husky 和 Commitlint 等工具,确保代码规范与质量。 ## 项目截图 diff --git a/fastapp/src/types/auto-imports.d.ts b/fastapp/src/types/auto-imports.d.ts index c26e54a6..4e1cc724 100644 --- a/fastapp/src/types/auto-imports.d.ts +++ b/fastapp/src/types/auto-imports.d.ts @@ -10,22 +10,17 @@ declare global { const EffectScope: typeof import('vue')['EffectScope'] const Storage: typeof import('../utils/storage')['Storage'] const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate'] - const applyCSSVariables: typeof import('../utils/theme')['applyCSSVariables'] - const applyThemeOnPageShow: typeof import('../utils/theme')['applyThemeOnPageShow'] - const applyThemeToMiniProgram: typeof import('../utils/theme')['applyThemeToMiniProgram'] const auth: typeof import('../api/auth')['default'] const checkLogin: typeof import('../utils/auth')['checkLogin'] const clearAll: typeof import('../utils/auth')['clearAll'] const clearToken: typeof import('../utils/storage')['clearToken'] const clearTokens: typeof import('../utils/auth')['clearTokens'] const clearUserInfo: typeof import('../utils/auth')['clearUserInfo'] - const colorColumns: typeof import('../composables/useTheme')['colorColumns'] const computed: typeof import('vue')['computed'] const config: typeof import('../api/config')['default'] const createApp: typeof import('vue')['createApp'] const createPinia: typeof import('pinia')['createPinia'] const createRouter: typeof import('uni-mini-router')['createRouter'] - const currentThemeColor: typeof import('../composables/useTheme')['currentThemeColor'] const customRef: typeof import('vue')['customRef'] const debounce: typeof import('../utils/index')['debounce'] const defineAsyncComponent: typeof import('vue')['defineAsyncComponent'] @@ -34,35 +29,22 @@ declare global { const dept: typeof import('../api/dept')['default'] const dict: typeof import('../api/dict')['default'] const effectScope: typeof import('vue')['effectScope'] - const extendedColorOptions: typeof import('../composables/useTheme')['extendedColorOptions'] const file: typeof import('../api/file')['default'] - const generateCSSVariables: typeof import('../utils/theme')['generateCSSVariables'] - const generateColorVariants: typeof import('../utils/theme')['generateColorVariants'] - const generateGradientBackground: typeof import('../utils/theme')['generateGradientBackground'] const getAccessToken: typeof import('../utils/auth')['getAccessToken'] const getActivePinia: typeof import('pinia')['getActivePinia'] - const getContrastColor: typeof import('../utils/theme')['getContrastColor'] const getCurrentInstance: typeof import('vue')['getCurrentInstance'] const getCurrentScope: typeof import('vue')['getCurrentScope'] - const getDarkerColor: typeof import('../utils/colorUtils')['getDarkerColor'] - const getLighterColor: typeof import('../utils/colorUtils')['getLighterColor'] const getRefreshToken: typeof import('../utils/auth')['getRefreshToken'] - const getThemeClassName: typeof import('../utils/theme')['getThemeClassName'] - const getThemeColor: typeof import('../utils/theme')['getThemeColor'] - const getThemeColors: typeof import('../utils/theme')['getThemeColors'] const getToken: typeof import('../utils/storage')['getToken'] const getUserInfo: typeof import('../utils/auth')['getUserInfo'] const guessSerializerType: typeof import('@uni-helper/uni-use')['guessSerializerType'] const h: typeof import('vue')['h'] - const initTheme: typeof import('../composables/useTheme')['initTheme'] const inject: typeof import('vue')['inject'] - const isDarkMode: typeof import('../utils/theme')['isDarkMode'] const isLoggedIn: typeof import('../utils/auth')['isLoggedIn'] const isProxy: typeof import('vue')['isProxy'] const isReactive: typeof import('vue')['isReactive'] const isReadonly: typeof import('vue')['isReadonly'] const isRef: typeof import('vue')['isRef'] - const isValidColor: typeof import('../utils/theme')['isValidColor'] const log: typeof import('../api/log')['default'] const mapActions: typeof import('pinia')['mapActions'] const mapGetters: typeof import('pinia')['mapGetters'] @@ -72,7 +54,6 @@ declare global { const markRaw: typeof import('vue')['markRaw'] const menu: typeof import('../api/menu')['default'] const nextTick: typeof import('vue')['nextTick'] - const normalizeColor: typeof import('../utils/theme')['normalizeColor'] const notice: typeof import('../api/notice')['default'] const onActivated: typeof import('vue')['onActivated'] const onAddToFavorites: typeof import('@dcloudio/uni-app')['onAddToFavorites'] @@ -121,15 +102,12 @@ declare global { const ref: typeof import('vue')['ref'] const request: typeof import('../utils/request')['default'] const requireLogin: typeof import('../utils/auth')['requireLogin'] - const resetTheme: typeof import('../composables/useTheme')['resetTheme'] const resolveComponent: typeof import('vue')['resolveComponent'] const role: typeof import('../api/role')['default'] const setAccessToken: typeof import('../utils/auth')['setAccessToken'] const setActivePinia: typeof import('pinia')['setActivePinia'] const setMapStoreSuffix: typeof import('pinia')['setMapStoreSuffix'] const setRefreshToken: typeof import('../utils/auth')['setRefreshToken'] - const setThemeColor: typeof import('../utils/theme')['setThemeColor'] - const setThemeColorCache: typeof import('../utils/theme')['setThemeColorCache'] const setToken: typeof import('../utils/storage')['setToken'] const setUserInfo: typeof import('../utils/auth')['setUserInfo'] const setupStore: typeof import('../store/index')['setupStore'] @@ -138,14 +116,10 @@ declare global { const shallowRef: typeof import('vue')['shallowRef'] const store: typeof import('../store/index')['store'] const storeToRefs: typeof import('pinia')['storeToRefs'] - const theme: typeof import('../composables/useTheme')['theme'] - const themeColorOptions: typeof import('../composables/useTheme')['themeColorOptions'] - const themeVars: typeof import('../composables/useTheme')['themeVars'] const toRaw: typeof import('vue')['toRaw'] const toRef: typeof import('vue')['toRef'] const toRefs: typeof import('vue')['toRefs'] const toValue: typeof import('vue')['toValue'] - const toggleTheme: typeof import('../composables/useTheme')['toggleTheme'] const triggerRef: typeof import('vue')['triggerRef'] const tryOnBackPress: typeof import('@uni-helper/uni-use')['tryOnBackPress'] const tryOnHide: typeof import('@uni-helper/uni-use')['tryOnHide'] @@ -196,13 +170,9 @@ declare global { const useStorageSync: typeof import('@uni-helper/uni-use')['useStorageSync'] const useTabbar: typeof import('../composables/useTabbar')['useTabbar'] const useTemplateRef: typeof import('vue')['useTemplateRef'] - const useTheme: typeof import('../composables/useTheme')['useTheme'] const useThemeStore: typeof import('../store/modules/theme.store')['useThemeStore'] const useToast: typeof import('wot-design-uni')['useToast'] - const useUploadFile: typeof import('@uni-helper/uni-use')['useUploadFile'] const useUserStore: typeof import('../store/modules/user.store')['useUserStore'] - const useVisible: typeof import('@uni-helper/uni-use')['useVisible'] - const useWechat: typeof import('../composables/useWechat')['useWechat'] const user: typeof import('../api/user')['default'] const watch: typeof import('vue')['watch'] const watchEffect: typeof import('vue')['watchEffect'] From 67f194f6cad81d82e245c115ac4c207fa183bc47 Mon Sep 17 00:00:00 2001 From: zhangtao <9480807882@qq.com> Date: Mon, 8 Sep 2025 21:02:21 +0800 Subject: [PATCH 6/6] =?UTF-8?q?fix(middleware):=20=E7=A6=81=E6=AD=A2?= =?UTF-8?q?=E6=BC=94=E7=A4=BA=E7=8E=AF=E5=A2=83=E4=B8=AD=E6=97=A0=E6=9D=83?= =?UTF-8?q?=E9=99=90=E7=94=A8=E6=88=B7=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除演示环境中权限检查的异常处理逻辑 - 直接返回错误响应,阻止无权限用户继续操作 fix(initialize): 修正PostgreSQL自增序列更新逻辑 - 新增私有方法更新PostgreSQL数据库中表的序列值 - 在初始化数据后更新序列,保证ID自增正确 - 处理更新序列过程中可能的异常并记录日志 - 优化导入语句,增加text支持数据库原生SQL执行 --- backend/app/core/middlewares.py | 15 ++----------- backend/app/scripts/initialize.py | 37 ++++++++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/backend/app/core/middlewares.py b/backend/app/core/middlewares.py index 22010823..33db1ea0 100644 --- a/backend/app/core/middlewares.py +++ b/backend/app/core/middlewares.py @@ -85,19 +85,8 @@ class DemoEnvMiddleware(BaseHTTPMiddleware): return await call_next(request) else: - try: - response = await call_next(request) - - # 现在检查用户是否有权限执行操作 - user_username = request.scope.get("user_username") - if user_username and user_username not in settings.DEMO_USER_WHITE_LIST: - # 如果用户没有权限,返回错误响应 - return ErrorResponse(msg="演示环境,禁止操作") - - return response - except Exception as e: - # 处理可能的异常 - raise e + # 直接返回错误响应,不继续执行后续操作 + return ErrorResponse(msg="演示环境,禁止操作") return await call_next(request) diff --git a/backend/app/scripts/initialize.py b/backend/app/scripts/initialize.py index c1f0d8f4..3290aeae 100644 --- a/backend/app/scripts/initialize.py +++ b/backend/app/scripts/initialize.py @@ -4,7 +4,7 @@ import uuid import json from pathlib import Path from typing import Dict, List -from sqlalchemy import inspect, select, func +from sqlalchemy import inspect, select, func, text from sqlalchemy.ext.asyncio import AsyncSession from app.core.base_model import MappedBase @@ -60,6 +60,7 @@ class InitializeData: RoleMenusModel, ] self.created_tables = set() + async def __get_existing_tables(self, db: AsyncSession) -> List[str]: return await db.run_sync( lambda sync_db: inspect(sync_db.get_bind()).get_table_names() @@ -111,6 +112,37 @@ class InitializeData: except Exception as e: logger.error(f"初始化 {table_name} 表数据失败: {str(e)}") raise + + # 更新 PostgreSQL 序列值,确保自增 ID 正确 + if settings.DATABASE_TYPE == "postgresql": + await self.__update_postgresql_sequences(db) + + async def __update_postgresql_sequences(self, db: AsyncSession) -> None: + """更新 PostgreSQL 序列值,确保自增 ID 正确""" + try: + # 为每个有初始化数据的表更新序列值 + for model in self.prepare_init_models: + table_name = model.__tablename__ + + # 检查表中是否有数据 + count_result = await db.execute(select(func.count()).select_from(model)) + existing_count = count_result.scalar() + + if existing_count > 0: + # 获取表中最大的 ID 值 + max_id_result = await db.execute(select(func.max(model.id)).select_from(model)) + max_id = max_id_result.scalar() + + if max_id is not None: + # 更新序列值 + sequence_name = f"{table_name}_id_seq" + await db.execute(text(f"SELECT setval('{sequence_name}', {max_id}, true)")) + logger.info(f"已更新 {table_name} 表的序列 {sequence_name} 值为 {max_id}") + + await db.commit() + except Exception as e: + logger.error(f"更新 PostgreSQL 序列值失败: {str(e)}") + raise async def __get_data(self, filename: str) -> List[Dict]: """读取初始化数据文件""" @@ -132,5 +164,4 @@ class InitializeData: """ 执行完整初始化流程 """ - await self.__init_model(db) - + await self.__init_model(db) \ No newline at end of file