openxiangda-cli 2.0.0-alpha.149 → 2.0.0-alpha.150

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openxiangda-cli",
3
- "version": "2.0.0-alpha.149",
3
+ "version": "2.0.0-alpha.150",
4
4
  "description": "Thin application-level CLI for OpenXiangda 2.0.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -21,10 +21,10 @@
21
21
  ],
22
22
  "dependencies": {
23
23
  "@oclif/core": "4.13.3",
24
- "openxiangda-contracts": "2.0.0-alpha.76",
25
- "openxiangda-devkit-core": "2.0.0-alpha.96",
26
- "openxiangda-mcp": "2.0.0-alpha.96",
27
- "openxiangda-skill-kit": "2.0.0-alpha.118"
24
+ "openxiangda-contracts": "2.0.0-alpha.77",
25
+ "openxiangda-devkit-core": "2.0.0-alpha.97",
26
+ "openxiangda-mcp": "2.0.0-alpha.97",
27
+ "openxiangda-skill-kit": "2.0.0-alpha.119"
28
28
  },
29
29
  "devDependencies": {
30
30
  "tsx": "4.23.12",
@@ -15,7 +15,7 @@
15
15
  "@nestjs/common": "11.1.29",
16
16
  "@nestjs/core": "11.1.29",
17
17
  "@nestjs/platform-fastify": "11.1.29",
18
- "openxiangda": "2.0.0-alpha.68",
18
+ "openxiangda": "2.0.0-alpha.69",
19
19
  "reflect-metadata": "0.2.2",
20
20
  "rxjs": "7.8.2"
21
21
  },
