
跟着一次“发起工程”把 CCPrj 源码走完本系列共 3 篇① 设计与实现 ② 产品介绍 ③ 源码导读本文面向二次开发。不从概念出发而从一次真实点击出发用户在发起列表点了一个模板系统如何创建实例、打开工作台、再按任务类型分发到不同页面。阅读顺序建议先不要按目录把 40 多个文件从头扫到尾。按这条调用链看会快很多GL_PrjStart.ts → WF_CCPrj.CreatePrj() → PrjDev2Interface.Prj_CreateBlankPrjID() → MyPrj.vue → TaskCenter / TaskGener / TaskFlow / TaskBill记住两个 Handler场景类名运行时BP.CCPrj.HttpHandler.WF_CCPrj管理端BP.CCPrj.HttpHandler.WF_Admin_CCPrj前端封装在Comm/PrjComm.tsPrjComm.GetHandler() // WF_CCPrj PrjComm.GetTaskHanlder() // WF_Admin_CCPrj业务不要写在 Vue 里拼 SQL也不要写在 Handler 里堆逻辑。Handler 只接参数、转 JSON真正干活的是PrjDev2Interface。一、目录地图前端Vue3/src/CCFast/CCPrj文件先看什么Port.vue模块入口按PageName分发GenerList/GL_PrjStart.ts点模板 → 创建实例GenerList/GL_PrjTodolist.ts等待办/在途/已完成复用GenerList.vueTaskCenter.vue个人任务工作台MyPrj.vue项目处理器工程模块的 MyFlowPrjToolBar.vue按状态和角色出按钮TaskGener.vue/TaskFlow.vue/TaskBill.vue三类任务页Comm/taskHandler.ts任务类型、待办加载、打开哪个组件SearchPrj.vue按模板查实例Admin/TemplateList.vue模板库Admin/Template/TemplatePrj.ts模板实体 设计表单/文件工作区Admin/Template/PG_TemplateTaskGroup2Task.ts步骤设计左组右任务FileWorkspace.vue文件工作区后端CCFlow/Components/BP.WF/CCPrj文件先看什么PrjDev2Interface.cs全部业务接口WF_CCPrj.cs运行时 HTTP 入口WF_Admin_CCPrj.cs模板库、步骤、文件工作区配置Template/*.cs设计态实体GenerPrj.cs/GenerTask.cs/GenerTaskGroup.cs运行态实体GenerWorker.cs待办人员PrjTrack.cs/PrjWorkerLog.cs轨迹 / 工时日志Template/PrjEnum.csPrjSta/TaskSta实体写法与流程模块相同XxxAttrEntityEntitiesEnMap。改字段先改 EnMap再改接口不要只改前端。二、入口点一个模板发生了什么GL_PrjStart继承PageBaseGenerList页面本身复用流程的GenerList.vue。它只做三件事列怎么显示、数据从哪来、点行去哪。async Init() { this.PageSize 0; this.LinkField Name; this.GroupFields SortName; this.HisGLShowModel GenerListPageShowModel.Windows; // ... const handler new HttpHandler(BP.CCPrj.HttpHandler.WF_CCPrj); const data await handler.DoMethodReturnJson(TaskStart_Init); this.Data data; } async LinkFieldClick(object: Recordstring, any) { const handler new HttpHandler(BP.CCPrj.HttpHandler.WF_CCPrj); handler.AddPara(TemplateNo, object.No); const PrjID await handler.DoMethodReturnString(CreatePrj); const url /src/CCFast/CCPrj/MyPrj.vue?PrjNo${PrjID}; return new GPNReturnObj(GPNReturnType.OpenUrlByDrawer90, url, 项目处理); }对应后端非常薄public string CreatePrj() { string templateNo this.GetRequestVal(TemplateNo); Int64 oid PrjDev2Interface.Prj_CreateBlankPrjID(templateNo); return oid.ToString(); }待办列表是同一模式。GL_PrjTodolist调PrjTodolist_Init点行同样打开MyPrj.vue?PrjNo...。二次开发如果要加“我延期的工程”优先抄这两个 GL 文件不要新写一张列表页。三、创建实例模板复制到运行时核心在Prj_CreateBlankPrjID。建议按注释里的步骤打断点读TemplatePrjOID DBAccess.GenerOID(PrjID)不要用数据库自增状态先写PrjSta.Draft用模板BillNoFormat调流程现成的WorkFlowBuessRole.GenerBillNo复制TemplateTaskGroup→GenerTaskGroup复制TemplateTask→GenerTaskSyncTaskWorkers写待办人EnsurePrjForm保证项目表单和物理表存在PrjTrack.WriteLog记一条“创建工程”任务主键约定必须守住任务组 No 工程OID _ 模板任务组No 任务 No 工程OID _ 模板任务No前端从实例号反推模板任务号时用的就是这个规则见taskHandler.deriveTemplateTaskNo()。乱改编号流程任务/单据任务会找不到绑定关系。复制任务时会带上TaskType和RefTemplateNo。通用任务、流程任务、单据任务在实例里只是不同类型的GenerTask不是三张表。草稿规则和流程对齐Draft 1保存到待办给发起人在 Idx 最小的任务上插一条GenerWorkerDraft 2保存到草稿箱只建实例不进待办Draft 0不走草稿策略所以“为什么创建后有的人立刻看到待办有的没有”先查模板的Draft字段。四、状态值不要靠猜Template/PrjEnum.cs里工程状态不是 0/1/2 递增那么直觉Draft 0; // 草稿 Complete 1; // 已完成 Runing 2; // 进行中 Pause 3; Invalid 4;任务状态None 0; // 未开始 Complete 1; Delay 2; Pause 3;人员状态在GenerWorker.csUnRead 0; Complete 1; Read 2; Refuse 3;前端PrjComm.PrjStaText()/NodeStaText()/WorkerStaText()必须和这里一致。工具栏判断也是按这些数字见PrjToolBar.vue。发起校验在CheckPrjStartData没任务、没名称、没负责人、日期范围缺日期都会返回err...。前端只要原样提示不要自己再写一套校验。完成任务走Node_SetOver任务置完成 → 相关 Worker 置完成 → 若全部任务完成则Prj_SetOver。自动完成工程的开关就在这里改产品规则优先改这一段。五、项目处理器MyPrj 怎么把数据摊开MyPrj_Init直接把甘特数据集吐给前端public string MyPrj_Init() { DataSet ds PrjDev2Interface.Prj_GetGanttData(this.PrjID); return BP.Tools.Json.ToJson(ds); }MyPrj.vue自己拼任务组和任务的树三个 Tabgantt节点进度form项目表单Fool 表单FrmID默认Prj 模板编号log轨迹按钮不写死在页面里而由PrjToolBar.vue按PrjSta 角色计算。草稿出发起/删除进行中出暂停/完成/移交/作废已完成出回滚。表单 Tab 只出保存和打印。权限字段在GenerPrj上BtnSaveRoleBtnCompleteRoleBtnTransferRoleBtnPrintRole二次开发加按钮时PrjToolBar加一个 actionMyPrj.vue的handleToolbarAction接住WF_CCPrj加一个薄方法PrjDev2Interface写业务并打 Track不要只改 Vue。打开具体任务前会走Node_CheckAuth/MyPrjFrm_CheckAuth。无权限就停不要假定点得开就能改。六、任务中心按类型打开不同组件TaskCenter.vue三个 scopetodo/running/complete数据来自PrjTaskTodolist_InitPrjTaskParticipatingList_InitPrjTaskDoneList_Init真正决定打开哪一页的是Comm/taskHandler.tsexport function getTaskTypeLabel(taskType: number) { switch (taskType) { case 1: return 流程任务; case 2: return 单据任务; default: return 通用任务; } } export function getTaskHandlerCompUrl(taskType: number) { if (taskType 1) return //CCFast/CCPrj/TaskFlow.vue; if (taskType 2) return //CCFast/CCPrj/TaskBill.vue; return //CCFast/CCPrj/TaskGener.vue; }TaskType页面背后依赖0TaskGener.vuePrjWorkerLog工时日志 附件1TaskFlow.vue模板任务绑定的流程RefTemplateNo/refFlowNo2TaskBill.vueFool 表单绑定单据如果要加第四种任务例如“绑定报表”TemplateTask.TaskType枚举加值模板设计里能选创建实例时把类型复制到GenerTaskgetTaskHandlerCompUrl增加映射新建一个TaskXxx.vue继续用loadTaskRuntimeData做鉴权和基本信息不要为新类型新建一套待办表。待办始终是Prj_GenerWorker。七、管理端模板库和步骤设计运行时看WF_CCPrj设计态看WF_Admin_CCPrj方法用途Prj_CreateTemplate新建模板TemplateList_Init模板库列表和统计TemplateList_Instances某模板下的实例TemplateList_DeleteTemplate删模板Task_CreateTaskFlow/Task_CreateTaskBill给任务绑定流程或单据FileWorkspace_Init/Save文件工作区配置前端模板实体TemplatePrj.ts上两个入口最常用fStep()打开表单设计器FrmID Prj 模板编号DoFileWorkspaceConfig()没有配置就先 Save 一份再打开配置实体步骤设计不是流程图是PG_TemplateTaskGroup2Task左边任务组右边任务支持组内排序、拖动。RefKey GroupNo。新增任务时会带上当前TemplateNo。模板主表关键字段PTable/ 表单编号BillNoFormatTitleRoleDraftIsCanEditTemplate改“发起后能不能改任务结构”看的是IsCanEditTemplate不是前端按钮显隐。八、文件工作区从哪接进去配置实体Admin/Template/TemplateFileWorkspaceConfig.ts表Prj_FileWorkspaceConfig字段要点ReviewFlowNo文件送审流程BucketName/ObjectPrefix对象存储ParticipantsNo工作区参与人运行时接口在WF_CCPrj后半段Workspace_Init、File_StartReview、File_BindReviewWork。MyPrj工具栏的「文件工作区」和任务页里的TaskFilePanel都走这套不是另一套附件表。改送审规则时先看文件是如何绑定WorkID的再改流程不要在 Vue 里写死流程编号。九、二次开发最常见的四个落点1. 加一张用户列表抄GL_PrjTodolist.tsWF_CCPrj一个xxx_InitPrjDev2Interface.DB_xxx。列表 UI 继续用GenerList.vue。2. 加一个工程按钮PrjToolBar.vue→MyPrj.vue→WF_CCPrj.MyPrj_Xxx→PrjDev2Interface.Prj_Xxx最后PrjTrack.WriteLog。3. 加业务字段不要改GenerPrj内核。去模板的表单设计器加字段数据落在PTable。EnsurePrjForm已经会创建默认字段和物理表。4. 改待办口径待办不是按工程算是按Prj_GenerWorker GenerTask算。改“谁能看见这条待办”改DB_TaskList不要改MyPrj.vue的过滤。十、调试时一眼能定位的问题现象先看发起列表是空的DB_Starter的模板表/类别表是否与当前实体表名一致点模板报错CreatePrj是否收到TemplateNo模板是否存在创建成功但没有待办模板Draft是否为 1GenerWorker有没有行打不开任务MyPrjFrm_CheckAuth/Node_CheckAuth流程任务是空白模板任务TaskType1且绑定了流程号单据任务提示未就绪是否走过Task_CreateTaskBillFrmID 是否存在状态显示错乱是不是把已完成1当成了进行中工具栏没有完成按钮BtnCompleteRole 是不是负责人/发起人项目表单是空的EnsurePrjForm有没有跑FrmID是否Prj 模板编号Handler 约定沿用 CCFlow成功返回数据或纯文本失败返回err原因。前端看到err就提示不要当 JSON 解析。十一、一条最小阅读清单如果只有半天按这个顺序打开文件GenerList/GL_PrjStart.tsWF_CCPrj.CreatePrj/MyPrj_Init/MyPrj_StartPrjDev2Interface.Prj_CreateBlankPrjIDPrjDev2Interface.Prj_StartCheckPrjStartDataGenerPrj.cs、GenerTask.cs、GenerWorker.csMyPrj.vuePrjToolBar.vueComm/taskHandler.tsTaskGener.vue通用任务是默认路径Admin/Template/PG_TemplateTaskGroup2Task.ts把这条链走通再去看文件工作区和甘特配置不会迷路。系列第 1 篇讲为什么这样分层第 2 篇讲业务怎么用本篇只解决一件事代码从哪进、改完往哪写。