refactor: simplify product copy

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
This commit is contained in:
lofyer
2026-08-25 11:37:59 +08:00
co-authored by factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
parent 248078113c
commit b9fbd4c6af
22 changed files with 364 additions and 362 deletions
@@ -210,7 +210,7 @@
"maxLength": 100 "maxLength": 100
}, },
"uniqueItems": true, "uniqueItems": true,
"description": "基于技能词典提取并归一的技能标签。" "description": "使用技能词典提取并统一名称的技能标签。"
}, },
"keywords": { "keywords": {
"type": "array", "type": "array",
@@ -1,8 +1,8 @@
{ {
"$schema": "https://json-schema.org/draft/2020-12/schema", "$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://schemas.edu-industry.cn/school-employment/2.2.0/schema.json", "$id": "https://schemas.edu-industry.cn/school-employment/2.2.0/schema.json",
"title": "SCHOOL-EMPLOYMENT V2.2 校内就业事实", "title": "SCHOOL-EMPLOYMENT V2.2 校内就业数据",
"description": "职业院校毕业生就业事实统一契约,采用租户隔离和身份最小化设计。", "description": "职业院校毕业生就业数据契约,要求租户隔离,并将身份字段限制在业务必需的最少范围。",
"type": "object", "type": "object",
"additionalProperties": false, "additionalProperties": false,
"required": [ "required": [
@@ -1,8 +1,8 @@
{ {
"$schema": "https://json-schema.org/draft/2020-12/schema", "$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://schemas.edu-industry.cn/school-internship/2.1.0/schema.json", "$id": "https://schemas.edu-industry.cn/school-internship/2.1.0/schema.json",
"title": "SCHOOL-INTERNSHIP V2.1 校内实习事实", "title": "SCHOOL-INTERNSHIP V2.1 校内实习数据",
"description": "职业院校学生实习事实统一契约,采用租户隔离、身份最小化和证据引用设计。", "description": "职业院校学生实习数据契约,要求租户隔离,将身份字段限制在业务必需的最少范围,并引用评价记录。",
"type": "object", "type": "object",
"additionalProperties": false, "additionalProperties": false,
"required": [ "required": [
+9 -9
View File
@@ -44,7 +44,7 @@
| Data Query Service | 标准、源端、原始快照和隔离记录的分页检索、字段权限与证据追溯 | Lakehouse/OLAP + 检索引擎 | | Data Query Service | 标准、源端、原始快照和隔离记录的分页检索、字段权限与证据追溯 | Lakehouse/OLAP + 检索引擎 |
| Audit Service | 统一 trace_id、事件签名、证据和留存 | WORM/Object Lock | | Audit Service | 统一 trace_id、事件签名、证据和留存 | WORM/Object Lock |
| Operations Service | 告警、问题、工单、SLA、指派、处置时间线和通知待办 | PostgreSQL + 事件总线 | | Operations Service | 告警、问题、工单、SLA、指派、处置时间线和通知待办 | PostgreSQL + 事件总线 |
| Release Approval Service | 候选版本、质量门禁、职责分离审批、稳定别名发布与回滚 | PostgreSQL + 策略引擎 | | Release Approval Service | 候选版本、发布质量检查、职责分离审批、稳定别名发布与回滚 | PostgreSQL + 策略引擎 |
| Tenant Delivery Service | 逐租户发送状态、幂等重试、回执验签、记录数/SHA校验和单租户回滚 | PostgreSQL + 消息队列 | | Tenant Delivery Service | 逐租户发送状态、幂等重试、回执验签、记录数/SHA校验和单租户回滚 | PostgreSQL + 消息队列 |
## 3. 连接器 SPI ## 3. 连接器 SPI
@@ -62,13 +62,13 @@ parse(snapshot) 解析为来源 Schema
health() 返回入口可达性、延迟和错误分类 health() 返回入口可达性、延迟和错误分类
``` ```
参考实现位于 [`../crawler/`](../crawler/),逐来源接入方式和授权门禁见 [`../../docs/crawler-source-implementation.md`](../../docs/crawler-source-implementation.md)。连接器运行时必须遵守以下硬约束: 参考实现位于 [`../crawler/`](../crawler/),逐来源接入方式和启用条件见 [`../../docs/crawler-source-implementation.md`](../../docs/crawler-source-implementation.md)。连接器运行时必须遵守以下要求:
- 所有外部来源默认禁用,只有来源审批状态为 `approved` 才允许公网运行; - 所有外部来源默认禁用,只有来源审批状态为 `approved` 才允许公网运行;
- 商业平台仅接入官方合作 API 或授权数据包,不实现登录自动化、验证码处理、私有接口逆向和反自动化规避; - 商业平台仅接入官方合作 API 或授权数据包,不实现登录自动化、验证码处理、私有接口逆向和反自动化规避;
- 公开页面任务同时执行书面授权、robots.txt、域名 allowlist、公共地址解析和来源级限速检查; - 公开页面任务同时执行书面授权、robots.txt、域名 allowlist、公共地址解析和来源级限速检查;
- 重定向后的每个 URL 重新执行相同安全校验,禁止访问回环、内网、链路本地和云元数据地址; - 重定向后的每个 URL 重新执行相同安全校验,禁止访问回环、内网、链路本地和云元数据地址;
- User-Agent 必须标识本系统并提供真实技术联系邮箱,不伪装普通浏览器; - User-Agent 必须标识本系统并提供可联系的技术邮箱,不伪装普通浏览器;
- Authorization、Cookie 和签名密钥只从 Vault/KMS 引用注入,不写入任务、Raw、日志或异常; - Authorization、Cookie 和签名密钥只从 Vault/KMS 引用注入,不写入任务、Raw、日志或异常;
- 登录页、验证码、安全验证、访问封禁和结构变化均触发停止或隔离,不尝试绕过。 - 登录页、验证码、安全验证、访问封禁和结构变化均触发停止或隔离,不尝试绕过。
@@ -148,7 +148,7 @@ RUNNING → THROTTLED → RUNNING
- 来源状态和平台状态; - 来源状态和平台状态;
- 原始版本、解析版本、标准版本和数据产品版本。 - 原始版本、解析版本、标准版本和数据产品版本。
跨来源相似岗位不能直接删除,应形成岗位信号簇: 跨来源相似岗位不能直接删除,应归入同一个岗位信号组:
```text ```text
JobSignalCluster JobSignalCluster
@@ -197,7 +197,7 @@ JobSignalCluster
- 每个文件的 SHA-256; - 每个文件的 SHA-256;
- 租户范围、截止日期和上一稳定版本。 - 租户范围、截止日期和上一稳定版本。
### 候选、审批与租户交付闭环 ### 候选、审批与租户交付流程
Manifest 生成与发布必须是两个不同事务: Manifest 生成与发布必须是两个不同事务:
@@ -216,17 +216,17 @@ ISSUE / WORK_ORDER
→ ACKNOWLEDGED(record_count 与 SHA-256 同时通过) → ACKNOWLEDGED(record_count 与 SHA-256 同时通过)
``` ```
- `FIX_REPLAY`、`WAIVE`、`DISCARD` 必须记录原因、复核人、操作者、时间、trace_id 和证据;动作只追加,不可覆盖。只有 `FIX_REPLAY` 同时满足重放记录数一致、质量规则全量通过和独立复核签名时,才可写入 `VERIFIED` 并解除候选版本质量门禁。 - `FIX_REPLAY`、`WAIVE`、`DISCARD` 必须记录原因、复核人、操作者、时间、trace_id 和证据;动作只追加,不可覆盖。只有 `FIX_REPLAY` 同时满足重放记录数一致、质量规则全部通过和独立复核签名时,才可写入 `VERIFIED` 并允许候选版本继续提交。
- `WAIVE` 不等于质量验证通过,若产品允许风险放行,必须进入单独的风险豁免审批状态、风险接受人和到期时间;`DISCARD` 必须先验证丢弃范围、完整性阈值和候选差异并重建候选。两者不得复用普通 `VERIFIED/PASS`。 - `WAIVE` 不等于质量验证通过,若产品允许风险放行,必须进入单独的风险豁免审批状态、风险接受人和到期时间;`DISCARD` 必须先验证丢弃范围、完整性阈值和候选差异并重建候选。两者不得复用普通 `VERIFIED/PASS`。
- `PACKAGE-MANIFEST V1.2` 增加 `release_id` 与 `release_status`。每个租户数据文件必须携带自身记录数和 SHA-256,`tenant_scope`、文件路径和租户授权清单必须一致。 - `PACKAGE-MANIFEST V1.2` 增加 `release_id` 与 `release_status`。每个租户数据文件必须携带自身记录数和 SHA-256,`tenant_scope`、文件路径和租户授权清单必须一致。
- 候选 Manifest 的 `release_status` 必须为 `DRAFT`,并在提交审批时冻结;驳回后旧候选失效。发布事务生成 `PUBLISHED` Manifest,`approval_reference` 固定引用真实 `APPROVED` 审批单。 - 候选 Manifest 的 `release_status` 必须为 `DRAFT`,提交审批后不可修改;驳回后旧候选失效。发布事务生成 `PUBLISHED` Manifest,`approval_reference` 必须引用状态为 `APPROVED` 的审批单。
- 候选 Manifest 生成接口必须接受幂等键或服务端输入指纹;相同产品、租户、截止日期、格式、质量处置和交付摘要不得重复产生候选或审计事件。 - 候选 Manifest 生成接口必须接受幂等键或服务端输入指纹;相同产品、租户、截止日期、格式、质量处置和交付摘要不得重复产生候选或审计事件。
- 后端必须强制申请人与审批人不同,前端校验只能作为交互提示。批准后再以原子别名切换发布稳定版本。 - 后端必须强制申请人与审批人不同,前端校验只能作为交互提示。批准后再以原子别名切换发布稳定版本。
- 每个学校是独立交付状态机:`PENDING → SENDING → DELIVERED → ACKNOWLEDGED`;异常使用 `FAILED → RETRYING`,并支持单租户 `ROLLED_BACK`。成功租户的幂等键阻止重复发送。 - 每个学校是独立交付状态机:`PENDING → SENDING → DELIVERED → ACKNOWLEDGED`;异常使用 `FAILED → RETRYING`,并支持单租户 `ROLLED_BACK`。成功租户的幂等键阻止重复发送。
- 只有回执记录数等于包记录数、回执 SHA-256 等于 Manifest 文件摘要且回执签名有效时,服务端才能写入 `ACKNOWLEDGED`。 - 只有回执记录数等于包记录数、回执 SHA-256 等于 Manifest 文件摘要且回执签名有效时,服务端才能写入 `ACKNOWLEDGED`。
- 全局版本回滚和单租户回滚是不同操作。全局回滚必须先创建独立回滚审批,审批人与申请人分离,再执行稳定别名切换;两类回滚均需目标上一稳定版本、范围锁与不可变审计事件。 - 全局版本回滚和单租户回滚是不同操作。全局回滚必须先创建独立回滚审批,审批人与申请人分离,再执行稳定别名切换;两类回滚均需目标上一稳定版本、范围锁与不可变审计事件。
原型中的 `localStorage` 只用于静态演示刷新持久化,不能作为跨端协议或生产事实源。 原型中的 `localStorage` 只用于静态演示刷新后继续操作,不能作为跨端协议或正式数据来源。
## 9. 安全与运维 ## 9. 安全与运维
@@ -250,7 +250,7 @@ ISSUE / WORK_ORDER
- `POST /issues/{id}/acknowledge|assign|investigate|resolve|close` 与带版本条件的工单更新; - `POST /issues/{id}/acknowledge|assign|investigate|resolve|close` 与带版本条件的工单更新;
- `POST /quality-dispositions`、`POST /quality-dispositions/{id}/verify`,处置动作写不可变事件存储; - `POST /quality-dispositions`、`POST /quality-dispositions/{id}/verify`,处置动作写不可变事件存储;
- `POST /releases/{id}/manifest|submit|approve|reject|publish|rollback`,服务端执行质量门禁和职责分离; - `POST /releases/{id}/manifest|submit|approve|reject|publish|rollback`,服务端检查发布质量条件和职责分离;
- `POST /deliveries/{tenant_id}/send|retry|acknowledge|rollback`,执行租户授权、幂等、签名和回执校验; - `POST /deliveries/{tenant_id}/send|retry|acknowledge|rollback`,执行租户授权、幂等、签名和回执校验;
- `GET /notifications` 与统一审计事件查询/导出 API; - `GET /notifications` 与统一审计事件查询/导出 API;
- OAuth/OIDC、RBAC/ABAC、审批人实时身份、请求签名、幂等键、乐观锁、限流和 WORM 审计。 - OAuth/OIDC、RBAC/ABAC、审批人实时身份、请求签名、幂等键、乐观锁、限流和 WORM 审计。
+14 -14
View File
@@ -1,6 +1,6 @@
# 产教数据中台,厂商运营原型 # 产教数据中台,厂商运营原型
本目录用于讨论厂商侧招聘数据采集与治理产品。商业招聘平台、公共就业平台和校内系统统一作为正式数据来源纳入数据生产与治理体系。 本目录展示厂商如何管理招聘数据采集、检查、发布和学校交付。数据来源包括商业招聘平台、公共就业平台和校内系统。
## 运行 ## 运行
@@ -14,7 +14,7 @@ python3 -m http.server 8080
## 产品定位 ## 产品定位
这不是多个招聘网站爬虫脚本的简单集合,而是面向产教分析的数据生产控制面: 该页面用于管理产教分析所需的数据:
1. 注册和版本化管理商业、公共、校内三类数据源; 1. 注册和版本化管理商业、公共、校内三类数据源;
2. 调度采集任务,管理地域、行业、岗位族、分片、失败隔离和增量水位; 2. 调度采集任务,管理地域、行业、岗位族、分片、失败隔离和增量水位;
@@ -49,40 +49,40 @@ python3 -m http.server 8080
- **数据标准**:外部岗位、校内就业、交付 Manifest 三套版本化契约。 - **数据标准**:外部岗位、校内就业、交付 Manifest 三套版本化契约。
- **导入与导出**:文件拖放、CSV 头部预检、样例下载、Manifest 生成和记录导出。 - **导入与导出**:文件拖放、CSV 头部预检、样例下载、Manifest 生成和记录导出。
- **质量与归一**:质量规则、发布阈值、岗位别名人工确认和批量处理。 - **质量与归一**:质量规则、发布阈值、岗位别名人工确认和批量处理。
- **审计与交付**:采集、质量、发布、导入导出事件及证据链。 - **审计与交付**:采集、质量、发布、导入导出事件及相关记录。
## 原型黄金闭环 ## 可重复演示流程
“运营处置”提供一条可重复演示、刷新后保留的最小生产黄金路径: “运营处置”提供一条刷新后仍可继续的示例流程:
```text ```text
告警 → 确认 → 指派 → 开始排障 告警 → 确认 → 指派 → 开始排障
→ 修复并重放 → 记录数 / 规则 / 复核签名 VERIFIED → 修复并重放 → 记录数 / 规则 / 复核签名 VERIFIED
→ 豁免 / 丢弃 → REVIEWED_BLOCKED,继续阻断 → 豁免 / 丢弃 → REVIEWED_BLOCKED,继续阻断
→ REL-20260823-01 候选版本 → 生成并冻结候选 Manifest → 提交审批 → REL-20260823-01 候选版本 → 生成候选 Manifest → 提交后不可修改
→ 独立审批人批准 / 驳回 → 发布 → 独立审批人批准 / 驳回 → 发布
→ 逐学校发送状态 → 记录数 + SHA-256 回执 → 逐学校发送状态 → 记录数 + SHA-256 回执
→ ACKNOWLEDGED / 单校失败重试 / 单租户回滚 → ACKNOWLEDGED / 单校失败重试 / 单租户回滚
→ 全局回滚申请 → 独立回滚审批 → 执行稳定别名回滚 → 全局回滚申请 → 独立回滚审批 → 执行稳定别名回滚
``` ```
- 杭州人才网问题 `ISSUE-HZRC-20260823-01` 可完整流转。只有最后一次处置是 `FIX_REPLAY`,且重放记录数一致、质量规则通过、复核签名存在时,候选版本质量门禁才进入 `PASS`。 - 杭州人才网问题 `ISSUE-HZRC-20260823-01` 可走完上述流程。只有最后一次处置是 `FIX_REPLAY`,且重放记录数一致、质量规则通过、复核签名存在时,候选版本的发布质量检查才进入 `PASS`。
- `WAIVE` 与 `DISCARD` 的独立复核会写入 `REVIEWED_BLOCKED`,分别提示另行风险审批或重建候选,不会复用 `VERIFIED/PASS`。 - `WAIVE` 与 `DISCARD` 的独立复核会写入 `REVIEWED_BLOCKED`,分别提示另行风险审批或重建候选,不会复用 `VERIFIED/PASS`。
- 发布申请人默认为陈致远,审批人若选择同一人会被四眼规则阻止。 - 发布申请人默认为陈致远,审批人若选择同一人会被四眼规则阻止。
- 候选发布必须同时满足质量门禁和候选 Manifest 已生成;审批中 Manifest 冻结,驳回后返回草稿并使旧候选失效。 - 候选版本必须通过发布质量检查并生成 Manifest 后才能提交;审批期间 Manifest 不可修改,驳回后返回草稿并使旧候选失效。
- 候选 Manifest 使用输入指纹保证重复生成幂等;产品、租户、截止日期、格式、质量处置和交付摘要未变化时复用原候选,不重复写审计或交换日志。 - 候选 Manifest 使用输入指纹保证重复生成幂等;产品、租户、截止日期、格式、质量处置和交付摘要未变化时复用原候选,不重复写审计或交换日志。
- 候选版本、数据版本和包分别为 `REL-20260823-01`、`V2026.08.23`、`EDU-PKG-20260823-01`。 - 候选版本、数据版本和包分别为 `REL-20260823-01`、`V2026.08.23`、`EDU-PKG-20260823-01`。
- 杭州科技职业技术学院使用共享标识 `TENANT-HZVTC`。另外展示浙江机电职业技术大学和宁波城市职业技术学院,交付状态按租户隔离。 - 杭州科技职业技术学院使用共享标识 `TENANT-HZVTC`。另外展示浙江机电职业技术大学和宁波城市职业技术学院,交付状态按租户隔离。
- 原型仓库使用 `localStorage` 命名空间 `eduIndustry.vendorOperations.v1`,当前 `schemaVersion=2`,包含 issues、workOrders、qualityDispositions、releases、approvals、deliveries、auditEvents。页面提供“重置演示数据”恢复种子。 - 原型仓库使用 `localStorage` 命名空间 `eduIndustry.vendorOperations.v1`,当前 `schemaVersion=2`,包含 issues、workOrders、qualityDispositions、releases、approvals、deliveries、auditEvents。页面提供“重置演示数据”恢复种子。
- `PACKAGE-MANIFEST V1.2` 新增 `release_id` 和 `release_status`,并按三个租户输出彼此独立的记录数与 SHA-256 文件项。候选 Manifest 保持 `DRAFT`,正式发布时生成 `PUBLISHED` Manifest,`approval_reference` 固定引用 `APPROVED` 审批单。 - `PACKAGE-MANIFEST V1.2` 新增 `release_id` 和 `release_status`,并按三个租户输出彼此独立的记录数与 SHA-256 文件项。候选 Manifest 保持 `DRAFT`,正式发布时生成 `PUBLISHED` Manifest,`approval_reference` 固定引用 `APPROVED` 审批单。
- 全局回滚和单租户回滚严格分离。全局回滚必须填写原因、由不同于申请人的审批人批准后才可执行,审计证据保存目标稳定版本、审批引用和影响范围锁。 - 全局回滚和单租户回滚分开办理。全局回滚必须填写原因,并由另一名审批人批准后才可执行;审计记录保存目标稳定版本、审批引用和执行时确定的影响范围,执行过程中不得扩大范围。
- 静态演示的审计、质量处置、问题时间线和交换日志采用明确保留上限;正式系统必须使用服务端分页、归档和 WORM 审计。 - 静态演示的审计、质量处置、问题时间线和交换日志采用明确保留上限;正式系统必须使用服务端分页、归档和 WORM 审计。
## 静态跨端边界 ## 静态跨端边界
本目录是**厂商端静态 SPA 原型**,与仓库根目录下的校园端 `/demo/` 没有运行时连接。双方仅通过约定标识(`TENANT-HZVTC`、`EDU-PKG-20260823-01`、`V2026.08.23`)对照展示,不共享浏览器存储,也不通过静态页面传输数据。 本目录是**厂商端静态 SPA 原型**,与仓库根目录下的校园端 `/demo/` 没有运行时连接。双方仅通过约定标识(`TENANT-HZVTC`、`EDU-PKG-20260823-01`、`V2026.08.23`)对照展示,不共享浏览器存储,也不通过静态页面传输数据。
按钮中的发送、回执、重试与回滚均为本地状态机模拟:不会访问学校接口、不会写入校园端、不会发送真实数据。正式跨端同步必须由经过鉴权、签名、幂等和审计控制的服务端 API 执行。 按钮中的发送、回执、重试与回滚均为本地状态机模拟:不会访问学校接口、不会写入校园端,也不会发送数据。正式跨端同步必须由服务端 API 完成身份校验、签名、重复请求处理和操作记录。
## 标准文件 ## 标准文件
@@ -91,10 +91,10 @@ python3 -m http.server 8080
- 商业和公共招聘平台的统一岗位信号契约 - 商业和公共招聘平台的统一岗位信号契约
- `schemas/school-employment.schema.json` - `schemas/school-employment.schema.json`
- `SCHOOL-EMPLOYMENT V2.2` - `SCHOOL-EMPLOYMENT V2.2`
- 校内就业事实契约,包含租户隔离和学生令牌化要求 - 校内就业数据契约,包含租户隔离和学生令牌化要求
- `schemas/school-internship.schema.json` - `schemas/school-internship.schema.json`
- `SCHOOL-INTERNSHIP V2.1` - `SCHOOL-INTERNSHIP V2.1`
- 校内实习事实契约,包含租户隔离、学生令牌化、岗位任务和评价证据 - 校内实习数据契约,包含租户隔离、学生令牌化、岗位任务和评价记录
- `schemas/package-manifest.schema.json` - `schemas/package-manifest.schema.json`
- `PACKAGE-MANIFEST V1.2` - `PACKAGE-MANIFEST V1.2`
- 版本化导入、导出和学校交付包清单 - 版本化导入、导出和学校交付包清单
@@ -124,11 +124,11 @@ python3 -m http.server 8080
- 移动:`390 × 844` - 移动:`390 × 844`
- 可见业务文字不小于 13px - 可见业务文字不小于 13px
- 页面级无横向溢出,宽表仅在自身容器内横向滚动 - 页面级无横向溢出,宽表仅在自身容器内横向滚动
- 所有深层按钮必须打开业务内容或形成列表状态变化 - 所有深层按钮必须打开业务内容或改变列表状态
- JavaScript 语法检查:`node --check app.js` - JavaScript 语法检查:`node --check app.js`
- JSON 文件检查:`python3 -m json.tool <file>` - JSON 文件检查:`python3 -m json.tool <file>`
新增闭环预览: 运营流程预览:
- `preview-admin-operations.png` - `preview-admin-operations.png`
- `preview-admin-operations-mobile.png` - `preview-admin-operations-mobile.png`
+50 -50
View File
@@ -738,7 +738,7 @@ const contracts = {
key: "JOB-SIGNAL", key: "JOB-SIGNAL",
title: "外部招聘岗位信号标准", title: "外部招聘岗位信号标准",
version: "V3.0.0", version: "V3.0.0",
description: "统一商业招聘平台、公共就业平台和活动聚合平台的岗位、企业、薪资、技能与来源证据,用于产教供需分析。", description: "规定商业招聘平台、公共就业平台和招聘活动数据中的岗位、企业、薪资、技能与来源字段,供产教分析使用。",
schemaPath: "./schemas/external-job-source.schema.json", schemaPath: "./schemas/external-job-source.schema.json",
fields: 39, fields: 39,
required: 19, required: 19,
@@ -748,7 +748,7 @@ const contracts = {
compatibility: "向后兼容 V2.6", compatibility: "向后兼容 V2.6",
fieldsPreview: [ fieldsPreview: [
["record_id", "string/uuid", "是", "平台记录唯一标识", "UUID v4"], ["record_id", "string/uuid", "是", "平台记录唯一标识", "UUID v4"],
["source_platform", "string", "是", "来源平台代码", "受控代码表"], ["source_platform", "string", "是", "来源平台代码", "固定代码表"],
["source_record_id", "string", "是", "来源记录标识", "同平台唯一"], ["source_record_id", "string", "是", "来源记录标识", "同平台唯一"],
["source_url", "string/uri", "是", "来源页面或接口定位", "http/https"], ["source_url", "string/uri", "是", "来源页面或接口定位", "http/https"],
["collected_at", "datetime", "是", "实际采集时间", "ISO-8601 +08:00"], ["collected_at", "datetime", "是", "实际采集时间", "ISO-8601 +08:00"],
@@ -767,14 +767,14 @@ const contracts = {
["来源证据", "必须保留 source_url、collected_at、content_hash 和采集任务编号。"], ["来源证据", "必须保留 source_url、collected_at、content_hash 和采集任务编号。"],
["薪资口径", "统一折算为税前月薪;面议、日薪、时薪保留原文并标注换算状态。"], ["薪资口径", "统一折算为税前月薪;面议、日薪、时薪保留原文并标注换算状态。"],
["时效与失效", "岗位状态和最后发现时间分开记录;失效采用版本化软删除。"], ["时效与失效", "岗位状态和最后发现时间分开记录;失效采用版本化软删除。"],
["文本治理", "岗位职责原文进入原始层,分析层只保留去标记、去联系方式后的业务文本。"], ["文本处理", "岗位职责原文保存在原始层,分析层只保留去标记、去联系方式后的业务文本。"],
], ],
}, },
"school-employment": { "school-employment": {
key: "SCHOOL-EMPLOYMENT", key: "SCHOOL-EMPLOYMENT",
title: "校内就业事实数据标准", title: "校内就业数据标准",
version: "V2.2.0", version: "V2.2.0",
description: "统一学校毕业生就业状态、岗位、企业、薪资、专业相关度和去向确认事实,支持租户隔离和敏感字段最小化。", description: "规定学校毕业生就业状态、岗位、企业、薪资、专业相关度和去向确认字段,并要求租户隔离,只保留业务必需的敏感字段。",
schemaPath: "./schemas/school-employment.schema.json", schemaPath: "./schemas/school-employment.schema.json",
fields: 32, fields: 32,
required: 16, required: 16,
@@ -787,7 +787,7 @@ const contracts = {
["student_token", "string", "是", "学生不可逆令牌", "禁止明文学号"], ["student_token", "string", "是", "学生不可逆令牌", "禁止明文学号"],
["cohort", "integer", "是", "毕业届次", "YYYY"], ["cohort", "integer", "是", "毕业届次", "YYYY"],
["program_code", "string", "是", "专业代码", "教育部专业目录"], ["program_code", "string", "是", "专业代码", "教育部专业目录"],
["employment_status", "string", "是", "就业状态", "受控枚举"], ["employment_status", "string", "是", "就业状态", "固定选项"],
["job_title", "string", "否", "就业岗位", "业务原文"], ["job_title", "string", "否", "就业岗位", "业务原文"],
["enterprise_token", "string", "否", "企业统一标识", "信用代码令牌化"], ["enterprise_token", "string", "否", "企业统一标识", "信用代码令牌化"],
["salary_monthly", "number", "否", "税前月薪", "元/月"], ["salary_monthly", "number", "否", "税前月薪", "元/月"],
@@ -806,9 +806,9 @@ const contracts = {
}, },
"school-internship": { "school-internship": {
key: "SCHOOL-INTERNSHIP", key: "SCHOOL-INTERNSHIP",
title: "校内实习事实数据标准", title: "校内实习数据标准",
version: "V2.1.0", version: "V2.1.0",
description: "统一学生实习岗位、企业、起止日期、状态、工资、岗位任务和评价事实,支持租户隔离和敏感身份最小化。", description: "规定学生实习岗位、企业、起止日期、状态、工资、岗位任务和评价字段,并要求租户隔离,只保留业务必需的身份字段。",
schemaPath: "./schemas/school-internship.schema.json", schemaPath: "./schemas/school-internship.schema.json",
fields: 30, fields: 30,
required: 14, required: 14,
@@ -826,7 +826,7 @@ const contracts = {
["job_tasks", "array<string>", "否", "实习岗位任务", "学校确认"], ["job_tasks", "array<string>", "否", "实习岗位任务", "学校确认"],
["start_date", "date", "是", "开始日期", "YYYY-MM-DD"], ["start_date", "date", "是", "开始日期", "YYYY-MM-DD"],
["end_date", "date", "否", "结束日期", "YYYY-MM-DD"], ["end_date", "date", "否", "结束日期", "YYYY-MM-DD"],
["status", "string", "是", "实习状态", "受控枚举"], ["status", "string", "是", "实习状态", "固定选项"],
["salary_monthly", "number", "否", "税前月实习工资", "元/月"], ["salary_monthly", "number", "否", "税前月实习工资", "元/月"],
["evidence_reference", "string", "否", "校内证据引用", "不传附件"], ["evidence_reference", "string", "否", "校内证据引用", "不传附件"],
["source_updated_at", "datetime", "否", "业务更新时间", "增量水位"], ["source_updated_at", "datetime", "否", "业务更新时间", "增量水位"],
@@ -837,7 +837,7 @@ const contracts = {
["身份最小化", "平台只接收 student_token,拒绝姓名、身份证、手机号、邮箱和明文学号。"], ["身份最小化", "平台只接收 student_token,拒绝姓名、身份证、手机号、邮箱和明文学号。"],
["企业要求", "进行中或已完成实习必须提供企业令牌或企业名称。"], ["企业要求", "进行中或已完成实习必须提供企业令牌或企业名称。"],
["证据引用", "敏感附件保留在学校系统,平台只保存 evidence_reference。"], ["证据引用", "敏感附件保留在学校系统,平台只保存 evidence_reference。"],
["增量幂等", "tenant_id + source_record_id + source_updated_at 形成增量与幂等边界。"], ["增量重复处理", "使用 tenant_id + source_record_id + source_updated_at 判断增量更新,并确保重复提交不会重复写入。"],
], ],
}, },
"package-manifest": { "package-manifest": {
@@ -1381,7 +1381,7 @@ const operationsStatusLabels = {
INVESTIGATING: "排障中", INVESTIGATING: "排障中",
QUALITY_REVIEW_PENDING: "待质量复核", QUALITY_REVIEW_PENDING: "待质量复核",
VERIFIED: "复核通过", VERIFIED: "复核通过",
REVIEWED_BLOCKED: "复核后仍阻断", REVIEWED_BLOCKED: "复核后仍不能发布",
RESOLVED: "已解决", RESOLVED: "已解决",
CLOSED: "已关闭", CLOSED: "已关闭",
OPEN: "已建单", OPEN: "已建单",
@@ -1401,7 +1401,7 @@ const operationsStatusLabels = {
PENDING_REVIEW: "待复核", PENDING_REVIEW: "待复核",
RECORDED: "已记录", RECORDED: "已记录",
PASS: "通过", PASS: "通过",
BLOCKED: "阻断", BLOCKED: "不能继续",
ROLLBACK_PENDING_APPROVAL: "回滚待审批", ROLLBACK_PENDING_APPROVAL: "回滚待审批",
ROLLBACK_APPROVED: "回滚已批准", ROLLBACK_APPROVED: "回滚已批准",
ROLLBACK_REJECTED: "回滚已驳回", ROLLBACK_REJECTED: "回滚已驳回",
@@ -1537,7 +1537,7 @@ function renderOperationsMetrics() {
const deliveryAttention = operationsStore.deliveries.filter((delivery) => ["PENDING", "SENDING", "FAILED", "RETRYING"].includes(delivery.status)).length; const deliveryAttention = operationsStore.deliveries.filter((delivery) => ["PENDING", "SENDING", "FAILED", "RETRYING"].includes(delivery.status)).length;
const acknowledged = operationsStore.deliveries.filter((delivery) => delivery.status === "ACKNOWLEDGED").length; const acknowledged = operationsStore.deliveries.filter((delivery) => delivery.status === "ACKNOWLEDGED").length;
document.getElementById("operationsMetrics").innerHTML = ` document.getElementById("operationsMetrics").innerHTML = `
<article><span>未闭环问题</span><strong>${openIssues}</strong><small>确认、指派、排障与质量处置</small></article> <article><span>未处理完问题</span><strong>${openIssues}</strong><small>确认、指派、排障与质量处置</small></article>
<article><span>审批待办</span><strong>${pendingApprovals}</strong><small>申请人与审批人强制分离</small></article> <article><span>审批待办</span><strong>${pendingApprovals}</strong><small>申请人与审批人强制分离</small></article>
<article><span>交付待办 / 异常</span><strong>${deliveryAttention}</strong><small>按租户隔离,不重复发送成功学校</small></article> <article><span>交付待办 / 异常</span><strong>${deliveryAttention}</strong><small>按租户隔离,不重复发送成功学校</small></article>
<article><span>已核验回执</span><strong>${acknowledged}</strong><small>记录数与 SHA-256 均一致</small></article> <article><span>已核验回执</span><strong>${acknowledged}</strong><small>记录数与 SHA-256 均一致</small></article>
@@ -1552,8 +1552,8 @@ function renderOperationsMetrics() {
const qualityDetail = document.getElementById("qualityReleaseDetail"); const qualityDetail = document.getElementById("qualityReleaseDetail");
if (overviewState) overviewState.textContent = release?.status === "PUBLISHED" ? "稳定版本已发布" : releaseReady ? "候选可提交审批" : "候选发布受阻"; if (overviewState) overviewState.textContent = release?.status === "PUBLISHED" ? "稳定版本已发布" : releaseReady ? "候选可提交审批" : "候选发布受阻";
if (overviewDetail) overviewDetail.textContent = release?.qualityGate === "PASS" ? (release?.manifestGeneratedAt ? "质量与候选 Manifest 已就绪" : "质量通过,待生成候选 Manifest") : "杭州人才网修复重放尚未验证"; if (overviewDetail) overviewDetail.textContent = release?.qualityGate === "PASS" ? (release?.manifestGeneratedAt ? "质量与候选 Manifest 已就绪" : "质量通过,待生成候选 Manifest") : "杭州人才网修复重放尚未验证";
if (qualityState) qualityState.textContent = release?.qualityGate === "PASS" ? "当前批次质量门禁已通过" : "当前批次仍需修复重放复核"; if (qualityState) qualityState.textContent = release?.qualityGate === "PASS" ? "当前批次已满足发布质量要求" : "当前批次仍需修复重放复核";
if (qualityDetail) qualityDetail.textContent = release?.qualityGate === "PASS" ? "质量证据已通过独立复核,可继续生成候选包" : "质量分达标不等于门禁通过,稳定版本继续保持不变"; if (qualityDetail) qualityDetail.textContent = release?.qualityGate === "PASS" ? "质量记录已经另一名复核人确认,可继续生成候选包" : "仅质量分达标还不能发布,当前稳定版本保持不变";
} }
function renderOverviewIssues() { function renderOverviewIssues() {
@@ -1571,7 +1571,7 @@ function renderOverviewIssues() {
`, `,
) )
.join("") .join("")
: `<div class="info-note">当前没有待处理问题,所有事项均已闭环。</div>`; : `<div class="info-note">当前没有待处理问题。</div>`;
const countBadge = list.closest(".alert-panel").querySelector(".panel-head > em"); const countBadge = list.closest(".alert-panel").querySelector(".panel-head > em");
countBadge.textContent = `${issues.length} 项`; countBadge.textContent = `${issues.length} 项`;
} }
@@ -1595,7 +1595,7 @@ function renderOperationsIssues() {
.join(""); .join("");
document.getElementById("operationsIssueTable").innerHTML = rows; document.getElementById("operationsIssueTable").innerHTML = rows;
const openCount = operationsStore.issues.filter((issue) => !["RESOLVED", "CLOSED"].includes(issue.status)).length; const openCount = operationsStore.issues.filter((issue) => !["RESOLVED", "CLOSED"].includes(issue.status)).length;
document.getElementById("issueQueueSummary").textContent = `${openCount} 项未闭环 · 状态刷新后保留`; document.getElementById("issueQueueSummary").textContent = `${openCount} 项未处理完 · 状态刷新后保留`;
} }
function releaseNextAction(release, approval) { function releaseNextAction(release, approval) {
@@ -1606,7 +1606,7 @@ function releaseNextAction(release, approval) {
if (release.status === "PENDING_APPROVAL") { if (release.status === "PENDING_APPROVAL") {
return ` return `
<label class="approval-field"><span>独立审批人</span><select id="releaseApprover"><option value="林若溪">林若溪 · 数据产品负责人</option><option value="王海宁">王海宁 · 发布审批人</option><option value="陈致远">陈致远 · 当前申请人</option></select></label> <label class="approval-field"><span>独立审批人</span><select id="releaseApprover"><option value="林若溪">林若溪 · 数据产品负责人</option><option value="王海宁">王海宁 · 发布审批人</option><option value="陈致远">陈致远 · 当前申请人</option></select></label>
<label class="approval-field approval-comment"><span>审批意见</span><input id="approvalComment" value="质量门禁与租户范围已复核" /></label> <label class="approval-field approval-comment"><span>审批意见</span><input id="approvalComment" value="质量检查结果与租户范围已复核" /></label>
<button class="button secondary" data-release-reject>驳回</button> <button class="button secondary" data-release-reject>驳回</button>
<button class="button primary" data-release-approve>批准</button> <button class="button primary" data-release-approve>批准</button>
`; `;
@@ -1654,7 +1654,7 @@ function renderReleaseWorkspace() {
<span><small>上一稳定版本</small><strong>${h(release.previousStableVersion)}</strong></span> <span><small>上一稳定版本</small><strong>${h(release.previousStableVersion)}</strong></span>
</div> </div>
<div class="release-facts"> <div class="release-facts">
<span><small>质量门禁</small><strong class="${release.qualityGate === "PASS" ? "gate-pass" : "gate-blocked"}">${h(operationStatusLabel(release.qualityGate))} · ${release.qualityScore}</strong></span> <span><small>发布质量检查</small><strong class="${release.qualityGate === "PASS" ? "gate-pass" : "gate-blocked"}">${h(operationStatusLabel(release.qualityGate))} · ${release.qualityScore}</strong></span>
<span><small>影响租户</small><strong>${release.impactTenants.length} 所学校</strong></span> <span><small>影响租户</small><strong>${release.impactTenants.length} 所学校</strong></span>
<span><small>申请人</small><strong>${h(release.applicant)}</strong></span> <span><small>申请人</small><strong>${h(release.applicant)}</strong></span>
<span><small>Manifest</small><strong>${release.publishedManifestGeneratedAt ? `发布版已生成 · ${h(operationTime(release.publishedManifestGeneratedAt))}` : release.manifestGeneratedAt ? `候选已生成 · ${h(operationTime(release.manifestGeneratedAt))}` : "尚未生成"}</strong></span> <span><small>Manifest</small><strong>${release.publishedManifestGeneratedAt ? `发布版已生成 · ${h(operationTime(release.publishedManifestGeneratedAt))}` : release.manifestGeneratedAt ? `候选已生成 · ${h(operationTime(release.manifestGeneratedAt))}` : "尚未生成"}</strong></span>
@@ -1662,11 +1662,11 @@ function renderReleaseWorkspace() {
<div class="release-quality-note ${release.qualityGate === "PASS" ? "passed" : ""}"> <div class="release-quality-note ${release.qualityGate === "PASS" ? "passed" : ""}">
${ ${
release.status === "PUBLISHED" release.status === "PUBLISHED"
? "质量证据、候选 Manifest 与独立审批已冻结,正式发布 Manifest 已生成;当前尚未代表学校接收。" ? "发布使用的质量记录、候选 Manifest 和审批结果均不可修改,正式发布 Manifest 已生成;这不表示学校已经接收。"
: release.status === "ROLLED_BACK" : release.status === "ROLLED_BACK"
? `稳定别名已回滚到 ${h(release.previousStableVersion)},原发布、审批和租户交付记录继续保留审计。` ? `稳定别名已回滚到 ${h(release.previousStableVersion)},原发布、审批和租户交付记录继续保留审计。`
: release.status === "PENDING_APPROVAL" : release.status === "PENDING_APPROVAL"
? "候选 Manifest 已冻结,正在等待不同于申请人的独立审批人处理。" ? "候选 Manifest 已提交,审批完成前不能修改,正在等待另一名审批人处理。"
: release.status === "APPROVED" : release.status === "APPROVED"
? "独立审批已通过,可以执行稳定别名切换并生成正式发布 Manifest。" ? "独立审批已通过,可以执行稳定别名切换并生成正式发布 Manifest。"
: release.status === "REJECTED" : release.status === "REJECTED"
@@ -1675,7 +1675,7 @@ function renderReleaseWorkspace() {
? release.manifestGeneratedAt ? release.manifestGeneratedAt
? "修复重放证据与候选 Manifest 已就绪,可以提交独立发布审批。" ? "修复重放证据与候选 Manifest 已就绪,可以提交独立发布审批。"
: "修复重放已由独立复核人验证;还必须生成候选 Manifest 后才能提交审批。" : "修复重放已由独立复核人验证;还必须生成候选 Manifest 后才能提交审批。"
: "质量门禁阻断:只有 FIX_REPLAY 的记录数、规则结果与复核签名全部验证通过才能解锁;豁免或丢弃均保持阻断。" : "当前不能发布:只有 FIX_REPLAY 的记录数、规则结果和复核签名全部通过检查才可继续;豁免或丢弃仍不能发布。"
} }
</div> </div>
<div class="candidate-actions"> <div class="candidate-actions">
@@ -1684,9 +1684,9 @@ function renderReleaseWorkspace() {
? `<button class="button secondary" data-release-official-manifest>下载发布 Manifest</button>` ? `<button class="button secondary" data-release-official-manifest>下载发布 Manifest</button>`
: release.status === "DRAFT" : release.status === "DRAFT"
? `<button class="button secondary" data-release-manifest ${release.qualityGate === "PASS" ? "" : "disabled"}>${release.qualityGate === "PASS" ? (release.manifestGeneratedAt ? "重新生成候选 Manifest" : "生成候选包 / Manifest") : "质量通过后生成 Manifest"}</button>` ? `<button class="button secondary" data-release-manifest ${release.qualityGate === "PASS" ? "" : "disabled"}>${release.qualityGate === "PASS" ? (release.manifestGeneratedAt ? "重新生成候选 Manifest" : "生成候选包 / Manifest") : "质量通过后生成 Manifest"}</button>`
: `<span class="release-final-note">候选 Manifest 已冻结,审批中不可重建。</span>` : `<span class="release-final-note">候选 Manifest 已提交,审批中不能重建。</span>`
} }
<button class="text-button" data-open-issue="ISSUE-HZRC-20260823-01">查看阻断问题</button> <button class="text-button" data-open-issue="ISSUE-HZRC-20260823-01">查看未解决问题</button>
</div> </div>
</article> </article>
<article class="panel approval-card"> <article class="panel approval-card">
@@ -1771,7 +1771,7 @@ function issueActionFooter(issue) {
const qualityReviewAction = const qualityReviewAction =
disposition?.action === "FIX_REPLAY" disposition?.action === "FIX_REPLAY"
? `<button class="button primary" data-issue-action="verify">验证重放并通过</button>` ? `<button class="button primary" data-issue-action="verify">验证重放并通过</button>`
: `<button class="button primary" data-issue-action="verify-blocked">完成复核并保持阻断</button>`; : `<button class="button primary" data-issue-action="verify-blocked">完成复核,仍不允许发布</button>`;
const actions = { const actions = {
ALERTED: `<button class="button primary" data-issue-action="acknowledge">确认告警</button>`, ALERTED: `<button class="button primary" data-issue-action="acknowledge">确认告警</button>`,
ACKNOWLEDGED: `<label class="footer-field"><span>指派负责人</span><select id="issueAssignee"><option>周敏 · 区域源运维</option><option>赵亦辰 · 采集工程师</option><option>数据标准组</option></select></label><button class="button primary" data-issue-action="assign">确认指派</button>`, ACKNOWLEDGED: `<label class="footer-field"><span>指派负责人</span><select id="issueAssignee"><option>周敏 · 区域源运维</option><option>赵亦辰 · 采集工程师</option><option>数据标准组</option></select></label><button class="button primary" data-issue-action="assign">确认指派</button>`,
@@ -1782,7 +1782,7 @@ function issueActionFooter(issue) {
QUALITY_REVIEW_PENDING: qualityReviewAction, QUALITY_REVIEW_PENDING: qualityReviewAction,
VERIFIED: `<button class="button primary" data-issue-action="resolve">标记已解决</button>`, VERIFIED: `<button class="button primary" data-issue-action="resolve">标记已解决</button>`,
RESOLVED: `<button class="button primary" data-issue-action="close">关闭问题</button>`, RESOLVED: `<button class="button primary" data-issue-action="close">关闭问题</button>`,
CLOSED: `<span class="release-final-note">问题已闭环,所有动作与证据已保留。</span>`, CLOSED: `<span class="release-final-note">问题已完成处理,操作记录和附件已保留。</span>`,
}; };
return `<button class="button secondary" data-issue-close>关闭抽屉</button>${actions[issue.status] || ""}`; return `<button class="button secondary" data-issue-close>关闭抽屉</button>${actions[issue.status] || ""}`;
} }
@@ -2063,7 +2063,7 @@ function renderSourceMapping(source) {
</article> </article>
<article class="drawer-card"> <article class="drawer-card">
<h3>样本回归</h3> <h3>样本回归</h3>
<p>最近回归样本 1,000 条,结构通过率 100%,必填完整率 98.8%,岗位归一覆盖率 96.4%。未匹配岗位进入人工复核队列,不以模型推断覆盖原始事实。</p> <p>最近回归样本 1,000 条,结构通过率 100%,必填完整率 98.8%,岗位归一覆盖率 96.4%。未匹配岗位进入人工复核队列,不用模型推断替换原始记录。</p>
</article> </article>
`; `;
} }
@@ -2103,7 +2103,7 @@ function renderSourceAudit(source) {
</article> </article>
<article class="drawer-card"> <article class="drawer-card">
<h3>数据使用边界</h3> <h3>数据使用边界</h3>
<p>平台只向产教分析产品交付经契约治理的岗位信号、企业画像和统计结果。原始层与交付层分区存储,租户交付范围由 Manifest 和平台数据范围策略共同控制。</p> <p>平台只向产教分析产品交付符合数据契约的岗位信息、企业信息和统计结果。原始数据与交付数据分开存储,Manifest 和租户授权共同决定每所学校可收到的数据。</p>
</article> </article>
`; `;
} }
@@ -2461,7 +2461,7 @@ function openStandardRecord(recordId) {
</dl> </dl>
</article> </article>
<article class="drawer-card"> <article class="drawer-card">
<h3>全链路证据</h3> <h3>来源与处理记录</h3>
<div class="record-lineage"> <div class="record-lineage">
<span><b>01</b><span><strong>采集任务</strong><small>${h(record.taskId)} · ${h(record.collectorVersion)}</small></span></span> <span><b>01</b><span><strong>采集任务</strong><small>${h(record.taskId)} · ${h(record.collectorVersion)}</small></span></span>
<span><b>02</b><span><strong>原始快照</strong><small>${h(record.snapshotId)} · payload SHA-256 ${h(record.payloadHash)}</small></span></span> <span><b>02</b><span><strong>原始快照</strong><small>${h(record.snapshotId)} · payload SHA-256 ${h(record.payloadHash)}</small></span></span>
@@ -2843,8 +2843,8 @@ function buildPackageManifest(options = {}) {
generated_by: "陈致远", generated_by: "陈致远",
approval_reference: approval ? `${approval.id}:${approvalStatus}` : null, approval_reference: approval ? `${approval.id}:${approvalStatus}` : null,
notes: published notes: published
? "该文件是独立审批通过后生成的发布 Manifest;静态原型只记录本地稳定版本状态,不会向学校真实发送。" ? "该文件是独立审批通过后生成的发布 Manifest;静态原型只记录本地稳定版本状态,不会向学校发送。"
: "该文件仅为候选包 Manifest;只有独立审批通过并执行发布后才成为稳定版本,静态原型不会向学校真实发送。", : "该文件仅为候选包 Manifest;只有独立审批通过并执行发布后才成为稳定版本,静态原型不会向学校发送。",
}; };
} }
@@ -2852,11 +2852,11 @@ function generateCandidateManifest() {
const release = currentRelease(); const release = currentRelease();
updateReleaseQualityGate(); updateReleaseQualityGate();
if (!release || release.status !== "DRAFT") { if (!release || release.status !== "DRAFT") {
showToast("候选已进入审批或发布流程,Manifest 已冻结;驳回后需返回草稿重建", "无法重建候选 Manifest"); showToast("候选已提交审批或发布,当前 Manifest 不能修改;驳回后可返回草稿重建", "无法重建候选 Manifest");
return; return;
} }
if (release.qualityGate !== "PASS") { if (release.qualityGate !== "PASS") {
showToast("只有 FIX_REPLAY 的完整验证证据通过后才能生成候选 Manifest", "质量门禁阻断"); showToast("只有 FIX_REPLAY 的记录数、规则结果和复核签名全部通过检查后,才能生成候选 Manifest", "当前不能生成候选");
return; return;
} }
const inputFingerprint = candidateManifestInputFingerprint(); const inputFingerprint = candidateManifestInputFingerprint();
@@ -3428,7 +3428,7 @@ function setupAudit() {
openInfoModal( openInfoModal(
"AUDIT POLICY", "AUDIT POLICY",
"生产审计与留存策略", "生产审计与留存策略",
`<div class="info-grid"><span>关键事件留存<strong>36个月</strong></span><span>审计存储<strong>WORM</strong></span><span>每日完整性校验<strong>SHA-256</strong></span><span>追踪覆盖率<strong>100%</strong></span></div><div class="info-note">采集请求、连接器版本、原始快照、映射规则、质量结果、审批和租户交付都写入统一 trace_id。敏感配置只记录密钥引用和变更摘要,不在日志中保存明文凭据。</div>`, `<div class="info-grid"><span>关键事件留存<strong>36个月</strong></span><span>审计存储<strong>WORM</strong></span><span>每日完整性校验<strong>SHA-256</strong></span><span>追踪覆盖率<strong>100%</strong></span></div><div class="info-note">采集请求、连接器版本、原始快照、映射规则、质量结果、审批和租户交付都使用同一个 trace_id。敏感配置只记录密钥引用和变更摘要,不在日志中保存明文凭据。</div>`,
); );
}); });
} }
@@ -3482,7 +3482,7 @@ function setupOperations() {
return; return;
} }
if (action === "investigate" && issue.status === "ASSIGNED") { if (action === "investigate" && issue.status === "ASSIGNED") {
transitionIssue(issue, "INVESTIGATING", "已锁定源端时延与解析隔离记录,开始执行排障。", ["排障工作区快照", issue.relatedTask]); transitionIssue(issue, "INVESTIGATING", "已确认问题来自源端延迟,并找到对应的解析隔离记录,开始排障。", ["排障工作区快照", issue.relatedTask]);
return; return;
} }
if (action === "submit-quality" && issue.status === "INVESTIGATING") { if (action === "submit-quality" && issue.status === "INVESTIGATING") {
@@ -3548,7 +3548,7 @@ function setupOperations() {
renderOperations(); renderOperations();
renderAudit(); renderAudit();
openIssueDrawer(issue.id); openIssueDrawer(issue.id);
showToast("处置动作已固化并写入审计,等待独立质量复核", "质量处置已提交"); showToast("处置动作已保存且不能修改,等待另一名质量复核人处理", "质量处置已提交");
return; return;
} }
if (action === "verify-blocked" && issue.status === "QUALITY_REVIEW_PENDING") { if (action === "verify-blocked" && issue.status === "QUALITY_REVIEW_PENDING") {
@@ -3574,8 +3574,8 @@ function setupOperations() {
evidence: [...metadata.evidence], evidence: [...metadata.evidence],
note: note:
disposition.action === "WAIVE" disposition.action === "WAIVE"
? "风险豁免不等同于质量验证通过;候选门禁保持阻断,必须另行提交风险审批。" ? "风险豁免不等同于质量验证通过;候选版本仍不能发布,必须另行提交风险审批。"
: "丢弃可能改变数据完整性;候选门禁保持阻断,必须重建候选并重新执行质量验证。", : "丢弃可能改变数据完整性;候选版本仍不能发布,必须重建候选并重新执行质量检查。",
}); });
const workOrder = operationsStore.workOrders.find((item) => item.issueId === issue.id); const workOrder = operationsStore.workOrders.find((item) => item.issueId === issue.id);
if (workOrder) migrateOperationsEntity(workOrder, "INVESTIGATING", metadata); if (workOrder) migrateOperationsEntity(workOrder, "INVESTIGATING", metadata);
@@ -3584,13 +3584,13 @@ function setupOperations() {
renderOperations(); renderOperations();
renderAudit(); renderAudit();
openIssueDrawer(issue.id); openIssueDrawer(issue.id);
showToast(`${actionLabel}已复核,但不能解除发布门禁`, "质量门禁仍阻断"); showToast(`${actionLabel}已复核,但当前候选版本仍不能发布`, "仍不满足发布条件");
return; return;
} }
if (action === "verify" && issue.status === "QUALITY_REVIEW_PENDING") { if (action === "verify" && issue.status === "QUALITY_REVIEW_PENDING") {
const disposition = latestQualityDisposition(issue.id); const disposition = latestQualityDisposition(issue.id);
if (!disposition || disposition.action !== "FIX_REPLAY") { if (!disposition || disposition.action !== "FIX_REPLAY") {
showToast("只有修复并重放可以进入质量验证通过状态", "质量门禁仍阻断"); showToast("只有修复并重放可以进入质量检查通过状态", "仍不满足发布条件");
return; return;
} }
const metadata = addOperationsAudit({ const metadata = addOperationsAudit({
@@ -3616,7 +3616,7 @@ function setupOperations() {
time: metadata.time, time: metadata.time,
trace: metadata.trace, trace: metadata.trace,
evidence: [...metadata.evidence], evidence: [...metadata.evidence],
note: "记录数、质量规则与重放证据已复核,候选版本质量门禁解除。", note: "记录数、质量规则和重放记录已复核,候选版本可以继续提交审批。",
}); });
const workOrder = operationsStore.workOrders.find((item) => item.issueId === issue.id); const workOrder = operationsStore.workOrders.find((item) => item.issueId === issue.id);
if (workOrder) migrateOperationsEntity(workOrder, "VERIFIED", metadata); if (workOrder) migrateOperationsEntity(workOrder, "VERIFIED", metadata);
@@ -3625,7 +3625,7 @@ function setupOperations() {
renderOperations(); renderOperations();
renderAudit(); renderAudit();
openIssueDrawer(issue.id); openIssueDrawer(issue.id);
showToast("质量处置已 VERIFIED,候选版本现在可提交审批", "质量门禁已通过"); showToast("质量处置已 VERIFIED,候选版本现在可提交审批", "已满足发布质量要求");
return; return;
} }
if (action === "resolve" && (issue.status === "VERIFIED" || (issue.status === "INVESTIGATING" && !issue.qualityRequired))) { if (action === "resolve" && (issue.status === "VERIFIED" || (issue.status === "INVESTIGATING" && !issue.qualityRequired))) {
@@ -3645,7 +3645,7 @@ function setupOperations() {
} }
if (event.target.closest("[data-release-official-manifest]")) { if (event.target.closest("[data-release-official-manifest]")) {
if (!release.publishedManifest) { if (!release.publishedManifest) {
showToast("尚未形成发布 Manifest", "下载不可用"); showToast("尚未生成发布 Manifest", "下载不可用");
return; return;
} }
downloadJson(`${release.packageId}-published-manifest.json`, release.publishedManifest); downloadJson(`${release.packageId}-published-manifest.json`, release.publishedManifest);
@@ -3656,7 +3656,7 @@ function setupOperations() {
updateReleaseQualityGate(); updateReleaseQualityGate();
if (!releaseReadyForApproval(release)) { if (!releaseReadyForApproval(release)) {
showToast( showToast(
release.qualityGate === "PASS" ? "质量门禁已通过,但必须先生成并冻结候选 Manifest" : "只有验证通过的 FIX_REPLAY 才能解除候选版本门禁", release.qualityGate === "PASS" ? "质量检查已通过,但必须先生成候选 Manifest 并提交审批" : "只有通过检查的 FIX_REPLAY 才能让候选版本继续提交",
"候选尚不可提交", "候选尚不可提交",
); );
return; return;
@@ -3666,7 +3666,7 @@ function setupOperations() {
event: "候选版本提交独立审批", event: "候选版本提交独立审批",
object: release.id, object: release.id,
result: "待审批", result: "待审批",
evidence: ["候选 Manifest", "质量门禁 PASS", "影响租户清单"], evidence: ["候选 Manifest", "发布质量检查 PASS", "影响租户清单"],
}); });
migrateOperationsEntity(release, "PENDING_APPROVAL", metadata); migrateOperationsEntity(release, "PENDING_APPROVAL", metadata);
migrateOperationsEntity(approval, "PENDING_APPROVAL", metadata); migrateOperationsEntity(approval, "PENDING_APPROVAL", metadata);
@@ -3794,7 +3794,7 @@ function setupOperations() {
rejectEvent: "全局版本回滚独立审批驳回", rejectEvent: "全局版本回滚独立审批驳回",
object: `${release.id} → ${release.previousStableVersion}`, object: `${release.id} → ${release.previousStableVersion}`,
evidence: ["回滚审批意见", "审批人身份", "四眼规则校验", "影响租户清单"], evidence: ["回滚审批意见", "审批人身份", "四眼规则校验", "影响租户清单"],
defaultApproveComment: "同意在受控窗口执行回滚", defaultApproveComment: "同意在已安排的时间窗口执行回滚",
defaultRejectComment: "回滚依据不足", defaultRejectComment: "回滚依据不足",
successMessage: (actor, passed) => `${actor} 已${passed ? "批准" : "驳回"}全局回滚`, successMessage: (actor, passed) => `${actor} 已${passed ? "批准" : "驳回"}全局回滚`,
successTitle: (passed) => (passed ? "回滚审批通过" : "回滚审批驳回"), successTitle: (passed) => (passed ? "回滚审批通过" : "回滚审批驳回"),
@@ -3807,7 +3807,7 @@ function setupOperations() {
rollbackApproval?.status !== "ROLLBACK_APPROVED" || rollbackApproval?.status !== "ROLLBACK_APPROVED" ||
!isIndependentApproval(rollbackApproval) !isIndependentApproval(rollbackApproval)
) { ) {
showToast("全局版本回滚必须先完成职责分离的独立审批", "回滚执行被阻断"); showToast("全局版本回滚必须先由另一名审批人批准", "当前不能执行回滚");
return; return;
} }
const metadata = addOperationsAudit({ const metadata = addOperationsAudit({
@@ -3846,7 +3846,7 @@ function setupOperations() {
saveOperationsStore(); saveOperationsStore();
renderOperations(); renderOperations();
renderAudit(); renderAudit();
showToast(`${pending.length} 所待发送学校已进入原型队列,未发生真实网络发送`, "交付队列已启动"); showToast(`${pending.length} 所待发送学校已进入原型队列,没有发出网络请求`, "交付队列已启动");
}); });
document.getElementById("deliveryTable").addEventListener("click", (event) => { document.getElementById("deliveryTable").addEventListener("click", (event) => {
const button = const button =
@@ -3949,7 +3949,7 @@ function setupGlobalActions() {
const deliveryTodos = operationsStore.deliveries.filter((delivery) => ["PENDING", "SENDING", "FAILED", "RETRYING"].includes(delivery.status)); const deliveryTodos = operationsStore.deliveries.filter((delivery) => ["PENDING", "SENDING", "FAILED", "RETRYING"].includes(delivery.status));
openInfoModal( openInfoModal(
"OPERATIONS NOTIFICATIONS", "OPERATIONS NOTIFICATIONS",
"真实运营待办", "运营待办",
`<div class="runtime-list notification-list"> `<div class="runtime-list notification-list">
${openIssues ${openIssues
.map( .map(
@@ -3963,7 +3963,7 @@ function setupGlobalActions() {
: "" : ""
} }
${deliveryTodos.length ? `<button data-operations-jump="deliveries"><strong>${deliveryTodos.length} 所学校交付待处理</strong><small>包含待发送、发送中、失败或重试状态</small></button>` : ""} ${deliveryTodos.length ? `<button data-operations-jump="deliveries"><strong>${deliveryTodos.length} 所学校交付待处理</strong><small>包含待发送、发送中、失败或重试状态</small></button>` : ""}
${!openIssues.length && !pendingApproval && !deliveryTodos.length ? `<span><strong>当前没有运营待办</strong><small>问题、审批和交付均已闭环</small></span>` : ""} ${!openIssues.length && !pendingApproval && !deliveryTodos.length ? `<span><strong>当前没有运营待办</strong><small>问题、审批和交付均已处理完成</small></span>` : ""}
</div>`, </div>`,
); );
}); });
+23 -23
View File
@@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta <meta
name="description" name="description"
content="产教数据中台,面向厂商数据运营团队管理招聘数据采集、标准契约、导入导出、质量治理与审计交付" content="产教数据中台,供厂商数据运营团队管理招聘数据采集、标准、导入导出、质量检查和学校交付"
/> />
<title>产教数据中台 · 厂商运营中心</title> <title>产教数据中台 · 厂商运营中心</title>
<link rel="icon" href="./favicon.svg" type="image/svg+xml" /> <link rel="icon" href="./favicon.svg" type="image/svg+xml" />
@@ -104,9 +104,9 @@
<section class="view active" id="view-overview" data-title="运行总览"> <section class="view active" id="view-overview" data-title="运行总览">
<div class="page-heading"> <div class="page-heading">
<div> <div>
<div class="eyebrow"><i></i> DATA OPERATIONS CONTROL PLANE</div> <div class="eyebrow"><i></i> DATA OPERATIONS</div>
<h1>招聘数据生产运行总览</h1> <h1>招聘数据生产运行总览</h1>
<p>统一管理商业招聘平台、公共就业平台和校内业务系统,从采集到交付全链路可追溯。</p> <p>集中查看商业招聘平台、公共就业平台和校内业务系统的数据,每批数据都保留采集、处理和交付记录。</p>
</div> </div>
<div class="heading-actions"> <div class="heading-actions">
<button class="button secondary" data-open-export> <button class="button secondary" data-open-export>
@@ -160,7 +160,7 @@
<article class="panel flow-panel"> <article class="panel flow-panel">
<div class="panel-head"> <div class="panel-head">
<div><span>处理链路</span><h2>今日数据流水线</h2></div> <div><span>处理步骤</span><h2>今日数据流水线</h2></div>
<span class="live-label"><i></i>实时</span> <span class="live-label"><i></i>实时</span>
</div> </div>
<div class="pipeline-flow"> <div class="pipeline-flow">
@@ -194,7 +194,7 @@
<section class="view" id="view-operations" data-title="运营处置"> <section class="view" id="view-operations" data-title="运营处置">
<div class="page-heading"> <div class="page-heading">
<div> <div>
<div class="eyebrow"><i></i> OPERATIONS RESOLUTION LOOP</div> <div class="eyebrow"><i></i> OPERATIONS WORKFLOW</div>
<h1>运营问题、发布与学校交付</h1> <h1>运营问题、发布与学校交付</h1>
<p>从告警确认、排障和质量复核,到独立审批、版本发布、逐学校回执与租户级回滚,全程保留状态与审计证据。</p> <p>从告警确认、排障和质量复核,到独立审批、版本发布、逐学校回执与租户级回滚,全程保留状态与审计证据。</p>
</div> </div>
@@ -237,7 +237,7 @@
<div><span>TENANT DELIVERY</span><h2>逐学校交付与回执</h2></div> <div><span>TENANT DELIVERY</span><h2>逐学校交付与回执</h2></div>
<button class="text-button" id="startPendingDeliveries">启动待发送学校</button> <button class="text-button" id="startPendingDeliveries">启动待发送学校</button>
</div> </div>
<div class="delivery-boundary-note">静态原型只模拟并持久化交付状态,不会向学校网络、接口或业务系统真实发送数据。</div> <div class="delivery-boundary-note">静态原型只记录交付状态,不会向学校网络、接口或业务系统发送数据。</div>
<div class="table-wrap"> <div class="table-wrap">
<table class="data-table delivery-table"> <table class="data-table delivery-table">
<thead><tr><th>学校 / 租户</th><th>包与数据版本</th><th>交付状态</th><th>记录数回执</th><th>SHA-256 回执</th><th>最近动作</th><th>操作</th></tr></thead> <thead><tr><th>学校 / 租户</th><th>包与数据版本</th><th>交付状态</th><th>记录数回执</th><th>SHA-256 回执</th><th>最近动作</th><th>操作</th></tr></thead>
@@ -252,8 +252,8 @@
<div class="page-heading"> <div class="page-heading">
<div> <div>
<div class="eyebrow"><i></i> SOURCE REGISTRY</div> <div class="eyebrow"><i></i> SOURCE REGISTRY</div>
<h1>统一数据源注册中心</h1> <h1>数据源管理</h1>
<p>商业招聘平台、公共就业平台、活动聚合平台和校内系统使用同一套资产、版本和运行模型。</p> <p>商业招聘平台、公共就业平台、招聘活动和校内系统都按数据源、版本和运行记录管理。</p>
</div> </div>
<div class="heading-actions"> <div class="heading-actions">
<button class="button secondary" id="sourceCatalogExport">导出数据源目录</button> <button class="button secondary" id="sourceCatalogExport">导出数据源目录</button>
@@ -291,7 +291,7 @@
<div> <div>
<div class="eyebrow"><i></i> COLLECTION ORCHESTRATION</div> <div class="eyebrow"><i></i> COLLECTION ORCHESTRATION</div>
<h1>采集任务编排中心</h1> <h1>采集任务编排中心</h1>
<p>按来源、地域、行业和岗位族编排任务,支持分片、限速、失败隔离、断点续采和版本化原始留存。</p> <p>按来源、地域、行业和岗位族创建采集任务,支持分片、限速、失败隔离、断点续采,并保存每次原始数据版本。</p>
</div> </div>
<div class="heading-actions"> <div class="heading-actions">
<button class="button secondary" id="pauseAllJobs">暂停全部</button> <button class="button secondary" id="pauseAllJobs">暂停全部</button>
@@ -329,8 +329,8 @@
<div class="page-heading"> <div class="page-heading">
<div> <div>
<div class="eyebrow"><i></i> DATA RECORD EXPLORER</div> <div class="eyebrow"><i></i> DATA RECORD EXPLORER</div>
<h1>采集数据浏览与追溯</h1> <h1>采集数据与来源记录</h1>
<p>按数据层、来源、地区和关键词检索岗位明细,向下追溯源端记录、原始快照、采集任务与内容哈希。</p> <p>按数据层、来源、地区和关键词检索岗位明细,并查看对应的源端记录、原始快照、采集任务与内容哈希。</p>
</div> </div>
<div class="heading-actions"> <div class="heading-actions">
<button class="button secondary" id="recordRefresh"> <button class="button secondary" id="recordRefresh">
@@ -382,9 +382,9 @@
<section class="view" id="view-contracts" data-title="数据标准"> <section class="view" id="view-contracts" data-title="数据标准">
<div class="page-heading"> <div class="page-heading">
<div> <div>
<div class="eyebrow"><i></i> DATA CONTRACT GOVERNANCE</div> <div class="eyebrow"><i></i> DATA CONTRACTS</div>
<h1>产教数据标准与契约中心</h1> <h1>产教数据标准与契约中心</h1>
<p>第三方招聘数据和校内业务数据按版本化契约交付,字段、代码、质量、脱敏和变更策略一次定义、全链路执行。</p> <p>第三方招聘数据和校内业务数据按版本化契约交付,字段、代码、质量、脱敏和变更规则统一设置。</p>
</div> </div>
<div class="heading-actions"> <div class="heading-actions">
<button class="button secondary" id="compareContractVersions">版本对比</button> <button class="button secondary" id="compareContractVersions">版本对比</button>
@@ -394,8 +394,8 @@
<div class="contract-tabs" id="contractTabs"> <div class="contract-tabs" id="contractTabs">
<button class="active" data-contract="external-job"><span>JOB-SIGNAL</span><strong>外部岗位信号</strong><small>V3.0 · 39字段</small></button> <button class="active" data-contract="external-job"><span>JOB-SIGNAL</span><strong>外部岗位信号</strong><small>V3.0 · 39字段</small></button>
<button data-contract="school-employment"><span>SCHOOL-EMPLOYMENT</span><strong>校内就业事实</strong><small>V2.2 · 32字段</small></button> <button data-contract="school-employment"><span>SCHOOL-EMPLOYMENT</span><strong>校内就业数据</strong><small>V2.2 · 32字段</small></button>
<button data-contract="school-internship"><span>SCHOOL-INTERNSHIP</span><strong>校内实习事实</strong><small>V2.1 · 30字段</small></button> <button data-contract="school-internship"><span>SCHOOL-INTERNSHIP</span><strong>校内实习数据</strong><small>V2.1 · 30字段</small></button>
<button data-contract="package-manifest"><span>PACKAGE-MANIFEST</span><strong>交付包清单</strong><small>V1.2 · 21字段</small></button> <button data-contract="package-manifest"><span>PACKAGE-MANIFEST</span><strong>交付包清单</strong><small>V1.2 · 21字段</small></button>
</div> </div>
<div id="contractContent"></div> <div id="contractContent"></div>
@@ -406,7 +406,7 @@
<div> <div>
<div class="eyebrow"><i></i> DATA EXCHANGE</div> <div class="eyebrow"><i></i> DATA EXCHANGE</div>
<h1>数据导入与交付中心</h1> <h1>数据导入与交付中心</h1>
<p>支持标准文件导入、Schema 预检、字段映射、质量干跑和带清单、校验和、质量报告的版本化导出。</p> <p>支持标准文件导入、Schema 预检、字段对应、发布前质量检查,以及带清单、校验和与质量报告的数据导出。</p>
</div> </div>
<div class="heading-actions"> <div class="heading-actions">
<a class="button secondary" href="./samples/external-job-sample.csv" download>下载导入样例</a> <a class="button secondary" href="./samples/external-job-sample.csv" download>下载导入样例</a>
@@ -436,7 +436,7 @@
</article> </article>
<article class="panel export-panel"> <article class="panel export-panel">
<div class="panel-head"><div><span>版本交付</span><h2>构建数据交付包</h2></div><em>可复核、可回滚</em></div> <div class="panel-head"><div><span>版本交付</span><h2>生成数据交付包</h2></div><em>可查看检查记录,可回滚</em></div>
<div class="export-form"> <div class="export-form">
<label><span>数据产品</span><select id="exportProduct"><option>区域招聘岗位基础包</option><option>薪资与企业画像增强包</option><option>产业趋势与政策信号包</option></select></label> <label><span>数据产品</span><select id="exportProduct"><option>区域招聘岗位基础包</option><option>薪资与企业画像增强包</option><option>产业趋势与政策信号包</option></select></label>
<label><span>目标租户</span><select id="exportTenant"><option>36所已授权学校</option><option>杭州科技职业技术学院</option><option>华东区域项目组</option></select></label> <label><span>目标租户</span><select id="exportTenant"><option>36所已授权学校</option><option>杭州科技职业技术学院</option><option>华东区域项目组</option></select></label>
@@ -467,7 +467,7 @@
<div> <div>
<div class="eyebrow"><i></i> QUALITY & NORMALIZATION</div> <div class="eyebrow"><i></i> QUALITY & NORMALIZATION</div>
<h1>数据质量与岗位归一</h1> <h1>数据质量与岗位归一</h1>
<p>执行结构、完整性、唯一性、时效性和业务规则校验,将多来源岗位映射到统一岗位与技能体系。</p> <p>检查结构、完整性、唯一性、时效性和业务规则,并把不同来源的岗位名称和技能名称对齐。</p>
</div> </div>
<div class="heading-actions"> <div class="heading-actions">
<button class="button secondary" id="qualityRuleButton">质量规则</button> <button class="button secondary" id="qualityRuleButton">质量规则</button>
@@ -478,7 +478,7 @@
<div class="quality-layout"> <div class="quality-layout">
<article class="quality-score-card"> <article class="quality-score-card">
<span class="quality-ring"><strong>94.7</strong><small>综合质量</small></span> <span class="quality-ring"><strong>94.7</strong><small>综合质量</small></span>
<div><span>生产发布阈值 ≥ 90</span><strong id="qualityReleaseState">当前批次仍需修复重放复核</strong><small id="qualityReleaseDetail">质量分达标不等于门禁通过,稳定版本继续保持不变</small></div> <div><span>生产发布阈值 ≥ 90</span><strong id="qualityReleaseState">当前批次仍需修复重放复核</strong><small id="qualityReleaseDetail">仅质量分达标还不能发布,当前稳定版本保持不变</small></div>
</article> </article>
<div class="quality-dimensions"> <div class="quality-dimensions">
<span><small>完整性</small><strong>97.8%</strong><i><b style="width:97.8%"></b></i></span> <span><small>完整性</small><strong>97.8%</strong><i><b style="width:97.8%"></b></i></span>
@@ -504,8 +504,8 @@
<div class="page-heading"> <div class="page-heading">
<div> <div>
<div class="eyebrow"><i></i> AUDIT & DELIVERY</div> <div class="eyebrow"><i></i> AUDIT & DELIVERY</div>
<h1>全链路审计与生产交付</h1> <h1>审计记录与生产交付</h1>
<p>记录来源、采集任务、代码版本、原始快照、处理规则、发布审批和租户交付,实现问题可定位、版本可回滚。</p> <p>记录来源、采集任务、代码版本、原始快照、处理规则、发布审批和租户交付。出现问题时可查到相关记录,也可回滚版本。</p>
</div> </div>
<div class="heading-actions"> <div class="heading-actions">
<button class="button secondary" id="auditPolicyButton">审计策略</button> <button class="button secondary" id="auditPolicyButton">审计策略</button>
@@ -516,7 +516,7 @@
<div class="audit-summary"> <div class="audit-summary">
<article><small>今日审计事件</small><strong>2,846</strong><em>全部已签名</em></article> <article><small>今日审计事件</small><strong>2,846</strong><em>全部已签名</em></article>
<article><small>数据版本</small><strong>128</strong><em>保留 36 个月</em></article> <article><small>数据版本</small><strong>128</strong><em>保留 36 个月</em></article>
<article><small>可追踪任务</small><strong>100%</strong><em>原始快照已绑定</em></article> <article><small>带追踪编号的任务</small><strong>100%</strong><em>已关联原始快照</em></article>
<article><small>交付租户</small><strong>36</strong><em>范围策略有效</em></article> <article><small>交付租户</small><strong>36</strong><em>范围策略有效</em></article>
</div> </div>
@@ -577,7 +577,7 @@
<div> <div>
<span id="recordDrawerKicker">DATA RECORD</span> <span id="recordDrawerKicker">DATA RECORD</span>
<h2 id="recordDrawerTitle">采集记录详情</h2> <h2 id="recordDrawerTitle">采集记录详情</h2>
<p id="recordDrawerDescription">查看业务字段和全链路来源证据。</p> <p id="recordDrawerDescription">查看业务字段、来源和处理记录。</p>
</div> </div>
<button class="icon-button" id="closeRecordDrawer" aria-label="关闭采集记录详情"> <button class="icon-button" id="closeRecordDrawer" aria-label="关闭采集记录详情">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 6l12 12M18 6 6 18" /></svg> <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 6l12 12M18 6 6 18" /></svg>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 297 KiB

After

Width:  |  Height:  |  Size: 289 KiB

@@ -210,7 +210,7 @@
"maxLength": 100 "maxLength": 100
}, },
"uniqueItems": true, "uniqueItems": true,
"description": "基于技能词典提取并归一的技能标签。" "description": "使用技能词典提取并统一名称的技能标签。"
}, },
"keywords": { "keywords": {
"type": "array", "type": "array",
@@ -1,8 +1,8 @@
{ {
"$schema": "https://json-schema.org/draft/2020-12/schema", "$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://schemas.edu-industry.cn/school-employment/2.2.0/schema.json", "$id": "https://schemas.edu-industry.cn/school-employment/2.2.0/schema.json",
"title": "SCHOOL-EMPLOYMENT V2.2 校内就业事实", "title": "SCHOOL-EMPLOYMENT V2.2 校内就业数据",
"description": "职业院校毕业生就业事实统一契约,采用租户隔离和身份最小化设计。", "description": "职业院校毕业生就业数据契约,要求租户隔离,并将身份字段限制在业务必需的最少范围。",
"type": "object", "type": "object",
"additionalProperties": false, "additionalProperties": false,
"required": [ "required": [
@@ -1,8 +1,8 @@
{ {
"$schema": "https://json-schema.org/draft/2020-12/schema", "$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://schemas.edu-industry.cn/school-internship/2.1.0/schema.json", "$id": "https://schemas.edu-industry.cn/school-internship/2.1.0/schema.json",
"title": "SCHOOL-INTERNSHIP V2.1 校内实习事实", "title": "SCHOOL-INTERNSHIP V2.1 校内实习数据",
"description": "职业院校学生实习事实统一契约,采用租户隔离、身份最小化和证据引用设计。", "description": "职业院校学生实习数据契约,要求租户隔离,将身份字段限制在业务必需的最少范围,并引用评价记录。",
"type": "object", "type": "object",
"additionalProperties": false, "additionalProperties": false,
"required": [ "required": [
+25 -25
View File
@@ -1,6 +1,6 @@
# 产教融智企业版前端 # 产教融智企业版前端
产教融智面向职业院校构建“产业信号、专业诊断、校企协同、改进任务、正式报告”一体化工作闭环。本目录是企业版产品前端基线,所有核心场景均可深入点击并形成可追踪的业务结果。 产教融智供职业院校查看岗位变化、分析专业差距、安排企业合作、跟进改进任务并出具正式报告。本目录保存企业版产品前端样例。
## 运行 ## 运行
@@ -12,7 +12,7 @@ python3 -m http.server 8080
然后访问 <http://localhost:8080>。 然后访问 <http://localhost:8080>。
## 核心产品能力 ## 主要功能
- 校级供需决策总览、周期切换、专业搜索和七步产品导览 - 校级供需决策总览、周期切换、专业搜索和七步产品导览
- “企业需求 → 学校接收/分析快照 → 专业建议决策 → 任务/项目 → 执行证据 → 企业评价 → 校级验收 → 报告审批发布 → 数据使用反馈 → 成效复核”11 节点可交互业务流程图 - “企业需求 → 学校接收/分析快照 → 专业建议决策 → 任务/项目 → 执行证据 → 企业评价 → 校级验收 → 报告审批发布 → 数据使用反馈 → 成效复核”11 节点可交互业务流程图
@@ -22,26 +22,26 @@ python3 -m http.server 8080
- 技术接收同时强校验租户、包号、版本、交付记录数和完整 64 位 SHA-256;任一不一致只写失败审计,不推进回执或分析快照 - 技术接收同时强校验租户、包号、版本、交付记录数和完整 64 位 SHA-256;任一不一致只写失败审计,不推进回执或分析快照
- 交付包记录数与分析样本量分开保存:样板包回执为 `2,846,320` 条,生成的校园分析快照为 `128,642` 条 - 交付包记录数与分析样本量分开保存:样板包回执为 `2,846,320` 条,生成的校园分析快照为 `128,642` 条
- 专业技能供需、岗位流向、薪资对标、课程技能映射与专业对比 - 专业技能供需、岗位流向、薪资对标、课程技能映射与专业对比
- 企业需求响应、潜力伙伴对接、协同项目里程碑和验收证据 - 企业需求响应、潜力伙伴对接、合作项目里程碑和验收证据
- 改进任务筛选、搜索、创建、阶段进展和报告建议转任务 - 改进任务筛选、搜索、创建、阶段进展和报告建议转任务
- 数据源初次导入、增量更新、质量处置、版本管理、授权与审计 - 数据源初次导入、增量更新、质量处置、版本管理、授权与审计
- 厂商基础数据包、校级数据、企业数据分类及授权状态筛选 - 厂商基础数据包、校级数据、企业数据分类及授权状态筛选
- 覆盖 6 个数据源和 42 份报告的“数据 → 指标/分析主题 → 报告”双向依赖图谱,支持只看缺口 - 覆盖 6 个数据源和 42 份报告的“数据 → 指标/分析主题 → 报告”双向依赖图谱,支持只看缺口
- 报告缺失字段、当前完整率、影响范围、业务索取人、技术接口人和要求完成日期一体化追踪 - 每份报告列出缺失字段、当前完整率、影响范围、业务索取人、技术接口人和要求完成日期
- 校级管理者、校级技术管理员、学院负责人、专业负责人、就业老师、企业导师、厂商超级管理员七种差异化工作台 - 校级管理者、校级技术管理员、学院负责人、专业负责人、就业老师、企业导师、厂商超级管理员七种差异化工作台
- 厂商平台级数据包导入、学校租户、账号权限、备份恢复和审计管理 - 厂商平台级数据包导入、学校租户、账号权限、备份恢复和审计管理
- 校级、学院、专业、产业专题与数据质量报告中心 - 校级、学院、专业、产业专题与数据质量报告中心
- 在线报告正文:封面、摘要、发现、供需分析、数据证据、指标口径和行动建议 - 在线报告正文:封面、摘要、发现、供需分析、数据证据、指标口径和行动建议
- 报告内置 ECharts / ECharts-GL 可视化:仪表盘、三基准柱状图、雷达图、趋势面积图、热力图、环图、象限气泡图和立体证据矩阵 - 报告内置 ECharts / ECharts-GL 可视化:仪表盘、三基准柱状图、雷达图、趋势面积图、热力图、环图、象限气泡图和立体证据矩阵
- 学校事实画像:在校生、毕业生、专业、教师、课程、合作企业、就业与实习指标均附证据编号、来源、更新时间、责任部门和计算口径 - 学校现状数据:在校生、毕业生、专业、教师、课程、合作企业、就业与实习指标均注明编号、来源、更新时间、责任部门和计算口径
- 结论证据链:学校值、区域均值、同类院校均值、排名、样本量、数据权属、置信度和已知限制 - 结论依据:学校值、区域均值、同类院校均值、排名、样本量、数据权属、可靠程度和已知限制
- 报告类型、周期、关键词筛选、目录跳转、建议转任务、打印与离线 HTML 下载 - 报告类型、周期、关键词筛选、目录跳转、建议转任务、打印与离线 HTML 下载
- 本期分析生成与供需会材料包生成 - 本期分析生成与供需会材料包生成
- 供需会展示大屏及桌面端、平板、移动端自适应 - 供需会展示大屏及桌面端、平板、移动端自适应
## 数据资产分类 ## 数据资产分类
- **互联网基础数据包**:由平台厂商合规归集、治理并按服务期导入,属于付费订阅数据。 - **互联网基础数据包**:由平台厂商按授权收集、检查并按服务期导入,属于付费订阅数据。
- **校级数据**:来自学校实习、就业、教务等业务系统,数据权属归学校。 - **校级数据**:来自学校实习、就业、教务等业务系统,数据权属归学校。
- **企业数据**:由合作企业确认提交,按照合作协议限定使用范围。 - **企业数据**:由合作企业确认提交,按照合作协议限定使用范围。
@@ -57,15 +57,15 @@ python3 -m http.server 8080
- 桌面端显示完整流程拓扑,移动端转换为带连接线的纵向节点流程,并用三张可点击关系卡保留整改、退回与下一周期回流; - 桌面端显示完整流程拓扑,移动端转换为带连接线的纵向节点流程,并用三张可点击关系卡保留整改、退回与下一周期回流;
- “进入下一周期”会归档上一周期报告,创建带 `previousVersionId` 的新需求、快照和回执版本,并清空新周期尚未产生的下游实体。 - “进入下一周期”会归档上一周期报告,创建带 `previousVersionId` 的新需求、快照和回执版本,并清空新周期尚未产生的下游实体。
流程图只负责展示并调用现有状态机,不维护第二套演示状态。因此原有租户、SHA、记录数、证据冻结、独立审批和角色授权规则继续生效。 流程图只展示并调用现有状态机,不另存一套演示状态。原有租户、SHA、记录数、报告生成后禁止追加证据、独立审批和角色授权规则继续生效。
## 数据与报告依赖图谱 ## 数据与报告依赖图谱
“数据资产”页提供两种追溯方向: “数据资产”页提供两种查询方式:
- **从报告看数据**:选择任一校级、学院、专业、产业专题或数据质量报告,查看必需数据、可选增强数据、分析主题、当前完备度和缺口。 - **从报告看数据**:选择任一校级、学院、专业、产业专题或数据质量报告,查看必需数据、可选增强数据、分析主题、当前完备度和缺口。
- **从数据看报告**:选择任一数据源,查看可形成的分析主题、支撑的报告类型和具体报告数量。 - **从数据看报告**:选择任一数据源,查看可做的分析、使用该数据的报告类型和具体报告数量。
- **只看缺口**:仅保留存在质量或字段问题的依赖关系,快速定位不能稳定支撑报告的数据。 - **只看缺口**:仅保留存在质量或字段问题的依赖关系,查看哪些数据暂时不能用于报告。
当前样板将 42 份报告映射到 6 个数据源,并以版本化依赖模板区分必需与可选关系。每个缺口展示: 当前样板将 42 份报告映射到 6 个数据源,并以版本化依赖模板区分必需与可选关系。每个缺口展示:
@@ -76,25 +76,25 @@ python3 -m http.server 8080
- 要求完成日期和受影响报告数; - 要求完成日期和受影响报告数;
- 可直接进入现有质量处置抽屉的操作入口。 - 可直接进入现有质量处置抽屉的操作入口。
依赖元数据用于跨部门补数协同,可以在数据运维角色下查看;报告正文仍按现有角色与数据范围授权,查看依赖关系不自动获得报告阅读权限。静态样板中的依赖、完整率和责任状态均为演示数据,正式系统应将 `ReportDataDependency`、`AnalysisTopic` 和 `DataRequest` 作为租户隔离、版本化、可审计的后端实体。 依赖信息供不同部门补数据时查看;报告正文仍按角色和数据范围授权,查看依赖关系不会自动获得报告阅读权限。静态样板中的依赖、完整率和责任状态均为演示数据,正式系统应按租户和版本保存 `ReportDataDependency`、`AnalysisTopic` 和 `DataRequest`,并记录修改人和时间。
## 角色视角 ## 角色视角
- **校级管理者**:全校决策总览、专业对比、校企协同、改进任务、数据资产与报告。 - **校级管理者**:全校决策总览、专业对比、校企合作、改进任务、数据资产与报告。
- **校级技术管理员**:学校数据源、初次导入、更新任务、字段契约、质量问题、版本、授权与审计。 - **校级技术管理员**:学校数据源、初次导入、更新任务、字段契约、质量问题、版本、授权与审计。
- **学院负责人**:本院专业洞察、校企协同、改进任务与学院报告。 - **学院负责人**:本院专业分析、校企合作、改进任务与学院报告。
- **专业负责人**:专业建议决策、关联任务与项目推进、执行证据和下一周期复核。 - **专业负责人**:专业建议决策、关联任务与项目进度、执行证据和下一周期复核。
- **就业老师**:就业侧数据使用确认和下一周期反馈;不能审批校级业务报告。 - **就业老师**:就业侧数据使用确认和下一周期反馈;不能审批校级业务报告。
- **企业导师**:企业人才需求、共建项目、学生参与和协同任务。 - **企业导师**:企业人才需求、共建项目、学生参与和合作任务。
- **厂商超级管理员**:平台数据包、学校租户、账号权限、备份恢复、服务监控与审计。 - **厂商超级管理员**:平台数据包、学校租户、账号权限、备份恢复、服务监控与审计。
关键职责分离: 关键职责分离:
- 技术接收成功后当前企业需求版本锁定;后续变更必须创建新版本并重新接收; - 技术接收完成后不能修改当前企业需求;后续变更必须创建新版本并重新接收;
- 当前报告一经生成,支撑该版本的任务证据冻结;新增证据必须进入下一周期或重开新版本; - 报告生成后不能再给当前任务追加证据;新增证据必须进入下一周期或新版本;
- 阶段进度必须达到 100%,企业导师才能提交通过或整改评价; - 阶段进度必须达到 100%,企业导师才能提交通过或整改评价;
- 企业评价为“需整改”时,校级验收继续阻断,补充证据并重新评价后才可进入验收; - 企业评价为“需整改”时不能进入校级验收,补充证据并重新评价后才可继续;
- 就业侧最新反馈为“需补充”时,成效复核继续阻断;改为“可用”后才可复核,周期关闭后不再接受追加反馈; - 就业侧最新反馈为“需补充”时不能进入成效复核;改为“可用”后才可继续,周期关闭后不再接受追加反馈;
- 报告提交人不能批准或退回自己的提交,非校级管理者不显示报告审批与发布动作; - 报告提交人不能批准或退回自己的提交,非校级管理者不显示报告审批与发布动作;
- 报告正式发布前,就业老师不能登记使用反馈,下载和打印均明确标识非正式版。 - 报告正式发布前,就业老师不能登记使用反馈,下载和打印均明确标识非正式版。
@@ -105,15 +105,15 @@ python3 -m http.server 8080
- 厂商超级管理员在“平台运营中心 → 数据包管理”完成基础数据包导入、Schema 与质量校验、租户授权和版本发布。 - 厂商超级管理员在“平台运营中心 → 数据包管理”完成基础数据包导入、Schema 与质量校验、租户授权和版本发布。
- 校级技术管理员登录后默认进入“学校数据运维中心”,管理学校自有数据和企业授权数据。 - 校级技术管理员登录后默认进入“学校数据运维中心”,管理学校自有数据和企业授权数据。
- 每个数据源的“资产详情”包含业务截止日期、入库日期、下次更新、更新内容、主键、必填字段、格式、Schema、质量阈值、责任人与审计事件。 - 每个数据源的“资产详情”包含业务截止日期、入库日期、下次更新、更新内容、主键、必填字段、格式、Schema、质量阈值、责任人与审计事件。
- “数据与报告双向依赖图谱”同时回答“这份报告还需要什么数据”和“这项数据可以形成哪些报告”,并把缺口直接分派到业务索取人与技术接口人。 - “数据与报告双向依赖图谱”同时回答“这份报告还需要什么数据”和“哪些报告使用这项数据”,并把缺口直接分派到业务索取人与技术接口人。
- “接收与使用反馈”展示租户、包号、版本、完整 SHA、交付包记录数、独立分析快照、支撑报告/项目/任务、业务可用确认和下一周期反馈。 - “接收与使用反馈”展示租户、包号、版本、完整 SHA、交付包记录数、独立分析快照、关联报告/项目/任务、业务可用确认和下一周期反馈。
- 更新采用“暂存 → 校验 → 审批 → 发布”流程。失败数据进入隔离区,不覆盖当前稳定版本。 - 更新采用“暂存 → 校验 → 审批 → 发布”流程。失败数据进入隔离区,不覆盖当前稳定版本。
详细角色权限、数据契约、初次导入要求、更新机制和未来后端实体设计见 [`../docs/enterprise-product-baseline.md`](../docs/enterprise-product-baseline.md)。 详细角色权限、数据契约、初次导入要求、更新方式和未来后端实体设计见 [`../docs/enterprise-product-baseline.md`](../docs/enterprise-product-baseline.md)。
## 报告与离线运行 ## 报告与离线运行
报告中心内置42份独立报告,包括32份专业人才需求报告、5份学院报告,以及校级、产业专题和数据质量报告。在线阅读支持章节目录、八类交互图表、学校事实证据、来源台账和行动建议;下载功能生成可独立归档、打开和打印的完整 HTML 报告。 报告中心内置42份独立报告,包括32份专业人才需求报告、5份学院报告,以及校级、产业专题和数据质量报告。在线阅读支持章节目录、八类交互图表、学校数据、来源台账和任务建议;下载功能生成可独立保存、打开和打印的完整 HTML 报告。
在线图表使用 `vendor/` 中本地化的 ECharts 5.6 与 ECharts-GL 2.0,无需 CDN。浏览器不支持图表运行时时自动显示静态 SVG 降级视图;下载报告直接内嵌全部图形和样式,不依赖外部脚本或网络。Apache-2.0、NOTICE 和 BSD-3-Clause 文件随库保存在 `vendor/`。 在线图表使用 `vendor/` 中本地化的 ECharts 5.6 与 ECharts-GL 2.0,无需 CDN。浏览器不支持图表运行时时自动显示静态 SVG 降级视图;下载报告直接内嵌全部图形和样式,不依赖外部脚本或网络。Apache-2.0、NOTICE 和 BSD-3-Clause 文件随库保存在 `vendor/`。
@@ -123,7 +123,7 @@ python3 -m http.server 8080
- 为避免静态原型长期演示导致浏览器存储无界增长,审计、证据、反馈、自定义集合和实体历史采用明确保留上限;正式系统应改用服务端分页、归档和不可变审计存储。 - 为避免静态原型长期演示导致浏览器存储无界增长,审计、证据、反馈、自定义集合和实体历史采用明确保留上限;正式系统应改用服务端分页、归档和不可变审计存储。
- 共享样板标识为租户 `TENANT-HZVTC`、厂商包 `EDU-PKG-20260823-01`、版本 `V2026.08.23`、学校回执 `RCT-HZVTC-20260823-01`。这些标识只用于本静态原型的业务链对照,不表示厂商端和校园端页面实时同步。 - 共享样板标识为租户 `TENANT-HZVTC`、厂商包 `EDU-PKG-20260823-01`、版本 `V2026.08.23`、学校回执 `RCT-HZVTC-20260823-01`。这些标识只用于本静态原型的业务链对照,不表示厂商端和校园端页面实时同步。
- 当前前端不向外部服务发送请求,可直接在隔离网络运行。 - 当前前端不向外部服务发送请求,可直接在隔离网络运行。
- 仓库内数据用于本地产品验收,不包含任何真实学校、学生或企业敏感信息。 - 仓库内数据用于本地产品验收,不包含任何实际学校、学生或企业的敏感信息。
- `localStorage` 只用于原型演示,不是正式数据库、鉴权或审计设施。正式接入必须由后端 API 执行租户隔离、身份认证、逐对象授权、并发控制、不可抵赖审计、文件安全存储、字段脱敏、授权台账和备份恢复;前端按钮隐藏或禁用不能作为权限控制。 - `localStorage` 只用于原型演示,不是正式数据库、鉴权或审计设施。正式接入必须由后端 API 执行租户隔离、身份认证、逐对象授权、并发控制、不可抵赖审计、文件安全存储、字段脱敏、授权台账和备份恢复;前端按钮隐藏或禁用不能作为权限控制。
- JavaScript 语法检查:`node --check app.js && node --check report-visuals.js` - JavaScript 语法检查:`node --check app.js && node --check report-visuals.js`
- 推荐桌面验收视口为 `1440 × 900`,移动验收视口为 `390 × 844`。 - 推荐桌面验收视口为 `1440 × 900`,移动验收视口为 `390 × 844`。
+122 -122
View File
@@ -29,7 +29,7 @@ const professionData = {
priority: "高优先级", priority: "高优先级",
title: "强化“云原生与容器化”实训模块", title: "强化“云原生与容器化”实训模块",
description: description:
"建议在综合实训中增加 Docker、Kubernetes 和 CI/CD 流水线,采用企业真实部署任务组织教学。", "建议在综合实训中增加 Docker、Kubernetes 和 CI/CD 流水线,并把企业部署任务用于课堂练习。",
evidence: "2,864条岗位样本中,相关技能出现率由42%升至78%,当前课程覆盖仅32%", evidence: "2,864条岗位样本中,相关技能出现率由42%升至78%,当前课程覆盖仅32%",
}, },
{ {
@@ -76,15 +76,15 @@ const professionData = {
priority: "高优先级", priority: "高优先级",
title: "新增工业视觉综合实训项目", title: "新增工业视觉综合实训项目",
description: description:
"联合装备企业建设缺陷检测场景,覆盖相机标定、图像处理、产线集成和质量评价。", "与装备企业共同设计缺陷检测任务,练习相机标定、图像处理、产线集成和质量评价。",
evidence: "机器视觉岗位近90天增长38%,课程覆盖度仅38%,技能缺口44个百分点", evidence: "机器视觉岗位近90天增长38%,课程覆盖度仅38%,技能缺口44个百分点",
}, },
{ {
priority: "中优先级", priority: "中优先级",
title: "引入设备数字孪生教学案例", title: "引入设备数字孪生教学案例",
description: description:
"将现有PLC和生产线实训映射到数字孪生模型,形成设备数据采集与仿真任务。", "把现有 PLC 和生产线实训对应到数字孪生模型,并安排设备数据采集与仿真任务。",
evidence: "73%的龙头制造企业将数字孪生列为智能工厂建设能力", evidence: "73%的龙头制造企业已把数字孪生列入智能工厂相关岗位要求",
}, },
], ],
companies: [ companies: [
@@ -123,7 +123,7 @@ const professionData = {
priority: "高优先级", priority: "高优先级",
title: "重构跨境电商平台运营课程", title: "重构跨境电商平台运营课程",
description: description:
"增加真实店铺、选品定价、海外投放和合规履约任务,引入企业运营数据进行过程评价。", "增加企业店铺运营、选品定价、海外投放和合规履约任务,并用企业运营数据评价学习过程。",
evidence: "跨境运营岗位增长34%,当前课程技能覆盖43%,企业反馈实操能力不足", evidence: "跨境运营岗位增长34%,当前课程技能覆盖43%,企业反馈实操能力不足",
}, },
{ {
@@ -182,7 +182,7 @@ const trendSets = {
const projects = [ const projects = [
{ type: "course", tone: "green", title: "云原生应用开发课程共建", meta: "信息工程学院 × 数梦工场", progress: 72, partners: ["李", "王", "企"] }, { type: "course", tone: "green", title: "云原生应用开发课程共建", meta: "信息工程学院 × 数梦工场", progress: 72, partners: ["李", "王", "企"] },
{ type: "lab", tone: "amber", title: "工业视觉缺陷检测实训", meta: "智能制造学院 × 大华股份", progress: 48, partners: ["陈", "赵", "企"] }, { type: "lab", tone: "amber", title: "工业视觉缺陷检测实训", meta: "智能制造学院 × 大华股份", progress: 48, partners: ["陈", "赵", "企"] },
{ type: "practice", tone: "blue", title: "跨境电商真实店铺运营", meta: "商贸旅游学院 × 连连数字", progress: 86, partners: ["徐", "周", "企"] }, { type: "practice", tone: "blue", title: "跨境电商店铺运营", meta: "商贸旅游学院 × 连连数字", progress: 86, partners: ["徐", "周", "企"] },
{ type: "course", tone: "green", title: "数字文旅内容生产工作坊", meta: "艺术设计学院 × 宋城集团", progress: 35, partners: ["许", "孙", "企"] }, { type: "course", tone: "green", title: "数字文旅内容生产工作坊", meta: "艺术设计学院 × 宋城集团", progress: 35, partners: ["许", "孙", "企"] },
]; ];
@@ -200,7 +200,7 @@ const enterpriseDemands = [
company: "遥望科技", company: "遥望科技",
industry: "数字商贸", industry: "数字商贸",
title: "直播电商运营实战项目", title: "直播电商运营实战项目",
description: "提供真实品牌运营任务,需要课程团队共同设计过程评价标准。", description: "提供品牌运营任务,需要课程团队共同设计过程评价标准。",
due: "本周五截止", due: "本周五截止",
}, },
{ {
@@ -215,7 +215,7 @@ const enterpriseDemands = [
const partners = [ const partners = [
{ logo: "吉利", name: "吉利汽车", industry: "汽车制造 · 龙头企业", reason: "近一年发布高匹配岗位186个,与机电专业技能重合度高。", tags: ["智能产线", "企业导师"], match: 95 }, { logo: "吉利", name: "吉利汽车", industry: "汽车制造 · 龙头企业", reason: "近一年发布高匹配岗位186个,与机电专业技能重合度高。", tags: ["智能产线", "企业导师"], match: 95 },
{ logo: "数梦", name: "数梦工场", industry: "数据智能 · 专精特新", reason: "已确认参与云原生课程共建,并提供真实项目案例。", tags: ["云平台", "课程共建"], match: 94 }, { logo: "数梦", name: "数梦工场", industry: "数据智能 · 专精特新", reason: "已确认参与云原生课程共建,并提供项目案例。", tags: ["云平台", "课程共建"], match: 94 },
{ logo: "遥望", name: "遥望科技", industry: "直播电商 · 上市企业", reason: "内容运营和直播投放需求稳定,愿意提供实训项目。", tags: ["直播电商", "项目实训"], match: 93 }, { logo: "遥望", name: "遥望科技", industry: "直播电商 · 上市企业", reason: "内容运营和直播投放需求稳定,愿意提供实训项目。", tags: ["直播电商", "项目实训"], match: 93 },
{ logo: "大华", name: "大华股份", industry: "智能物联 · 龙头企业", reason: "工业视觉岗位增长显著,与学校智能制造方向互补。", tags: ["机器视觉", "实训基地"], match: 92 }, { logo: "大华", name: "大华股份", industry: "智能物联 · 龙头企业", reason: "工业视觉岗位增长显著,与学校智能制造方向互补。", tags: ["机器视觉", "实训基地"], match: 92 },
]; ];
@@ -399,7 +399,7 @@ const sources = [
categoryLabel: "企业数据", categoryLabel: "企业数据",
commercial: "合作授权", commercial: "合作授权",
provider: "126家合作企业", provider: "126家合作企业",
rights: "限定合作场景使用", rights: "只限约定合作用途",
coverage: "岗位与技能需求", coverage: "岗位与技能需求",
frequency: "按需更新", frequency: "按需更新",
status: "授权有效", status: "授权有效",
@@ -953,7 +953,7 @@ const closedLoopActionCatalog = {
description: "项目自动绑定 demandId、recommendationId 与 taskId。", description: "项目自动绑定 demandId、recommendationId 与 taskId。",
roles: ["专业负责人"], roles: ["专业负责人"],
fields: [ fields: [
["title", "项目名称", "text", "边缘计算测试真实项目进课堂"], ["title", "项目名称", "text", "边缘计算测试项目进课堂"],
["profession", "牵头专业", "text", "软件技术"], ["profession", "牵头专业", "text", "软件技术"],
["owner", "项目负责人", "text", "李雯"], ["owner", "项目负责人", "text", "李雯"],
], ],
@@ -981,7 +981,7 @@ const closedLoopActionCatalog = {
roles: ["企业导师"], roles: ["企业导师"],
fields: [ fields: [
["result", "评价结论", "select", "通过|需整改"], ["result", "评价结论", "select", "通过|需整改"],
["comment", "评价意见", "textarea", "任务覆盖真实设备测试流程,验收量规清晰,同意进入校级验收。"], ["comment", "评价意见", "textarea", "任务覆盖企业设备测试流程,验收量规清晰,同意进入校级验收。"],
], ],
}, },
acceptance: { acceptance: {
@@ -999,7 +999,7 @@ const closedLoopActionCatalog = {
title: "生成业务报告草稿", title: "生成业务报告草稿",
queueLabel: "生成业务报告草稿", queueLabel: "生成业务报告草稿",
nodeKey: "report", nodeKey: "report",
description: "报告关联需求、快照、任务和全部证据,生成后进入真实审批流。", description: "报告关联需求、快照、任务和全部证据,生成后进入校内审批流程。",
roles: ["专业负责人", "学院负责人", "校级管理者"], roles: ["专业负责人", "学院负责人", "校级管理者"],
fields: [["title", "报告名称", "text", "边缘计算测试人才共育成效报告"]], fields: [["title", "报告名称", "text", "边缘计算测试人才共育成效报告"]],
}, },
@@ -1065,14 +1065,14 @@ function closedLoopActionState(action) {
const checks = { const checks = {
demand: [ demand: [
e.snapshot.status === "待接收" && !e.task && !e.report, e.snapshot.status === "待接收" && !e.task && !e.report,
e.snapshot.status !== "待接收" ? "技术接收后需求版本已锁定;后续变更必须创建新版本并重新接收。" : "已有下游任务或报告,当前需求版本不可原地修改。", e.snapshot.status !== "待接收" ? "技术接收完成后不能修改当前需求;如需变更,请创建新版本并重新接收。" : "已有下游任务或报告,当前需求版本不能直接修改。",
], ],
receive: [e.demand.status === "已提交" && e.snapshot.status !== "已验收", e.snapshot.status === "已验收" ? "技术接收与快照验收已完成。" : "需先由企业提交完整需求。"], receive: [e.demand.status === "已提交" && e.snapshot.status !== "已验收", e.snapshot.status === "已验收" ? "技术接收与快照验收已完成。" : "需先由企业提交完整需求。"],
decision: [e.snapshot.status === "已验收" && e.recommendation.status !== "已采纳", e.recommendation.status === "已采纳" ? "建议已采纳并创建关联任务。" : "需先完成数据接收并生成已验收快照。"], decision: [e.snapshot.status === "已验收" && e.recommendation.status !== "已采纳", e.recommendation.status === "已采纳" ? "建议已采纳并创建关联任务。" : "需先完成数据接收并生成已验收快照。"],
project: [Boolean(e.task && !e.project), e.project ? "关联项目已创建。" : "需先采纳建议并自动创建任务。"], project: [Boolean(e.task && !e.project), e.project ? "关联项目已创建。" : "需先采纳建议并自动创建任务。"],
evidence: [ evidence: [
Boolean(e.task && e.project && ["进行中", "需整改", "已退回"].includes(e.task.status) && !e.report), Boolean(e.task && e.project && ["进行中", "需整改", "已退回"].includes(e.task.status) && !e.report),
e.report ? "报告版本已生成,当前任务证据已冻结;新增证据必须进入下一周期或重开新版本。" : e.task?.status === "已完成" ? "任务已完成校级验收,不能继续追加当前版本证据。" : "需先创建处于执行或整改状态的关联任务和项目。", e.report ? "报告已生成,当前任务不能再追加证据;新增证据请放到下一周期或新版本。" : e.task?.status === "已完成" ? "任务已完成校级验收,不能继续追加当前版本证据。" : "需先创建处于执行或整改状态的关联任务和项目。",
], ],
evaluation: [ evaluation: [
e.evidences.length > 0 && e.evidences.length > 0 &&
@@ -1102,7 +1102,7 @@ function closedLoopActionState(action) {
feedback: [e.report?.status === "已发布" && !e.review, e.review ? "本周期已完成成效复核,不能继续追加使用反馈。" : "需先正式发布报告。"], feedback: [e.report?.status === "已发布" && !e.review, e.review ? "本周期已完成成效复核,不能继续追加使用反馈。" : "需先正式发布报告。"],
review: [ review: [
e.usageFeedback.at(-1)?.usable === "可用" && !e.review, e.usageFeedback.at(-1)?.usable === "可用" && !e.review,
e.review ? "本周期成效复核已完成。" : e.usageFeedback.length ? "最新业务使用反馈仍为需补充,确认可用后才能复核。" : "需先形成就业侧数据使用反馈。", e.review ? "本周期成效复核已完成。" : e.usageFeedback.length ? "最新业务使用反馈仍为需补充,确认可用后才能复核。" : "需先由就业老师登记使用反馈。",
], ],
}; };
const [enabled, reason] = checks[action] || [false, "动作不可用。"]; const [enabled, reason] = checks[action] || [false, "动作不可用。"];
@@ -1229,9 +1229,9 @@ function closedLoopNodeDefinitions() {
id: e.demand.id, id: e.demand.id,
status: e.demand.status, status: e.demand.status,
owner: "企业导师", owner: "企业导师",
description: "企业提交真实岗位、技能、人数与授权信息,形成后续分析和共育项目的业务起点。", description: "企业提交岗位、技能、人数与授权信息,学校据此开展分析并安排共育项目。",
input: "岗位、技能、计划人数、授权编号", input: "岗位、技能、计划人数、授权编号",
output: "可追踪的企业需求版本", output: "带编号的企业需求版本",
complete: e.demand.status === "已提交", complete: e.demand.status === "已提交",
risk: false, risk: false,
relations: [e.demand.enterpriseId, e.demand.previousVersionId, e.recommendation.demandId], relations: [e.demand.enterpriseId, e.demand.previousVersionId, e.recommendation.demandId],
@@ -1269,7 +1269,7 @@ function closedLoopNodeDefinitions() {
id: e.recommendation.id, id: e.recommendation.id,
status: e.recommendation.status, status: e.recommendation.status,
owner: "专业负责人", owner: "专业负责人",
description: "专业负责人基于快照和企业需求采纳、暂缓或驳回建议,采纳后自动创建任务。", description: "专业负责人查看数据快照和企业需求后采纳、暂缓或驳回建议,采纳后自动创建任务。",
input: "分析结论、企业需求、课程差距", input: "分析结论、企业需求、课程差距",
output: "带理由的专业决策", output: "带理由的专业决策",
complete: e.recommendation.status === "已采纳", complete: e.recommendation.status === "已采纳",
@@ -1291,7 +1291,7 @@ function closedLoopNodeDefinitions() {
owner: e.task?.owner || "专业负责人", owner: e.task?.owner || "专业负责人",
description: "采纳专业建议后自动生成改进任务,保存负责人、期限、进度和验收历史。", description: "采纳专业建议后自动生成改进任务,保存负责人、期限、进度和验收历史。",
input: "已采纳建议与任务负责人", input: "已采纳建议与任务负责人",
output: "可执行、可验收的改进任务", output: "有负责人、期限和验收要求的任务",
reached: e.recommendation.status === "已采纳", reached: e.recommendation.status === "已采纳",
complete: Boolean(e.task), complete: Boolean(e.task),
risk: ["需整改", "已退回"].includes(e.task?.status), risk: ["需整改", "已退回"].includes(e.task?.status),
@@ -1400,7 +1400,7 @@ function closedLoopNodeDefinitions() {
status: e.report?.status || "未生成", status: e.report?.status || "未生成",
owner: "编制人 / 独立审批人", owner: "编制人 / 独立审批人",
description: "报告关联需求、快照、任务和证据,依次经过草稿、提交、独立审批和正式发布。", description: "报告关联需求、快照、任务和证据,依次经过草稿、提交、独立审批和正式发布。",
input: "验收通过的任务与冻结证据", input: "验收通过的任务与报告生成时登记的证据(不可追加)",
output: "可归档的正式报告版本", output: "可归档的正式报告版本",
complete: e.report?.status === "已发布", complete: e.report?.status === "已发布",
risk: e.report?.status === "已退回", risk: e.report?.status === "已退回",
@@ -1645,7 +1645,7 @@ function renderClosedLoopNodeDetail(node) {
</div>` </div>`
: ` : `
<div class="loop-node-action readonly"> <div class="loop-node-action readonly">
<span><strong>当前角色只读</strong><small>该节点由${safeText(node.owner)}负责,切换对应角色后可办理已解锁动作。</small></span> <span><strong>当前角色只读</strong><small>该节点由${safeText(node.owner)}负责;切换到对应角色后,可办理满足前置条件的动作。</small></span>
</div>`; </div>`;
document.getElementById("loopNodeDetail").innerHTML = ` document.getElementById("loopNodeDetail").innerHTML = `
<div class="loop-node-hero ${detailState}"> <div class="loop-node-hero ${detailState}">
@@ -1691,7 +1691,7 @@ function renderClosedLoopAction(action, nodes) {
<button data-loop-action="${action}" data-loop-action-node="${node.key}" ${availability.enabled ? "" : "disabled"}> <button data-loop-action="${action}" data-loop-action-node="${node.key}" ${availability.enabled ? "" : "disabled"}>
<i>${String(node.index + 1).padStart(2, "0")}</i> <i>${String(node.index + 1).padStart(2, "0")}</i>
<span><small>${node.title}</small><strong>${closedLoopActionCatalog[action].queueLabel}</strong><em>${availability.reason}</em></span> <span><small>${node.title}</small><strong>${closedLoopActionCatalog[action].queueLabel}</strong><em>${availability.reason}</em></span>
<b>${availability.enabled ? "办理" : "未解锁"}</b> <b>${availability.enabled ? "办理" : "条件未满足"}</b>
</button>`; </button>`;
} }
@@ -2164,9 +2164,9 @@ const reports = [
{ label: "现代服务类", value: 69 }, { label: "现代服务类", value: 69 },
], ],
actions: [ actions: [
{ priority: "P0", title: "推动11个专业完成高优技能缺口响应", detail: "由教务处牵头,4月底前形成课程调整或实训项目方案。" }, { priority: "P0", title: "推动11个专业处理高优技能缺口", detail: "由教务处牵头,4月底前提交课程调整或实训项目方案。" },
{ priority: "P1", title: "建设工业视觉与云原生两类校企共享实训", detail: "优先对接大华、数梦工场等已表达合作意向的企业。" }, { priority: "P1", title: "建设工业视觉与云原生两类校企共享实训", detail: "优先对接大华、数梦工场等已表达合作意向的企业。" },
{ priority: "P1", title: "建立企业需求季度确认机制", detail: "区分互联网招聘信号与合作企业正式确认需求,提升决策可信度。" }, { priority: "P1", title: "每季度请企业确认一次需求", detail: "把互联网招聘信息与合作企业确认的需求分开,避免混用。" },
], ],
}, },
{ {
@@ -2195,7 +2195,7 @@ const reports = [
], ],
findings: [ findings: [
{ title: "Java/Spring能力供需匹配良好", detail: "市场需求强度92%,课程覆盖86%,可继续保持项目化教学。", value: "差值6" }, { title: "Java/Spring能力供需匹配良好", detail: "市场需求强度92%,课程覆盖86%,可继续保持项目化教学。", value: "差值6" },
{ title: "Docker/K8s形成明显技能缺口", detail: "市场需求81%,课程覆盖仅32%,缺口达到49个百分点。", value: "-49" }, { title: "Docker/K8s技能缺口明显", detail: "市场需求81%,课程覆盖仅32%,相差49个百分点。", value: "-49" },
{ title: "AI辅助开发进入企业基础要求", detail: "69%的重点岗位提出相关要求,当前课程覆盖仅28%。", value: "-41" }, { title: "AI辅助开发进入企业基础要求", detail: "69%的重点岗位提出相关要求,当前课程覆盖仅28%。", value: "-41" },
], ],
bars: [ bars: [
@@ -2208,7 +2208,7 @@ const reports = [
actions: [ actions: [
{ priority: "P0", title: "强化云原生与容器化实训模块", detail: "在综合实训中覆盖Docker、Kubernetes、CI/CD和可观测性。" }, { priority: "P0", title: "强化云原生与容器化实训模块", detail: "在综合实训中覆盖Docker、Kubernetes、CI/CD和可观测性。" },
{ priority: "P1", title: "将AI辅助开发纳入软件工程实践", detail: "增加代码生成、测试辅助、安全审查和人工复核规范。" }, { priority: "P1", title: "将AI辅助开发纳入软件工程实践", detail: "增加代码生成、测试辅助、安全审查和人工复核规范。" },
{ priority: "P1", title: "联合企业建设真实交付项目", detail: "引入数梦工场、海康威视的工程任务和企业导师评价。" }, { priority: "P1", title: "联合企业建设交付项目", detail: "引入数梦工场、海康威视的工程任务和企业导师评价。" },
], ],
}, },
{ {
@@ -2227,7 +2227,7 @@ const reports = [
author: "信息工程学院", author: "信息工程学院",
roles: ["校级管理者", "学院负责人"], roles: ["校级管理者", "学院负责人"],
summary: summary:
"学院6个专业平均匹配度80.4分,软件技术、物联网应用技术表现较好。当前需要跨专业统筹云平台、数据工程和AI应用三类共享能力建设。", "学院6个专业平均匹配度80.4分,软件技术、物联网应用技术表现较好。云平台、数据工程和 AI 应用课程可由多个专业共用。",
metrics: [ metrics: [
{ label: "学院匹配度", value: "80.4", note: "较上期 +5.1" }, { label: "学院匹配度", value: "80.4", note: "较上期 +5.1" },
{ label: "覆盖专业", value: "6", note: "2个高匹配专业" }, { label: "覆盖专业", value: "6", note: "2个高匹配专业" },
@@ -2235,8 +2235,8 @@ const reports = [
{ label: "合作企业", value: "38", note: "本学期新增6家" }, { label: "合作企业", value: "38", note: "本学期新增6家" },
], ],
findings: [ findings: [
{ title: "共享技术底座课程重复建设", detail: "数据库、Linux和软件工程内容在多个专业重复,可建设学院共享模块。", value: "6专业" }, { title: "基础技术课程重复开设", detail: "数据库、Linux 和软件工程内容在多个专业重复,可由学院统一开设共用模块。", value: "6专业" },
{ title: "云平台能力成为共同短板", detail: "云部署、容器和运维能力在5个专业中均出现覆盖不足。", value: "5专业" }, { title: "5个专业都缺云平台课程内容", detail: "云部署、容器和运维内容在5个专业中均覆盖不足。", value: "5专业" },
{ title: "企业项目集中度偏高", detail: "前5家企业承担了61%的项目,需要扩展中型技术企业伙伴。", value: "61%" }, { title: "企业项目集中度偏高", detail: "前5家企业承担了61%的项目,需要扩展中型技术企业伙伴。", value: "61%" },
], ],
bars: [ bars: [
@@ -2247,8 +2247,8 @@ const reports = [
{ label: "计算机网络", value: 75 }, { label: "计算机网络", value: 75 },
], ],
actions: [ actions: [
{ priority: "P0", title: "建立学院共享工程实践课程群", detail: "统一云平台、数据库、DevOps基础能力,按专业配置差异化项目。" }, { priority: "P0", title: "开设学院共用工程实践课程", detail: "云平台、数据库和 DevOps 基础内容由学院共用,各专业再安排不同项目。" },
{ priority: "P1", title: "扩展8家中型技术企业合作", detail: "降低项目来源集中度,为不同专业提供多样化真实任务。" }, { priority: "P1", title: "扩展8家中型技术企业合作", detail: "减少项目对少数企业的依赖,为不同专业提供更多企业任务。" },
{ priority: "P1", title: "建立跨专业学生项目团队", detail: "围绕智能物联场景组织软件、数据和网络方向联合实训。" }, { priority: "P1", title: "建立跨专业学生项目团队", detail: "围绕智能物联场景组织软件、数据和网络方向联合实训。" },
], ],
}, },
@@ -2268,7 +2268,7 @@ const reports = [
author: "产教融合中心", author: "产教融合中心",
roles: ["校级管理者"], roles: ["校级管理者"],
summary: summary:
"杭州区域人才需求持续向智能制造、云计算、跨境电商和数字内容方向集中。全校识别23项重点技能缺口,其中8项需要在本学期形成明确响应。", "杭州区域人才需求持续向智能制造、云计算、跨境电商和数字内容方向集中。全校有23项重点技能缺口,其中8项需要在本学期安排课程或项目调整。",
metrics: [ metrics: [
{ label: "重点缺口", value: "23", note: "8项高优" }, { label: "重点缺口", value: "23", note: "8项高优" },
{ label: "关联专业", value: "11", note: "覆盖5个学院" }, { label: "关联专业", value: "11", note: "覆盖5个学院" },
@@ -2330,7 +2330,7 @@ const reports = [
{ label: "现代服务类", value: 88 }, { label: "现代服务类", value: 88 },
], ],
actions: [ actions: [
{ priority: "P1", title: "将真实项目成果纳入就业推荐材料", detail: "强化学生技能证据,提升企业对岗位胜任力的判断效率。" }, { priority: "P1", title: "将企业项目成果纳入就业推荐材料", detail: "用学生作品和企业评价说明其岗位能力。" },
{ priority: "P1", title: "建立分专业薪资预期指导", detail: "使用分位数而非平均数,为学生提供地域和岗位差异说明。" }, { priority: "P1", title: "建立分专业薪资预期指导", detail: "使用分位数而非平均数,为学生提供地域和岗位差异说明。" },
{ priority: "P2", title: "持续核验企业薪资数据完整性", detail: "对缺失和区间过宽的薪资记录降低统计权重。" }, { priority: "P2", title: "持续核验企业薪资数据完整性", detail: "对缺失和区间过宽的薪资记录降低统计权重。" },
], ],
@@ -2372,7 +2372,7 @@ const reports = [
], ],
actions: [ actions: [
{ priority: "P0", title: "补齐就业薪资缺失记录", detail: "由就业处在本期正式材料发布前完成字段确认。" }, { priority: "P0", title: "补齐就业薪资缺失记录", detail: "由就业处在本期正式材料发布前完成字段确认。" },
{ priority: "P1", title: "审核218个新增岗位名称", detail: "优先处理需求量前50的岗位,并沉淀别名规则。" }, { priority: "P1", title: "审核218个新增岗位名称", detail: "先处理需求量前50的岗位,并把确认后的别名加入规则表。" },
{ priority: "P2", title: "增加数据包服务期自动提醒", detail: "基础数据包到期前30天通知厂商和学校管理员。" }, { priority: "P2", title: "增加数据包服务期自动提醒", detail: "基础数据包到期前30天通知厂商和学校管理员。" },
], ],
}, },
@@ -2450,7 +2450,7 @@ const reports = [
{ label: "AI内容生产", value: 75 }, { label: "AI内容生产", value: 75 },
], ],
actions: [ actions: [
{ priority: "P0", title: "重构跨境电商平台运营课程", detail: "增加真实店铺、海外投放和合规履约任务。" }, { priority: "P0", title: "重构跨境电商平台运营课程", detail: "增加企业店铺运营、海外投放和合规履约任务。" },
{ priority: "P1", title: "增加AI营销内容生产工作流", detail: "纳入AI文案、图片、视频辅助生产与人工审核。" }, { priority: "P1", title: "增加AI营销内容生产工作流", detail: "纳入AI文案、图片、视频辅助生产与人工审核。" },
], ],
}, },
@@ -2487,7 +2487,7 @@ const reports = [
{ label: "文化创意类", value: 68 }, { label: "文化创意类", value: 68 },
], ],
actions: [ actions: [
{ priority: "P0", title: "建立周期性分析机制", detail: "从年度人工报告转向季度数据快照和任务跟踪。" }, { priority: "P0", title: "每季度更新一次分析", detail: "用季度数据快照和任务进展替代一年一次的人工报告。" },
{ priority: "P1", title: "完善岗位分类与技能词典", detail: "提高跨数据源岗位匹配和趋势比较的稳定性。" }, { priority: "P1", title: "完善岗位分类与技能词典", detail: "提高跨数据源岗位匹配和趋势比较的稳定性。" },
], ],
}, },
@@ -2505,7 +2505,7 @@ const professionReportCatalog = [
["新能源汽车技术", "智能制造学院", 83.1, "三电检测与智能诊断"], ["新能源汽车技术", "智能制造学院", 83.1, "三电检测与智能诊断"],
["汽车检测与维修技术", "智能制造学院", 74.9, "新能源汽车售后与诊断"], ["汽车检测与维修技术", "智能制造学院", 74.9, "新能源汽车售后与诊断"],
["跨境电子商务", "商贸旅游学院", 81.2, "海外投放与合规履约"], ["跨境电子商务", "商贸旅游学院", 81.2, "海外投放与合规履约"],
["国际商务", "商贸旅游学院", 73.6, "数字贸易与供应链协同"], ["国际商务", "商贸旅游学院", 73.6, "数字贸易与供应链协作"],
["市场营销", "商贸旅游学院", 72.8, "数据营销与用户增长"], ["市场营销", "商贸旅游学院", 72.8, "数据营销与用户增长"],
["现代物流管理", "商贸旅游学院", 78.1, "智慧物流与仓配优化"], ["现代物流管理", "商贸旅游学院", 78.1, "智慧物流与仓配优化"],
["酒店管理与数字化运营", "商贸旅游学院", 71.5, "收益管理与数字化服务"], ["酒店管理与数字化运营", "商贸旅游学院", 71.5, "收益管理与数字化服务"],
@@ -2545,7 +2545,7 @@ professionReportCatalog.forEach(([name, college, score, focus], index) => {
updated: `2026-03-${String(18 - (index % 8)).padStart(2, "0")}`, updated: `2026-03-${String(18 - (index % 8)).padStart(2, "0")}`,
author: college, author: college,
roles: ["校级管理者"], roles: ["校级管理者"],
summary: `${name}专业供需匹配度${score}分。当前培养基础总体稳定,${focus}是下一阶段专业建设和校企协同的重点方向。`, summary: `${name}专业供需匹配度${score}分。当前课程基础总体稳定,下一阶段应优先补充${focus}相关课程和企业项目。`,
metrics: [ metrics: [
{ label: "专业匹配度", value: String(score), note: score >= 80 ? "高匹配" : score >= 74 ? "保持关注" : "需要改进" }, { label: "专业匹配度", value: String(score), note: score >= 80 ? "高匹配" : score >= 74 ? "保持关注" : "需要改进" },
{ label: "对口岗位", value: demand.toLocaleString("zh-CN"), note: "近90天有效样本" }, { label: "对口岗位", value: demand.toLocaleString("zh-CN"), note: "近90天有效样本" },
@@ -2554,8 +2554,8 @@ professionReportCatalog.forEach(([name, college, score, focus], index) => {
], ],
findings: [ findings: [
{ title: `${focus}需求持续增长`, detail: `重点企业正在将相关能力纳入岗位要求,近90天需求信号保持上升。`, value: `+${16 + (index % 23)}%` }, { title: `${focus}需求持续增长`, detail: `重点企业正在将相关能力纳入岗位要求,近90天需求信号保持上升。`, value: `+${16 + (index % 23)}%` },
{ title: "课程实践与企业任务仍有差距", detail: "现有课程具备基础知识覆盖,但真实场景、工具链和交付评价需要加强。", value: `-${gap}` }, { title: "课程实践与企业任务仍有差距", detail: "现有课程已覆盖基础知识,但企业场景、工具链和交付评价练习仍然不足。", value: `-${gap}` },
{ title: "校企合作具备扩展条件", detail: `已识别${companyCount}家高匹配企业,可围绕项目实训和企业导师形成合作。`, value: `${companyCount}家` }, { title: "可以联系更多合作企业", detail: `已有${companyCount}家企业与该专业较匹配,可讨论项目实训和企业导师安排。`, value: `${companyCount}家` },
], ],
bars: [ bars: [
{ label: "专业基础能力", value: Math.min(95, coverage + 8) }, { label: "专业基础能力", value: Math.min(95, coverage + 8) },
@@ -2565,9 +2565,9 @@ professionReportCatalog.forEach(([name, college, score, focus], index) => {
{ label: "企业项目交付", value: Math.max(50, coverage - 12) }, { label: "企业项目交付", value: Math.max(50, coverage - 12) },
], ],
actions: [ actions: [
{ priority: "P0", title: `强化${focus}教学模块`, detail: "引入企业真实任务,明确工具链、过程产物和验收标准。" }, { priority: "P0", title: `强化${focus}教学模块`, detail: "引入企业任务,明确使用的工具、过程产物和验收标准。" },
{ priority: "P1", title: "邀请企业导师参与课程评审", detail: `优先对接已识别的${companyCount}家潜力企业,核验岗位技能与课程映射。` }, { priority: "P1", title: "邀请企业导师参与课程评审", detail: `优先对接已识别的${companyCount}家潜力企业,核验岗位技能与课程映射。` },
{ priority: "P1", title: "建立学生能力证据档案", detail: "将项目作品、企业评价和技能达成情况纳入就业推荐材料。" }, { priority: "P1", title: "整理学生项目材料", detail: "把项目作品、企业评价和技能考核结果放入就业推荐材料。" },
], ],
}); });
}); });
@@ -2593,7 +2593,7 @@ professionReportCatalog.forEach(([name, college, score, focus], index) => {
updated: `2026-03-${18 - index}`, updated: `2026-03-${18 - index}`,
author: name, author: name,
roles: ["校级管理者"], roles: ["校级管理者"],
summary: `${name}整体供需表现保持稳定,${focus}是跨专业共享能力建设的主要方向。`, summary: `${name}整体供需表现稳定。多个专业都需要${focus}相关课程,可由学院统一开设部分内容。`,
metrics: [ metrics: [
{ label: "学院匹配度", value: String(76.8 + index * 1.3), note: "较上期持续提升" }, { label: "学院匹配度", value: String(76.8 + index * 1.3), note: "较上期持续提升" },
{ label: "覆盖专业", value: scope.replace("个专业", ""), note: "全部纳入分析" }, { label: "覆盖专业", value: scope.replace("个专业", ""), note: "全部纳入分析" },
@@ -2601,9 +2601,9 @@ professionReportCatalog.forEach(([name, college, score, focus], index) => {
{ label: "合作企业", value: String(26 + index * 7), note: "持续扩展" }, { label: "合作企业", value: String(26 + index * 7), note: "持续扩展" },
], ],
findings: [ findings: [
{ title: `${focus}形成共同需求`, detail: "多个专业出现相近技能缺口,适合建设学院共享课程或实训平台。", value: "高关联" }, { title: `多个专业都需要${focus}`, detail: "多个专业的技能缺口相近,适合共用学院课程或实训环境。", value: "高关联" },
{ title: "企业项目分布仍需优化", detail: "建议降低头部企业集中度,引入更多中型和专精特新企业。", value: "待改善" }, { title: "企业项目分布仍需优化", detail: "建议降低头部企业集中度,引入更多中型和专精特新企业。", value: "待改善" },
{ title: "建议执行进入跟踪阶段", detail: "重点事项已明确负责人和周期,可纳入学院改进任务闭环。", value: "可执行" }, { title: "建议可以开始执行", detail: "重点事项已有负责人和期限,可加入学院任务清单继续跟进。", value: "可执行" },
], ],
bars: [ bars: [
{ label: "专业匹配", value: 80 + index }, { label: "专业匹配", value: 80 + index },
@@ -2612,9 +2612,9 @@ professionReportCatalog.forEach(([name, college, score, focus], index) => {
{ label: "项目实践", value: 70 + index * 2 }, { label: "项目实践", value: 70 + index * 2 },
], ],
actions: [ actions: [
{ priority: "P0", title: `建设${focus}共享模块`, detail: "明确学院统一底座和各专业差异化应用场景。" }, { priority: "P0", title: `建设${focus}共享模块`, detail: "列出学院共用内容,以及各专业需要单独设置的练习。" },
{ priority: "P1", title: "形成企业合作伙伴分层清单", detail: "区分课程共建、项目实训、实习就业和企业导师资源。" }, { priority: "P1", title: "按合作类型整理企业名单", detail: "分别列出可参与课程共建、项目实训、实习就业和企业导师工作的企业。" },
{ priority: "P1", title: "按月跟踪专业改进任务", detail: "对逾期、未响应和缺少证据的任务进行校院协同督办。" }, { priority: "P1", title: "按月检查专业改进任务", detail: "校级和学院共同跟进逾期、未响应或缺少材料的任务。" },
], ],
}); });
}); });
@@ -2634,7 +2634,7 @@ const reportDataProfiles = {
}, },
college: { college: {
label: "学院专业建设分析", label: "学院专业建设分析",
topics: ["专业结构对比", "共享能力分析", "培养成效验证", "企业协同机会"], topics: ["专业结构对比", "共用课程分析", "培养结果检查", "企业合作机会"],
dependencies: [ dependencies: [
{ sourceId: "regional-jobs", requirement: "required", purpose: "学院相关岗位与技能趋势" }, { sourceId: "regional-jobs", requirement: "required", purpose: "学院相关岗位与技能趋势" },
{ sourceId: "salary-company", requirement: "optional", purpose: "专业群薪资和企业结构参考" }, { sourceId: "salary-company", requirement: "optional", purpose: "专业群薪资和企业结构参考" },
@@ -2646,14 +2646,14 @@ const reportDataProfiles = {
}, },
profession: { profession: {
label: "专业人才需求分析", label: "专业人才需求分析",
topics: ["岗位技能需求", "课程能力映射", "学生达成验证", "企业需求复核"], topics: ["岗位技能需求", "课程技能对应", "学生学习结果", "企业需求复核"],
dependencies: [ dependencies: [
{ sourceId: "regional-jobs", requirement: "required", purpose: "对口岗位、技能频次与需求变化" }, { sourceId: "regional-jobs", requirement: "required", purpose: "对口岗位、技能频次与需求变化" },
{ sourceId: "salary-company", requirement: "optional", purpose: "区域同岗位薪资竞争力" }, { sourceId: "salary-company", requirement: "optional", purpose: "区域同岗位薪资竞争力" },
{ sourceId: "internship", requirement: "optional", purpose: "学生实践岗位与企业评价" }, { sourceId: "internship", requirement: "optional", purpose: "学生实践岗位与企业评价" },
{ sourceId: "employment", requirement: "optional", purpose: "毕业去向和岗位匹配验证" }, { sourceId: "employment", requirement: "optional", purpose: "毕业去向和岗位匹配验证" },
{ sourceId: "curriculum", requirement: "required", purpose: "课程标准、学时与技能覆盖" }, { sourceId: "curriculum", requirement: "required", purpose: "课程标准、学时与技能覆盖" },
{ sourceId: "enterprise-demand", requirement: "required", purpose: "真实企业需求与合作意向确认" }, { sourceId: "enterprise-demand", requirement: "required", purpose: "企业确认的人才需求与合作意向" },
], ],
}, },
industry: { industry: {
@@ -2716,7 +2716,7 @@ const dataGapCatalog = [
levelLabel: "需补数", levelLabel: "需补数",
title: "就业薪资与缺失原因未完整提供", title: "就业薪资与缺失原因未完整提供",
drawerTitle: "就业系统薪资字段缺失", drawerTitle: "就业系统薪资字段缺失",
drawerLevel: "阻断发布", drawerLevel: "当前不能发布",
amount: "86 条记录 · 当前字段完整率 91.2%", amount: "86 条记录 · 当前字段完整率 91.2%",
affected: "86 条记录 · 电子商务专业 41 条、现代服务类专业 45 条", affected: "86 条记录 · 电子商务专业 41 条、现代服务类专业 45 条",
fields: ["employment_salary", "salary_period", "missing_reason"], fields: ["employment_salary", "salary_period", "missing_reason"],
@@ -2856,7 +2856,7 @@ function applyRole(role, options = {}) {
document.getElementById("dataPageTitle").textContent = isDataAdministrator ? "学校数据运维中心" : "数据资产与质量"; document.getElementById("dataPageTitle").textContent = isDataAdministrator ? "学校数据运维中心" : "数据资产与质量";
document.getElementById("dataPageDescription").textContent = isDataAdministrator document.getElementById("dataPageDescription").textContent = isDataAdministrator
? "管理学校数据源、初次导入、增量更新、字段契约、质量问题、版本与审计。" ? "管理学校数据源、初次导入、增量更新、字段契约、质量问题、版本与审计。"
: "区分厂商基础数据包、学校自有数据与企业授权数据,所有分析结论均可追溯。"; : "区分厂商基础数据包、学校自有数据与企业授权数据,每项分析结论都注明数据来源。";
document.getElementById("syncAllButtonText").textContent = isDataAdministrator ? "新建更新任务" : "同步全部数据"; document.getElementById("syncAllButtonText").textContent = isDataAdministrator ? "新建更新任务" : "同步全部数据";
document.getElementById("schoolNav").hidden = isPlatformRole; document.getElementById("schoolNav").hidden = isPlatformRole;
@@ -2888,8 +2888,8 @@ function applyRole(role, options = {}) {
}; };
if (role === "企业导师") { if (role === "企业导师") {
collaborationHeading.textContent = "企业协同工作台"; collaborationHeading.textContent = "企业合作工作台";
collaborationDescription.textContent = "提交真实岗位与技能需求,参与课程共建并评价学生项目成果。"; collaborationDescription.textContent = "提交岗位与技能需求,参与课程共建并评价学生项目成果。";
demandButton.innerHTML = `${svgIcon("file")}提交企业需求`; demandButton.innerHTML = `${svgIcon("file")}提交企业需求`;
projectButton.innerHTML = `${svgIcon("course")}发起共建项目`; projectButton.innerHTML = `${svgIcon("course")}发起共建项目`;
renderCollaborationStats([ renderCollaborationStats([
@@ -2899,24 +2899,24 @@ function applyRole(role, options = {}) {
{ label: "参与学生", value: "86", unit: "人", note: "企业评价 4.7 / 5" }, { label: "参与学生", value: "86", unit: "人", note: "企业评价 4.7 / 5" },
]); ]);
} else if (role === "学院负责人" || role === "专业负责人") { } else if (role === "学院负责人" || role === "专业负责人") {
collaborationHeading.textContent = "学院校企协同"; collaborationHeading.textContent = "学院校企合作";
collaborationDescription.textContent = "围绕本院专业对接企业需求,推进课程共建、实训与企业导师协作。"; collaborationDescription.textContent = "围绕本院专业对接企业需求,推进课程共建、实训与企业导师协作。";
demandButton.innerHTML = `${svgIcon("file")}邀请企业调研`; demandButton.innerHTML = `${svgIcon("file")}邀请企业调研`;
projectButton.innerHTML = `${svgIcon("course")}新建协同项目`; projectButton.innerHTML = `${svgIcon("course")}新建合作项目`;
renderCollaborationStats([ renderCollaborationStats([
{ label: "本院合作企业", value: "38", unit: "家", note: "本学期新增 6 家" }, { label: "本院合作企业", value: "38", unit: "家", note: "本学期新增 6 家" },
{ label: "本院协同项目", value: "8", unit: "个", note: "3 个进行中" }, { label: "本院合作项目", value: "8", unit: "个", note: "3 个进行中" },
{ label: "企业导师", value: "21", unit: "人", note: "覆盖 6 个专业" }, { label: "企业导师", value: "21", unit: "人", note: "覆盖 6 个专业" },
{ label: "学生参与", value: "386", unit: "人次", note: "满意度 94%" }, { label: "学生参与", value: "386", unit: "人次", note: "满意度 94%" },
]); ]);
} else { } else {
collaborationHeading.textContent = "校企协同中心"; collaborationHeading.textContent = "校企合作";
collaborationDescription.textContent = "把产业需求转化为可执行的课程、项目与人才共育计划。"; collaborationDescription.textContent = "根据企业需求安排课程共建、合作项目和人才培养计划。";
demandButton.innerHTML = `${svgIcon("file")}发起需求调研`; demandButton.innerHTML = `${svgIcon("file")}发起需求调研`;
projectButton.innerHTML = `${svgIcon("course")}新建协同项目`; projectButton.innerHTML = `${svgIcon("course")}新建合作项目`;
renderCollaborationStats([ renderCollaborationStats([
{ label: "在库合作企业", value: "126", unit: "家", note: "本学期新增 18 家" }, { label: "在库合作企业", value: "126", unit: "家", note: "本学期新增 18 家" },
{ label: "本学期协同项目", value: "24", unit: "个", note: "8 个进行中" }, { label: "本学期合作项目", value: "24", unit: "个", note: "8 个进行中" },
{ label: "企业导师", value: "68", unit: "人", note: "覆盖 17 个专业" }, { label: "企业导师", value: "68", unit: "人", note: "覆盖 17 个专业" },
{ label: "学生参与", value: "1,284", unit: "人次", note: "满意度 92%" }, { label: "学生参与", value: "1,284", unit: "人次", note: "满意度 92%" },
]); ]);
@@ -3238,7 +3238,7 @@ function renderProfessionJobsView(data) {
</div> </div>
</article> </article>
</div> </div>
${professionEvidenceNote("证据 PRO-JOB-301", `岗位流向基于区域招聘基础包去重岗位、学校近三届就业去向及合作企业确认记录。互联网岗位反映需求信号,不等于实际录用人数。`)} ${professionEvidenceNote("证据 PRO-JOB-301", `岗位流向使用区域招聘基础包中的去重岗位、学校近三届就业去向及合作企业确认记录计算。互联网岗位反映需求信号,不等于实际录用人数。`)}
`; `;
} }
@@ -3280,7 +3280,7 @@ function renderProfessionSalaryView(data) {
<article class="panel profession-detail-panel"> <article class="panel profession-detail-panel">
<div class="panel-header"><div><span class="panel-kicker">影响因素</span><h2>技能证据与起薪</h2></div></div> <div class="panel-header"><div><span class="panel-kicker">影响因素</span><h2>技能证据与起薪</h2></div></div>
<div class="salary-factor-list"> <div class="salary-factor-list">
<span><b>+14%</b><strong>企业真实项目经历</strong></span> <span><b>+14%</b><strong>企业项目经历</strong></span>
<span><b>+9%</b><strong>高质量作品集</strong></span> <span><b>+9%</b><strong>高质量作品集</strong></span>
<span><b>+7%</b><strong>企业导师评价</strong></span> <span><b>+7%</b><strong>企业导师评价</strong></span>
</div> </div>
@@ -3567,7 +3567,7 @@ function renderLineageTopicNode(topic, index) {
<div class="lineage-topic-node"> <div class="lineage-topic-node">
<span>${String(index + 1).padStart(2, "0")}</span> <span>${String(index + 1).padStart(2, "0")}</span>
<strong>${topic}</strong> <strong>${topic}</strong>
<small>统一口径计算 · 保留证据定位</small> <small>按同一统计口径计算 · 可查看数据来源</small>
</div> </div>
`; `;
} }
@@ -3641,7 +3641,7 @@ function renderReportLineageCanvas(report) {
return ` return `
<div class="lineage-stage-grid report-direction"> <div class="lineage-stage-grid report-direction">
${renderLineageStage("数据资产", `${visibleDependencies.length} / ${profile.dependencies.length} 项`, "sources", sourceNodes)} ${renderLineageStage("数据资产", `${visibleDependencies.length} / ${profile.dependencies.length} 项`, "sources", sourceNodes)}
${lineageConnector("形成指标")} ${lineageConnector("计算指标")}
${renderLineageStage("指标 / 分析主题", `${profile.topics.length} 类`, "topics", topicNodes)} ${renderLineageStage("指标 / 分析主题", `${profile.topics.length} 类`, "topics", topicNodes)}
${lineageConnector("生成报告")} ${lineageConnector("生成报告")}
${renderLineageStage("目标报告", "1 份", "reports", renderLineageReportNode(report, readableIds))} ${renderLineageStage("目标报告", "1 份", "reports", renderLineageReportNode(report, readableIds))}
@@ -3667,10 +3667,10 @@ function renderSourceLineageCanvas(source) {
return ` return `
<div class="lineage-stage-grid source-direction"> <div class="lineage-stage-grid source-direction">
${renderLineageStage("选中数据", "1 项", "sources", renderLineageSourceNode(source, null, true))} ${renderLineageStage("选中数据", "1 项", "sources", renderLineageSourceNode(source, null, true))}
${lineageConnector("支撑分析")} ${lineageConnector("用于分析")}
${renderLineageStage("可形成的分析", `${topics.length} 类`, "topics", topics.map(renderLineageTopicNode).join(""))} ${renderLineageStage("可做的分析", `${topics.length} 类`, "topics", topics.map(renderLineageTopicNode).join(""))}
${lineageConnector("支撑报告")} ${lineageConnector("用于报告")}
${renderLineageStage("可形成的报告", `${visibleReports.length} 份`, "reports", reportNodes)} ${renderLineageStage("使用该数据的报告", `${visibleReports.length} 份`, "reports", reportNodes)}
</div> </div>
`; `;
} }
@@ -3698,7 +3698,7 @@ function renderLineageSummary(report, source) {
const gaps = gapsForSource(source.id); const gaps = gapsForSource(source.id);
summary.innerHTML = [ summary.innerHTML = [
lineageSummaryCard("当前数据", source.categoryLabel, source.version), lineageSummaryCard("当前数据", source.categoryLabel, source.version),
lineageSummaryCard("支撑报告", `${sourceReports.length} 份`, `${reportsGroupedByType(sourceReports).size} 类报告`), lineageSummaryCard("使用该数据的报告", `${sourceReports.length} 份`, `${reportsGroupedByType(sourceReports).size} 类报告`),
lineageSummaryCard("当前质量", source.quality, `${source.records} 条有效记录`), lineageSummaryCard("当前质量", source.quality, `${source.records} 条有效记录`),
lineageSummaryCard("数据缺口", `${gaps.length} 项`, gaps.length ? "已定位责任人与时限" : "当前无数据缺口", gaps.length ? "warning" : "ready"), lineageSummaryCard("数据缺口", `${gaps.length} 项`, gaps.length ? "已定位责任人与时限" : "当前无数据缺口", gaps.length ? "warning" : "ready"),
].join(""); ].join("");
@@ -3761,7 +3761,7 @@ function renderDataReportLineage() {
button.setAttribute("aria-pressed", String(selected)); button.setAttribute("aria-pressed", String(selected));
}); });
document.getElementById("dataLineageSelectorLabel").textContent = mode === "report" ? "选择报告" : "选择数据"; document.getElementById("dataLineageSelectorLabel").textContent = mode === "report" ? "选择报告" : "选择数据";
selector.setAttribute("aria-label", mode === "report" ? "选择要追溯的报告" : "选择要反查的数据"); selector.setAttribute("aria-label", mode === "report" ? "选择报告查看所需数据" : "选择数据查看使用它的报告");
selector.innerHTML = selector.innerHTML =
mode === "report" mode === "report"
? reports ? reports
@@ -3841,7 +3841,7 @@ function renderDataOpsOverview(source) {
<article class="data-ops-highlight"> <article class="data-ops-highlight">
<span>本次更新内容</span> <span>本次更新内容</span>
<strong>${source.changeSummary}</strong> <strong>${source.changeSummary}</strong>
<p>更新采用暂存校验机制,未通过质量门槛的数据进入隔离区,不会覆盖当前已发布版本。</p> <p>更新数据先放入暂存区检查;不满足最低质量要求的数据进入隔离区,不会覆盖当前已发布版本。</p>
</article> </article>
<div class="data-ops-two-column"> <div class="data-ops-two-column">
<article class="data-ops-card"> <article class="data-ops-card">
@@ -3880,7 +3880,7 @@ function renderDataOpsRequirements(source) {
<div class="data-requirement-steps"> <div class="data-requirement-steps">
<span><b>01</b><strong>准备文件或连接</strong><small>支持标准模板导入,也可按更新频率配置 API、数据库视图或 SFTP。</small></span> <span><b>01</b><strong>准备文件或连接</strong><small>支持标准模板导入,也可按更新频率配置 API、数据库视图或 SFTP。</small></span>
<span><b>02</b><strong>字段映射与样本预检</strong><small>确认主键、必填字段、代码字典和敏感字段处理规则。</small></span> <span><b>02</b><strong>字段映射与样本预检</strong><small>确认主键、必填字段、代码字典和敏感字段处理规则。</small></span>
<span><b>03</b><strong>暂存与质量校验</strong><small>先写入暂存区,阻断性错误不覆盖生产版本。</small></span> <span><b>03</b><strong>暂存与质量校验</strong><small>先写入暂存区,发现严重错误时不更新生产版本。</small></span>
<span><b>04</b><strong>审批发布与留痕</strong><small>数据管理员确认质量和授权后,生成不可变版本并进入分析。</small></span> <span><b>04</b><strong>审批发布与留痕</strong><small>数据管理员确认质量和授权后,生成不可变版本并进入分析。</small></span>
</div> </div>
</article> </article>
@@ -3893,7 +3893,7 @@ function renderDataOpsRequirements(source) {
<table class="data-ops-table"> <table class="data-ops-table">
<thead><tr><th>校验项</th><th>门槛</th><th>失败处理</th></tr></thead> <thead><tr><th>校验项</th><th>门槛</th><th>失败处理</th></tr></thead>
<tbody> <tbody>
<tr><td>主键唯一性</td><td>100%</td><td>整批阻断,下载冲突明细</td></tr> <tr><td>主键唯一性</td><td>100%</td><td>整批不发布,可下载冲突明细</td></tr>
<tr><td>必填完整性</td><td>≥ 95%</td><td>进入隔离区,修复后重试</td></tr> <tr><td>必填完整性</td><td>≥ 95%</td><td>进入隔离区,修复后重试</td></tr>
<tr><td>代码与日期合法性</td><td>≥ 98%</td><td>错误记录不进入分析</td></tr> <tr><td>代码与日期合法性</td><td>≥ 98%</td><td>错误记录不进入分析</td></tr>
<tr><td>综合质量</td><td>${source.threshold}</td><td>低于阈值不得发布</td></tr> <tr><td>综合质量</td><td>${source.threshold}</td><td>低于阈值不得发布</td></tr>
@@ -3925,7 +3925,7 @@ function renderDataOpsHistory(source) {
</div> </div>
<article class="data-ops-card"> <article class="data-ops-card">
<h3>失败处理策略</h3> <h3>失败处理策略</h3>
<p>网络失败从检查点自动重试 3 次;数据错误进入隔离区;主键冲突、授权缺失和 Schema 不兼容将整批阻断。历史已发布版本不原地覆盖。</p> <p>网络失败从检查点自动重试 3 次;数据错误进入隔离区;出现主键冲突、授权缺失或 Schema 不兼容时,整批数据不发布。历史已发布版本不直接覆盖。</p>
</article> </article>
`; `;
} }
@@ -3966,7 +3966,7 @@ function renderDataOpsUsage() {
<div><span>SHA校验<strong>${safeText(e.receipt.receivedSha256 || e.receipt.expectedSha256)}</strong></span><span>交付包记录数<strong>${e.receipt.receivedRecords.toLocaleString("zh-CN")} / ${e.receipt.expectedRecords.toLocaleString("zh-CN")}</strong></span><span>分析快照<strong>${e.snapshot.id} · ${e.snapshot.checkedRecords.toLocaleString("zh-CN")}条</strong></span></div> <div><span>SHA校验<strong>${safeText(e.receipt.receivedSha256 || e.receipt.expectedSha256)}</strong></span><span>交付包记录数<strong>${e.receipt.receivedRecords.toLocaleString("zh-CN")} / ${e.receipt.expectedRecords.toLocaleString("zh-CN")}</strong></span><span>分析快照<strong>${e.snapshot.id} · ${e.snapshot.checkedRecords.toLocaleString("zh-CN")}条</strong></span></div>
</div> </div>
<article class="data-ops-card"> <article class="data-ops-card">
<h3>业务支撑关系</h3> <h3>业务使用情况</h3>
<div class="data-impact-grid"> <div class="data-impact-grid">
<span>报告<strong>${e.report?.id || "待生成"}</strong></span> <span>报告<strong>${e.report?.id || "待生成"}</strong></span>
<span>项目<strong>${e.project?.id || "待创建"}</strong></span> <span>项目<strong>${e.project?.id || "待创建"}</strong></span>
@@ -4069,7 +4069,7 @@ function updateDataOpsDrawer() {
if (dataOpsState.context === "batch") { if (dataOpsState.context === "batch") {
document.getElementById("dataOpsKicker").textContent = "DATA UPDATE CENTER"; document.getElementById("dataOpsKicker").textContent = "DATA UPDATE CENTER";
document.getElementById("dataOpsTitle").textContent = "数据更新任务中心"; document.getElementById("dataOpsTitle").textContent = "数据更新任务中心";
document.getElementById("dataOpsDescription").textContent = "先确认业务截止日期、变更内容和质量门槛,再创建可追踪的更新任务。"; document.getElementById("dataOpsDescription").textContent = "先确认业务截止日期、变更内容和最低质量要求,再创建带编号的更新任务。";
content.innerHTML = ` content.innerHTML = `
<div class="batch-update-summary">${dataOpsStat("待更新", "2 个来源", "1个自动调度 · 1个人工导入")}${dataOpsStat("运行正常", "4 个来源", "最近24小时无失败")}${dataOpsStat("隔离记录", "86 条", "未进入生产版本")}</div> <div class="batch-update-summary">${dataOpsStat("待更新", "2 个来源", "1个自动调度 · 1个人工导入")}${dataOpsStat("运行正常", "4 个来源", "最近24小时无失败")}${dataOpsStat("隔离记录", "86 条", "未进入生产版本")}</div>
<article class="data-ops-card"> <article class="data-ops-card">
@@ -4106,7 +4106,7 @@ function updateDataOpsDrawer() {
if (dataOpsState.context === "authorization") { if (dataOpsState.context === "authorization") {
document.getElementById("dataOpsKicker").textContent = "DATA AUTHORIZATION"; document.getElementById("dataOpsKicker").textContent = "DATA AUTHORIZATION";
document.getElementById("dataOpsTitle").textContent = "数据权属与授权中心"; document.getElementById("dataOpsTitle").textContent = "数据权属与授权中心";
document.getElementById("dataOpsDescription").textContent = "统一管理用途、可见范围、服务期限、撤权和审计要求。"; document.getElementById("dataOpsDescription").textContent = "设置数据用途、可见范围、服务期限、撤权方式和操作记录要求。";
content.innerHTML = renderAuthorizationOverview(); content.innerHTML = renderAuthorizationOverview();
footer.innerHTML = `<button class="button secondary" data-data-ops-close>关闭</button><button class="button primary" data-data-ops-result="授权台账已导出并写入审计日志">导出授权台账</button>`; footer.innerHTML = `<button class="button secondary" data-data-ops-close>关闭</button><button class="button primary" data-data-ops-result="授权台账已导出并写入审计日志">导出授权台账</button>`;
return; return;
@@ -4195,7 +4195,7 @@ function openWorkspaceDetail(kind, value = "") {
description: `${task.profession} · 来源:${task.source}`, description: `${task.profession} · 来源:${task.source}`,
content: ` content: `
<div class="workspace-metric-grid">${workspaceMetric("负责人", task.owner, "主责")}${workspaceMetric("截止日期", task.due, task.statusText)}${workspaceMetric("当前进度", `${task.progress}%`, "自动汇总")}</div> <div class="workspace-metric-grid">${workspaceMetric("负责人", task.owner, "主责")}${workspaceMetric("截止日期", task.due, task.statusText)}${workspaceMetric("当前进度", `${task.progress}%`, "自动汇总")}</div>
<article class="workspace-detail-card"><h3>任务目标</h3><p>将分析建议转化为课程、项目或校企协同调整,并以正式方案、企业确认和学生达成证据作为验收依据。</p></article> <article class="workspace-detail-card"><h3>任务目标</h3><p>根据分析建议调整课程、项目或企业合作安排,并用正式方案、企业确认和学生考核结果验收。</p></article>
<article class="workspace-detail-card"><h3>进展记录</h3><div class="workspace-log-list">${loopTask ? loopTask.progressLogs.map((item) => `<span><strong>${safeText(item.detail)}</strong><small>${safeText(item.operator)} · ${safeText(item.at)} · 进度 ${item.progress}%</small></span>`).join("") : `<span><strong>完成现状与差距复核</strong><small>李雯 · 2026-03-18 16:20</small></span><span><strong>企业导师已确认技能清单</strong><small>陈凯 · 2026-03-20 10:42</small></span><span><strong>课程调整方案进入教研室评审</strong><small>系统 · 今天 08:30</small></span>`}</div></article> <article class="workspace-detail-card"><h3>进展记录</h3><div class="workspace-log-list">${loopTask ? loopTask.progressLogs.map((item) => `<span><strong>${safeText(item.detail)}</strong><small>${safeText(item.operator)} · ${safeText(item.at)} · 进度 ${item.progress}%</small></span>`).join("") : `<span><strong>完成现状与差距复核</strong><small>李雯 · 2026-03-18 16:20</small></span><span><strong>企业导师已确认技能清单</strong><small>陈凯 · 2026-03-20 10:42</small></span><span><strong>课程调整方案进入教研室评审</strong><small>系统 · 今天 08:30</small></span>`}</div></article>
<article class="workspace-detail-card"><h3>验收要求</h3><div class="workspace-evidence-list"><span>课程或项目方案<strong>${loopTask && closedLoopState.entities.evidences.length ? "已提交" : "必需"}</strong></span><span>企业确认回执<strong>${closedLoopState.entities.evaluation ? closedLoopState.entities.evaluation.result : "必需"}</strong></span><span>校级验收<strong>${loopTask?.status || "待执行"}</strong></span></div>${loopTask ? `<button class="button primary loop-inline-action" data-loop-action="evidence">提交阶段进展与证据</button>` : ""}</article>`, <article class="workspace-detail-card"><h3>验收要求</h3><div class="workspace-evidence-list"><span>课程或项目方案<strong>${loopTask && closedLoopState.entities.evidences.length ? "已提交" : "必需"}</strong></span><span>企业确认回执<strong>${closedLoopState.entities.evaluation ? closedLoopState.entities.evaluation.result : "必需"}</strong></span><span>校级验收<strong>${loopTask?.status || "待执行"}</strong></span></div>${loopTask ? `<button class="button primary loop-inline-action" data-loop-action="evidence">提交阶段进展与证据</button>` : ""}</article>`,
primary: loopTask ? "关闭详情" : "提交阶段进展", primary: loopTask ? "关闭详情" : "提交阶段进展",
@@ -4223,7 +4223,7 @@ function openWorkspaceDetail(kind, value = "") {
description: `${partner.industry} · 综合匹配度 ${partner.match}%`, description: `${partner.industry} · 综合匹配度 ${partner.match}%`,
content: ` content: `
<article class="workspace-detail-card"><h3>推荐依据</h3><p>${partner.reason}</p><div class="workspace-tag-row">${partner.tags.map((tag) => `<span>${tag}</span>`).join("")}</div></article> <article class="workspace-detail-card"><h3>推荐依据</h3><p>${partner.reason}</p><div class="workspace-tag-row">${partner.tags.map((tag) => `<span>${tag}</span>`).join("")}</div></article>
<article class="workspace-detail-card"><h3>对接安排</h3><div class="workspace-form-grid"><label><span>校内负责人</span><input value="产教融合中心 · 王健"></label><label><span>建议时间</span><input type="date" value="2026-04-15"></label><label class="full"><span>沟通议题</span><textarea rows="4">岗位技能确认、课程共建、真实项目进课堂、企业导师与学生实习安排。</textarea></label></div></article>`, <article class="workspace-detail-card"><h3>对接安排</h3><div class="workspace-form-grid"><label><span>校内负责人</span><input value="产教融合中心 · 王健"></label><label><span>建议时间</span><input type="date" value="2026-04-15"></label><label class="full"><span>沟通议题</span><textarea rows="4">岗位技能确认、课程共建、企业项目进课堂、企业导师与学生实习安排。</textarea></label></div></article>`,
primary: "创建对接事项", primary: "创建对接事项",
}; };
}, },
@@ -4238,14 +4238,14 @@ function openWorkspaceDetail(kind, value = "") {
kicker: "ORGANIZATION SCOPE", kicker: "ORGANIZATION SCOPE",
title: "组织与数据范围", title: "组织与数据范围",
description: "根据账号角色切换组织,数据权限同步变化。", description: "根据账号角色切换组织,数据权限同步变化。",
content: `<div class="organization-list"><button class="active"><span class="tenant-logo">杭</span><span><strong>杭州科技职业技术学院</strong><small>校级管理者 · 全校32个专业</small></span><em>当前</em></button><button><span class="tenant-logo blue">信</span><span><strong>信息工程学院</strong><small>学院负责人 · 6个专业</small></span><em>可进入</em></button><button><span class="tenant-logo amber">企</span><span><strong>海康威视协同空间</strong><small>企业导师 · 3个共建项目</small></span><em>可进入</em></button></div><article class="workspace-detail-card"><h3>权限说明</h3><p>组织切换只改变业务范围,不改变底层租户隔离。平台运营人员无法默认查看学校明文业务数据。</p></article>`, content: `<div class="organization-list"><button class="active"><span class="tenant-logo">杭</span><span><strong>杭州科技职业技术学院</strong><small>校级管理者 · 全校32个专业</small></span><em>当前</em></button><button><span class="tenant-logo blue">信</span><span><strong>信息工程学院</strong><small>学院负责人 · 6个专业</small></span><em>可进入</em></button><button><span class="tenant-logo amber">企</span><span><strong>海康威视合作空间</strong><small>企业导师 · 3个共建项目</small></span><em>可进入</em></button></div><article class="workspace-detail-card"><h3>权限说明</h3><p>切换组织只改变可查看的业务范围,不改变租户隔离。平台运营人员默认不能查看学校明细数据。</p></article>`,
primary: "确认当前范围", primary: "确认当前范围",
}), }),
templates: () => ({ templates: () => ({
kicker: "REPORT TEMPLATE LIBRARY", kicker: "REPORT TEMPLATE LIBRARY",
title: "报告模板库", title: "报告模板库",
description: "按不同决策场景统一报告结构、证据和审批流程。", description: "按报告用途设置章节、数据说明和审批步骤。",
content: `<div class="template-library"><article><span>校级报告</span><strong>全校产教供需分析总报告</strong><small>学校事实、区域基准、专业结构、行动清单</small><em>42页 · 已启用</em></article><article><span>学院报告</span><strong>学院专业建设分析报告</strong><small>专业对比、共享能力、企业合作与任务跟踪</small><em>36页 · 已启用</em></article><article><span>专业报告</span><strong>专业人才需求分析报告</strong><small>岗位、技能、薪资、课程映射和企业推荐</small><em>24—30页 · 已启用</em></article><article><span>数据质量</span><strong>数据资产质量与口径报告</strong><small>来源、权属、版本、质量规则、限制和审计</small><em>19页 · 已启用</em></article></div>`, content: `<div class="template-library"><article><span>校级报告</span><strong>全校产教供需分析总报告</strong><small>学校数据、区域基准、专业结构、任务清单</small><em>42页 · 已启用</em></article><article><span>学院报告</span><strong>学院专业建设分析报告</strong><small>专业对比、共用课程、企业合作与任务跟踪</small><em>36页 · 已启用</em></article><article><span>专业报告</span><strong>专业人才需求分析报告</strong><small>岗位、技能、薪资、课程对应和企业推荐</small><em>24—30页 · 已启用</em></article><article><span>数据质量</span><strong>数据资产质量与口径报告</strong><small>来源、权属、版本、质量规则、限制和审计</small><em>19页 · 已启用</em></article></div>`,
primary: "新建模板版本", primary: "新建模板版本",
}), }),
compare: () => ({ compare: () => ({
@@ -4323,7 +4323,7 @@ function renderSources(filter = "all") {
<span>数据提供方<strong>${source.provider}</strong></span> <span>数据提供方<strong>${source.provider}</strong></span>
<span>权属与授权<strong>${source.rights}</strong></span> <span>权属与授权<strong>${source.rights}</strong></span>
<span>覆盖范围<strong>${source.coverage}</strong></span> <span>覆盖范围<strong>${source.coverage}</strong></span>
<span>更新机制<strong>${source.frequency}</strong></span> <span>更新频率<strong>${source.frequency}</strong></span>
</div> </div>
<div class="source-card-meta"> <div class="source-card-meta">
<span>有效记录<strong>${source.records}</strong></span> <span>有效记录<strong>${source.records}</strong></span>
@@ -4473,14 +4473,14 @@ function renderReportCenter() {
const roleReports = reportsForCurrentRole(); const roleReports = reportsForCurrentRole();
const role = document.getElementById("roleSelect")?.value || "校级管理者"; const role = document.getElementById("roleSelect")?.value || "校级管理者";
const descriptions = { const descriptions = {
校级管理者: "统一管理校级、学院、专业、产业与数据质量报告,支持在线阅读和版本追溯。", 校级管理者: "查看和管理校级、学院、专业、产业与数据质量报告,并保留各版本。",
学院负责人: "查看本院、所属专业及相关数据质量报告,将分析结论转化为专业建设行动。", 学院负责人: "查看本院、所属专业及相关数据质量报告,并根据分析结论安排专业建设任务。",
专业负责人: "查看本专业报告、提交业务流程报告审核并追踪审批历史;校级批准与发布由校级管理者执行。", 专业负责人: "查看本专业报告、提交业务流程报告审核并追踪审批历史;校级批准与发布由校级管理者执行。",
就业老师: "查看校级与数据质量报告,登记就业侧使用反馈;不能审批校级业务报告。", 就业老师: "查看校级与数据质量报告,登记就业侧使用反馈;不能审批校级业务报告。",
校级技术管理员: "查看数据质量、版本、口径和授权报告,确保进入分析的每个数据版本均可追溯。", 校级技术管理员: "查看数据质量、版本、口径和授权报告,并检查每个分析版本的数据来源和处理记录。",
}; };
document.getElementById("reportCenterDescription").textContent = document.getElementById("reportCenterDescription").textContent =
descriptions[role] || "统一管理分析报告,支持在线阅读和版本追溯。"; descriptions[role] || "查看和管理分析报告,并保留各版本。";
document.getElementById("reportTotalCount").textContent = roleReports.length; document.getElementById("reportTotalCount").textContent = roleReports.length;
document.getElementById("reportNewCount").textContent = roleReports.filter((item) => item.periodKey === "current").length; document.getElementById("reportNewCount").textContent = roleReports.filter((item) => item.periodKey === "current").length;
document.getElementById("reportReviewCount").textContent = roleReports.filter((item) => item.status === "待审核").length; document.getElementById("reportReviewCount").textContent = roleReports.filter((item) => item.status === "待审核").length;
@@ -4516,8 +4516,8 @@ function renderReportDocument(report, options = {}) {
<div class="report-cover-main"> <div class="report-cover-main">
<span>${report.typeLabel} · ${report.period}</span> <span>${report.typeLabel} · ${report.period}</span>
<h1>${report.title}</h1> <h1>${report.title}</h1>
<p>${report.scope}。报告基于统一数据快照生成,结论均保留来源、样本量与统计口径。</p> <p>${report.scope}。报告使用同一数据快照生成,每项结论都注明来源、样本量和统计口径。</p>
<mark class="report-standard-stamp">STANDARD REPORT · 数据、口径与结论全链路可追溯</mark> <mark class="report-standard-stamp">STANDARD REPORT · 可查看数据来源、统计口径和结论依据</mark>
</div> </div>
<div class="report-cover-foot"> <div class="report-cover-foot">
<span>编制单位<strong>${report.author}</strong></span> <span>编制单位<strong>${report.author}</strong></span>
@@ -4546,16 +4546,16 @@ function renderReportDocument(report, options = {}) {
${window.ReportVisuals.renderExecutiveCharts(report, { interactive })} ${window.ReportVisuals.renderExecutiveCharts(report, { interactive })}
<div class="report-interpretation"> <div class="report-interpretation">
<span>综合解读</span> <span>综合解读</span>
<p>本期${evidence.scoreLabel}为<strong>${evidence.score.toFixed(1)}分</strong>,高于区域可比均值<strong>${(evidence.score - evidence.benchmark.regional).toFixed(1)}分</strong>,高于同类院校均值<strong>${(evidence.score - evidence.benchmark.peer).toFixed(1)}分</strong>。该判断建立在${evidence.benchmark.sampleText}及统一数据快照之上;所有低样本指标已降权,不将互联网招聘数量直接解释为人才缺口人数。</p> <p>本期${evidence.scoreLabel}为<strong>${evidence.score.toFixed(1)}分</strong>,高于区域可比均值<strong>${(evidence.score - evidence.benchmark.regional).toFixed(1)}分</strong>,高于同类院校均值<strong>${(evidence.score - evidence.benchmark.peer).toFixed(1)}分</strong>。计算使用${evidence.benchmark.sampleText}和同一数据快照;低样本指标已降低权重,互联网招聘数量不直接当作人才缺口人数。</p>
</div> </div>
</section> </section>
<section class="report-section" id="report-section-profile"> <section class="report-section" id="report-section-profile">
${reportSectionHeading(2, "INSTITUTION PROFILE", report.type === "profession" ? "专业与学校事实画像" : report.type === "college" ? "学院与学校事实画像" : "学校现状与事实画像")} ${reportSectionHeading(2, "INSTITUTION PROFILE", report.type === "profession" ? "专业与学校现状" : report.type === "college" ? "学院与学校现状" : "学校现状")}
${window.ReportVisuals.renderProfileEvidence(report, { interactive })} ${window.ReportVisuals.renderProfileEvidence(report, { interactive })}
<div class="report-interpretation"> <div class="report-interpretation">
<span>学校现状判断</span> <span>学校现状判断</span>
<p>学校现状以学籍、教务、人事、实习就业和校企合作台账为事实底座。当前全校专业、课程和企业合作规模能够支撑常规人才培养,但真实项目实训、企业导师评价与课程技能映射仍需进一步覆盖。每项现状指标均可展开查看来源系统、更新时间、责任部门和计算口径。</p> <p>学校现状数据来自学籍、教务、人事、实习就业和校企合作台账。当前全校专业、课程和企业合作规模能够满足常规人才培养需要,但企业项目实训、企业导师评价和课程技能对应关系仍不完整。每项指标都可查看来源系统、更新时间、责任部门和计算口径。</p>
</div> </div>
</section> </section>
@@ -4580,7 +4580,7 @@ function renderReportDocument(report, options = {}) {
</div> </div>
<div class="report-finding-validation"> <div class="report-finding-validation">
<strong>结论交叉验证规则</strong> <strong>结论交叉验证规则</strong>
<span>外部需求趋势</span><i>+</i><span>校内培养事实</span><i>+</i><span>企业确认信号</span><i>→</i><span>业务负责人复核</span> <span>外部岗位变化</span><i>+</i><span>校内培养数据</span><i>+</i><span>企业确认需求</span><i>→</i><span>业务负责人复核</span>
</div> </div>
</section> </section>
@@ -4616,12 +4616,12 @@ function renderReportDocument(report, options = {}) {
</div> </div>
<div class="report-interpretation"> <div class="report-interpretation">
<span>结构性结论</span> <span>结构性结论</span>
<p>高需求但课程覆盖不足的能力位于象限图左上区域,应优先进入专业建设清单;高需求且覆盖充分的能力应转向学生达成和企业评价验证。趋势图显示培养响应仍滞后于外部需求,建议以真实项目和企业验收缩短响应周期,而不是简单增加课程名称。</p> <p>高需求但课程覆盖不足的能力位于象限图左上区域,应优先加入专业建设清单;高需求且覆盖充分的能力需要检查学生掌握情况和企业评价。趋势图显示课程调整仍慢于岗位需求变化,建议增加企业项目和企业验收,不要只增加课程名称。</p>
</div> </div>
</section> </section>
<section class="report-section" id="report-section-evidence"> <section class="report-section" id="report-section-evidence">
${reportSectionHeading(5, "DATA EVIDENCE", "证据链、样本与数据来源")} ${reportSectionHeading(5, "DATA EVIDENCE", "样本与数据来源")}
${window.ReportVisuals.renderEvidenceLedger(report)} ${window.ReportVisuals.renderEvidenceLedger(report)}
</section> </section>
@@ -4630,8 +4630,8 @@ function renderReportDocument(report, options = {}) {
<div class="report-method-steps"> <div class="report-method-steps">
<article><span>01</span><strong>数据采集</strong><p>采集近90天岗位、校内主数据、课程标准、实习就业回执和合作企业确认记录,保留权属与授权标签。</p></article> <article><span>01</span><strong>数据采集</strong><p>采集近90天岗位、校内主数据、课程标准、实习就业回执和合作企业确认记录,保留权属与授权标签。</p></article>
<article><span>02</span><strong>清洗归一</strong><p>按岗位ID、企业、发布时间去重;专业依据教育部专业代码归一;技能使用版本化词典映射。</p></article> <article><span>02</span><strong>清洗归一</strong><p>按岗位ID、企业、发布时间去重;专业依据教育部专业代码归一;技能使用版本化词典映射。</p></article>
<article><span>03</span><strong>基准构建</strong><p>仅纳入同层次、同区域且有效样本达到100条的院校;同类院校按专业结构、规模和产业方向匹配。</p></article> <article><span>03</span><strong>选择对比样本</strong><p>只纳入同层次、同区域且有效样本达到100条的院校;同类院校按专业结构、规模和产业方向选择。</p></article>
<article><span>04</span><strong>交叉验证</strong><p>外部需求、校内事实与企业确认至少两类证据方向一致才形成中高置信结论,AI文本须人工审核。</p></article> <article><span>04</span><strong>相互核对</strong><p>外部岗位、校内数据和企业确认中至少两类结果一致,才列为较可靠结论;AI草拟文字必须人工审核。</p></article>
</div> </div>
<div class="report-table-wrap"> <div class="report-table-wrap">
<table class="report-table"> <table class="report-table">
@@ -4647,7 +4647,7 @@ function renderReportDocument(report, options = {}) {
</table> </table>
</div> </div>
<div class="report-method-note"> <div class="report-method-note">
本报告用于专业建设和校企协同决策参考。AI负责结构化归纳和文本草拟,不修改原始数据,不隐藏相反证据。业务负责人需结合政策、办学定位和资源约束审核,不直接替代招生、专业撤并或课程调整的正式决策程序。 本报告用于讨论专业建设和校企合作。AI只整理数据和草拟文字,不修改原始数据,也不删除相反结果。业务负责人仍需结合政策、办学定位和资源情况审核;报告不能替代招生、专业撤并或课程调整的正式决策程序。
</div> </div>
</section> </section>
@@ -4673,7 +4673,7 @@ function renderReportDocument(report, options = {}) {
<div class="report-action-cycle"> <div class="report-action-cycle">
<span><strong>责任确认</strong><small>5个工作日内</small></span> <span><strong>责任确认</strong><small>5个工作日内</small></span>
<i></i> <i></i>
<span><strong>方案与资源</strong><small>形成可验收产物</small></span> <span><strong>方案与资源</strong><small>提交可按验收要求检查的成果</small></span>
<i></i> <i></i>
<span><strong>阶段复核</strong><small>按月更新证据</small></span> <span><strong>阶段复核</strong><small>按月更新证据</small></span>
<i></i> <i></i>
@@ -4720,7 +4720,7 @@ function openReportReader(reportId) {
["profile", "学校现状"], ["profile", "学校现状"],
["findings", "关键发现"], ["findings", "关键发现"],
["analysis", "供需结构"], ["analysis", "供需结构"],
["evidence", "证据链"], ["evidence", "数据来源"],
["method", "指标口径"], ["method", "指标口径"],
["actions", "行动建议"], ["actions", "行动建议"],
]; ];
@@ -4975,10 +4975,10 @@ function setupWorkspaceDetails() {
} }
const productTourSteps = [ const productTourSteps = [
{ view: "dashboard", selector: ".quality-strip", title: "可信数据底座", description: "先确认数据来源、更新状态和质量门槛,所有分析只引用已验收版本。" }, { view: "dashboard", selector: ".quality-strip", title: "先核对数据", description: "先看数据来自哪里、何时更新、是否通过检查;分析只使用已验收版本。" },
{ view: "dashboard", selector: ".ai-panel", title: "发现关键变化", description: "AI将岗位、技能和专业变化归纳为可解释的决策简报,并保留证据定位。" }, { view: "dashboard", selector: ".ai-panel", title: "查看关键变化", description: "系统整理岗位、技能和专业变化,每条结论都可打开查看数据来源。" },
{ view: "profession", selector: ".profile-banner", title: "定位专业差距", description: "从岗位、技能、薪资和课程映射判断专业优势与结构性缺口。" }, { view: "profession", selector: ".profile-banner", title: "定位专业差距", description: "从岗位、技能、薪资和课程映射判断专业优势与结构性缺口。" },
{ view: "collaboration", selector: ".collab-stats", title: "连接企业协同", description: "把企业需求转化为课程共建、真实项目、企业导师和实习就业合作。" }, { view: "collaboration", selector: ".collab-stats", title: "安排企业合作", description: "把企业需求写入课程共建、企业项目、企业导师和实习就业计划。" },
{ view: "actions", selector: ".action-overview", title: "跟踪改进成效", description: "每项建议都有负责人、截止日期、进展证据和下一周期效果复核。" }, { view: "actions", selector: ".action-overview", title: "跟踪改进成效", description: "每项建议都有负责人、截止日期、进展证据和下一周期效果复核。" },
{ view: "data", selector: ".source-summary-grid", title: "管理数据资产", description: "厂商、学校和企业三类数据分权维护,支持初次导入、增量更新、版本和审计。" }, { view: "data", selector: ".source-summary-grid", title: "管理数据资产", description: "厂商、学校和企业三类数据分权维护,支持初次导入、增量更新、版本和审计。" },
{ view: "reports", selector: ".featured-report-grid", title: "完成正式交付", description: "在线报告、材料包和展示大屏使用同一数据快照,适用于决策、汇报与报送。" }, { view: "reports", selector: ".featured-report-grid", title: "完成正式交付", description: "在线报告、材料包和展示大屏使用同一数据快照,适用于决策、汇报与报送。" },
@@ -5268,7 +5268,7 @@ function setupReportCenterInteractions() {
const task = { const task = {
id: `TSK-REPORT-${Date.now()}`, id: `TSK-REPORT-${Date.now()}`,
title, title,
source: `报告建议 · ${report?.version || "当前版本"} · 证据链已关联`, source: `报告建议 · ${report?.version || "当前版本"} · 已关联数据来源`,
profession: report?.type === "profession" ? report.scope.split("·").pop().trim() : "全校专业", profession: report?.type === "profession" ? report.scope.split("·").pop().trim() : "全校专业",
owner: "待确认", owner: "待确认",
due: "2026-04-30", due: "2026-04-30",
@@ -5357,7 +5357,7 @@ const platformActionTemplates = {
<label><span>预计记录数</span><input value="92.6 万条" readonly></label> <label><span>预计记录数</span><input value="92.6 万条" readonly></label>
<label><span>数据版本</span><input value="V2026.04"></label> <label><span>数据版本</span><input value="V2026.04"></label>
<label><span>Schema 版本</span><input value="JOB-PACK 3.3"></label> <label><span>Schema 版本</span><input value="JOB-PACK 3.3"></label>
<label class="full"><span>本次更新内容</span><textarea rows="3">新增约 8.4 万条岗位,更新 1.2 万条岗位状态;补充具身智能、AI应用工程和工业软件分类,失效记录保留版本追溯。</textarea></label> <label class="full"><span>本次更新内容</span><textarea rows="3">新增约 8.4 万条岗位,更新 1.2 万条岗位状态;补充具身智能、AI应用工程和工业软件分类,并保留失效记录的旧版本。</textarea></label>
<fieldset> <fieldset>
<legend>导入要求与发布门槛</legend> <legend>导入要求与发布门槛</legend>
<div class="platform-contract-summary"> <div class="platform-contract-summary">
@@ -5458,7 +5458,7 @@ const platformActionTemplates = {
permission: { permission: {
kicker: "ROLE PERMISSION", kicker: "ROLE PERMISSION",
title: "角色与权限模板", title: "角色与权限模板",
description: "统一配置学校、学院、企业和平台运营角色权限。", description: "分别设置学校、学院、企业和平台运营人员的权限。",
confirm: "进入配置", confirm: "进入配置",
content: `<div class="platform-detail-card"><strong>7 套权限模板</strong><small>采用租户隔离、角色权限和数据范围三层控制,最近修改已通过审计复核。</small></div>`, content: `<div class="platform-detail-card"><strong>7 套权限模板</strong><small>采用租户隔离、角色权限和数据范围三层控制,最近修改已通过审计复核。</small></div>`,
}, },
@@ -5472,7 +5472,7 @@ const platformActionTemplates = {
audit: { audit: {
kicker: "AUDIT LOG", kicker: "AUDIT LOG",
title: "平台审计日志", title: "平台审计日志",
description: "追溯数据导入、权限变更、租户操作和系统任务。", description: "查看数据导入、权限变更、租户操作和系统任务记录。",
confirm: "查看完整日志", confirm: "查看完整日志",
content: `<div class="platform-detail-card"><strong>今日记录 286 条关键操作</strong><small>数据操作68条,权限操作12条,系统任务201条,安全事件5条,全部保留操作者和时间戳。</small></div>`, content: `<div class="platform-detail-card"><strong>今日记录 286 条关键操作</strong><small>数据操作68条,权限操作12条,系统任务201条,安全事件5条,全部保留操作者和时间戳。</small></div>`,
}, },
@@ -5553,7 +5553,7 @@ function setupAnalysis() {
"读取本期分析快照…", "读取本期分析快照…",
"归一并匹配产业岗位…", "归一并匹配产业岗位…",
"计算专业技能覆盖差距…", "计算专业技能覆盖差距…",
"生成可解释决策洞察…", "整理分析结果和建议…",
]; ];
openModal(modal); openModal(modal);
progress.style.width = "0"; progress.style.width = "0";
@@ -5635,7 +5635,7 @@ function configureFormModal(type) {
task: { task: {
kicker: "ACTION FORM", kicker: "ACTION FORM",
title: "创建改进任务", title: "创建改进任务",
description: "将分析洞察转化为可追踪、可验证的行动。", description: "把分析结果写成有负责人、截止日期和验收要求的任务。",
label: "任务名称", label: "任务名称",
value: "强化云原生与容器化实训内容", value: "强化云原生与容器化实训内容",
scopeLabel: "关联专业", scopeLabel: "关联专业",
@@ -5651,16 +5651,16 @@ function configureFormModal(type) {
}, },
project: { project: {
kicker: "COLLABORATION PROJECT", kicker: "COLLABORATION PROJECT",
title: "新建协同项目", title: "新建合作项目",
description: "连接专业团队与企业伙伴,共同推进人才培养项目。", description: "连接专业团队与企业伙伴,共同推进人才培养项目。",
label: "项目名称", label: "项目名称",
value: "企业真实项目进课堂", value: "企业项目进课堂",
scopeLabel: "牵头专业", scopeLabel: "牵头专业",
scopeOptions: ["软件技术", "机电一体化技术", "电子商务"], scopeOptions: ["软件技术", "机电一体化技术", "电子商务"],
priorityLabel: "项目类型", priorityLabel: "项目类型",
priorityOptions: ["企业项目进课堂", "课程共建", "实训基地", "企业导师"], priorityOptions: ["企业项目进课堂", "课程共建", "实训基地", "企业导师"],
goalLabel: "共建目标与验收方式", goalLabel: "共建目标与验收方式",
goal: "围绕企业真实任务共同设计教学项目、过程评价和成果验收,保留企业任务书与导师评价证据。", goal: "围绕企业任务共同设计教学项目、过程评价和成果验收,并保存企业任务书与导师评价。",
ownerLabel: "校内负责人", ownerLabel: "校内负责人",
owner: "王健 · 产教融合中心", owner: "王健 · 产教融合中心",
dueLabel: "计划启动时间", dueLabel: "计划启动时间",
@@ -5688,15 +5688,15 @@ function configureFormModal(type) {
configs.demand = { configs.demand = {
kicker: "ENTERPRISE DEMAND", kicker: "ENTERPRISE DEMAND",
title: "提交企业人才需求", title: "提交企业人才需求",
description: "提交真实岗位、技能与共育需求,供学校专业团队确认响应。", description: "提交岗位、技能与共育需求,供学校专业团队确认是否承接。",
label: "需求名称", label: "需求名称",
value: "边缘计算软件测试人才共育需求", value: "边缘计算软件测试人才共育需求",
scopeLabel: "关联专业", scopeLabel: "关联专业",
scopeOptions: ["软件技术", "物联网应用技术", "计算机网络技术"], scopeOptions: ["软件技术", "物联网应用技术", "计算机网络技术"],
priorityLabel: "合作方式", priorityLabel: "合作方式",
priorityOptions: ["人才共育", "真实项目", "课程共建", "实习就业"], priorityOptions: ["人才共育", "企业项目", "课程共建", "实习就业"],
goalLabel: "企业需求说明", goalLabel: "企业需求说明",
goal: "提交真实岗位、技能、计划人数和合作方式,并由企业联系人确认数据授权用途与有效期。", goal: "填写岗位、技能、计划人数和合作方式,并由企业联系人确认数据用途与有效期。",
ownerLabel: "企业联系人", ownerLabel: "企业联系人",
owner: "陈凯 · 企业人才发展部", owner: "陈凯 · 企业人才发展部",
dueLabel: "期望响应时间", dueLabel: "期望响应时间",
@@ -5707,15 +5707,15 @@ function configureFormModal(type) {
configs.project = { configs.project = {
kicker: "CO-CREATION PROJECT", kicker: "CO-CREATION PROJECT",
title: "发起校企共建项目", title: "发起校企共建项目",
description: "邀请学校共同设计企业真实项目、课程内容和评价标准。", description: "邀请学校共同设计企业项目、课程内容和评价标准。",
label: "项目名称", label: "项目名称",
value: "智能物联边缘计算综合实训", value: "智能物联边缘计算综合实训",
scopeLabel: "面向专业", scopeLabel: "面向专业",
scopeOptions: ["物联网应用技术", "软件技术", "计算机网络技术"], scopeOptions: ["物联网应用技术", "软件技术", "计算机网络技术"],
priorityLabel: "项目类型", priorityLabel: "项目类型",
priorityOptions: ["企业真实项目", "课程共建", "企业导师", "实训基地"], priorityOptions: ["企业项目", "课程共建", "企业导师", "实训基地"],
goalLabel: "企业任务与验收要求", goalLabel: "企业任务与验收要求",
goal: "基于边缘计算测试场景设计实训任务,由企业导师参与中期评审,并依据测试报告、代码质量和协作过程验收。", goal: "按边缘计算测试场景设计实训任务,由企业导师参加中期评审,并检查测试报告、代码质量和协作过程。",
ownerLabel: "企业负责人", ownerLabel: "企业负责人",
owner: "陈凯 · 企业人才发展部", owner: "陈凯 · 企业人才发展部",
dueLabel: "建议启动时间", dueLabel: "建议启动时间",
@@ -5816,7 +5816,7 @@ function setupForms() {
closeModal(document.getElementById("formModal")); closeModal(document.getElementById("formModal"));
const messages = { const messages = {
task: "改进任务已创建,并通知专业负责人", task: "改进任务已创建,并通知专业负责人",
project: "协同项目草案已创建,可继续邀请企业伙伴", project: "合作项目草案已创建,可继续邀请企业伙伴",
demand: "企业需求调研已创建,共有126家在库企业可发送", demand: "企业需求调研已创建,共有126家在库企业可发送",
}; };
showToast(messages[type] || "内容已保存"); showToast(messages[type] || "内容已保存");
@@ -6007,7 +6007,7 @@ function init() {
addClosedLoopAudit( addClosedLoopAudit(
"LEGACY_NEXT_CYCLE_MIGRATED", "LEGACY_NEXT_CYCLE_MIGRATED",
closedLoopState.entities.demand.id, closedLoopState.entities.demand.id,
`旧版复核 ${legacyReview.id || "RVW-旧记录"} 已转换为真实的新周期实体。`, `旧版复核 ${legacyReview.id || "RVW-旧记录"} 已转换为可继续办理的新周期记录。`,
"流程状态迁移器", "流程状态迁移器",
"系统", "系统",
); );
+41 -41
View File
@@ -5,9 +5,9 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta <meta
name="description" name="description"
content="产教融智,面向职业院校的供需分析、校企协同、数据治理与改进闭环平台" content="产教融智,面向职业院校的供需分析、校企合作、数据检查与改进任务平台"
/> />
<title>产教融智 · 供需分析与协同平台</title> <title>产教融智 · 供需分析与校企合作</title>
<link rel="icon" href="./favicon.svg" type="image/svg+xml" /> <link rel="icon" href="./favicon.svg" type="image/svg+xml" />
<link rel="stylesheet" href="./styles.css" /> <link rel="stylesheet" href="./styles.css" />
<link rel="stylesheet" href="./enterprise.css" /> <link rel="stylesheet" href="./enterprise.css" />
@@ -58,14 +58,14 @@
<svg viewBox="0 0 24 24" aria-hidden="true"> <svg viewBox="0 0 24 24" aria-hidden="true">
<path d="M3 11h18M5 7l7-4 7 4M5 11v7m4-7v7m6-7v7m4-7v7M3 21h18" /> <path d="M3 11h18M5 7l7-4 7 4M5 11v7m4-7v7m6-7v7m4-7v7M3 21h18" />
</svg> </svg>
<span>专业洞察</span> <span>专业分析</span>
<span class="nav-count">32</span> <span class="nav-count">32</span>
</button> </button>
<button class="nav-item" data-view="collaboration" data-menu-key="collaboration"> <button class="nav-item" data-view="collaboration" data-menu-key="collaboration">
<svg viewBox="0 0 24 24" aria-hidden="true"> <svg viewBox="0 0 24 24" aria-hidden="true">
<path d="M8 12h8m-4-4v8M4 7h3l2-3h6l2 3h3v13H4V7Z" /> <path d="M8 12h8m-4-4v8M4 7h3l2-3h6l2 3h3v13H4V7Z" />
</svg> </svg>
<span>校企协同</span> <span>校企合作</span>
</button> </button>
<button class="nav-item" data-view="actions" data-menu-key="actions"> <button class="nav-item" data-view="actions" data-menu-key="actions">
<svg viewBox="0 0 24 24" aria-hidden="true"> <svg viewBox="0 0 24 24" aria-hidden="true">
@@ -224,7 +224,7 @@
<div> <div>
<div class="eyebrow"><span></span> CAMPUS WORKFLOW</div> <div class="eyebrow"><span></span> CAMPUS WORKFLOW</div>
<h1>企业需求到成效复核流程</h1> <h1>企业需求到成效复核流程</h1>
<p>点击流程节点查看实体、责任人与输入输出;当前角色可在已解锁节点直接推进业务。</p> <p>点击节点查看责任人、输入、输出和关联记录;当前角色可办理已满足前置条件的事项。</p>
</div> </div>
<button class="button secondary" id="resetClosedLoop"> <button class="button secondary" id="resetClosedLoop">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M20 11a8 8 0 1 0-2.34 5.66M20 4v7h-7" /></svg> <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M20 11a8 8 0 1 0-2.34 5.66M20 4v7h-7" /></svg>
@@ -289,7 +289,7 @@
<div> <div>
<div class="eyebrow"><span></span> SCHOOL OVERVIEW</div> <div class="eyebrow"><span></span> SCHOOL OVERVIEW</div>
<h1>产教供需决策总览</h1> <h1>产教供需决策总览</h1>
<p>把产业需求信号转化为专业建设任务,并用报告与改进证据形成决策闭环。</p> <p>根据产业岗位变化建立专业建设任务,并通过报告、过程证据和后续复核检查结果。</p>
</div> </div>
<div class="heading-actions"> <div class="heading-actions">
<button class="button secondary" data-report-generate="package"> <button class="button secondary" data-report-generate="package">
@@ -361,7 +361,7 @@
</article> </article>
<article class="metric-card"> <article class="metric-card">
<div class="metric-top"> <div class="metric-top">
<span class="metric-label">协同改进完成率</span> <span class="metric-label">改进任务完成率</span>
<span class="metric-tag blue">本学期</span> <span class="metric-tag blue">本学期</span>
</div> </div>
<div class="metric-value"><strong id="metricActions">68</strong><small>%</small></div> <div class="metric-value"><strong id="metricActions">68</strong><small>%</small></div>
@@ -455,7 +455,7 @@
</div> </div>
<div class="ai-source"> <div class="ai-source">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20ZM12 8v5m0 3h.01" /></svg> <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20ZM12 8v5m0 3h.01" /></svg>
结论综合基础数据包、校级数据与企业确认数据,所有引用均可追溯 结论使用基础数据包、校级数据与企业确认数据,每条引用都注明来源
</div> </div>
</article> </article>
</div> </div>
@@ -517,11 +517,11 @@
</div> </div>
</section> </section>
<!-- 专业洞察 --> <!-- 专业分析 -->
<section class="view" id="view-profession" data-title="专业洞察"> <section class="view" id="view-profession" data-title="专业分析">
<div class="page-heading profession-heading"> <div class="page-heading profession-heading">
<div> <div>
<div class="eyebrow"><span></span> PROGRAM INSIGHT</div> <div class="eyebrow"><span></span> PROGRAM ANALYSIS</div>
<div class="heading-inline"> <div class="heading-inline">
<h1 id="professionTitle">软件技术</h1> <h1 id="professionTitle">软件技术</h1>
<label class="profession-select"> <label class="profession-select">
@@ -641,13 +641,13 @@
<div class="profession-tab-view" id="professionDetailView" hidden></div> <div class="profession-tab-view" id="professionDetailView" hidden></div>
</section> </section>
<!-- 校企协同 --> <!-- 校企合作 -->
<section class="view" id="view-collaboration" data-title="校企协同"> <section class="view" id="view-collaboration" data-title="校企合作">
<div class="page-heading heading-with-actions"> <div class="page-heading heading-with-actions">
<div> <div>
<div class="eyebrow"><span></span> COLLABORATION HUB</div> <div class="eyebrow"><span></span> COLLABORATION HUB</div>
<h1 id="collaborationHeading">校企协同中心</h1> <h1 id="collaborationHeading">校企合作</h1>
<p id="collaborationDescription">把产业需求转化为可执行的课程、项目与人才共育计划。</p> <p id="collaborationDescription">根据企业需求安排课程共建、合作项目和人才培养计划。</p>
</div> </div>
<div class="heading-actions"> <div class="heading-actions">
<button class="button secondary" id="enterpriseDemandButton"> <button class="button secondary" id="enterpriseDemandButton">
@@ -656,14 +656,14 @@
</button> </button>
<button class="button primary" id="newProjectButton"> <button class="button primary" id="newProjectButton">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 5v14M5 12h14" /></svg> <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 5v14M5 12h14" /></svg>
新建协同项目 新建合作项目
</button> </button>
</div> </div>
</div> </div>
<div class="collab-stats"> <div class="collab-stats">
<div><span>在库合作企业</span><strong>126</strong><small>家</small><em>↑ 18</em></div> <div><span>在库合作企业</span><strong>126</strong><small>家</small><em>↑ 18</em></div>
<div><span>本学期协同项目</span><strong>24</strong><small>个</small><em>8 个进行中</em></div> <div><span>本学期合作项目</span><strong>24</strong><small>个</small><em>8 个进行中</em></div>
<div><span>企业导师</span><strong>68</strong><small>人</small><em>覆盖 17 个专业</em></div> <div><span>企业导师</span><strong>68</strong><small>人</small><em>覆盖 17 个专业</em></div>
<div><span>学生参与</span><strong>1,284</strong><small>人次</small><em>满意度 92%</em></div> <div><span>学生参与</span><strong>1,284</strong><small>人次</small><em>满意度 92%</em></div>
</div> </div>
@@ -672,7 +672,7 @@
<article class="panel pipeline-panel"> <article class="panel pipeline-panel">
<div class="panel-header"> <div class="panel-header">
<div> <div>
<span class="panel-kicker">协同进度</span> <span class="panel-kicker">项目进度</span>
<h2>本学期重点项目</h2> <h2>本学期重点项目</h2>
</div> </div>
<div class="segmented"> <div class="segmented">
@@ -713,8 +713,8 @@
<div class="page-heading heading-with-actions"> <div class="page-heading heading-with-actions">
<div> <div>
<div class="eyebrow"><span></span> ACTION TRACKER</div> <div class="eyebrow"><span></span> ACTION TRACKER</div>
<h1>改进任务闭环</h1> <h1>改进任务进展</h1>
<p>从数据洞察到责任落实,持续追踪专业建设行动与实际成效。</p> <p>查看每项专业建设任务的负责人、进度和实际效果。</p>
</div> </div>
<button class="button primary" id="newTaskButton"> <button class="button primary" id="newTaskButton">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 5v14M5 12h14" /></svg> <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 5v14M5 12h14" /></svg>
@@ -779,7 +779,7 @@
<div> <div>
<div class="eyebrow"><span></span> DATA FOUNDATION</div> <div class="eyebrow"><span></span> DATA FOUNDATION</div>
<h1 id="dataPageTitle">数据资产与质量</h1> <h1 id="dataPageTitle">数据资产与质量</h1>
<p id="dataPageDescription">区分厂商基础数据包、学校自有数据与企业授权数据,所有分析结论均可追溯。</p> <p id="dataPageDescription">区分厂商基础数据包、学校自有数据与企业授权数据,每项分析结论都注明数据来源。</p>
</div> </div>
<button class="button primary" id="syncAllButton"> <button class="button primary" id="syncAllButton">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M20 11a8 8 0 1 0-2.34 5.66M20 4v7h-7" /></svg> <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M20 11a8 8 0 1 0-2.34 5.66M20 4v7h-7" /></svg>
@@ -824,7 +824,7 @@
<strong>互联网基础数据包</strong> <strong>互联网基础数据包</strong>
<em class="commercial-pill paid">付费订阅</em> <em class="commercial-pill paid">付费订阅</em>
</span> </span>
<small>由平台厂商合规归集、治理并按服务周期导入</small> <small>由平台厂商按授权收集、检查,并按服务周期导入</small>
<span class="source-summary-metrics"> <span class="source-summary-metrics">
<span><strong>2</strong> 个数据源</span> <span><strong>2</strong> 个数据源</span>
<span><strong>77,520</strong> 条记录</span> <span><strong>77,520</strong> 条记录</span>
@@ -895,7 +895,7 @@
<div> <div>
<span class="panel-kicker">DATA → ANALYSIS → REPORT</span> <span class="panel-kicker">DATA → ANALYSIS → REPORT</span>
<h2>数据与报告双向依赖图谱</h2> <h2>数据与报告双向依赖图谱</h2>
<p>从报告反查必需数据,也可从数据查看能形成的报告;缺口直接定位业务索取人和技术接口人。</p> <p>选择报告可查看所需数据;选择数据源可查看使用它的报告。缺口会列出业务索取人和技术接口人。</p>
</div> </div>
<span class="lineage-snapshot-badge"><i></i>分析快照 V2026.03</span> <span class="lineage-snapshot-badge"><i></i>分析快照 V2026.03</span>
</div> </div>
@@ -907,7 +907,7 @@
</div> </div>
<label class="lineage-selector"> <label class="lineage-selector">
<span id="dataLineageSelectorLabel">选择报告</span> <span id="dataLineageSelectorLabel">选择报告</span>
<select id="dataLineageSelector" aria-label="选择要追溯的报告"></select> <select id="dataLineageSelector" aria-label="选择报告查看所需数据"></select>
</label> </label>
<label class="lineage-gap-toggle"> <label class="lineage-gap-toggle">
<input type="checkbox" id="dataLineageGapToggle"> <input type="checkbox" id="dataLineageGapToggle">
@@ -965,7 +965,7 @@
<article class="panel lineage-panel"> <article class="panel lineage-panel">
<div class="panel-header"> <div class="panel-header">
<div> <div>
<span class="panel-kicker">处理链路</span> <span class="panel-kicker">处理步骤</span>
<h2>本期数据加工血缘</h2> <h2>本期数据加工血缘</h2>
</div> </div>
<span class="version-badge">分析版本 V2026.03</span> <span class="version-badge">分析版本 V2026.03</span>
@@ -1009,7 +1009,7 @@
<div> <div>
<div class="eyebrow"><span></span> REPORT CENTER</div> <div class="eyebrow"><span></span> REPORT CENTER</div>
<h1>分析报告中心</h1> <h1>分析报告中心</h1>
<p id="reportCenterDescription">统一管理校级、学院、专业、产业与数据质量报告,支持在线阅读和版本追溯。</p> <p id="reportCenterDescription">查看和管理校级、学院、专业、产业与数据质量报告,并保留各版本。</p>
</div> </div>
<div class="heading-actions"> <div class="heading-actions">
<button class="button secondary" id="reportTemplateButton"> <button class="button secondary" id="reportTemplateButton">
@@ -1306,17 +1306,17 @@
<div class="product-tour-hero"> <div class="product-tour-hero">
<span>PRODUCT WALKTHROUGH</span> <span>PRODUCT WALKTHROUGH</span>
<h2 id="productTourTitle">5分钟看懂产教融智</h2> <h2 id="productTourTitle">5分钟看懂产教融智</h2>
<p>不是再做一套数据看板,而是把“产业信号、专业诊断、校企协同、改进任务、正式报告”串成可追踪的工作闭环。</p> <p>这里不只是数据看板。岗位变化、专业分析、企业合作、改进任务和正式报告都在同一套流程中办理。</p>
</div> </div>
<div class="tour-value-grid"> <div class="tour-value-grid">
<article><i>01</i><strong>看得清</strong><span>多源数据统一口径,定位专业、岗位与技能差距。</span></article> <article><i>01</i><strong>看得清</strong><span>先对齐各来源的字段和统计口径,再查看专业、岗位与技能差距。</span></article>
<article><i>02</i><strong>落得下</strong><span>分析建议直接转为责任明确、可验收的改进任务。</span></article> <article><i>02</i><strong>能执行</strong><span>分析建议转成有负责人和验收要求的改进任务。</span></article>
<article><i>03</i><strong>讲得明</strong><span>学校事实、区域基准、样本和来源形成完整证据链。</span></article> <article><i>03</i><strong>讲得明</strong><span>每项结论都列出学校数据、区域基准、样本量和来源。</span></article>
</div> </div>
<div class="tour-route"> <div class="tour-route">
<span><b>1</b>数据可信</span><i></i> <span><b>1</b>先核对数据</span><i></i>
<span><b>2</b>发现差距</span><i></i> <span><b>2</b>发现差距</span><i></i>
<span><b>3</b>协同改进</span><i></i> <span><b>3</b>任务跟进</span><i></i>
<span><b>4</b>报告交付</span> <span><b>4</b>报告交付</span>
</div> </div>
<div class="product-tour-actions"> <div class="product-tour-actions">
@@ -1335,7 +1335,7 @@
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 6l12 12M18 6 6 18" /></svg> <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 6l12 12M18 6 6 18" /></svg>
</button> </button>
</div> </div>
<strong id="tourStepTitle">可信数据底座</strong> <strong id="tourStepTitle">先核对数据</strong>
<p id="tourStepDescription">区分厂商基础数据包、学校自有数据和企业授权数据,让每个结论都能回溯。</p> <p id="tourStepDescription">区分厂商基础数据包、学校自有数据和企业授权数据,让每个结论都能回溯。</p>
<div class="tour-coach-actions"> <div class="tour-coach-actions">
<button id="tourPrevious">上一步</button> <button id="tourPrevious">上一步</button>
@@ -1392,14 +1392,14 @@
<article class="showcase-panel showcase-focus"> <article class="showcase-panel showcase-focus">
<div class="showcase-panel-head"><span>本期决策重点</span><strong>ACTION FOCUS</strong></div> <div class="showcase-panel-head"><span>本期决策重点</span><strong>ACTION FOCUS</strong></div>
<div class="showcase-focus-list"> <div class="showcase-focus-list">
<span><b>P0</b><strong>11个专业响应高优技能缺口</strong><small>4月底前形成课程或实训调整方案</small></span> <span><b>P0</b><strong>11个专业响应高优技能缺口</strong><small>4月底前提交课程或实训调整方案</small></span>
<span><b>P1</b><strong>建设工业视觉与云原生共享实训</strong><small>已识别 7 家高匹配合作企业</small></span> <span><b>P1</b><strong>建设工业视觉与云原生共享实训</strong><small>已识别 7 家高匹配合作企业</small></span>
<span><b>P1</b><strong>建立企业需求季度确认机制</strong><small>互联网信号与企业确认分开验证</small></span> <span><b>P1</b><strong>每季度请企业确认一次需求</strong><small>互联网招聘信息与企业确认分开检查</small></span>
</div> </div>
</article> </article>
</section> </section>
<footer class="showcase-footer"> <footer class="showcase-footer">
<span>数据快照 SNP-2026-03-22-0830 · 质量评分 92.6 · 全链路可追溯</span> <span>数据快照 SNP-2026-03-22-0830 · 质量评分 92.6 · 可查看来源与处理记录</span>
<strong>从产业信号到专业改进,让每项决策都有证据</strong> <strong>从产业信号到专业改进,让每项决策都有证据</strong>
</footer> </footer>
</main> </main>
@@ -1413,7 +1413,7 @@
</button> </button>
<div class="modal-kicker" id="formModalKicker">ACTION FORM</div> <div class="modal-kicker" id="formModalKicker">ACTION FORM</div>
<h2 id="formModalTitle">创建改进任务</h2> <h2 id="formModalTitle">创建改进任务</h2>
<p id="formModalDescription">将分析洞察转化为可追踪的行动。</p> <p id="formModalDescription">把分析结果写成有负责人和截止日期的任务。</p>
<form id="actionForm"> <form id="actionForm">
<label> <label>
<span id="formNameLabel">任务名称</span> <span id="formNameLabel">任务名称</span>
@@ -1537,14 +1537,14 @@
</div> </div>
</div> </div>
<!-- 闭环动作表单 --> <!-- 业务流程表单 -->
<div class="modal-backdrop" id="closedLoopModal" aria-hidden="true"> <div class="modal-backdrop" id="closedLoopModal" aria-hidden="true">
<div class="modal loop-modal" role="dialog" aria-modal="true" aria-labelledby="closedLoopModalTitle"> <div class="modal loop-modal" role="dialog" aria-modal="true" aria-labelledby="closedLoopModalTitle">
<button class="modal-close" data-close-modal aria-label="关闭"> <button class="modal-close" data-close-modal aria-label="关闭">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 6l12 12M18 6 6 18" /></svg> <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 6l12 12M18 6 6 18" /></svg>
</button> </button>
<div class="modal-kicker" id="closedLoopModalKicker">CLOSED LOOP ACTION</div> <div class="modal-kicker" id="closedLoopModalKicker">WORKFLOW ACTION</div>
<h2 id="closedLoopModalTitle">闭环动作</h2> <h2 id="closedLoopModalTitle">办理流程节点</h2>
<p id="closedLoopModalDescription">提交后将写入本地样板状态和审计事件。</p> <p id="closedLoopModalDescription">提交后将写入本地样板状态和审计事件。</p>
<form id="closedLoopForm"> <form id="closedLoopForm">
<div class="loop-modal-fields" id="closedLoopFields"></div> <div class="loop-modal-fields" id="closedLoopFields"></div>
@@ -1589,7 +1589,7 @@
<p id="analysisStatus">读取本期分析快照…</p> <p id="analysisStatus">读取本期分析快照…</p>
<div class="analysis-progress"><i id="analysisProgress"></i></div> <div class="analysis-progress"><i id="analysisProgress"></i></div>
<div class="analysis-steps"> <div class="analysis-steps">
<span class="active">数据校验</span><span>岗位匹配</span><span>技能分析</span><span>生成洞察</span> <span class="active">数据校验</span><span>岗位匹配</span><span>技能分析</span><span>生成建议</span>
</div> </div>
</div> </div>
</div> </div>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 290 KiB

After

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 330 KiB

After

Width:  |  Height:  |  Size: 329 KiB

+19 -19
View File
@@ -216,7 +216,7 @@
}, },
{ {
code: `${prefix}-PRJ-006`, code: `${prefix}-PRJ-006`,
label: "真实项目实训", label: "企业项目实训",
value: String(isCollege ? 18 + (seed % 8) : 6 + (seed % 6)), value: String(isCollege ? 18 + (seed % 8) : 6 + (seed % 6)),
unit: "项", unit: "项",
note: "均有企业任务书或验收记录", note: "均有企业任务书或验收记录",
@@ -359,9 +359,9 @@
source: "126家合作企业需求确认", source: "126家合作企业需求确认",
sample: "8,350 条", sample: "8,350 条",
updated: "2026-03-21", updated: "2026-03-21",
owner: "合作企业(场景授权)", owner: "合作企业(按协议用途)",
confidence: "高", confidence: "高",
limitation: "仅用于约定的专业建设和协同分析", limitation: "仅用于协议约定的专业建设分析",
}, },
], ],
evidenceCodes: { evidenceCodes: {
@@ -526,10 +526,10 @@
) )
.join("")} .join("")}
<circle cx="438" cy="18" r="5" fill="${palette.green}"/><text x="449" y="22" font-size="12" fill="${palette.muted}">产业需求</text> <circle cx="438" cy="18" r="5" fill="${palette.green}"/><text x="449" y="22" font-size="12" fill="${palette.muted}">产业需求</text>
<circle cx="530" cy="18" r="5" fill="${palette.amber}"/><text x="541" y="22" font-size="12" fill="${palette.muted}">培养响应</text> <circle cx="530" cy="18" r="5" fill="${palette.amber}"/><text x="541" y="22" font-size="12" fill="${palette.muted}">课程调整</text>
`, `,
285, 285,
"产业需求与学校培养响应趋势", "产业需求与学校课程调整趋势",
); );
} }
@@ -685,7 +685,7 @@
.join("")} .join("")}
`, `,
300, 300,
"供需能力矩阵立体图", "岗位需求与课程覆盖对照图",
); );
} }
@@ -720,7 +720,7 @@
"overall", "overall",
"1-1", "1-1",
`${evidence.scoreLabel}与区域排名`, `${evidence.scoreLabel}与区域排名`,
`本期得分基于快照 ${evidence.snapshot.id} 的 ${evidence.snapshot.records} 条有效记录计算;区域排名采用 ${evidence.benchmark.sampleText}。`, `本期得分使用快照 ${evidence.snapshot.id} 中的 ${evidence.snapshot.records} 条有效记录计算;区域排名采用 ${evidence.benchmark.sampleText}。`,
gaugeSvg(evidence), gaugeSvg(evidence),
options, options,
)} )}
@@ -742,9 +742,9 @@
return ` return `
<div class="report-profile-banner"> <div class="report-profile-banner">
<div> <div>
<span class="report-profile-kicker">INSTITUTION FACTS · 学校事实底座</span> <span class="report-profile-kicker">INSTITUTION FACTS · 学校现状数据</span>
<h3>${evidence.profile.name}</h3> <h3>${evidence.profile.name}</h3>
<p>学校现状指标只使用校方自有业务数据;产业需求使用厂商订阅数据,企业确认使用合作授权数据。三类证据分开标识,不以招聘信号替代校内事实。</p> <p>学校现状指标只使用校方业务数据;产业需求使用厂商订阅数据,企业确认使用合作授权数据。三类数据分开标识,不用互联网招聘信息替代学校业务数据。</p>
</div> </div>
<div class="report-profile-attributes"> <div class="report-profile-attributes">
${evidence.profile.attributes.map(([label, value]) => `<span>${label}<strong>${value}</strong></span>`).join("")} ${evidence.profile.attributes.map(([label, value]) => `<span>${label}<strong>${value}</strong></span>`).join("")}
@@ -779,7 +779,7 @@
"composition", "composition",
"2-1", "2-1",
"学校合作企业产业结构", "学校合作企业产业结构",
"企业须同时具备有效协议和近12个月业务记录;126家合作企业均可追溯至协议、需求、课程、项目、实习或就业证据。", "企业须同时具备有效协议和近12个月业务记录;126家合作企业都能找到对应的协议、需求、课程、项目、实习或就业记录。",
donutSvg(evidence), donutSvg(evidence),
options, options,
)} )}
@@ -804,8 +804,8 @@
report, report,
"trend", "trend",
"4-1", "4-1",
"产业需求与培养响应趋势", "产业需求与课程调整趋势",
"需求序列按月度新增岗位、企业确认和薪资变化综合计算;培养响应按课程覆盖、实训项目和学生达成证据计算,二者均以2025年二季度为可比基期。", "需求序列按每月新增岗位、企业确认和薪资变化计算;课程调整序列按课程覆盖、实训项目和学生考核结果计算,二者均以2025年二季度为对比起点。",
trendSvg(evidence), trendSvg(evidence),
options, options,
)} )}
@@ -814,7 +814,7 @@
"matrix", "matrix",
"4-2", "4-2",
"技能供需证据热力矩阵", "技能供需证据热力矩阵",
"每个单元格均可回溯到岗位样本、课程标准、学生项目达成及企业确认四类证据;低于60分视为需要业务复核。", "每个单元格都列出对应的岗位样本、课程标准、学生项目结果和企业确认记录;低于60分时需要业务负责人复核。",
heatmapSvg(evidence), heatmapSvg(evidence),
options, options,
)} )}
@@ -831,7 +831,7 @@
report, report,
"threeD", "threeD",
"4-4", "4-4",
"供需能力立体证据矩阵", "岗位需求与课程覆盖数据表",
"立体柱高同时呈现岗位需求、课程覆盖、学生达成和企业确认四个观察面。在线版支持拖拽旋转,下载版保留固定等距视图。", "立体柱高同时呈现岗位需求、课程覆盖、学生达成和企业确认四个观察面。在线版支持拖拽旋转,下载版保留固定等距视图。",
isometricSvg(evidence), isometricSvg(evidence),
{ ...options, wide: false }, { ...options, wide: false },
@@ -844,15 +844,15 @@
const evidence = buildEvidence(report); const evidence = buildEvidence(report);
return ` return `
<div class="report-evidence-summary"> <div class="report-evidence-summary">
<span><small>统一快照</small><strong>${evidence.snapshot.id}</strong></span> <span><small>本报告快照</small><strong>${evidence.snapshot.id}</strong></span>
<span><small>有效记录</small><strong>${evidence.snapshot.records}</strong></span> <span><small>有效记录</small><strong>${evidence.snapshot.records}</strong></span>
<span><small>质量评分</small><strong>${evidence.snapshot.quality}</strong></span> <span><small>质量评分</small><strong>${evidence.snapshot.quality}</strong></span>
<span><small>技能映射覆盖</small><strong>${evidence.snapshot.coverage}</strong></span> <span><small>技能映射覆盖</small><strong>${evidence.snapshot.coverage}</strong></span>
</div> </div>
<div class="report-proof-chain"> <div class="report-proof-chain">
<span><i>01</i><strong>原始事实</strong><small>保留来源、权属、时间戳</small></span> <span><i>01</i><strong>原始记录</strong><small>保留来源、权属、时间戳</small></span>
<b></b> <b></b>
<span><i>02</i><strong>规则治理</strong><small>去重、归一、异常降权</small></span> <span><i>02</i><strong>数据处理</strong><small>去重、统一名称、降低异常数据权重</small></span>
<b></b> <b></b>
<span><i>03</i><strong>指标计算</strong><small>样本阈值与基准校验</small></span> <span><i>03</i><strong>指标计算</strong><small>样本阈值与基准校验</small></span>
<b></b> <b></b>
@@ -882,7 +882,7 @@
</div> </div>
<div class="report-evidence-notice"> <div class="report-evidence-notice">
<strong>证据使用边界</strong> <strong>证据使用边界</strong>
<p>校内学生、课程、教师、实习和就业事实以学校业务系统为准;互联网岗位仅用于判断外部需求趋势;企业数据只在协议授权范围内用于需求确认。任何单一来源都不直接触发专业撤并或招生调整。</p> <p>校内学生、课程、教师、实习和就业数据以学校业务系统为准;互联网岗位只用于判断外部需求变化;企业数据只在协议授权范围内用于确认需求。任何单一来源都不能直接决定专业撤并或招生调整。</p>
</div> </div>
`; `;
} }
@@ -1063,7 +1063,7 @@
}, },
}, },
{ {
name: "培养响应", name: "课程调整",
type: "line", type: "line",
smooth: true, smooth: true,
symbolSize: 7, symbolSize: 7,
+4 -4
View File
@@ -23,11 +23,11 @@
2. 使用官方 API、授权数据包或明确允许自动访问的公开页面; 2. 使用官方 API、授权数据包或明确允许自动访问的公开页面;
3. 运行时 robots.txt 允许当前 User-Agent 和 URL; 3. 运行时 robots.txt 允许当前 User-Agent 和 URL;
4. 来源域名在连接器 allowlist 中,禁止任意 URL 和内网地址; 4. 来源域名在连接器 allowlist 中,禁止任意 URL 和内网地址;
5. 使用可识别的 User-Agent 和真实技术联系邮箱; 5. 使用可识别的 User-Agent 和可联系的技术邮箱;
6. 遵守来源级请求速率、并发、时间窗、停止条件和数据保留策略; 6. 遵守来源级请求速率、并发、时间窗、停止条件和数据保留策略;
7. 页面出现登录、验证码、访问验证、封禁提示或条款变化时立即停止,不尝试绕过。 7. 页面出现登录、验证码、访问验证、封禁提示或条款变化时立即停止,不尝试绕过。
校内来源必须基于学校授权的数据处理协议,使用只读账号、租户隔离和最小字段集。平台禁止接收姓名、身份证号、手机号和明文学号。 校内来源必须取得学校的数据处理授权,并使用只读账号、租户隔离和最小字段集。平台禁止接收姓名、身份证号、手机号和明文学号。
## 3. 九个来源的实现方式 ## 3. 九个来源的实现方式
@@ -93,7 +93,7 @@
- 不是网页爬虫,使用学校提供的只读视图、API 或标准文件; - 不是网页爬虫,使用学校提供的只读视图、API 或标准文件;
- 来源记录在学校侧先生成不可逆 `student_token`; - 来源记录在学校侧先生成不可逆 `student_token`;
- 连接器拒绝包含姓名、身份证、手机号、邮箱或明文学号的输入; - 连接器拒绝包含姓名、身份证、手机号、邮箱或明文学号的输入;
- 以 `tenant_id + source_record_id + source_updated_at` 形成增量和幂等边界。 - 使用 `tenant_id + source_record_id + source_updated_at` 判断增量更新和重复请求。
### 3.9 校内实习管理系统 ### 3.9 校内实习管理系统
@@ -113,7 +113,7 @@
→ normalize(JOB-SIGNAL / SCHOOL-*) → normalize(JOB-SIGNAL / SCHOOL-*)
→ schema validate → schema validate
→ standard.ndjson / quarantine.ndjson / summary.json → standard.ndjson / quarantine.ndjson / summary.json
→ 质量门禁与候选版本 → 发布质量检查与候选版本
``` ```
失败分类至少包括: 失败分类至少包括:
+11 -11
View File
@@ -1,8 +1,8 @@
# 厂商数据中台与校园平台闭环基线 # 厂商数据中台与校园平台对接说明
## 1. 目标 ## 1. 目标
两端产品使用同一组业务标识展示完整证据链,但职责和数据边界保持分离: 两端产品使用同一组业务标识核对记录,但各自负责不同的工作和数据:
- 厂商端负责数据源、采集、质量、数据产品发布、学校交付和交付回执; - 厂商端负责数据源、采集、质量、数据产品发布、学校交付和交付回执;
- 校园端负责学校接收、校内验收、分析快照、专业诊断、改进执行、报告审批和使用反馈; - 校园端负责学校接收、校内验收、分析快照、专业诊断、改进执行、报告审批和使用反馈;
@@ -24,7 +24,7 @@
| 企业需求 | `DEM-HKVS-20260823-01` | 校园端/企业 | | 企业需求 | `DEM-HKVS-20260823-01` | 校园端/企业 |
| 专业建议 | `REC-SOFTWARE-20260823-01` | 校园端 | | 专业建议 | `REC-SOFTWARE-20260823-01` | 校园端 |
| 改进任务 | `TSK-SOFTWARE-20260823-01` | 校园端 | | 改进任务 | `TSK-SOFTWARE-20260823-01` | 校园端 |
| 协同项目 | `PRJ-HKVS-20260823-01` | 校园端 | | 合作项目 | `PRJ-HKVS-20260823-01` | 校园端 |
| 执行证据 | `EVD-HKVS-01…` | 校园端 | | 执行证据 | `EVD-HKVS-01…` | 校园端 |
| 企业评价 | `EVL-HKVS-20260823-01` | 企业 | | 企业评价 | `EVL-HKVS-20260823-01` | 企业 |
| 报告版本 | `RPT-HZVTC-20260823-01` | 校园端 | | 报告版本 | `RPT-HZVTC-20260823-01` | 校园端 |
@@ -48,11 +48,11 @@ PENDING → SENDING → DELIVERED
ACKNOWLEDGED → ROLLED_BACK ACKNOWLEDGED → ROLLED_BACK
``` ```
“数据包已发布”只表示厂商稳定版本已生成,不能直接显示“学校已收到”。厂商端只有 `FIX_REPLAY` 的记录数、规则结果和独立复核签名全部通过后才可解除质量门禁;`WAIVE`、`DISCARD` 保持阻断。学校回执中的租户、包号、版本、记录数、完整 SHA-256 和授权范围全部通过后,交付才能进入 `ACKNOWLEDGED`。 “数据包已发布”只表示厂商稳定版本已生成,不能直接显示“学校已收到”。厂商端只有 `FIX_REPLAY` 的记录数、规则结果和独立复核签名全部通过检查后才可继续发布;`WAIVE`、`DISCARD` 仍不能发布。学校回执中的租户、包号、版本、记录数、完整 SHA-256 和授权范围全部通过后,交付才能进入 `ACKNOWLEDGED`。
交付记录数和学校分析快照样本量是不同口径:样板杭州租户文件为 `2,846,320` 条,校园端验收后生成 `128,642` 条有效分析快照,不能互相覆盖。 交付记录数和学校分析快照样本量是不同口径:样板杭州租户文件为 `2,846,320` 条,校园端验收后生成 `128,642` 条有效分析快照,不能互相覆盖。
### 校园业务闭环 ### 校园业务流程
```text ```text
DeliveryReceipt DeliveryReceipt
@@ -78,7 +78,7 @@ BASELINE → FOLLOW_UP → IMPROVED | UNCHANGED | WORSENED
每次状态迁移都必须产生不可变审计事件,包含操作者、前后状态、时间、意见、证据和 `trace_id`。 每次状态迁移都必须产生不可变审计事件,包含操作者、前后状态、时间、意见、证据和 `trace_id`。
## 4. 静态原型的可信边界 ## 4. 静态原型能做什么
两个静态页面分别使用自己的浏览器本地状态,只用于刷新后继续当前页面的演示: 两个静态页面分别使用自己的浏览器本地状态,只用于刷新后继续当前页面的演示:
@@ -87,7 +87,7 @@ BASELINE → FOLLOW_UP → IMPROVED | UNCHANGED | WORSENED
- 页面必须明确“未连接后端,不代表另一端已实时收到”; - 页面必须明确“未连接后端,不代表另一端已实时收到”;
- 两端相同的固定 ID 只用于人工核对业务链,不等于网络同步。 - 两端相同的固定 ID 只用于人工核对业务链,不等于网络同步。
需要展示真实跨页面交接时,使用可下载、可导入的文件: 需要展示两个页面之间的数据交接时,使用可下载、可导入的文件:
1. 厂商导出 Manifest 和交付信封 JSON; 1. 厂商导出 Manifest 和交付信封 JSON;
2. 学校导入后校验文件哈希与租户授权; 2. 学校导入后校验文件哈希与租户授权;
@@ -100,19 +100,19 @@ BASELINE → FOLLOW_UP → IMPROVED | UNCHANGED | WORSENED
| 服务 | 关键职责 | | 服务 | 关键职责 |
|---|---| |---|---|
| Data Product API | 数据包构建、质量门禁、审批、发布和回滚 | | Data Product API | 数据包生成、质量检查、审批、发布和回滚 |
| Entitlement & Delivery API | 租户授权、逐学校交付、重试、撤回 | | Entitlement & Delivery API | 租户授权、逐学校交付、重试、撤回 |
| Receipt API | 幂等接收回执、记录数和哈希校验 | | Receipt API | 幂等接收回执、记录数和哈希校验 |
| Campus Ingestion API | 学校暂存、质量校验、业务审批、激活和回滚 | | Campus Ingestion API | 学校暂存、质量校验、业务审批、激活和回滚 |
| Analysis API | 基于不可变数据版本生成分析快照 | | Analysis API | 使用不可修改的数据版本生成分析快照 |
| Collaboration API | 需求、建议、项目、任务、证据、评价和验收 | | Collaboration API | 需求、建议、项目、任务、证据、评价和验收 |
| Report API | 报告版本、审批、发布、下载和证据引用 | | Report API | 报告版本、审批、发布、下载和证据引用 |
| Feedback API | 学校反馈、厂商处置、学校复验和关闭 | | Feedback API | 学校反馈、厂商处置、学校复验和关闭 |
| Audit & Notification | 统一追踪、不可篡改审计、通知和超时升级 | | Audit & Notification | 统一追踪、不可篡改审计、通知和超时升级 |
大文件只通过对象存储短期签名地址传递,业务 API 不直接承载数据包或附件正文。 大文件只通过对象存储短期签名地址传递,业务 API 不直接传输数据包或附件正文。
## 6. 验收黄金路径 ## 6. 验收顺序
1. 厂商完成质量处置并创建 `REL-20260823-01`; 1. 厂商完成质量处置并创建 `REL-20260823-01`;
2. 独立审批人批准后发布 `EDU-PKG-20260823-01`; 2. 独立审批人批准后发布 `EDU-PKG-20260823-01`;
+24 -24
View File
@@ -2,9 +2,9 @@
## 1. 产品定位 ## 1. 产品定位
产教融智不是单一数据看板,而是面向职业院校的供需分析与产教协同工作平台。产品将外部产业信号、学校培养事实和企业确认需求分层治理,并把分析结论转化为可执行、可验收、可复核的改进任务。 产教融智供职业院校查看岗位变化和专业差距,安排企业合作,跟进改进任务并出具报告。数据分为外部岗位数据、学校业务数据和企业确认需求三类。
核心闭环: 主要流程:
1. 数据接入与版本验收; 1. 数据接入与版本验收;
2. 产业岗位、技能和企业需求分析; 2. 产业岗位、技能和企业需求分析;
@@ -20,15 +20,15 @@
|---|---|---|---| |---|---|---|---|
| 校级管理者 | 决策总览 | 查看全校供需态势、批准重点行动、协调学院与企业资源 | 可查看全校汇总和授权范围内明细 | | 校级管理者 | 决策总览 | 查看全校供需态势、批准重点行动、协调学院与企业资源 | 可查看全校汇总和授权范围内明细 |
| 校级技术管理员 | 学校数据运维中心 | 接入学校数据源、执行更新、处理质量问题、管理版本与审计 | 可维护学校租户数据,不默认拥有业务审批权 | | 校级技术管理员 | 学校数据运维中心 | 接入学校数据源、执行更新、处理质量问题、管理版本与审计 | 可维护学校租户数据,不默认拥有业务审批权 |
| 学院负责人 | 专业洞察 | 复核本院专业差距、推进课程和项目调整、提交阶段证据 | 仅本学院及所属专业 | | 学院负责人 | 专业分析 | 复核本院专业差距、推进课程和项目调整、提交阶段证据 | 仅本学院及所属专业 |
| 专业负责人 | 业务流程 | 决策专业建议、推进关联任务与项目、提交证据、完成下一周期复核 | 仅负责专业及其关联需求、项目和任务 | | 专业负责人 | 业务流程 | 决策专业建议、推进关联任务与项目、提交证据、完成下一周期复核 | 仅负责专业及其关联需求、项目和任务 |
| 就业老师 | 业务流程 | 确认就业侧数据可用性、记录使用反馈和下一周期关注项 | 就业业务域及授权汇总,不拥有校级报告审批权 | | 就业老师 | 业务流程 | 确认就业侧数据可用性、记录使用反馈和下一周期关注项 | 就业业务域及授权汇总,不拥有校级报告审批权 |
| 企业导师 | 企业协同工作台 | 提交企业需求、参与项目和课程共建、确认企业评价 | 仅本企业授权及参与项目 | | 企业导师 | 企业合作工作台 | 提交企业需求、参与项目和课程共建、确认企业评价 | 仅本企业授权及参与项目 |
| 厂商超级管理员 | 平台运营中心 | 维护基础数据包、租户、平台账号、备份、服务和平台审计 | 默认不可读取学校明文业务数据 | | 厂商超级管理员 | 平台运营中心 | 维护基础数据包、租户、平台账号、备份、服务和平台审计 | 默认不可读取学校明文业务数据 |
### 2.1 职责分离 ### 2.1 职责分离
- 厂商负责公共基础数据包的采集治理、Schema、版本、订阅授权和平台运行。 - 厂商负责公共基础数据包的采集、检查、Schema、版本、订阅授权和平台运行。
- 学校信息中心负责校内接口、文件接入、技术校验、调度、隔离区和版本发布。 - 学校信息中心负责校内接口、文件接入、技术校验、调度、隔离区和版本发布。
- 教务处、就业处、产教融合中心等业务部门负责字段含义、数据正确性和发布审批。 - 教务处、就业处、产教融合中心等业务部门负责字段含义、数据正确性和发布审批。
- 企业联系人负责企业身份、需求内容、授权用途和有效期确认。 - 企业联系人负责企业身份、需求内容、授权用途和有效期确认。
@@ -38,7 +38,7 @@
### 2.2 可交互业务流程图 ### 2.2 可交互业务流程图
校园端“业务流程”必须用节点和有向边表达真实状态流,而不是把实体状态平铺成卡片: 校园端“业务流程”必须用节点和有向边表达业务办理顺序,而不是把状态平铺成卡片:
1. 企业需求; 1. 企业需求;
2. 接收与分析快照; 2. 接收与分析快照;
@@ -70,7 +70,7 @@
### 3.2 学校自有数据 ### 3.2 学校自有数据
包括专业、课程、学生、教师、实习、就业、校企合作项目等学校业务事实。数据权属归学校,厂商只按合同约定提供处理能力。 包括专业、课程、学生、教师、实习、就业、校企合作项目等学校业务数据。数据权属归学校,厂商只按合同约定处理。
### 3.3 企业授权数据 ### 3.3 企业授权数据
@@ -84,7 +84,7 @@
| 薪资与企业画像基础包 | 岗位薪资区间、企业行业、规模和统计周期 | Parquet / CSV UTF-8 | `package_id + enterprise_id + position_code` | 月度增量 | 厂商数据产品部 | 厂商数据运维组 | | 薪资与企业画像基础包 | 岗位薪资区间、企业行业、规模和统计周期 | Parquet / CSV UTF-8 | `package_id + enterprise_id + position_code` | 月度增量 | 厂商数据产品部 | 厂商数据运维组 |
| 专业与课程数据 | 有效专业、课程、课程标准、教学班、学时、技能标签和版本 | XLSX / CSV / API | `tenant_id + course_code + curriculum_version` | 学期快照,变更事件增量 | 教务处 | 学校信息中心 | | 专业与课程数据 | 有效专业、课程、课程标准、教学班、学时、技能标签和版本 | XLSX / CSV / API | `tenant_id + course_code + curriculum_version` | 学期快照,变更事件增量 | 教务处 | 学校信息中心 |
| 实习数据 | 学生、专业、企业、岗位、起止日期、状态和评价 | API JSON / 数据库视图 | `tenant_id + internship_id` | 每日增量 | 就业处或实习管理部门 | 学校信息中心 | | 实习数据 | 学生、专业、企业、岗位、起止日期、状态和评价 | API JSON / 数据库视图 | `tenant_id + internship_id` | 每日增量 | 就业处或实习管理部门 | 学校信息中心 |
| 就业数据 | 毕业届次、就业状态、岗位、企业、薪资和更新时间 | API JSON / 数据库视图 | `tenant_id + student_id + cohort` | 每日增量,关键统计期冻结快照 | 就业处 | 学校信息中心 | | 就业数据 | 毕业届次、就业状态、岗位、企业、薪资和更新时间 | API JSON / 数据库视图 | `tenant_id + student_id + cohort` | 每日增量,关键统计期内快照不再修改 | 就业处 | 学校信息中心 |
| 企业确认需求 | 企业身份、岗位、人数、技能、有效期、提交人、确认时间和授权编号 | 工作台表单 / API / XLSX | `tenant_id + enterprise_credit_code + demand_id` | 企业提交后事件增量 | 产教融合中心与企业联系人 | 学校信息中心 | | 企业确认需求 | 企业身份、岗位、人数、技能、有效期、提交人、确认时间和授权编号 | 工作台表单 / API / XLSX | `tenant_id + enterprise_credit_code + demand_id` | 企业提交后事件增量 | 产教融合中心与企业联系人 | 学校信息中心 |
### 4.1 所有来源必须提供 ### 4.1 所有来源必须提供
@@ -97,7 +97,7 @@
- Schema 版本、数据版本、变更说明和样例数据; - Schema 版本、数据版本、变更说明和样例数据;
- 质量阈值、失败处理、回滚要求和留存期限。 - 质量阈值、失败处理、回滚要求和留存期限。
### 4.2 推荐基础质量门槛 ### 4.2 建议的最低质量要求
- 主键唯一率:100%; - 主键唯一率:100%;
- 核心代码合法率:100%; - 核心代码合法率:100%;
@@ -111,12 +111,12 @@
### 4.3 数据与报告双向依赖 ### 4.3 数据与报告双向依赖
每个报告模板必须登记版本化的数据依赖,不允许只在报告生成代码中形成不可见的隐式关系。依赖至少包含: 每个报告模板必须登记版本化的数据依赖,不能只把依赖写在报告生成代码中。依赖至少包含:
- 报告模板、报告类型和适用组织范围; - 报告模板、报告类型和适用组织范围;
- 数据源、数据契约和最低版本; - 数据源、数据契约和最低版本;
- `required`(必需)或 `optional`(可选增强)关系; - `required`(必需)或 `optional`(可选增强)关系;
- 支撑的指标或分析主题; - 使用该数据的指标或分析主题;
- 最低完整率、质量阈值、时效与授权要求; - 最低完整率、质量阈值、时效与授权要求;
- 缺失字段、降权或阻断策略; - 缺失字段、降权或阻断策略;
- 业务索取人、技术接口人、要求完成日期和处理状态。 - 业务索取人、技术接口人、要求完成日期和处理状态。
@@ -124,9 +124,9 @@
产品提供两个方向的查询: 产品提供两个方向的查询:
1. 从报告反查必需和可选数据,计算当前完备度并列出缺口; 1. 从报告反查必需和可选数据,计算当前完备度并列出缺口;
2. 从数据反查可形成的分析主题、报告类型、具体报告和影响范围。 2. 从数据反查可做的分析、使用该数据的报告类型、具体报告和影响范围。
依赖元数据用于数据治理和补数协同,可以向获得数据运维权限的角色开放;报告正文、明细指标和样本仍按组织、角色与数据范围独立鉴权。查看依赖关系不得自动授予报告阅读权限。 依赖信息供数据检查和跨部门补数据时使用,可向有数据运维权限的角色开放;报告正文、明细指标和样本仍按组织、角色与数据范围单独授权。查看依赖关系不会自动获得报告阅读权限。
## 5. 导入与发布流程 ## 5. 导入与发布流程
@@ -182,7 +182,7 @@
### 7.1 静态原型持久化与正式 API 边界 ### 7.1 静态原型持久化与正式 API 边界
校园闭环静态原型采用 `localStorage` 命名空间 `eduIndustry.campusClosedLoop.TENANT-HZVTC.v1`,当前 `schemaVersion=2`,包含安全迁移、可重置种子、闭环实体和 `auditEvents`。共享样板标识固定为: 校园业务流程静态原型采用 `localStorage` 命名空间 `eduIndustry.campusClosedLoop.TENANT-HZVTC.v1`,当前 `schemaVersion=2`,包含安全迁移、可重置种子、流程实体和 `auditEvents`。共享样板标识固定为:
- 租户:`TENANT-HZVTC`; - 租户:`TENANT-HZVTC`;
- 厂商包:`EDU-PKG-20260823-01`; - 厂商包:`EDU-PKG-20260823-01`;
@@ -196,29 +196,29 @@
技术接收必须对租户、包号、版本、记录数和完整 SHA-256 执行强一致性校验。任一失败时回执、分析快照和业务状态均不得前进,只能追加失败审计。交付包记录数不能覆盖分析快照样本量,两者必须作为不同口径分别保存。 技术接收必须对租户、包号、版本、记录数和完整 SHA-256 执行强一致性校验。任一失败时回执、分析快照和业务状态均不得前进,只能追加失败审计。交付包记录数不能覆盖分析快照样本量,两者必须作为不同口径分别保存。
正式系统必须将状态流转放在后端事务/API 中:服务端依据租户、组织、角色、数据范围、对象所属企业和当前状态校验每个命令;采用幂等键与乐观锁防止重复或越序流转;证据文件进入受控对象存储并进行病毒扫描、哈希和访问授权;审计日志追加写入且不可由业务用户修改。前端菜单、按钮隐藏和 `disabled` 仅用于交互提示,不能替代服务端鉴权。 正式系统必须将状态流转放在后端事务/API 中:服务端依据租户、组织、角色、数据范围、对象所属企业和当前状态校验每个命令;采用幂等键和版本号校验防止重复或越序流转;证据文件保存到限制访问的对象存储,并进行病毒扫描、哈希校验和访问授权;审计日志只允许追加,不可由业务用户修改。前端菜单、按钮隐藏和 `disabled` 仅用于交互提示,不能替代服务端鉴权。
## 8. 产品验收基线 ## 8. 产品验收基线
- 七种角色默认入口和菜单范围正确; - 七种角色默认入口和菜单范围正确;
- 业务流程图完整显示 11 个节点、主路径和三类回流边,节点选择会联动输入、输出、责任角色、关键字段和关联实体; - 业务流程图完整显示 11 个节点、主路径和三类回流边,节点选择会联动输入、输出、责任角色、关键字段和关联实体;
- 业务流程按企业导师、校级技术管理员、专业负责人、学院负责人、校级管理者和就业老师显示可办理节点与禁用原因,厂商超级管理员只读; - 业务流程按企业导师、校级技术管理员、专业负责人、学院负责人、校级管理者和就业老师显示可办理节点与禁用原因,厂商超级管理员只读;
- 当前角色可从已解锁节点直接打开原有业务表单,节点状态推进后流程图、详情、角色待办和审计同步更新; - 当前角色可从满足条件的节点直接打开原有业务表单,节点状态推进后流程图、详情、角色待办和审计同步更新;
- 闭环状态、审批历史和审计事件刷新后保留,重置后恢复 Schema V2 种子; - 流程状态、审批历史和审计事件刷新后保留,重置后恢复 Schema V2 种子;
- 技术接收后当前企业需求版本锁定,报告生成后当前任务证据冻结; - 技术接收后不能修改当前企业需求,报告生成后不能再给当前任务追加证据;
- 损坏的 V2 深层实体或历史数组不会导致页面崩溃,而是按安全策略重建并记录 `SECURITY_SCHEMA_RESET`; - 损坏的 V2 深层实体或历史数组不会导致页面崩溃,而是按安全策略重建并记录 `SECURITY_SCHEMA_RESET`;
- 租户、包号、版本、交付记录数或 SHA-256 任一错误时,技术接收和分析快照均保持原状态; - 租户、包号、版本、交付记录数或 SHA-256 任一错误时,技术接收和分析快照均保持原状态;
- 阶段进度未达到 100% 时不能企业评价,企业评价缺失或为“需整改”时任务不能校级验收; - 阶段进度未达到 100% 时不能企业评价,企业评价缺失或为“需整改”时任务不能校级验收;
- 报告提交人与审批人必须分离,非校级管理者不能审批发布;报告未批准时不能发布,未正式发布时反馈阻断且下载明确标识非正式版; - 报告提交人与审批人必须分离,非校级管理者不能审批发布;报告未批准时不能发布,未正式发布时反馈阻断且下载明确标识非正式版;
- 专业四个标签页均有完整内容和证据入口; - 专业四个标签页均有完整内容和证据入口;
- 数据源可查看更新日期、更新内容、数据要求、版本任务和授权审计; - 数据源可查看更新日期、更新内容、数据要求、版本任务和授权审计;
- 42 份报告均可反查必需和可选数据,6 个数据源均可反查支撑的分析主题与报告; - 42 份报告均可反查必需和可选数据,6 个数据源均可反查相关分析主题与使用它的报告;
- 缺口视图展示缺失字段、完整率、影响报告、业务索取人、技术接口人、完成日期与状态,并可进入质量处置; - 缺口视图展示缺失字段、完整率、影响报告、业务索取人、技术接口人、完成日期与状态,并可进入质量处置;
- 依赖元数据可见性与报告正文权限分离,未授权角色不能从图谱绕过报告阅读权限; - 依赖元数据可见性与报告正文权限分离,未授权角色不能从图谱绕过报告阅读权限;
- 新建任务、项目和需求后立即进入对应列表; - 新建任务、项目和需求后立即进入对应列表;
- 报告建议加入任务后可在任务中心追踪; - 报告建议加入任务后可在任务中心追踪;
- 报告生成后新增可审核版本; - 报告生成后新增可审核版本;
- 报告包含八类图表、学校事实、四类证据源和七章正文; - 报告包含八类图表、学校数据、四类数据来源和七章正文;
- ECharts 不可用时显示静态 SVG; - ECharts 不可用时显示静态 SVG;
- 离线报告无外部依赖; - 离线报告无外部依赖;
- 桌面 `1440 × 900` 和移动 `390 × 844` 无页面级横向溢出; - 桌面 `1440 × 900` 和移动 `390 × 844` 无页面级横向溢出;
@@ -228,11 +228,11 @@
## 9. 推荐客户展示路径 ## 9. 推荐客户展示路径
1. 产品导览说明“看得清、落得下、讲得明”; 1. 产品导览说明“看得清、落得下、讲得明”;
2. 决策总览展示可信数据和本期关键变化; 2. 决策总览展示数据来源和本期变化;
3. 专业洞察展示岗位、薪资、课程和技能证据; 3. 专业分析展示岗位、薪资、课程和技能证据;
4. 校企协同展示企业需求到项目验收; 4. 校企合作展示企业需求到项目验收;
5. 在业务流程图依次点击需求、快照、建议、任务、项目、证据、评价、验收、报告、反馈和复核节点,并切换角色验证办理与回流; 5. 在业务流程图依次点击需求、快照、建议、任务、项目、证据、评价、验收、报告、反馈和复核节点,并切换角色验证办理与回流;
6. 改进任务展示负责人、进度和验收证据; 6. 改进任务展示负责人、进度和验收证据;
7. 在数据资产页双向演示“报告需要哪些数据”和“数据可形成哪些报告”,切换只看缺口并进入补数责任处置; 7. 在数据资产页双向演示“报告需要哪些数据”和“哪些报告使用这些数据”,切换只看缺口并进入补数责任处置;
8. 切换校级技术管理员,展示数据导入、更新、质量、接收反馈和审计; 8. 切换校级技术管理员,展示数据导入、更新、质量、接收反馈和审计;
9. 打开全校报告和供需会展示大屏完成交付说明。 9. 打开全校报告和供需会展示大屏完成交付说明。
+12 -10
View File
@@ -1,10 +1,12 @@
我先把这组方向整理成一个清晰的产品矩阵。整体可归纳为 **平台产品、工具产品、定制服务、垂直行业方案** 四条产品线。 # 产品线建议
产品分为 **平台产品、工具产品、定制服务、行业方案** 四类。
| 产品线 | 方向 | 主要客户 | 产品形态 | 核心内容 | | 产品线 | 方向 | 主要客户 | 产品形态 | 核心内容 |
|---|---|---|---|---| |---|---|---|---|---|
| 平台产品 | 产教结合 | 高校、职业院校、产业学院、企业培训部门 | 产教融合平台 | 专业建设、课程共建、项目实训、企业导师、过程管理、成果评价 | | 平台产品 | 产教结合 | 高校、职业院校、产业学院、企业培训部门 | 产教融合平台 | 专业建设、课程共建、项目实训、企业导师、过程管理、成果评价 |
| 工具产品 | 录播课程转 AI 课程 | 教师、教研室、课程制作团队 | AI 课程生产工具 | 从录播内容提取教纲,生成课程思政建议、PPT、数字人课程及配套教学材料 | | 工具产品 | 录播课程转 AI 课程 | 教师、教研室、课程制作团队 | AI 课程生产工具 | 从录播内容提取教纲,生成课程思政建议、PPT、数字人课程及配套教学材料 |
| 定制服务 | 知识库与个性化应用 | 学校、学院、专业团队及机构客户 | 私有知识库+定制智能应用 | 文档治理、知识检索、智能问答、个性化教学与业务工作流 | | 定制服务 | 知识库与个性化应用 | 学校、学院、专业团队及机构客户 | 私有知识库+定制智能应用 | 文档整理、知识检索、智能问答、个性化教学与业务工作流 |
| 垂直方案 | 宴席/越剧 | 专业、学院及行业机构 | 专业知识平台+教学应用 | 专业知识整理、课程资源建设、行业问答、数字内容生产及特色人才培养 | | 垂直方案 | 宴席/越剧 | 专业、学院及行业机构 | 专业知识平台+教学应用 | 专业知识整理、课程资源建设、行业问答、数字内容生产及特色人才培养 |
## 建议采用的产品架构 ## 建议采用的产品架构
@@ -52,14 +54,14 @@
- 校级、院级和专业级知识库; - 校级、院级和专业级知识库;
- 教材、教案、制度、案例和行业资料入库; - 教材、教案、制度、案例和行业资料入库;
- 基于授权资料的检索与问答; - 检索已获授权的资料并回答问题;
- 面向教师、学生和管理人员的不同入口; - 面向教师、学生和管理人员的不同入口;
- 个性化学习建议; - 个性化学习建议;
- 专业术语词典和引用溯源; - 专业术语词典和引用溯源;
- 权限、版本、审计与内容更新; - 权限、版本、审计与内容更新;
- 与现有教学平台或业务系统对接。 - 与现有教学平台或业务系统对接。
产品化部分应尽量沉淀为统一知识库平台;客户特有的数据治理、接口和工作流作为定制项目交付。 各客户都需要的功能放进统一知识库平台;客户特有的数据处理、接口和工作流单独交付。
### 四、宴席与越剧垂直方案 ### 四、宴席与越剧垂直方案
@@ -103,7 +105,7 @@
│ ├─ 课程思政辅助 │ ├─ 课程思政辅助
│ └─ 数字人课程 │ └─ 数字人课程
├─ 专业知识库 ├─ 专业知识库
│ ├─ 文档治理 │ ├─ 文档整理
│ ├─ 检索问答 │ ├─ 检索问答
│ ├─ 内容溯源 │ ├─ 内容溯源
│ └─ 个性化应用 │ └─ 个性化应用
@@ -116,8 +118,8 @@
- **产教融合平台**负责组织、课程、项目和教学过程; - **产教融合平台**负责组织、课程、项目和教学过程;
- **AI 课程工具**负责内容加工; - **AI 课程工具**负责内容加工;
- **知识库**负责专业资料沉淀和可信问答; - **知识库**负责保存专业资料,并在回答中注明引用;
- **宴席、越剧**是平台与工具在具体专业中的落地方案。 - **宴席、越剧**按各专业的资料和教学要求单独配置。
## 更简洁的对外表述 ## 更简洁的对外表述
@@ -125,8 +127,8 @@
## 建议优先级 ## 建议优先级
1. **先做录播转 AI 课程工具**:输入输出明确,容易形成可演示产品。 1. **先做录播转 AI 课程工具**:输入输出明确,容易做出演示版本。
2. **同步建设知识库底层能力**:为教纲、PPT、问答和垂直专业应用提供统一事实来源。 2. **同步完成知识库的检索、引用和权限功能**:供教纲、PPT、问答和专业应用共用。
3. **将工具接入产教融合平台**:形成课程建设、项目实训和评价的完整业务流程。 3. **将工具接入产教融合平台**:让课程建设、项目实训和评价在同一流程中办理。
4. **选择一个垂直专业做样板**:如果已有越剧学院、教师和授权资料,优先做越剧;如果宴席专业的数据和课程更完备,则先做宴席。 4. **选择一个垂直专业做样板**:如果已有越剧学院、教师和授权资料,优先做越剧;如果宴席专业的数据和课程更完备,则先做宴席。
5. **唱腔生成放在研究或联合实验室阶段**:首期避免把实验能力写成正式交付承诺。 5. **唱腔生成放在研究或联合实验室阶段**:首期避免把实验能力写成正式交付承诺。