Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions backend/app/core/base_model.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from datetime import UTC, datetime

from sqlalchemy import Boolean, DateTime, ForeignKey, Index, Integer, MetaData, String
from sqlalchemy import JSON, Boolean, DateTime, Index, Integer, MetaData, String
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.ext.asyncio import AsyncAttrs
from sqlalchemy.orm import DeclarativeBase, Mapped, declared_attr, mapped_column, relationship

Expand All @@ -18,6 +19,12 @@
"pk": "pk_%(table_name)s",
}

# 跨方言 JSON 类型:PostgreSQL(生产)使用 JSONB,SQLite/MySQL(测试环境)降级为
# 通用 JSON,保证 create_all 与 autogenerate 在三种方言下均可渲染、零漂移。
# 各模块定义 JSON 列时统一使用 JSONType,而非直接硬编码 JSONB,避免破坏基类
# 「兼容 SQLite、MySQL 和 PostgreSQL」的承诺。
JSONType = JSONB().with_variant(JSON(), "sqlite", "mysql")


class MappedBase(AsyncAttrs, DeclarativeBase):
"""声明式基类
Expand Down Expand Up @@ -132,15 +139,13 @@ class UserMixin(MappedBase):

created_id: Mapped[int | None] = mapped_column(
Integer,
ForeignKey("sys_user.id", ondelete="SET NULL", onupdate="CASCADE"),
default=None,
nullable=True,
index=True,
comment="创建人ID",
)
updated_id: Mapped[int | None] = mapped_column(
Integer,
ForeignKey("sys_user.id", ondelete="SET NULL", onupdate="CASCADE"),
default=None,
nullable=True,
index=True,
Expand All @@ -149,7 +154,6 @@ class UserMixin(MappedBase):

deleted_id: Mapped[int | None] = mapped_column(
Integer,
ForeignKey("sys_user.id", ondelete="SET NULL", onupdate="CASCADE"),
default=None,
nullable=True,
index=True,
Expand All @@ -161,7 +165,7 @@ def created_by(self):
"""创建人关联关系"""
return relationship(
"UserModel",
foreign_keys=lambda: self.created_id, # pyright: ignore[reportArgumentType]
primaryjoin=f"foreign({self.__name__}.created_id) == remote(UserModel.id)",
uselist=False,
)

Expand All @@ -170,7 +174,7 @@ def updated_by(self):
"""更新人关联关系"""
return relationship(
"UserModel",
foreign_keys=lambda: self.updated_id, # pyright: ignore[reportArgumentType]
primaryjoin=f"foreign({self.__name__}.updated_id) == remote(UserModel.id)",
uselist=False,
)

Expand All @@ -179,6 +183,6 @@ def deleted_by(self):
"""删除人关联关系"""
return relationship(
"UserModel",
foreign_keys=lambda: self.deleted_id, # pyright: ignore[reportArgumentType]
primaryjoin=f"foreign({self.__name__}.deleted_id) == remote(UserModel.id)",
uselist=False,
)
23 changes: 19 additions & 4 deletions backend/app/modules/system/user/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,25 @@ class UserModel(ModelMixin, UserMixin):
status: Mapped[int] = mapped_column(Integer, default=0, nullable=False, comment="状态(0:启动 1:停用)")
description: Mapped[str | None] = mapped_column(Text, default=None, nullable=True, comment="备注")

dept_id: Mapped[int | None] = mapped_column(Integer, ForeignKey("sys_dept.id", ondelete="SET NULL", onupdate="CASCADE", use_alter=True), nullable=True, index=True, comment="部门ID")
dept_id: Mapped[int | None] = mapped_column(Integer, ForeignKey("sys_dept.id", ondelete="SET NULL", onupdate="CASCADE"), nullable=True, index=True, comment="部门ID")
dept: Mapped["DeptModel | None"] = relationship(back_populates="users", foreign_keys=[dept_id])
roles: Mapped[list["RoleModel"]] = relationship(secondary="sys_user_roles", back_populates="users")
positions: Mapped[list["PositionModel"]] = relationship(secondary="sys_user_positions", back_populates="users")
created_by: Mapped["UserModel | None"] = relationship("UserModel", foreign_keys="UserModel.created_id", remote_side="UserModel.id", uselist=False, viewonly=True)
updated_by: Mapped["UserModel | None"] = relationship("UserModel", foreign_keys="UserModel.updated_id", remote_side="UserModel.id", uselist=False, viewonly=True)
deleted_by: Mapped["UserModel | None"] = relationship("UserModel", foreign_keys="UserModel.deleted_id", remote_side="UserModel.id", uselist=False, viewonly=True)
created_by: Mapped["UserModel | None"] = relationship(
"UserModel",
primaryjoin="foreign(UserModel.created_id) == remote(UserModel.id)",
uselist=False,
viewonly=True,
)
updated_by: Mapped["UserModel | None"] = relationship(
"UserModel",
primaryjoin="foreign(UserModel.updated_id) == remote(UserModel.id)",
uselist=False,
viewonly=True,
)
deleted_by: Mapped["UserModel | None"] = relationship(
"UserModel",
primaryjoin="foreign(UserModel.deleted_id) == remote(UserModel.id)",
uselist=False,
viewonly=True,
)
4 changes: 2 additions & 2 deletions frontend/app/src/composables/useListPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ export function useListPage<T, AG extends AlovaGenerics = AlovaGenerics>(options
watchingStates: [],
preloadNextPage: false,
preloadPreviousPage: false,
// 响应已由 http 层 responded 解包为业务结构 { list, total }
data: res => (res as PageResult<T>).list ?? [],
// 响应已由 http 层 responded 解包为业务结构 { items, total }
data: res => (res as PageResult<T>).items ?? [],
total: res => (res as PageResult<T>).total ?? 0,
},
)
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/src/pages/index/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ async function loadData() {
async function loadNotices() {
try {
const res = await NoticeAPI.getPage({ page_no: 1, page_size: 3, status: 1 })
recentNotices.value = res.list || []
recentNotices.value = res.items || []
}
catch { /* silent */ }
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/src/subPages/module_ai/chat/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ async function loadSessions() {
loading.value = true
try {
const res = await ChatAPI.getSessions()
sessions.value = res.list || []
sessions.value = res.items || []
}
catch {
sessions.value = []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ async function loadComments() {
return
try {
const res = await TicketAPI.getComments(ticketId.value, { page_no: commentPage.page_no, page_size: commentPage.page_size })
comments.value = res.list || []
comments.value = res.items || []
commentTotal.value = res.total || 0
}
catch (e) {
Expand Down
4 changes: 2 additions & 2 deletions frontend/app/src/types/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ declare global {
* 分页响应对象(列表接口 `data` 统一为该结构)
*/
interface PageResult<T = any> {
/** 数据列表 */
list: T[]
/** 数据列表(后端 PageResultSchema 统一返回 items,而非 list) */
items: T[]
/** 总数 */
total: number
page_no?: number
Expand Down
Loading