docs(flow): add withdraw resubmit design

This commit is contained in:
PIGCLOUD committed 2026-03-19 08:39:53 +08:00
1 parent 2c70387ace
commit b553787cfd
1 file changed
+377
@@ -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