From e895daf8fc40e131cc49ce8a1706baec58aef0d8 Mon Sep 17 00:00:00 2001 From: zlwu <704541015@qq.com> Date: Thu, 5 Nov 2026 14:41:41 +0800 Subject: [PATCH] =?UTF-8?q?feat(project):=20=E9=A1=B9=E7=9B=AE=E7=BC=96?= =?UTF-8?q?=E5=8F=B7=E6=94=AF=E6=8C=81=E6=96=B0=E5=A2=9E=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E8=87=AA=E7=94=B1=E5=A1=AB=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 项目管理弹窗增加项目编号输入;后端保存改为接收客户端编号并校验租户内唯一,不再自动生成。 Co-authored-by: Cursor --- backend/app/api/project_management.py | 1 + backend/app/services/project_management.py | 13 +++++++++++-- backend/tests/test_project_management.py | 4 ++-- web-admin/src/utils/project-management.ts | 3 ++- .../src/views/project-management/ManagementPage.vue | 8 ++++++++ 5 files changed, 24 insertions(+), 5 deletions(-) diff --git a/backend/app/api/project_management.py b/backend/app/api/project_management.py index 8711e85d..8b4e7845 100644 --- a/backend/app/api/project_management.py +++ b/backend/app/api/project_management.py @@ -45,6 +45,7 @@ class TeamBody(Body): class ProjectBody(Body): projectName: str = Field(min_length=1, max_length=200) + projectNo: str = Field(min_length=1, max_length=64) teamId: str leaderUserId: str bizTypes: List[str] diff --git a/backend/app/services/project_management.py b/backend/app/services/project_management.py index 40b87a3c..a1747d3a 100644 --- a/backend/app/services/project_management.py +++ b/backend/app/services/project_management.py @@ -333,8 +333,17 @@ def save_entity(db, tenant, user, model, body, row_id=None): if status not in ('pending', 'active', 'completed', 'disabled'): raise HTTPException(400, '项目状态无效') row.project_name, row.team_id, row.biz_types, row.status = body[name_key].strip(), team.id, ','.join(dict.fromkeys(kinds)), status - if not row_id: - row.project_no = 'XM' + datetime.now().strftime('%Y%m%d') + generate_uuid().replace('-', '')[:16].upper() + project_no = str(body.get('projectNo') or '').strip() + if not project_no: + raise HTTPException(400, '项目编号不能为空') + if len(project_no) > 64: + raise HTTPException(400, '项目编号不能超过 64 个字符') + conflict = scoped(db, Project, tenant).filter(Project.project_no == project_no) + if row_id: + conflict = conflict.filter(Project.id != row.id) + if conflict.with_for_update().first(): + raise HTTPException(400, '项目编号已存在') + row.project_no = project_no try: row.start_date = date.fromisoformat(body['startDate']) if body.get('startDate') else None row.end_date = date.fromisoformat(body['endDate']) if body.get('endDate') else None diff --git a/backend/tests/test_project_management.py b/backend/tests/test_project_management.py index 0d848fd7..8add57bd 100644 --- a/backend/tests/test_project_management.py +++ b/backend/tests/test_project_management.py @@ -148,8 +148,8 @@ class ProjectManagementTest(unittest.TestCase): self.db.add(SysUser(id='u', tenant_no='t', user_no='u', nick_name='User')) self.db.commit() result = self.svc.save_entity(self.db, 't', self.user, self.Project, - dict(projectName='New', leaderUserId='u', teamId='g', bizTypes=['basic_experiment'], startDate='', endDate='')) - self.assertTrue(result['projectNo'].startswith('XM')) + dict(projectName='New', projectNo='CUSTOM-001', leaderUserId='u', teamId='g', bizTypes=['basic_experiment'], startDate='', endDate='')) + self.assertEqual(result['projectNo'], 'CUSTOM-001') self.assertIsNone(result['startDate']) def test_conversion_table_reverse_graph_and_audit(self): diff --git a/web-admin/src/utils/project-management.ts b/web-admin/src/utils/project-management.ts index 9ca2de21..cd393bf6 100644 --- a/web-admin/src/utils/project-management.ts +++ b/web-admin/src/utils/project-management.ts @@ -22,13 +22,14 @@ export function assignmentSnapshot(records: ProjectRecord[]) { })) } -/** Write bodies intentionally exclude response-only labels, timestamps and generated numbers. */ +/** Write bodies intentionally exclude response-only labels and timestamps. */ export function managementPayload(kind: 'teams' | 'projects', form: ProjectRecord): ProjectRecord { const fields = kind === 'teams' ? ['teamName', 'leaderUserId', 'enabled', 'remark'] : [ 'projectName', + 'projectNo', 'teamId', 'leaderUserId', 'bizTypes', diff --git a/web-admin/src/views/project-management/ManagementPage.vue b/web-admin/src/views/project-management/ManagementPage.vue index 7a0ac273..4151ce27 100644 --- a/web-admin/src/views/project-management/ManagementPage.vue +++ b/web-admin/src/views/project-management/ManagementPage.vue @@ -149,6 +149,13 @@ v-else v-model="form.projectName" /> +