Merge pull request 'feat(project): 项目编号支持新增编辑自由填写' (#49) from codex/issue-45-project-leader-autofill-a9912a48015b into V2.0

This commit was merged in pull request #49.
This commit is contained in:
cykj committed 2026-11-05 06:47:23 +00:00
commit 352a4b7402
5 files changed
+24 -5

No files matched your search

+1
View File
@@ -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]
+11 -2
View File
@@ -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
+2 -2
View File
@@ -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):
+2 -1
View File
@@ -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',
@@ -149,6 +149,13 @@
v-else
v-model="form.projectName"
/></el-form-item>
<el-form-item
v-if="!isTeam"
label="项目编号"
prop="projectNo"
:rules="[{ required: true, message: '请输入项目编号' }]"
><el-input v-model="form.projectNo" maxlength="64" show-word-limit
/></el-form-item>
<el-form-item
v-if="!isTeam"
label="所属项目组"
@@ -356,6 +363,7 @@
: {
teamName: '',
projectName: '',
projectNo: '',
leaderUserId: '',
enabled: true,
status: 'pending',