openxiangda 1.0.22 → 1.0.24

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.
Files changed (89) hide show
  1. package/README.md +28 -10
  2. package/lib/cli.js +271 -11
  3. package/lib/workspace-init.js +13 -0
  4. package/openxiangda-skills/SKILL.md +25 -10
  5. package/openxiangda-skills/references/architecture-patterns.md +44 -22
  6. package/openxiangda-skills/references/best-practices.md +163 -0
  7. package/openxiangda-skills/references/pages/workspace-structure.md +5 -3
  8. package/openxiangda-skills/references/workspace-state.md +6 -0
  9. package/openxiangda-skills/skills/openxiangda-app/SKILL.md +11 -7
  10. package/openxiangda-skills/skills/openxiangda-core/SKILL.md +22 -4
  11. package/openxiangda-skills/skills/openxiangda-form/SKILL.md +6 -1
  12. package/openxiangda-skills/skills/openxiangda-page/SKILL.md +7 -1
  13. package/openxiangda-skills/skills/openxiangda-permission-settings/SKILL.md +3 -0
  14. package/openxiangda-skills/skills/openxiangda-workflow-automation/SKILL.md +7 -0
  15. package/package.json +1 -1
  16. package/templates/sy-lowcode-app-workspace/examples/best-practices/README.md +32 -0
  17. package/templates/sy-lowcode-app-workspace/examples/best-practices/catalog.json +61 -0
  18. package/templates/sy-lowcode-app-workspace/examples/best-practices/decision-guide.md +44 -0
  19. package/templates/sy-lowcode-app-workspace/examples/best-practices/design-style.md +30 -0
  20. package/templates/sy-lowcode-app-workspace/examples/best-practices/module-structure.md +48 -0
  21. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/role-governance/index.ts +2 -0
  22. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/role-governance/permissions.test.ts +35 -0
  23. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/role-governance/permissions.ts +24 -0
  24. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/role-governance/types.ts +17 -0
  25. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/index.ts +4 -0
  26. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/permissions.test.ts +42 -0
  27. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/permissions.ts +23 -0
  28. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/state-machine.test.ts +63 -0
  29. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/state-machine.ts +73 -0
  30. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/ticket-query.test.ts +34 -0
  31. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/ticket-query.ts +73 -0
  32. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/domain/service-ticket/types.ts +64 -0
  33. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/app-role/page.tsx +1 -0
  34. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/app-role/schema.ts +57 -0
  35. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/customer-profile/page.tsx +1 -0
  36. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/customer-profile/schema.ts +83 -0
  37. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/service-ticket/page.tsx +1 -0
  38. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/service-ticket/schema.ts +97 -0
  39. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/ticket-action-log/page.tsx +1 -0
  40. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/forms/ticket-action-log/schema.ts +65 -0
  41. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/js-code-nodes/daily_ticket_digest/index.ts +44 -0
  42. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/js-code-nodes/sync_roles_to_platform/index.ts +33 -0
  43. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/App.tsx +7 -0
  44. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/WorkbenchPage.tsx +36 -0
  45. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/components/ConfigPanel.tsx +34 -0
  46. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/components/PreviewPanel.tsx +17 -0
  47. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/index.tsx +10 -0
  48. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/page.config.ts +9 -0
  49. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/reducer.ts +29 -0
  50. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/interactive-workbench/styles.css +24 -0
  51. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/App.tsx +7 -0
  52. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/MobilePortalShell.tsx +31 -0
  53. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/index.tsx +10 -0
  54. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/modules/MobileHome.tsx +13 -0
  55. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/page.config.ts +14 -0
  56. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/routes.ts +13 -0
  57. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/mobile-portal-shell/styles.css +11 -0
  58. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/App.tsx +7 -0
  59. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/PcPortalShell.tsx +35 -0
  60. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/components/PortalMetric.tsx +11 -0
  61. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/index.tsx +10 -0
  62. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/modules/HomeModule.tsx +25 -0
  63. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/modules/TicketsModule.tsx +14 -0
  64. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/page.config.ts +14 -0
  65. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/routes.ts +19 -0
  66. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/pc-portal-shell/styles.css +35 -0
  67. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/App.tsx +7 -0
  68. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/TicketOpsPage.tsx +105 -0
  69. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/components/TicketActionTimeline.tsx +22 -0
  70. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/components/TicketDetailDrawer.tsx +41 -0
  71. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/components/TicketTableActions.tsx +55 -0
  72. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/index.tsx +10 -0
  73. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/page.config.ts +9 -0
  74. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/pages/service-ticket-ops/styles.css +35 -0
  75. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/resources/automations/daily-ticket-digest/automation.json +25 -0
  76. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/resources/automations/daily-ticket-digest/trigger.json +9 -0
  77. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/resources/notifications/daily-ticket-digest.json +24 -0
  78. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/resources/permissions/form-groups/service-ticket-college.json +21 -0
  79. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/resources/permissions/roles.json +17 -0
  80. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/resources/workflows/expense-approval-workflow.json +48 -0
  81. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/components/ConfirmAction.tsx +22 -0
  82. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/components/QueryState.tsx +37 -0
  83. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/components/StatusTag.tsx +20 -0
  84. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/hooks/useTicketOps.ts +96 -0
  85. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/services/role-governance.ts +48 -0
  86. package/templates/sy-lowcode-app-workspace/examples/best-practices/src/shared/services/service-ticket.ts +113 -0
  87. package/templates/sy-lowcode-app-workspace/package.json +1 -0
  88. package/templates/sy-lowcode-app-workspace/src/dev/App.tsx +11 -1
  89. package/templates/sy-lowcode-app-workspace/tsconfig.examples.json +24 -0
@@ -0,0 +1,48 @@
1
+ import type { PageSdk } from "openxiangda/runtime";
2
+
3
+ import { buildRoleCode, type AppRoleRecord } from "@/domain/role-governance";
4
+
5
+ export const APP_ROLE_FORM_UUID = "FORM_APP_ROLE";
6
+
7
+ export async function queryEnabledBusinessRoles(sdk: PageSdk) {
8
+ const response = await sdk.form.advancedSearch<AppRoleRecord>({
9
+ formUuid: APP_ROLE_FORM_UUID,
10
+ currentPage: 1,
11
+ pageSize: 100,
12
+ filters: {
13
+ id: "enabled_roles",
14
+ logic: "AND",
15
+ rules: [
16
+ {
17
+ id: "enabled_EQ",
18
+ key: "enabled",
19
+ componentName: "RadioField",
20
+ operator: "EQ",
21
+ value: "enabled",
22
+ },
23
+ ],
24
+ conditions: [],
25
+ } as never,
26
+ });
27
+ return response.result?.data || [];
28
+ }
29
+
30
+ export async function syncBusinessRoleToPlatform(sdk: PageSdk, role: AppRoleRecord) {
31
+ const roleCode = buildRoleCode(role);
32
+ const platformRole = await sdk.role.create({
33
+ code: roleCode,
34
+ name: role.roleName,
35
+ scope: "app",
36
+ description: "由业务角色维护表同步",
37
+ });
38
+ const roleId = platformRole.result?.id;
39
+ if (!roleId) return platformRole;
40
+
41
+ for (const member of role.members || []) {
42
+ await sdk.role.assignRoles({
43
+ userId: member.value,
44
+ roleIds: [roleId],
45
+ });
46
+ }
47
+ return platformRole;
48
+ }
@@ -0,0 +1,113 @@
1
+ import type { PageSdk } from "openxiangda/runtime";
2
+
3
+ import {
4
+ assertTicketTransition,
5
+ buildTicketFilterGroup,
6
+ type TicketAction,
7
+ type TicketActionLog,
8
+ type TicketOperator,
9
+ type TicketRecord,
10
+ type TicketSearchState,
11
+ } from "@/domain/service-ticket";
12
+
13
+ export const SERVICE_TICKET_FORM_UUID = "FORM_SERVICE_TICKET";
14
+ export const TICKET_ACTION_LOG_FORM_UUID = "FORM_TICKET_ACTION_LOG";
15
+
16
+ export interface TicketQueryInput {
17
+ currentPage: number;
18
+ pageSize: number;
19
+ search: TicketSearchState;
20
+ }
21
+
22
+ export interface TicketQueryResult {
23
+ records: TicketRecord[];
24
+ total: number;
25
+ }
26
+
27
+ export async function queryTickets(
28
+ sdk: PageSdk,
29
+ input: TicketQueryInput,
30
+ ): Promise<TicketQueryResult> {
31
+ const response = await sdk.form.advancedSearch<TicketRecord>({
32
+ formUuid: SERVICE_TICKET_FORM_UUID,
33
+ currentPage: input.currentPage,
34
+ pageSize: input.pageSize,
35
+ filters: buildTicketFilterGroup(input.search) as never,
36
+ order: [{ id: "modifiedTime", isAsc: "n" }],
37
+ });
38
+
39
+ return {
40
+ records: response.result?.data || [],
41
+ total: response.result?.totalCount || 0,
42
+ };
43
+ }
44
+
45
+ export async function transitionTicket(
46
+ sdk: PageSdk,
47
+ ticket: TicketRecord,
48
+ action: TicketAction,
49
+ operator: TicketOperator,
50
+ comment?: string,
51
+ ) {
52
+ const nextStatus = assertTicketTransition(ticket, action, operator);
53
+ const operatedAt = new Date().toISOString();
54
+
55
+ await sdk.form.update({
56
+ formUuid: SERVICE_TICKET_FORM_UUID,
57
+ formInstanceId: ticket.formInstanceId,
58
+ data: {
59
+ status: nextStatus,
60
+ lastActionAt: operatedAt,
61
+ ownerUserId: ticket.ownerUserId,
62
+ ownerDeptId: ticket.ownerDeptId,
63
+ collegeId: ticket.collegeId,
64
+ classId: ticket.classId,
65
+ },
66
+ } as never);
67
+
68
+ const log: TicketActionLog = {
69
+ ticketId: ticket.formInstanceId,
70
+ action,
71
+ fromStatus: ticket.status,
72
+ toStatus: nextStatus,
73
+ operatorId: operator.userId,
74
+ operatorName: operator.userName,
75
+ comment,
76
+ operatedAt,
77
+ };
78
+
79
+ await sdk.form.create({
80
+ formUuid: TICKET_ACTION_LOG_FORM_UUID,
81
+ data: log,
82
+ } as never);
83
+
84
+ return { nextStatus, operatedAt };
85
+ }
86
+
87
+ export async function queryTicketActionLogs(
88
+ sdk: PageSdk,
89
+ ticketId: string,
90
+ ): Promise<TicketActionLog[]> {
91
+ const response = await sdk.form.advancedSearch<TicketActionLog>({
92
+ formUuid: TICKET_ACTION_LOG_FORM_UUID,
93
+ currentPage: 1,
94
+ pageSize: 50,
95
+ filters: {
96
+ id: "ticket_log_filters",
97
+ logic: "AND",
98
+ rules: [
99
+ {
100
+ id: "ticketId_EQ",
101
+ key: "ticketId",
102
+ componentName: "TextField",
103
+ operator: "EQ",
104
+ value: ticketId,
105
+ },
106
+ ],
107
+ conditions: [],
108
+ } as never,
109
+ order: [{ id: "createdAt", isAsc: "n" }],
110
+ });
111
+
112
+ return response.result?.data || [];
113
+ }
@@ -12,6 +12,7 @@
12
12
  "build-js-code": "node scripts/build-js-code.mjs",
13
13
  "build:js-code": "node scripts/build-js-code.mjs",
14
14
  "typecheck:js-code": "tsc -p tsconfig.js-code-nodes.json --noEmit",
15
+ "examples:check": "tsc -p tsconfig.examples.json --noEmit",
15
16
  "sync-schema": "lowcode-workspace sync-schema",
16
17
  "publish:oss": "lowcode-workspace publish-oss",
17
18
  "register": "lowcode-workspace register",
@@ -1,4 +1,4 @@
1
- import { Card, Space, Typography } from "antd";
1
+ import { Card, Divider, Space, Typography } from "antd";
2
2
 
3
3
  const { Paragraph, Text, Title } = Typography;
4
4
 
@@ -19,6 +19,16 @@ export default function App() {
19
19
  Publish from this workspace with{" "}
20
20
  <Text code>openxiangda workspace publish --profile &lt;name&gt;</Text>.
21
21
  </Paragraph>
22
+ <Divider style={{ margin: "4px 0" }} />
23
+ <Paragraph style={{ margin: 0 }}>
24
+ Best-practice templates live under{" "}
25
+ <Text code>examples/best-practices</Text>. They are not published by
26
+ default. Copy selected modules into <Text code>src</Text> when you
27
+ want to use them.
28
+ </Paragraph>
29
+ <Paragraph style={{ margin: 0 }}>
30
+ Validate the cookbook with <Text code>pnpm examples:check</Text>.
31
+ </Paragraph>
22
32
  </Space>
23
33
  </Card>
24
34
  </main>
@@ -0,0 +1,24 @@
1
+ {
2
+ "extends": "./tsconfig.app.json",
3
+ "compilerOptions": {
4
+ "baseUrl": ".",
5
+ "paths": {
6
+ "@/*": ["examples/best-practices/src/*", "src/*"],
7
+ "openxiangda": [
8
+ "../../packages/sdk/src/components/index.ts",
9
+ "node_modules/openxiangda"
10
+ ],
11
+ "openxiangda/runtime": [
12
+ "../../packages/sdk/src/runtime/index.ts",
13
+ "node_modules/openxiangda/runtime"
14
+ ]
15
+ }
16
+ },
17
+ "include": [
18
+ "examples/best-practices/src/**/*.ts",
19
+ "examples/best-practices/src/**/*.tsx",
20
+ "examples/best-practices/**/*.json",
21
+ "src/types/**/*.ts",
22
+ "src/shared/form-schema.ts"
23
+ ]
24
+ }