mirror of
http://git.pig4cloud.com/pig/pigx.git
synced 2026-11-08 04:39:00 +08:00
Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
cbb68a0e5b
2 files changed
+808
No files matched your search
@@ -0,0 +1,431 @@
|
||||
# Flow Starter Withdraw Design
|
||||
|
||||
## Scope
|
||||
|
||||
This design covers the starter-side "withdraw process" capability across:
|
||||
|
||||
- `pigx/pigx-flow`
|
||||
- `pigx-ui-pro/src/views/flow`
|
||||
|
||||
The goal is to add a clear "withdraw" action for starters without conflating it with the existing "terminate process" capability.
|
||||
|
||||
## Problem Statement
|
||||
|
||||
The current starter-facing page [started.vue](/Users/lengleng/work/dev1227/pigx-ui-pro/src/views/flow/task/started.vue) exposes `终止流程`, but the backend implementation is a force-stop semantic:
|
||||
|
||||
- API: `POST /task/task/stopProcessInstance`
|
||||
- Service: `TaskServiceImpl.stopProcessInstance`
|
||||
- End reason: `finishReason=9`
|
||||
|
||||
This is not the same as business-level "withdraw":
|
||||
|
||||
- `withdraw` means the starter takes back a just-submitted process before the first approval has been consumed
|
||||
- `terminate` means a stronger administrative stop on an in-flight process
|
||||
|
||||
If the project keeps reusing terminate for starter withdraw, UI labels, audit semantics, business status sync, and future permission rules will remain mixed.
|
||||
|
||||
## Confirmed Product Decisions
|
||||
|
||||
### Withdraw Semantics
|
||||
|
||||
Use product option `B`:
|
||||
|
||||
- the starter can withdraw only when the first approval stage has not been processed yet
|
||||
|
||||
### Starter-Side Operation Set
|
||||
|
||||
On the starter side:
|
||||
|
||||
- remove the generic `终止流程` button
|
||||
- keep `撤回` as the only starter-side stop action
|
||||
|
||||
### Business Visibility
|
||||
|
||||
Business pages such as leave requests must explicitly show `已撤回`, not collapse it into `已结束`.
|
||||
|
||||
## Goals
|
||||
|
||||
1. Add a clear starter-only `撤回` action
|
||||
2. Keep `撤回` and `终止` as separate backend semantics
|
||||
3. Compute withdraw availability server-side and expose it to the UI
|
||||
4. Sync withdraw result to business tables through the existing flow status event chain
|
||||
5. Avoid duplicating withdraw logic in each business form page
|
||||
|
||||
## Non-Goals
|
||||
|
||||
1. Do not redesign admin-side force-stop permissions in this iteration
|
||||
2. Do not add withdraw-reason input in V1
|
||||
3. Do not add business-form-specific withdraw buttons in every detail page in V1
|
||||
|
||||
## Recommended Placement
|
||||
|
||||
### Primary Entry
|
||||
|
||||
Use the starter list page:
|
||||
|
||||
- [started.vue](/Users/lengleng/work/dev1227/pigx-ui-pro/src/views/flow/task/started.vue)
|
||||
|
||||
Reason:
|
||||
|
||||
- it already represents the "我发起的" mental model
|
||||
- it already groups starter-only actions such as `重新提交`
|
||||
- it keeps withdraw as a platform capability instead of pushing it into each business page
|
||||
|
||||
### Secondary Entry
|
||||
|
||||
Add the same withdraw action in the detail drawer header opened from `started.vue`.
|
||||
|
||||
Reason:
|
||||
|
||||
- users often inspect details before acting
|
||||
- it avoids forcing the user back to the list page
|
||||
|
||||
### Not Recommended for V1
|
||||
|
||||
Do not make business detail pages such as [detail.vue](/Users/lengleng/work/dev1227/pigx-ui-pro/src/views/flow/oaLeave/detail.vue) the primary entry.
|
||||
|
||||
Reason:
|
||||
|
||||
- this would duplicate logic across each business form
|
||||
- withdraw is a workflow-center capability, not a business-form-specific capability
|
||||
|
||||
## User Interaction Design
|
||||
|
||||
### Starter List Display Rules
|
||||
|
||||
On [started.vue](/Users/lengleng/work/dev1227/pigx-ui-pro/src/views/flow/task/started.vue):
|
||||
|
||||
- show `撤回` only when `canWithdraw === true`
|
||||
- show `重新提交` when `rejectToStarter === true`
|
||||
- do not show the old `终止流程` button for normal starters
|
||||
- show `已撤回` when `finishReason === '3'`
|
||||
|
||||
### Detail Drawer Display Rules
|
||||
|
||||
In the detail drawer header:
|
||||
|
||||
- show `撤回` when `canWithdraw === true`
|
||||
- optionally show disabled state plus `withdrawDisabledReason` when not allowed
|
||||
|
||||
### Confirmation Copy
|
||||
|
||||
Use a confirmation dialog before submit:
|
||||
|
||||
- title: `确认撤回流程?`
|
||||
- content: `仅首个审批节点尚未处理时可撤回。撤回后流程将结束,且不可恢复。`
|
||||
|
||||
## Approach Comparison
|
||||
|
||||
### Option 1: Reuse Existing Stop API
|
||||
|
||||
Description:
|
||||
|
||||
- keep calling `stopProcessInstance`
|
||||
- only change button label from `终止流程` to `撤回`
|
||||
|
||||
Pros:
|
||||
|
||||
- lowest implementation cost
|
||||
|
||||
Cons:
|
||||
|
||||
- backend semantic remains wrong
|
||||
- audit and business sync still treat starter withdraw as terminate
|
||||
- impossible to distinguish `已撤回` from `已终止`
|
||||
|
||||
Conclusion:
|
||||
|
||||
- reject
|
||||
|
||||
### Option 2: New Withdraw API with Shared Internal Termination Path
|
||||
|
||||
Description:
|
||||
|
||||
- add a new starter-facing withdraw API
|
||||
- keep terminate as a separate API
|
||||
- internally share low-level engine shutdown logic
|
||||
|
||||
Pros:
|
||||
|
||||
- clear product semantics
|
||||
- supports distinct UI labels and business status mapping
|
||||
- keeps future admin permission expansion clean
|
||||
|
||||
Cons:
|
||||
|
||||
- needs small backend refactor
|
||||
|
||||
Conclusion:
|
||||
|
||||
- recommend
|
||||
|
||||
### Option 3: Business-Form-Specific Withdraw Entry First
|
||||
|
||||
Description:
|
||||
|
||||
- add withdraw directly into each business detail page
|
||||
|
||||
Pros:
|
||||
|
||||
- strong local context
|
||||
|
||||
Cons:
|
||||
|
||||
- duplicated logic across forms
|
||||
- weak platform consistency
|
||||
|
||||
Conclusion:
|
||||
|
||||
- reject for V1
|
||||
|
||||
## Backend Design
|
||||
|
||||
### New API
|
||||
|
||||
Add a new endpoint in [ProcessTaskController.java](/Users/lengleng/work/dev1227/pigx/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/controller/ProcessTaskController.java):
|
||||
|
||||
```http
|
||||
POST /task/task/withdrawProcessInstance
|
||||
```
|
||||
|
||||
Request body:
|
||||
|
||||
```json
|
||||
{
|
||||
"processInstanceId": "xxx"
|
||||
}
|
||||
```
|
||||
|
||||
Use existing DTO [TaskParamDto.java](/Users/lengleng/work/dev1227/pigx/pigx-flow/pigx-flow-api/src/main/java/com/pig4cloud/pigx/flow/dto/TaskParamDto.java) in V1.
|
||||
|
||||
### Service Contract
|
||||
|
||||
Add method to [ITaskService.java](/Users/lengleng/work/dev1227/pigx/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/service/ITaskService.java):
|
||||
|
||||
```java
|
||||
R withdrawProcessInstance(TaskParamDto taskParamDto);
|
||||
```
|
||||
|
||||
Implement in [TaskServiceImpl.java](/Users/lengleng/work/dev1227/pigx/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/service/impl/TaskServiceImpl.java).
|
||||
|
||||
### Withdraw Eligibility Rule
|
||||
|
||||
Do not try to hard-parse "first approval node" from the process graph for V1.
|
||||
|
||||
Instead, use the current persistence model:
|
||||
|
||||
1. query `process_instance_record`
|
||||
2. require:
|
||||
- current user is starter
|
||||
- `status == 1`
|
||||
- no final `finishReason`
|
||||
3. reject when runtime variable `rejectToStarter == true`
|
||||
4. inspect `process_node_record_assign_user`
|
||||
5. if any record exists for the same `processInstanceId` where:
|
||||
- `nodeId != 'root'`
|
||||
- and the task has already been processed
|
||||
then withdraw is not allowed
|
||||
|
||||
Suggested definition of "already processed":
|
||||
|
||||
- `end_time is not null`, or
|
||||
- `status != JXZ`
|
||||
|
||||
This rule aligns with the current audit model because completed-task reads already rely on [ProcessNodeRecordAssignUser.java](/Users/lengleng/work/dev1227/pigx/pigx-flow/pigx-flow-api/src/main/java/com/pig4cloud/pigx/flow/entity/ProcessNodeRecordAssignUser.java).
|
||||
|
||||
### Shared Internal Termination Logic
|
||||
|
||||
Refactor the current terminate implementation into a shared internal method, for example:
|
||||
|
||||
```java
|
||||
private R terminateProcessInstance(String processInstanceId, String finishReason)
|
||||
```
|
||||
|
||||
Use it from:
|
||||
|
||||
- `stopProcessInstance(..., finishReason='9')`
|
||||
- `withdrawProcessInstance(..., finishReason='3')`
|
||||
|
||||
This keeps engine-level stop logic shared while preserving product-level semantics.
|
||||
|
||||
### Persistence Update Rules
|
||||
|
||||
On successful withdraw:
|
||||
|
||||
1. end the Flowable runtime instance
|
||||
2. update `process_instance_record`
|
||||
- `status = 2`
|
||||
- `finish_reason = '3'`
|
||||
- `end_time = now`
|
||||
3. close in-progress `process_node_record`
|
||||
4. close in-progress `process_node_record_assign_user`
|
||||
|
||||
The main requirement is that no runtime or local audit record remains in a "进行中" state after withdraw.
|
||||
|
||||
## Frontend Design
|
||||
|
||||
### API Layer
|
||||
|
||||
Add a new API in [src/api/flow/task/index.ts](/Users/lengleng/work/dev1227/pigx-ui-pro/src/api/flow/task/index.ts):
|
||||
|
||||
```ts
|
||||
export function withdrawProcessInstance(param: { processInstanceId: string }) { ... }
|
||||
```
|
||||
|
||||
### Starter List Data
|
||||
|
||||
Extend [ProcessInstanceRecordVo.java](/Users/lengleng/work/dev1227/pigx/pigx-flow/pigx-flow-api/src/main/java/com/pig4cloud/pigx/flow/vo/ProcessInstanceRecordVo.java) with:
|
||||
|
||||
- `Boolean canWithdraw`
|
||||
- `String withdrawDisabledReason`
|
||||
|
||||
Populate both in:
|
||||
|
||||
- `queryMineStarted`
|
||||
- `detail(processInstanceId)`
|
||||
|
||||
This keeps all action availability server-driven.
|
||||
|
||||
### Starter Page Behavior
|
||||
|
||||
Update [started.vue](/Users/lengleng/work/dev1227/pigx-ui-pro/src/views/flow/task/started.vue):
|
||||
|
||||
1. remove starter-facing `终止流程`
|
||||
2. add `撤回`
|
||||
3. keep `重新提交` unchanged for `rejectToStarter`
|
||||
4. add `已撤回` tag for `finishReason === '3'`
|
||||
5. add withdraw action in drawer header as secondary entry
|
||||
|
||||
## Flow Status and Business Status Design
|
||||
|
||||
### Flow-Level Final States
|
||||
|
||||
Keep `process_instance_record.status` as coarse state:
|
||||
|
||||
- `1` 进行中
|
||||
- `2` 已结束
|
||||
|
||||
Use `finish_reason` for final meaning:
|
||||
|
||||
- `1` 通过
|
||||
- `0` 拒绝
|
||||
- `3` 撤回
|
||||
- `9` 终止
|
||||
|
||||
### Business Table Mapping
|
||||
|
||||
For leave requests in [BpmOaLeaveEntity.java](/Users/lengleng/work/dev1227/pigx/pigx-flow/pigx-flow-api/src/main/java/com/pig4cloud/pigx/flow/entity/BpmOaLeaveEntity.java), the current `leaveStatus` values are too coarse.
|
||||
|
||||
Recommended mapping:
|
||||
|
||||
- `0` 待审批
|
||||
- `1` 进行中
|
||||
- `2` 已通过
|
||||
- `3` 已撤回
|
||||
- `4` 已拒绝
|
||||
- `5` 已终止
|
||||
|
||||
If schema change must stay minimal, a fallback is adding a separate finish-reason field. That is not recommended for V1 because UI filtering and display would become more fragmented.
|
||||
|
||||
### Event-Driven Sync
|
||||
|
||||
Continue using the existing status event chain:
|
||||
|
||||
- [FlowProcessEventListener.java](/Users/lengleng/work/dev1227/pigx/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/support/listeners/FlowProcessEventListener.java)
|
||||
- [NodeTaskCompleteNotify.java](/Users/lengleng/work/dev1227/pigx/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/support/listeners/NodeTaskCompleteNotify.java)
|
||||
- [IProcessInstanceStatusEventService.java](/Users/lengleng/work/dev1227/pigx/pigx-flow/pigx-flow-api/src/main/java/com/pig4cloud/pigx/flow/event/IProcessInstanceStatusEventService.java)
|
||||
|
||||
Update [BpmOaLeaveServiceImpl.java](/Users/lengleng/work/dev1227/pigx/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/service/impl/BpmOaLeaveServiceImpl.java) so `handleStatusEvent` maps based on:
|
||||
|
||||
- `status`
|
||||
- `finishReason`
|
||||
|
||||
not just `status`.
|
||||
|
||||
This design should become the standard pattern for other business tables too.
|
||||
|
||||
## Detail Response Contract
|
||||
|
||||
The current [ProcessInstanceServiceImpl.java](/Users/lengleng/work/dev1227/pigx/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/service/impl/ProcessInstanceServiceImpl.java) `detail(processInstanceId)` response should be extended with:
|
||||
|
||||
- `canWithdraw`
|
||||
- `withdrawDisabledReason`
|
||||
- current `finishReason`
|
||||
|
||||
This lets the drawer header and later business detail integrations share one source of truth.
|
||||
|
||||
## Validation and Error Handling
|
||||
|
||||
### Backend Errors
|
||||
|
||||
Suggested failure messages:
|
||||
|
||||
- `流程不存在或已结束`
|
||||
- `仅发起人可撤回流程`
|
||||
- `驳回待提交状态不可撤回`
|
||||
- `首个审批节点已处理,无法撤回`
|
||||
|
||||
### Frontend Behavior
|
||||
|
||||
On withdraw failure:
|
||||
|
||||
- show backend error message directly when available
|
||||
- refresh list after success
|
||||
- close detail drawer after success if triggered there
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
### UI Acceptance
|
||||
|
||||
1. `我发起的` page shows `撤回` only for eligible in-progress instances
|
||||
2. `重新提交` remains available only for reject-to-starter instances
|
||||
3. starter-facing `终止流程` no longer appears
|
||||
4. withdrawn instances show `已撤回`
|
||||
5. detail drawer header stays consistent with list action availability
|
||||
|
||||
### Backend Acceptance
|
||||
|
||||
1. withdraw is rejected once any non-root approval record has been processed
|
||||
2. withdraw ends the runtime instance cleanly
|
||||
3. `process_instance_record.finish_reason='3'` after withdraw
|
||||
4. no in-progress node or assign-user record remains after withdraw
|
||||
5. existing terminate path still yields `finishReason='9'`
|
||||
|
||||
### Business Acceptance
|
||||
|
||||
1. leave request business status explicitly displays `已撤回`
|
||||
2. leave request no longer collapses withdraw into generic `已结束`
|
||||
|
||||
## Risks
|
||||
|
||||
1. `ProcessNodeRecordAssignUser.status` comments and actual usage are not fully consistent, so withdraw implementation should rely on current persisted behavior, not comments alone
|
||||
2. some business modules may currently map only `status` and ignore `finishReason`, causing partial UI mismatch until each listener implementation is updated
|
||||
3. parallel first-approval scenarios must use "any processed non-root approval record" as the blocking condition
|
||||
|
||||
## Rollout Order
|
||||
|
||||
1. add backend withdraw API and shared termination helper
|
||||
2. add `finishReason='3'` support in flow list/detail responses
|
||||
3. update starter page actions and status tags
|
||||
4. update leave business status mapping and display
|
||||
5. verify happy path and blocked path with real process instances
|
||||
|
||||
## Implementation Outline
|
||||
|
||||
The `writing-plans` skill referenced by the brainstorming workflow is not available in this workspace. As a fallback, use this execution order:
|
||||
|
||||
1. Backend
|
||||
- add `withdrawProcessInstance` controller/service method
|
||||
- extract shared terminate helper
|
||||
- return `canWithdraw` and `withdrawDisabledReason` from starter list and detail
|
||||
2. Frontend
|
||||
- add withdraw API client
|
||||
- replace starter-side terminate button with withdraw
|
||||
- add withdrawn status tag and detail-header action
|
||||
3. Business sync
|
||||
- extend leave status mapping for withdrawn
|
||||
- update leave list/detail labels and filters if needed
|
||||
4. Verification
|
||||
- test starter can withdraw before first approval action
|
||||
- test withdraw blocked after any first-stage approval processing
|
||||
- test business page shows `已撤回`
|
||||
@@ -0,0 +1,377 @@
|
||||
# Flow Withdraw Resubmit Design
|
||||
|
||||
## Scope
|
||||
|
||||
This design covers starter-side "resubmit after withdraw" behavior for:
|
||||
|
||||
- `pigx-ui-pro/src/views/flow/task/started.vue`
|
||||
- dynamic flow forms
|
||||
- custom business forms
|
||||
|
||||
The capability is limited to processes already withdrawn by the starter. It does not reopen the old process instance.
|
||||
|
||||
## Problem Statement
|
||||
|
||||
The current flow center supports:
|
||||
|
||||
- withdraw for starter-side in-progress instances
|
||||
- resubmit for `rejectToStarter`
|
||||
|
||||
But it does not support the common case where the starter withdraws because they found mistakes in the form and wants to:
|
||||
|
||||
1. edit the old submitted data
|
||||
2. keep the withdrawn record as history
|
||||
3. start a brand new process instance from the corrected data
|
||||
|
||||
This must work for both:
|
||||
|
||||
- dynamic flow forms
|
||||
- custom business forms
|
||||
|
||||
## Confirmed Product Decisions
|
||||
|
||||
1. After withdraw, resubmission must create a new process instance
|
||||
2. The old withdrawn record must remain as a separate historical record
|
||||
3. The entry point should be a single user-facing capability: `重新编辑提交`
|
||||
4. The implementation path should split by form type:
|
||||
- dynamic flow form: edit in flow center drawer
|
||||
- business form: edit in a page/container path
|
||||
5. Previous manually selected approvers / copy recipients should be carried as defaults and remain editable
|
||||
|
||||
## Goals
|
||||
|
||||
1. Add `重新编辑提交` for withdrawn starter records
|
||||
2. Let users correct form mistakes before submitting again
|
||||
3. Preserve withdrawn process history
|
||||
4. Reuse existing form loading and start-process capabilities where possible
|
||||
5. Support both dynamic and business forms in the same product capability
|
||||
|
||||
## Non-Goals
|
||||
|
||||
1. Do not reopen the old withdrawn Flowable instance
|
||||
2. Do not merge new submission into the old withdrawn record
|
||||
3. Do not copy approval history from the old instance to the new one
|
||||
4. Do not introduce a dedicated backend "withdraw-resubmit" API in V1
|
||||
|
||||
## Recommended Approach
|
||||
|
||||
### Option 1: Unified Entry, Split by Form Type
|
||||
|
||||
Description:
|
||||
|
||||
- show one action named `重新编辑提交`
|
||||
- branch internally by form type
|
||||
- dynamic flow forms open an editable drawer in flow center
|
||||
- business forms go through a common restart container page
|
||||
|
||||
Pros:
|
||||
|
||||
- unified user mental model
|
||||
- minimal duplication
|
||||
- works for both form types
|
||||
- avoids forcing every business form page to implement workflow-side participant editing on its own
|
||||
|
||||
Cons:
|
||||
|
||||
- needs a common restart context loader
|
||||
- needs one new common business-form restart container page
|
||||
|
||||
Conclusion:
|
||||
|
||||
- recommend
|
||||
|
||||
### Option 2: Always Jump to a Full Page
|
||||
|
||||
Description:
|
||||
|
||||
- both dynamic forms and business forms always jump to a dedicated page
|
||||
|
||||
Pros:
|
||||
|
||||
- interaction form is consistent
|
||||
|
||||
Cons:
|
||||
|
||||
- duplicates current dynamic-form drawer flow
|
||||
- larger change surface
|
||||
|
||||
Conclusion:
|
||||
|
||||
- not recommended for V1
|
||||
|
||||
### Option 3: Always Stay in started.vue Drawer
|
||||
|
||||
Description:
|
||||
|
||||
- both dynamic forms and business forms are handled inside `started.vue`
|
||||
|
||||
Pros:
|
||||
|
||||
- entry is centralized
|
||||
|
||||
Cons:
|
||||
|
||||
- business forms often depend on route/page context
|
||||
- harder to keep complex custom forms maintainable
|
||||
|
||||
Conclusion:
|
||||
|
||||
- reject
|
||||
|
||||
## Product Behavior
|
||||
|
||||
### Starter List
|
||||
|
||||
On [started.vue](/Users/lengleng/work/dev1227/pigx-ui-pro/src/views/flow/task/started.vue):
|
||||
|
||||
- records with process status `已撤回` should display `重新编辑提交`
|
||||
- records with `rejectToStarter` should keep the current `重新提交`
|
||||
- these are different capabilities and must remain separate
|
||||
|
||||
### Old Record Handling
|
||||
|
||||
After successful resubmission:
|
||||
|
||||
- the old record remains `已撤回`
|
||||
- a new record appears as `进行中`
|
||||
|
||||
### Button Naming
|
||||
|
||||
Use a single starter-facing action name:
|
||||
|
||||
- `重新编辑提交`
|
||||
|
||||
Reason:
|
||||
|
||||
- it makes the user intent explicit
|
||||
- it distinguishes this flow from `驳回待提交 -> 重新提交`
|
||||
|
||||
## Data Flow Design
|
||||
|
||||
### Shared Source Data
|
||||
|
||||
When the user clicks `重新编辑提交`, frontend should load:
|
||||
|
||||
1. old instance snapshot via `detail(processInstanceId)`
|
||||
2. current flow definition via `getFlowDetail(flowId)`
|
||||
|
||||
The old instance snapshot provides:
|
||||
|
||||
- previous form data
|
||||
- previous manually selected participant values stored in submitted process params
|
||||
|
||||
The current flow definition provides:
|
||||
|
||||
- current form type
|
||||
- current form component path / dynamic form schema
|
||||
- current selectable participant nodes
|
||||
|
||||
### Participant Default Value Strategy
|
||||
|
||||
Only carry forward values the user explicitly selected before.
|
||||
|
||||
Use old submitted process params such as:
|
||||
|
||||
- `nodeId_assignee_select`
|
||||
|
||||
Do not carry forward:
|
||||
|
||||
- historical approval results
|
||||
- historical comments
|
||||
- runtime-derived approval outcomes
|
||||
|
||||
If a previously selected node no longer exists in the current flow definition:
|
||||
|
||||
- ignore the old value
|
||||
|
||||
If a new required selectable node is present in the current definition:
|
||||
|
||||
- require the user to select it again before submit
|
||||
|
||||
## Form-Type Split
|
||||
|
||||
### Dynamic Flow Form
|
||||
|
||||
When `formType=10`:
|
||||
|
||||
- stay in [started.vue](/Users/lengleng/work/dev1227/pigx-ui-pro/src/views/flow/task/started.vue)
|
||||
- open an editable restart drawer
|
||||
- left side reuses dynamic form rendering
|
||||
- right side reuses [FlowNodeFormatData.vue](/Users/lengleng/work/dev1227/pigx-ui-pro/src/views/flow/form/tools/FlowNodeFormatData.vue)
|
||||
- old participant selections are injected into `nodeUser`
|
||||
- submit starts a new process instance
|
||||
|
||||
### Business Form
|
||||
|
||||
When `formType=20`:
|
||||
|
||||
- do not jump directly to each existing business create page as the primary architecture
|
||||
- add a common restart container page under flow task module
|
||||
- the container page is responsible for:
|
||||
- loading the business form create component
|
||||
- loading the current flow definition
|
||||
- rendering the right-side participant panel
|
||||
- orchestrating final submit as a new process start
|
||||
|
||||
Reason:
|
||||
|
||||
- existing business pages usually do not own a common workflow participant panel
|
||||
- a common restart container keeps workflow behavior centralized and reusable
|
||||
|
||||
## Frontend Component Boundary
|
||||
|
||||
### started.vue
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- expose `重新编辑提交` entry for withdrawn records
|
||||
- decide route vs drawer by form type
|
||||
- continue handling current starter list concerns
|
||||
|
||||
### New Restart Context Loader
|
||||
|
||||
Add a shared loader/composable responsible for:
|
||||
|
||||
- fetching old instance detail
|
||||
- fetching current flow detail
|
||||
- building initial form values
|
||||
- building initial participant defaults
|
||||
- exposing the resolved restart mode
|
||||
|
||||
### FlowNodeFormatData.vue
|
||||
|
||||
Needs a small enhancement:
|
||||
|
||||
- allow external default `nodeUser` injection for restart scenarios
|
||||
|
||||
### New Business Restart Container Page
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- render the business create component dynamically
|
||||
- render `FlowNodeFormatData`
|
||||
- merge edited business form data and participant selections
|
||||
- start a new process instance
|
||||
|
||||
## Existing Capabilities Reused
|
||||
|
||||
### Frontend
|
||||
|
||||
- [dynamicComponent.ts](/Users/lengleng/work/dev1227/pigx-ui-pro/src/views/flow/workflow/utils/dynamicComponent.ts)
|
||||
- [useTaskForm.ts](/Users/lengleng/work/dev1227/pigx-ui-pro/src/views/flow/task/composables/useTaskForm.ts)
|
||||
- [FlowNodeFormatData.vue](/Users/lengleng/work/dev1227/pigx-ui-pro/src/views/flow/form/tools/FlowNodeFormatData.vue)
|
||||
- [startFlow](/Users/lengleng/work/dev1227/pigx-ui-pro/src/api/flow/flow/index.ts)
|
||||
|
||||
### Backend
|
||||
|
||||
V1 should reuse existing APIs:
|
||||
|
||||
- `detail(processInstanceId)`
|
||||
- `getFlowDetail(flowId)`
|
||||
- `startProcessInstance / startFlow`
|
||||
|
||||
No dedicated backend restart API is required in V1.
|
||||
|
||||
## Business Form Compatibility
|
||||
|
||||
For business forms to participate in V1:
|
||||
|
||||
- their create component must support loading old data by `processInstanceId`
|
||||
|
||||
Example:
|
||||
|
||||
- [create.vue](/Users/lengleng/work/dev1227/pigx-ui-pro/src/views/flow/oaLeave/create.vue) already supports querying old data with `processInstanceId`
|
||||
|
||||
If some business form cannot load old data this way:
|
||||
|
||||
- it is out of V1 support unless adapted
|
||||
|
||||
## Submit Semantics
|
||||
|
||||
### Dynamic Form Submit
|
||||
|
||||
Payload:
|
||||
|
||||
- edited dynamic form data
|
||||
- participant selections from `FlowNodeFormatData`
|
||||
|
||||
Behavior:
|
||||
|
||||
- call process start API
|
||||
- create a new process instance
|
||||
|
||||
### Business Form Submit
|
||||
|
||||
Payload:
|
||||
|
||||
- edited business form data from the business create component
|
||||
- participant selections from `FlowNodeFormatData`
|
||||
|
||||
Behavior:
|
||||
|
||||
- call business-form submit path that starts a new process instance
|
||||
- create a new process instance
|
||||
|
||||
## Success and Failure UX
|
||||
|
||||
### Success
|
||||
|
||||
Message:
|
||||
|
||||
- `已重新发起流程`
|
||||
|
||||
Behavior:
|
||||
|
||||
- close restart drawer or leave restart page
|
||||
- return to starter list
|
||||
- refresh list
|
||||
|
||||
### Failure
|
||||
|
||||
If current flow definition is unavailable:
|
||||
|
||||
- `当前流程已不可发起`
|
||||
|
||||
If business form component path is invalid:
|
||||
|
||||
- `业务表单不可用,无法重新发起`
|
||||
|
||||
If old participant values are no longer valid:
|
||||
|
||||
- do not block opening
|
||||
- require reselection at validation time
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
1. Withdrawn starter records show `重新编辑提交`
|
||||
2. Dynamic flow forms open editable restart drawer with old form values
|
||||
3. Business forms open common restart container with old form values
|
||||
4. Previous manually selected approvers/copy users are prefilled when possible
|
||||
5. User can change both form data and participant selections before submit
|
||||
6. Submit creates a new process instance
|
||||
7. Old withdrawn record remains unchanged
|
||||
8. New record appears independently in starter list
|
||||
|
||||
## Risks
|
||||
|
||||
1. Business forms vary in how much they depend on route context
|
||||
2. Some business create components may not yet support restart-container integration cleanly
|
||||
3. Participant default values rely on old submitted explicit selections, not on all runtime assignment types
|
||||
|
||||
## Recommended V1 Rollout
|
||||
|
||||
1. Dynamic flow forms first
|
||||
2. Common restart container for business forms
|
||||
3. Verify `oaLeave` as the first business-form example
|
||||
4. Expand to additional business forms that already support `processInstanceId`-based reload
|
||||
|
||||
## Implementation Outline
|
||||
|
||||
The `writing-plans` skill referenced by brainstorming is unavailable in this workspace. As a fallback, implement in this order:
|
||||
|
||||
1. Add withdrawn-record `重新编辑提交` action to starter list
|
||||
2. Add restart context loader and split logic by form type
|
||||
3. Add dynamic-form restart drawer path
|
||||
4. Add business-form restart container page
|
||||
5. Enhance participant panel to accept default values
|
||||
6. Verify `oaLeave` and one dynamic form end to end
|
||||
Reference in new issue
Block a user