From b22777fa2daf83a75525bc00289cccccc83228f9 Mon Sep 17 00:00:00 2001 From: zlwu <704541015@qq.com> Date: Thu, 30 Jul 2026 17:22:41 +0800 Subject: [PATCH] feat(user): add hire_date and probation_months to sys_user and user admin Co-authored-by: Cursor --- backend/app/api/admin.py | 43 ++++++++++++++--------- backend/app/api/public.py | 2 ++ backend/app/crud/user.py | 32 +++++++++++++++-- backend/app/models/models.py | 2 ++ docs/sql/sys_user_hire_probation.sql | 5 +++ web-admin/src/api/admin.ts | 4 +++ web-admin/src/types/api.d.ts | 2 ++ web-admin/src/views/system/user/index.vue | 42 ++++++++++++++++++++++ 8 files changed, 113 insertions(+), 19 deletions(-) create mode 100644 docs/sql/sys_user_hire_probation.sql diff --git a/backend/app/api/admin.py b/backend/app/api/admin.py index ec6ae0aa..0332c39e 100644 --- a/backend/app/api/admin.py +++ b/backend/app/api/admin.py @@ -253,6 +253,8 @@ class UserCreateBody(BaseModel): supervisor_user_id: Optional[str] = Field(None, alias="supervisorUserId") email: Optional[str] = Field("", alias="email") phone_no: Optional[str] = Field("", alias="phoneNo") + hire_date: Optional[str] = Field(None, alias="hireDate") + probation_months: Optional[int] = Field(None, alias="probationMonths") sex: Optional[str] = Field("0", alias="sex") avatar: Optional[str] = Field(None, alias="avatar") status: Optional[str] = Field("1", alias="status") @@ -269,6 +271,8 @@ class UserUpdateBody(BaseModel): supervisor_user_id: Optional[str] = Field(None, alias="supervisorUserId") email: Optional[str] = Field(None, alias="email") phone_no: Optional[str] = Field(None, alias="phoneNo") + hire_date: Optional[str] = Field(None, alias="hireDate") + probation_months: Optional[int] = Field(None, alias="probationMonths") sex: Optional[str] = Field(None, alias="sex") avatar: Optional[str] = Field(None, alias="avatar") status: Optional[str] = Field(None, alias="status") @@ -378,6 +382,8 @@ async def create_user( supervisor_user_id=body.supervisor_user_id, email=body.email, phone_no=body.phone_no, + hire_date=body.hire_date, + probation_months=body.probation_months, sex=body.sex, avatar=body.avatar, status=body.status, @@ -402,23 +408,26 @@ async def update_user( ): try: payload: dict[str, Any] = body.model_dump(exclude_unset=True, by_alias=False) - obj = user_svc.update_user( - db, - user_id, - nick_name=payload.get("nick_name"), - dept_id=payload.get("dept_id"), - supervisor_user_id=payload.get("supervisor_user_id"), - email=payload.get("email"), - phone_no=payload.get("phone_no"), - sex=payload.get("sex"), - avatar=payload.get("avatar"), - status=payload.get("status"), - order_num=payload.get("order_num"), - remark=payload.get("remark"), - user_id_updater=user.get("user_id"), - role_ids=payload.get("role_ids"), - post_ids=payload.get("post_ids"), - ) + update_kwargs: dict[str, Any] = { + "nick_name": payload.get("nick_name"), + "dept_id": payload.get("dept_id"), + "supervisor_user_id": payload.get("supervisor_user_id"), + "email": payload.get("email"), + "phone_no": payload.get("phone_no"), + "sex": payload.get("sex"), + "avatar": payload.get("avatar"), + "status": payload.get("status"), + "order_num": payload.get("order_num"), + "remark": payload.get("remark"), + "user_id_updater": user.get("user_id"), + "role_ids": payload.get("role_ids"), + "post_ids": payload.get("post_ids"), + } + if "hire_date" in payload: + update_kwargs["hire_date"] = payload.get("hire_date") + if "probation_months" in payload: + update_kwargs["probation_months"] = payload.get("probation_months") + obj = user_svc.update_user(db, user_id, **update_kwargs) return success_response(user_svc._row_to_dict(obj), message="更新成功") except ValueError as e: return error_response(400, str(e)) diff --git a/backend/app/api/public.py b/backend/app/api/public.py index 92d09704..30b40382 100644 --- a/backend/app/api/public.py +++ b/backend/app/api/public.py @@ -59,6 +59,8 @@ def _build_user_info_payload(user: SysUser, web_role: str, role_names: list = No "realName": user.nick_name, "phone": phone, "email": (getattr(user, "email", None) or "").strip() or None, + "hireDate": user.hire_date.strftime("%Y-%m-%d") if getattr(user, "hire_date", None) else None, + "probationMonths": getattr(user, "probation_months", None), "sex": getattr(user, "sex", None) or "0", "remark": (getattr(user, "remark", None) or "").strip() or None, "role": web_role, diff --git a/backend/app/crud/user.py b/backend/app/crud/user.py index 512a789e..60c9e37c 100644 --- a/backend/app/crud/user.py +++ b/backend/app/crud/user.py @@ -2,8 +2,8 @@ from __future__ import annotations import math -from datetime import datetime -from typing import Any, Dict, List, Optional, Tuple +from datetime import date, datetime +from typing import Any, Dict, List, Optional, Tuple, Union import bcrypt from sqlalchemy import and_, func, or_ @@ -44,6 +44,10 @@ def _row_to_dict(u: SysUser, dept_name: str = "") -> Dict[str, Any]: "nickName": u.nick_name, "email": u.email or "", "phoneNo": u.phone_no or "", + "hireDate": u.hire_date.strftime("%Y-%m-%d") if getattr(u, "hire_date", None) else "", + "probationMonths": ( + u.probation_months if getattr(u, "probation_months", None) is not None else None + ), "sex": u.sex or "0", "avatar": u.avatar or "", "status": u.status, @@ -285,6 +289,17 @@ def _replace_associations( )) +def _parse_hire_date(value: Optional[Union[str, date]]) -> Optional[date]: + if value is None or value == "": + return None + if isinstance(value, date) and not isinstance(value, datetime): + return value + s = str(value).strip() + if not s: + return None + return datetime.strptime(s[:10], "%Y-%m-%d").date() + + def create_user( db: Session, *, @@ -294,6 +309,8 @@ def create_user( dept_id: Optional[str] = None, email: str = "", phone_no: str = "", + hire_date: Optional[Union[str, date]] = None, + probation_months: Optional[int] = None, sex: str = "0", avatar: Optional[str] = None, status: str = "1", @@ -323,6 +340,8 @@ def create_user( nick_name=nn, email=(email or "").strip(), phone_no=(phone_no or "").strip(), + hire_date=_parse_hire_date(hire_date), + probation_months=probation_months, sex=sex or "0", avatar=avatar, password=_hash_password(pw), @@ -354,6 +373,8 @@ def update_user( dept_id: Optional[str] = None, email: Optional[str] = None, phone_no: Optional[str] = None, + hire_date: Any = ..., + probation_months: Any = ..., sex: Optional[str] = None, avatar: Optional[str] = None, status: Optional[str] = None, @@ -378,6 +399,13 @@ def update_user( obj.email = (email or "").strip() if phone_no is not None: obj.phone_no = (phone_no or "").strip() + if hire_date is not ...: + obj.hire_date = _parse_hire_date(hire_date) + if probation_months is not ...: + if probation_months is None or probation_months == "": + obj.probation_months = None + else: + obj.probation_months = int(probation_months) if sex is not None: obj.sex = sex if avatar is not None: diff --git a/backend/app/models/models.py b/backend/app/models/models.py index fe6ad256..e9fe5dd6 100644 --- a/backend/app/models/models.py +++ b/backend/app/models/models.py @@ -31,6 +31,8 @@ class SysUser(Base): nick_name = Column(String(30), nullable=False, comment="用户名") email = Column(String(50), nullable=False, default="", comment="用户邮箱") phone_no = Column(String(11), nullable=False, default="", comment="手机号码") + hire_date = Column(Date, nullable=True, comment="入职日期") + probation_months = Column(Integer, nullable=True, comment="试用期月数") sex = Column(CHAR(1), nullable=True, default="0", comment="用户性别") avatar = Column(String(512), nullable=True, comment="头像") password = Column("password", String(100), nullable=False, default="", comment="密码") diff --git a/docs/sql/sys_user_hire_probation.sql b/docs/sql/sys_user_hire_probation.sql new file mode 100644 index 00000000..746e0775 --- /dev/null +++ b/docs/sql/sys_user_hire_probation.sql @@ -0,0 +1,5 @@ +-- docs/sql/sys_user_hire_probation.sql +-- 用户表补齐入职日期、试用期月数(转正套件主数据) +ALTER TABLE `sys_user` + ADD COLUMN `hire_date` date DEFAULT NULL COMMENT '入职日期' AFTER `phone_no`, + ADD COLUMN `probation_months` int(11) DEFAULT NULL COMMENT '试用期月数' AFTER `hire_date`; diff --git a/web-admin/src/api/admin.ts b/web-admin/src/api/admin.ts index 39afbb07..3ab9218e 100644 --- a/web-admin/src/api/admin.ts +++ b/web-admin/src/api/admin.ts @@ -132,6 +132,8 @@ export function fetchCreateUser(data: { supervisorUserId?: string email?: string phoneNo?: string + hireDate?: string + probationMonths?: number | null sex?: string avatar?: string status?: string @@ -155,6 +157,8 @@ export function fetchUpdateUser( supervisorUserId: string email: string phoneNo: string + hireDate: string | null + probationMonths: number | null sex: string avatar: string status: string diff --git a/web-admin/src/types/api.d.ts b/web-admin/src/types/api.d.ts index d07ee70a..fd5d39f8 100644 --- a/web-admin/src/types/api.d.ts +++ b/web-admin/src/types/api.d.ts @@ -43,6 +43,8 @@ declare namespace Api { nickName: string email: string phoneNo: string + hireDate?: string + probationMonths?: number | null sex: string avatar: string status: string diff --git a/web-admin/src/views/system/user/index.vue b/web-admin/src/views/system/user/index.vue index f8dffbfe..a9e22c83 100644 --- a/web-admin/src/views/system/user/index.vue +++ b/web-admin/src/views/system/user/index.vue @@ -313,6 +313,27 @@ + + + + + + @@ -479,6 +500,8 @@ supervisorUserId: '' as string, email: '', phoneNo: '', + hireDate: '' as string, + probationMonths: null as number | null, sex: '0', avatar: '', status: '1', @@ -584,6 +607,8 @@ formData.supervisorUserId = '' formData.email = '' formData.phoneNo = '' + formData.hireDate = '' + formData.probationMonths = null formData.sex = '0' formData.avatar = '' formData.status = '1' @@ -618,6 +643,11 @@ formData.supervisorUserId = detail.supervisorUserId || '' formData.email = detail.email || '' formData.phoneNo = detail.phoneNo || '' + formData.hireDate = detail.hireDate || '' + formData.probationMonths = + detail.probationMonths === null || detail.probationMonths === undefined + ? null + : Number(detail.probationMonths) formData.sex = detail.sex || '0' formData.avatar = detail.avatar || '' formData.status = detail.status || '1' @@ -651,6 +681,8 @@ supervisorUserId: formData.supervisorUserId || '', email: formData.email?.trim() || undefined, phoneNo: formData.phoneNo?.trim() || undefined, + hireDate: formData.hireDate || null, + probationMonths: formData.probationMonths, sex: formData.sex, status: formData.status, orderNum: formData.orderNum, @@ -666,6 +698,8 @@ supervisorUserId: formData.supervisorUserId || undefined, email: formData.email?.trim() || undefined, phoneNo: formData.phoneNo?.trim() || undefined, + hireDate: formData.hireDate || undefined, + probationMonths: formData.probationMonths ?? undefined, sex: formData.sex, status: formData.status, orderNum: formData.orderNum, @@ -769,6 +803,14 @@ { label: '所属组织', value: formatUserDeptDisplay(row) }, { label: '手机号', value: row.phoneNo }, { label: '邮箱', value: row.email }, + { label: '入职日期', value: row.hireDate || '—' }, + { + label: '试用期', + value: + row.probationMonths === null || row.probationMonths === undefined + ? '—' + : `${row.probationMonths} 个月` + }, { label: '性别', value: