openxiangda 1.0.262 → 1.0.264
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/README.md +1 -1
- package/openxiangda-skills/SKILL.md +6 -3
- package/openxiangda-skills/references/pages/page-sdk.md +2 -2
- package/openxiangda-skills/references/school-contact-relations.md +62 -3
- package/openxiangda-skills/skills/openxiangda-page/SKILL.md +2 -2
- package/package.json +1 -1
- package/packages/sdk/dist/runtime/index.cjs +42 -42
- package/packages/sdk/dist/runtime/index.d.mts +1 -1
- package/packages/sdk/dist/runtime/index.d.ts +1 -1
- package/packages/sdk/dist/runtime/index.mjs +7 -7
- package/packages/sdk/dist/runtime/react.cjs +46 -46
- package/packages/sdk/dist/runtime/react.d.mts +29 -1
- package/packages/sdk/dist/runtime/react.d.ts +29 -1
- package/packages/sdk/dist/runtime/react.mjs +5 -5
- package/templates/openxiangda-react-spa/AGENTS.md +1 -1
- package/templates/sy-lowcode-app-workspace/AGENTS.md +1 -1
package/README.md
CHANGED
|
@@ -415,7 +415,7 @@ openxiangda form export customer --mode package --profile dev --output ./exports
|
|
|
415
415
|
|
|
416
416
|
运行时页面读取当前用户信息时,优先使用 `sdk.user.getCurrent<PageUserRecord>()`。用户对象会返回常规组织成员关系 `departments`,也会返回系统维护的所属单位字段 `affiliatedDepartmentId` / `affiliatedDepartment`。`departments` 表示用户真实所在的部门、班级、专业等成员关系;`affiliatedDepartment` 表示业务上用于统计、筛选和展示的归属单位,通常是学院、单位或在源单位缺失时可用的具体部门节点,不用于替代权限部门成员关系。
|
|
417
417
|
|
|
418
|
-
钉钉家校通讯录的家长、学生、教师身份和明确监护关系使用 `sdk.organization.schoolContact.*`(页面)或 `ctx.organization.schoolContact.*`(App Function
|
|
418
|
+
钉钉家校通讯录的家长、学生、教师身份和明确监护关系使用 `sdk.organization.schoolContact.*`(页面)或 `ctx.organization.schoolContact.*`(App Function)。已登录非游客用户无需给应用角色额外绑定权限,默认可查询当前租户全部关系,返回平台用户 ID、手机号、钉钉 userid 和姓名;应用可显式声明 `:self:read` / `:class:read` 收紧范围。完整示例见 [`docs/dingtalk-school-contact-relations.md`](docs/dingtalk-school-contact-relations.md)。
|
|
419
419
|
|
|
420
420
|
```ts
|
|
421
421
|
import type { PageUserRecord } from "openxiangda/runtime"
|
|
@@ -191,9 +191,12 @@ The lease is app-level promotion ownership, while worktree ownership prevents tw
|
|
|
191
191
|
- Use platform roles, permission groups, public grants, and backend Function checks for authorization; frontend hiding is presentation only.
|
|
192
192
|
- Keep tokens and secrets out of project files and chat.
|
|
193
193
|
- Use official public SDK entrypoints and platform form/file components.
|
|
194
|
-
- Read school-contact guardian/student relationships through
|
|
195
|
-
`sdk.organization.schoolContact` or the trusted App Function bridge.
|
|
196
|
-
|
|
194
|
+
- Read school-contact guardian/student and teacher/class relationships through
|
|
195
|
+
`sdk.organization.schoolContact` or the trusted App Function bridge. Use
|
|
196
|
+
`SCHOOL_HEAD_TEACHER` only for global identity and `teachers.list` for the
|
|
197
|
+
exact class relationship. Keep the
|
|
198
|
+
authenticated non-guest default tenant-wide scope without adding an app-role
|
|
199
|
+
permission binding unless the product explicitly requires self/class
|
|
197
200
|
restrictions; never infer relations from department membership.
|
|
198
201
|
- Report platform defects or repeated workarounds with `openxiangda feedback submit --yes` when a configured feedback channel is available.
|
|
199
202
|
- Run `openxiangda update check --json` once at the start of substantial work, when a version mismatch is suspected, or when the cached check is older than one day. Do not repeat it on every confirmation turn.
|
|
@@ -19,7 +19,7 @@ Guidelines:
|
|
|
19
19
|
- Use `sdk.export.create` and `sdk.export.get` for asynchronous XLSX exports. Simple pages may send a declarative workbook definition. Complex or reusable exports should send only a published App Function `definitionCode`, the current query snapshot, export scope, and stable selected row IDs. The server executes `structured_export_provider_v1` with fresh user permissions; never upload executable rendering code from the browser. See `docs/structured-export-v1.md`.
|
|
20
20
|
- Use `AttachmentPreviewList`, `ImagePreviewGrid`, or `useFilePreview` from `openxiangda/runtime/react` for in-page attachment previews in a custom React SPA page. They use the current PageSdk context and enforce the platform capability and ticket contracts. Use `sdk.createFileAccessTicket(bucketName, objectName, fileName, "preview", { appType })` only when the page needs a shareable or new-window preview link. `appType` defaults to the current page context. Open `response.result.previewPageUrl`; do not use `previewUrl` or `/service/file/preview-by-ticket/:ticket` as the page entry.
|
|
21
21
|
- Use `sdk.organization.departments.*` and `sdk.organization.accounts.*` only for intentional organization pages. Read-only list/detail pages need `app:organization:read` or `app:organization:manage`; writes and password operations need `app:organization:manage`. Do not call legacy `/user` or `/department` endpoints from pages.
|
|
22
|
-
- Use `sdk.organization.schoolContact.*` for synchronized guardian/student relationships.
|
|
22
|
+
- Use `sdk.organization.schoolContact.*` for synchronized guardian/student and teacher/class relationships. `SCHOOL_HEAD_TEACHER` identifies a user who currently heads at least one class; use `teachers.list({ classId, isHeadTeacher: true })` to resolve the exact class. Authenticated non-guest users default to all relationships in the current tenant without an app-role permission binding. Use the optional `self:read` or `class:read` permission only when the product explicitly needs a narrower data scope. The response intentionally includes platform user ID, mobile, DingTalk userid, and name. Read `references/school-contact-relations.md` before building a family or class page.
|
|
23
23
|
- Synchronized school-contact users also receive platform identity codes: `SCHOOL_GUARDIAN`, `SCHOOL_STUDENT`, and `SCHOOL_TEACHER`. Page permission groups select them with `platformRoleCodes` (additive to app `roles`), and runtime permissions expose them in `permissions.platformRoleCodes`. App Functions can use a `platform_roles` invocation audience and trusted `ctx.operator.platformRoleCodes`; these roles are maintained only by the daily organization sync.
|
|
24
24
|
- Use `sdk.workCenter.listItems({ boxType })` and `sdk.workCenter.getStats()` for current-user work center lists and counts. `boxType` is one of `todo`, `done`, `cc`, or `initiated`. This is the end-user task/handled/cc/initiated surface; do not build todo pages by reading workflow operation logs, automation logs, or raw process-task tables.
|
|
25
25
|
- `sdk.form.create` returns identifiers and generated serial number values only. Treat `formInstId` / `formInstanceId` as the required success contract; `serialNumber` / `serialNumbers` are present only when the form has `SerialNumberField`. Do not expect the save response to contain the full row, formula results, or other server-generated field values. Call `sdk.form.getDetail` explicitly after create when those values are needed.
|
|
@@ -253,7 +253,7 @@ await sdk.organization.accounts.resetPassword("alice", {
|
|
|
253
253
|
|
|
254
254
|
Use `ctx.organization.departments.*` and `ctx.organization.accounts.*` inside App Functions or trusted JS nodes for the same capability. Runtime service principals must resolve a real operator/audit actor; permission is checked against that user, not against the runtime service account. Keep password changes on dedicated endpoints: update account metadata with `update`, reset another user's password with `resetPassword`, and change the current user's password with `changeMyPassword({ oldPassword, newPassword })`.
|
|
255
255
|
|
|
256
|
-
For synchronized school-contact relationships, use `sdk.organization.schoolContact.relations.list`, `children.list`, `guardians.list`, or `myFamily.get`; App Functions use the same paths under `ctx.organization.schoolContact`. Do not infer a family relationship from class membership or persist a second relationship master inside application forms. See `references/school-contact-relations.md` for permission codes, filters, response fields, and examples.
|
|
256
|
+
For synchronized school-contact relationships, use `sdk.organization.schoolContact.relations.list`, `teachers.list`, `children.list`, `guardians.list`, or `myFamily.get`; App Functions use the same paths under `ctx.organization.schoolContact`. Do not infer a family relationship from class membership, infer a specific head-teacher class from the global role, or persist a second relationship master inside application forms. See `references/school-contact-relations.md` for permission codes, filters, response fields, and examples.
|
|
257
257
|
|
|
258
258
|
Work center:
|
|
259
259
|
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
## 权限与默认范围
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
已登录非游客用户无需给应用角色绑定家校权限,默认查询当前租户的全部关系,范围为 `all`。跨租户、游客和匿名访问仍然拒绝。
|
|
8
|
+
|
|
9
|
+
应用若要显式保留全量范围,可以在 `src/resources/roles/<code>.json` 中声明:
|
|
8
10
|
|
|
9
11
|
```json
|
|
10
12
|
{
|
|
@@ -14,24 +16,27 @@
|
|
|
14
16
|
}
|
|
15
17
|
```
|
|
16
18
|
|
|
17
|
-
`app:organization:school-contact:read`
|
|
19
|
+
`app:organization:school-contact:read` 与未声明权限时的默认范围相同。只有产品明确要求收紧时,才改用以下权限之一:
|
|
18
20
|
|
|
19
21
|
- `app:organization:school-contact:self:read`:只返回当前操作者作为家长或学生直接参与的关系。
|
|
20
22
|
- `app:organization:school-contact:class:read`:只返回当前操作者以 `teacher` 身份加入的班级关系。
|
|
21
23
|
|
|
24
|
+
同一应用角色拥有多项家校能力时按 `all > class > self` 取最宽范围。平台身份角色只表达用户身份,不参与通用应用权限计算;默认 `all` 由家校关系服务统一执行。
|
|
25
|
+
|
|
22
26
|
默认全量可见不等于公开访问:跨租户、游客和匿名页面仍然拒绝。不要通过公开访问策略给游客授予家庭关系能力。
|
|
23
27
|
|
|
24
28
|
## 页面 SDK
|
|
25
29
|
|
|
26
30
|
### 平台内置身份角色
|
|
27
31
|
|
|
28
|
-
|
|
32
|
+
每次成功的钉钉家校通讯录全量同步都会对账并维护四种平台层系统身份角色:
|
|
29
33
|
|
|
30
34
|
| 展示名 | 稳定角色编码 | 含义 |
|
|
31
35
|
| --- | --- | --- |
|
|
32
36
|
| 家长 | `SCHOOL_GUARDIAN` | 在家校成员关系中作为 guardian |
|
|
33
37
|
| 学生 | `SCHOOL_STUDENT` | 在家校成员关系中作为 student |
|
|
34
38
|
| 老师 | `SCHOOL_TEACHER` | 在家校成员关系中作为 teacher |
|
|
39
|
+
| 班主任 | `SCHOOL_HEAD_TEACHER` | 至少一个 teacher 班级成员带 `is_adviser=true` |
|
|
35
40
|
|
|
36
41
|
身份角色可组合,一个平台用户可以同时是老师和家长;角色由同步维护,不能在平台角色管理中手工分配、修改、删除,也不会被当前平台角色切换隐藏。应用权限组把这些编码填入 `platformRoleCodes`,与应用角色 `roles` 是并列的 OR 条件;两个数组都为空仍表示不限制。
|
|
37
42
|
|
|
@@ -40,8 +45,13 @@
|
|
|
40
45
|
```ts
|
|
41
46
|
const isGuardian =
|
|
42
47
|
sdk.context.permissions?.platformRoleCodes?.includes("SCHOOL_GUARDIAN")
|
|
48
|
+
|
|
49
|
+
const isHeadTeacher =
|
|
50
|
+
sdk.context.permissions?.platformRoleCodes?.includes("SCHOOL_HEAD_TEACHER")
|
|
43
51
|
```
|
|
44
52
|
|
|
53
|
+
`SCHOOL_HEAD_TEACHER` 只说明当前用户至少担任一个班的班主任。班主任是班级维度的关系;要判断具体班级,必须使用下方 `teachers.list` 返回的 `isHeadTeacher`,不能用全局角色推断。
|
|
54
|
+
|
|
45
55
|
App Function 的调用受众可以声明平台身份角色,服务端按真实操作者的同步结果校验:
|
|
46
56
|
|
|
47
57
|
```json
|
|
@@ -84,6 +94,13 @@ await sdk.organization.schoolContact.guardians.list(studentUserId, {
|
|
|
84
94
|
})
|
|
85
95
|
|
|
86
96
|
await sdk.organization.schoolContact.myFamily.get({ pageSize: 50 })
|
|
97
|
+
|
|
98
|
+
await sdk.organization.schoolContact.teachers.list({
|
|
99
|
+
classId,
|
|
100
|
+
isHeadTeacher: true,
|
|
101
|
+
page: 1,
|
|
102
|
+
pageSize: 20,
|
|
103
|
+
})
|
|
87
104
|
```
|
|
88
105
|
|
|
89
106
|
关系列表支持以下服务端过滤条件:
|
|
@@ -96,6 +113,16 @@ await sdk.organization.schoolContact.myFamily.get({ pageSize: 50 })
|
|
|
96
113
|
- `role`:`guardian` 或 `student`,用于限定通用人员过滤作用在哪一端。
|
|
97
114
|
- `relationCode`、`page`、`pageSize`;`pageSize` 最大为 100。
|
|
98
115
|
|
|
116
|
+
老师班级成员列表 `teachers.list` 支持:
|
|
117
|
+
|
|
118
|
+
- `userId`:老师的平台用户 ID。
|
|
119
|
+
- `dingtalkUserId`:老师的钉钉 userid。
|
|
120
|
+
- `mobile`:精确手机号。
|
|
121
|
+
- `name`:老师姓名。
|
|
122
|
+
- `classId`:平台家校班级 ID 或钉钉教育 `class_id`。
|
|
123
|
+
- `isHeadTeacher`:布尔值;`true` 只返回班主任,`false` 只返回普通任课老师。
|
|
124
|
+
- `page`、`pageSize`;`pageSize` 最大为 100。
|
|
125
|
+
|
|
99
126
|
## App Function
|
|
100
127
|
|
|
101
128
|
App Function、Automation 或 Workflow 中需要复用关系时,调用对应的受控后端桥接:
|
|
@@ -112,10 +139,24 @@ export default async function(ctx, input) {
|
|
|
112
139
|
}
|
|
113
140
|
```
|
|
114
141
|
|
|
142
|
+
查询某位老师担任班主任的班级:
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
export default async function(ctx, input) {
|
|
146
|
+
return await ctx.organization.schoolContact.teachers.list({
|
|
147
|
+
userId: input.teacherUserId,
|
|
148
|
+
isHeadTeacher: true,
|
|
149
|
+
page: 1,
|
|
150
|
+
pageSize: 100,
|
|
151
|
+
})
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
115
155
|
对应方法为:
|
|
116
156
|
|
|
117
157
|
```ts
|
|
118
158
|
ctx.organization.schoolContact.relations.list(params)
|
|
159
|
+
ctx.organization.schoolContact.teachers.list(params)
|
|
119
160
|
ctx.organization.schoolContact.children.list(userId, params)
|
|
120
161
|
ctx.organization.schoolContact.guardians.list(userId, params)
|
|
121
162
|
ctx.organization.schoolContact.myFamily.get(params)
|
|
@@ -155,6 +196,24 @@ interface SchoolContactRelation {
|
|
|
155
196
|
}
|
|
156
197
|
```
|
|
157
198
|
|
|
199
|
+
老师班级成员的返回项为:
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
interface SchoolContactTeacherMembership {
|
|
203
|
+
membershipId: string
|
|
204
|
+
teacher: {
|
|
205
|
+
userId: string
|
|
206
|
+
dingtalkUserId: string
|
|
207
|
+
name: string
|
|
208
|
+
mobile: string | null
|
|
209
|
+
}
|
|
210
|
+
class: SchoolContactRelation["class"]
|
|
211
|
+
isHeadTeacher: boolean
|
|
212
|
+
syncedAt: string
|
|
213
|
+
syncState: "current" | "not_synced" | "disabled"
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
158
217
|
手机号可能为空。`sync.state=disabled` 表示管理员关闭了后续同步,现有数据仍保留但可能过期;业务页面在对时效敏感时应展示 `lastSuccessfulSyncAt`。
|
|
159
218
|
|
|
160
219
|
## 持久化边界
|
|
@@ -36,7 +36,7 @@ openxiangda workspace publish --profile <name> --page <pageCode>
|
|
|
36
36
|
- ✅ For external APIs use `src/resources/connectors/<code>.json` + `sdk.connector.invoke()`; for joined read-only lists use row data views + `sdk.dataView.query`; for stable dashboard metrics use aggregate data views + `sdk.dataView.stats`.
|
|
37
37
|
- ✅ Choose data view `storageMode` deliberately: `materialized` for refreshed reports/lists that tolerate delay, `live` for bounded real-time multi-form reads.
|
|
38
38
|
- ✅ For reusable backend orchestration use App Function (`src/functions/<functionCode>/index.ts` + `src/resources/functions/<functionCode>.json`) and call `sdk.function.invoke(code, { input })`; keep page components out of multi-table business orchestration.
|
|
39
|
-
- ✅
|
|
39
|
+
- ✅ 家长、学生、教师、班主任身份或班级/监护关系页面使用 `sdk.organization.schoolContact.*`;先读 `references/school-contact-relations.md`。用 `SCHOOL_HEAD_TEACHER` 判断全局身份,用 `teachers.list({ classId, isHeadTeacher: true })` 判断具体班主任班级;默认使用已登录用户的租户内全部关系,仅在业务要求时声明 self/class 收紧范围,并保持服务端分页。
|
|
40
40
|
- ✅ Filters, search bars, modal forms, drawers, and inline edits use platform components for platform data fields, otherwise `antd` / `antd-mobile` controls.
|
|
41
41
|
- ❌ Single-file giant pages. Split per `references/best-practices.md`.
|
|
42
42
|
- ❌ Hardcoded `/view/...&isRenderNav=false` URLs scattered through page code; use the runtime navigation helper.
|
|
@@ -132,7 +132,7 @@ Read these references only when editing page code:
|
|
|
132
132
|
- All visible page copy must be end-user-facing business text. Do not put developer explanations, implementation notes, schema descriptions, or "this module is generated by..." text into sections, cards, alerts, empty states, tooltips, or helper copy.
|
|
133
133
|
- Store live `pageId`, `routeKey`, and `legacyFormUuid` under the current profile only.
|
|
134
134
|
- Use `openxiangda/runtime` for platform data access instead of hardcoding backend URLs in page code.
|
|
135
|
-
- 家校关系必须通过 `sdk.organization.schoolContact` / `ctx.organization.schoolContact`
|
|
135
|
+
- 家校关系必须通过 `sdk.organization.schoolContact` / `ctx.organization.schoolContact` 读取;班主任班级使用 `teachers.list` 的 `isHeadTeacher`,不要用全局角色推断具体班级,也不要直连钉钉、查询系统表或用同班成员推断亲属关系。
|
|
136
136
|
- For reminders, alerts, and business messages, declare `src/resources/notifications/` first and call `sdk.notification`; do not hardcode notification API URLs.
|
|
137
137
|
- For backend business logic shared by pages, automations, or workflows, declare an App Function and call `sdk.function.invoke`; do not duplicate the same multi-form query/connector/notification orchestration in page code.
|
|
138
138
|
- Before hand-writing mature UI behavior, consult `references/component-guide.md` and use established libraries: platform components for platform data fields, antd/antd-mobile for controls and overlays, ECharts for charts, GSAP for complex animation timelines, and maintained packages such as dnd-kit for drag/drop. Do not rebuild mature controls with raw DOM/native inputs.
|