@@ -116,14 +116,14 @@ const adminPages = [
116
116
  {
117
117
  code: 'workflow:task',
118
118
  kind: 'workflow-task',
119
- path: '/admin/tasks/:taskId',
119
+ path: '/tasks/:taskId',
120
120
  label: '审批任务',
121
121
  navigationEligible: false,
122
122
  },
123
123
  {
124
124
  code: 'workflow:instance',
125
125
  kind: 'workflow-instance',
126
- path: '/admin/workflows/:instanceId',
126
+ path: '/workflows/:instanceId',
127
127
  label: '流程详情',
128
128
  navigationEligible: false,
129
129
  },
@@ -184,7 +184,7 @@ const routeManifest = {
184
184
  kind: 'workflow-task',
185
185
  desktop: {
186
186
  routeCode: 'workflow.task.desktop',
187
- path: '/admin/tasks/:taskId',
187
+ path: '/tasks/:taskId',
188
188
  surface: 'admin',
189
189
  pathParams: ['taskId'],
190
190
  requiresAuthentication: true,
@@ -202,7 +202,7 @@ const routeManifest = {
202
202
  kind: 'workflow-instance',
203
203
  desktop: {
204
204
  routeCode: 'workflow.instance.desktop',
205
- path: '/admin/workflows/:instanceId',
205
+ path: '/workflows/:instanceId',
206
206
  surface: 'admin',
207
207
  pathParams: ['instanceId'],
208
208
  requiresAuthentication: true,
@@ -17,7 +17,7 @@ function detailNavigation(custom = false) {
17
17
  }
18
18
  : {
19
19
  custom: false,
20
- desktopPath: `/admin/tasks/${taskId}`,
20
+ desktopPath: `/tasks/${taskId}`,
21
21
  mobilePath: `/m/tasks/${taskId}`,
22
22
  };
23
23
  }
@@ -115,12 +115,12 @@ function surface(completed = false, customDetail = false) {
115
115
  projectionDigest: 'c'.repeat(64),
116
116
  },
117
117
  businessDetail: {
118
- status: 'ready',
118
+ status: 'stale',
119
119
  resourceCode: 'purchase-orders',
120
120
  resourceName: '采购申请',
121
121
  recordId: 'purchase-1',
122
122
  requestedRevision: 8,
123
- sourceRevision: 8,
123
+ sourceRevision: 9,
124
124
  surface: {
125
125
  mutationOwner: 'workflow',
126
126
  fields: {
@@ -133,10 +133,26 @@ function surface(completed = false, customDetail = false) {
133
133
  createCapabilities: [],
134
134
  updateCapabilities: [],
135
135
  },
136
+ internalVenue: {
137
+ label: '技术场地引用',
138
+ type: 'reference',
139
+ widget: 'reference',
140
+ section: '系统信息',
141
+ system: true,
142
+ readCapabilities: [],
143
+ createCapabilities: [],
144
+ updateCapabilities: [],
145
+ },
146
+ },
147
+ detail: {
148
+ layout: 'sections',
149
+ fieldOrder: ['amount', 'internalVenue'],
136
150
  },
137
- detail: { layout: 'sections', fieldOrder: ['amount'] },
138
151
  },
139
- record: { amount: 28600 },
152
+ record: {
153
+ amount: 30000,
154
+ internalVenue: '77777777-7777-4777-8777-777777777777',
155
+ },
140
156
  subtables: {},
141
157
  projectionDigest: 'd'.repeat(64),
142
158
  },
@@ -234,6 +250,7 @@ function timeline(completed = false) {
234
250
  startedAt: '2026-08-25T01:00:00.000Z',
235
251
  completedAt: '2026-08-25T01:00:00.000Z',
236
252
  assignees: [],
253
+ operations: [],
237
254
  },
238
255
  {
239
256
  key: 'manager',
@@ -244,6 +261,18 @@ function timeline(completed = false) {
244
261
  startedAt: '2026-08-25T01:01:00.000Z',
245
262
  completedAt: completed ? '2026-08-25T01:12:00.000Z' : null,
246
263
  assignees: [{ userId: 'acceptance-user', displayName: '李明' }],
264
+ operations: [{
265
+ id: 'operation-transfer',
266
+ operation: 'transfer',
267
+ operationLabel: '转交',
268
+ actorUserId: 'acceptance-user',
269
+ actorDisplayName: '李明',
270
+ actingForUserId: null,
271
+ reason: '由值班负责人继续处理',
272
+ detail: {},
273
+ severity: 'normal',
274
+ createdAt: '2026-08-25T01:08:00.000Z',
275
+ }],
247
276
  },
248
277
  {
249
278
  key: 'finance',
@@ -254,9 +283,21 @@ function timeline(completed = false) {
254
283
  startedAt: null,
255
284
  completedAt: null,
256
285
  assignees: [{ userId: 'finance-user', displayName: '财务负责人' }],
286
+ operations: [],
257
287
  },
258
288
  ],
259
- items: [],
289
+ items: [{
290
+ id: 'operation-transfer',
291
+ operation: 'transfer',
292
+ operationLabel: '转交',
293
+ actorUserId: 'acceptance-user',
294
+ actorDisplayName: '李明',
295
+ actingForUserId: null,
296
+ reason: '由值班负责人继续处理',
297
+ detail: {},
298
+ severity: 'normal',
299
+ createdAt: '2026-08-25T01:08:00.000Z',
300
+ }],
260
301
  };
261
302
  }
262
303
 
@@ -410,7 +451,11 @@ function todoPage() {
410
451
 
411
452
  async function mockWorkflow(
412
453
  page: Page,
413
- options: { forbidden?: boolean; customDetail?: boolean } = {}
454
+ options: {
455
+ commandConflict?: boolean;
456
+ forbidden?: boolean;
457
+ customDetail?: boolean;
458
+ } = {}
414
459
  ) {
415
460
  let completed = false;
416
461
  await page.route('**/service/**', async route => {
@@ -593,6 +638,15 @@ async function mockWorkflow(
593
638
  expect(route.request().postDataJSON()).not.toHaveProperty(
594
639
  'expectedInstanceVersion'
595
640
  );
641
+ if (options.commandConflict) {
642
+ return route.fulfill({
643
+ status: 409,
644
+ contentType: 'application/json',
645
+ body: JSON.stringify(
646
+ envelope({ freshSurface: surface(false, options.customDetail) }, 409)
647
+ ),
648
+ });
649
+ }
596
650
  completed = true;
597
651
  return route.fulfill({
598
652
  contentType: 'application/json',
@@ -704,13 +758,48 @@ test('redirects a direct standard task URL to the declared custom detail page',
704
758
  }) => {
705
759
  await mockWorkflow(page, { customDetail: true });
706
760
  await page.goto(
707
- `/workflow-experience.e2e.html?initial=/admin/tasks/${taskId}`
761
+ `/workflow-experience.e2e.html?initial=/tasks/${taskId}`
708
762
  );
709
763
  await expect(page.getByTestId('custom-workflow-detail')).toContainText(
710
764
  `${instanceId} / ${taskId}`
711
765
  );
712
766
  });
713
767
 
768
+ test('renders a standalone desktop detail and redirects the legacy admin URL', async ({
769
+ page,
770
+ }) => {
771
+ await mockWorkflow(page);
772
+ await page.goto(
773
+ workflowFixtureUrl(`/admin/tasks/${taskId}?from=legacy#approval`),
774
+ );
775
+ await expect(page.locator('.oxa-workflow-desktop-standalone-page')).toBeVisible();
776
+ await expect(page).toHaveURL(
777
+ new RegExp(`/tasks/${taskId}\\?from=legacy#approval$`),
778
+ );
779
+ await expect(page.locator('.oxa-app-layout')).toHaveCount(0);
780
+ await expect(page.locator('.oxa-topbar')).toHaveCount(0);
781
+ await expect(page.getByText('¥30,000')).toBeVisible();
782
+ await expect(page.getByText('技术场地引用')).toHaveCount(0);
783
+ await expect(page.getByText('业务数据已变化')).toHaveCount(0);
784
+ await expect(page.getByText('流程信息')).toHaveCount(0);
785
+ await expect(page.getByText('操作记录')).toHaveCount(0);
786
+ await expect(page.getByText('由值班负责人继续处理')).toHaveCount(1);
787
+ await expect(page.getByRole('button', { name: /同\s*意/ })).toBeVisible();
788
+ await expect(page.getByRole('button', { name: /拒\s*绝/ })).toBeVisible();
789
+ });
790
+
791
+ test('shows a friendly refresh prompt only after a real command conflict', async ({
792
+ page,
793
+ }) => {
794
+ await mockWorkflow(page, { commandConflict: true });
795
+ await page.goto(workflowFixtureUrl(`/tasks/${taskId}`));
796
+ await expect(page.getByText('业务数据已变化')).toHaveCount(0);
797
+ await page.getByRole('button', { name: /同\s*意/ }).click();
798
+ await page.getByLabel('审批意见').fill('同意采购');
799
+ await page.getByRole('button', { name: '确认同意' }).click();
800
+ await expect(page.getByText('内容已更新,请刷新后重试')).toBeVisible();
801
+ });
802
+
714
803
  test('renders the independent mobile task and executes only a Surface operation', async ({
715
804
  page,
716
805
  }) => {
@@ -718,7 +807,7 @@ test('renders the independent mobile task and executes only a Surface operation'
718
807
  await page.setViewportSize({ width: 390, height: 844 });
719
808
  await page.goto(`/workflow-experience.e2e.html?initial=/m/tasks/${taskId}`);
720
809
  await expect(page.locator('.oxa-workflow-mobile-page')).toBeVisible();
721
- await expect(page.getByText('¥28,600')).toBeVisible();
810
+ await expect(page.getByText('¥30,000')).toBeVisible();
722
811
  await expect(page.getByText('财务负责人').first()).toBeVisible();
723
812
  await expect(page.getByRole('button', { name: /同\s*意/ })).toBeVisible();
724
813
  await page.getByRole('button', { name: /同\s*意/ }).click();
@@ -785,7 +874,7 @@ test('negotiates direct standard routes after BrowserRouter listener setup', asy
785
874
  // context to the independent mobile renderer at the narrow width.
786
875
  await page.setViewportSize({ width: 360, height: 844 });
787
876
  await page.goto(
788
- workflowFixtureUrl(`/admin/tasks/${taskId}?from=todo#approval`),
877
+ workflowFixtureUrl(`/tasks/${taskId}?from=todo#approval`),
789
878
  );
790
879
  await expect(page.locator('.oxa-workflow-detail-mobile-native')).toBeVisible();
791
880
  await expect(page).toHaveURL(
@@ -793,7 +882,7 @@ test('negotiates direct standard routes after BrowserRouter listener setup', asy
793
882
  );
794
883
 
795
884
  await page.goto(
796
- workflowFixtureUrl(`/admin/workflows/${instanceId}?from=todo#timeline`),
885
+ workflowFixtureUrl(`/workflows/${instanceId}?from=todo#timeline`),
797
886
  );
798
887
  await expect(page.locator('.oxa-workflow-detail-mobile-native')).toBeVisible();
799
888
  await expect(page).toHaveURL(
@@ -14,7 +14,7 @@
14
14
  "@ant-design/icons": "6.2.3",
15
15
  "@refinedev/core": "5.0.12",
16
16
  "antd": "6.4.3",
17
- "openxiangda": "2.0.0-alpha.68",
17
+ "openxiangda": "2.0.0-alpha.69",
18
18
  "react": "19.2.8",
19
19
  "react-dom": "19.2.8",
20
20
  "react-router-dom": "7.8.2"
@@ -23,7 +23,7 @@
23
23
  "build": "pnpm --recursive build"
24
24
  },
25
25
  "devDependencies": {
26
- "openxiangda": "2.0.0-alpha.68",
26
+ "openxiangda": "2.0.0-alpha.69",
27
27
  "typescript": "5.9.3"
28
28
  }
29
29
  }