Compare commits
7 Commits
a01d2ab708
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1e234df768 | ||
|
|
c3eaa7c643 | ||
|
|
3fa7ffa4c9 | ||
|
|
5d51a6bf7a | ||
|
|
ff4b7b67dc | ||
|
|
cf82f25611 | ||
|
|
b14425da5a |
@@ -13,7 +13,8 @@
|
|||||||
},
|
},
|
||||||
"versionCollaboration": {
|
"versionCollaboration": {
|
||||||
"remote": {
|
"remote": {
|
||||||
"url": "https://gitea.lnh2e.com/wangmian/OneOS1.2.git"
|
"url": "https://gitea.lnh2e.com/wangmian/OneOS1.2.git",
|
||||||
|
"defaultBranch": "main"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"cloudPublishing": {
|
"cloudPublishing": {
|
||||||
|
|||||||
@@ -1,7 +1,49 @@
|
|||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"updatedAt": "2026-07-21T08:13:15.367Z",
|
"updatedAt": "2026-07-24T17:38:43.442Z",
|
||||||
"prototypes": [
|
"prototypes": [
|
||||||
|
{
|
||||||
|
"id": "item-prototypes-autorodo-web",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "autorodo web",
|
||||||
|
"itemKey": "prototypes/autorodo-web"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item-prototypes-oneos-v2-h5-vehicle-assets",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "oneos v2 h5 vehicle assets",
|
||||||
|
"itemKey": "prototypes/oneos-v2-h5-vehicle-assets"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item-prototypes-oneos-v2-form-kit",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "oneos v2 form kit",
|
||||||
|
"itemKey": "prototypes/oneos-v2-form-kit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:payment-qr-code",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "羚牛收款二维码",
|
||||||
|
"itemKey": "prototypes/payment-qr-code"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:lease-contract-redesign",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "lease-contract-redesign",
|
||||||
|
"itemKey": "prototypes/lease-contract-redesign"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:vehicle-inspection",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "验车入库",
|
||||||
|
"itemKey": "prototypes/vehicle-inspection"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:vehicle-purchase-contract",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "车辆采购合同",
|
||||||
|
"itemKey": "prototypes/vehicle-purchase-contract"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "folder-1782874576229-r8atbu",
|
"id": "folder-1782874576229-r8atbu",
|
||||||
"kind": "folder",
|
"kind": "folder",
|
||||||
@@ -13,12 +55,24 @@
|
|||||||
"title": "原型演示",
|
"title": "原型演示",
|
||||||
"itemKey": "prototypes/oneos-prototype-demo"
|
"itemKey": "prototypes/oneos-prototype-demo"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:oneos-v2",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "OneOS V2 全局规范示范",
|
||||||
|
"itemKey": "prototypes/oneos-v2"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "item:prototypes:oneos-web-workbench-new",
|
"id": "item:prototypes:oneos-web-workbench-new",
|
||||||
"kind": "item",
|
"kind": "item",
|
||||||
"title": "工作台",
|
"title": "工作台",
|
||||||
"itemKey": "prototypes/oneos-web-workbench-new"
|
"itemKey": "prototypes/oneos-web-workbench-new"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:message-center",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "消息中心",
|
||||||
|
"itemKey": "prototypes/message-center"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "folder-oneos-approval",
|
"id": "folder-oneos-approval",
|
||||||
"kind": "folder",
|
"kind": "folder",
|
||||||
@@ -63,6 +117,19 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "folder-oneos-vehicle-ops",
|
||||||
|
"kind": "folder",
|
||||||
|
"title": "车辆运维",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:vehicle-fault-handling",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "故障处置",
|
||||||
|
"itemKey": "prototypes/vehicle-fault-handling"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "folder-1782874624657-4c8hzv",
|
"id": "folder-1782874624657-4c8hzv",
|
||||||
"kind": "folder",
|
"kind": "folder",
|
||||||
@@ -262,11 +329,300 @@
|
|||||||
"title": "业务条线说明",
|
"title": "业务条线说明",
|
||||||
"itemKey": "prototypes/lease-business-line-overview"
|
"itemKey": "prototypes/lease-business-line-overview"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:autorodo-web",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "AutoRDO 需求清洗工作台",
|
||||||
|
"itemKey": "prototypes/autorodo-web"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "item:prototypes:yunxiao-pipeline-handbook",
|
"id": "item:prototypes:yunxiao-pipeline-handbook",
|
||||||
"kind": "item",
|
"kind": "item",
|
||||||
"title": "云效生产线手册",
|
"title": "云效生产线手册",
|
||||||
"itemKey": "prototypes/yunxiao-pipeline-handbook"
|
"itemKey": "prototypes/yunxiao-pipeline-handbook"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "folder-ds-v2-legacy-snapshots",
|
||||||
|
"kind": "folder",
|
||||||
|
"title": "设计规范对照·旧版",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:business-dept-ledger-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】项目盈亏情况",
|
||||||
|
"itemKey": "prototypes/business-dept-ledger-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:contract-template-management-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】合同模板管理",
|
||||||
|
"itemKey": "prototypes/contract-template-management-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:customer-management-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】客户管理",
|
||||||
|
"itemKey": "prototypes/customer-management-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:customer-payment-collection-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】客户回款情况",
|
||||||
|
"itemKey": "prototypes/customer-payment-collection-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:insurance-procurement-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】保险采购",
|
||||||
|
"itemKey": "prototypes/insurance-procurement-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:lease-business-detail-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】租赁业务明细",
|
||||||
|
"itemKey": "prototypes/lease-business-detail-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:lease-business-ledger-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】租赁业务台账",
|
||||||
|
"itemKey": "prototypes/lease-business-ledger-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:lease-business-line-overview-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】业务条线说明",
|
||||||
|
"itemKey": "prototypes/lease-business-line-overview-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:lease-contract-management-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】租赁合同",
|
||||||
|
"itemKey": "prototypes/lease-contract-management-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:message-center-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】消息中心",
|
||||||
|
"itemKey": "prototypes/message-center-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:oneos-h5-h2-order-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】加氢记录(H5)",
|
||||||
|
"itemKey": "prototypes/oneos-h5-h2-order-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:oneos-h5-vehicle-assets-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】车辆资产(H5)",
|
||||||
|
"itemKey": "prototypes/oneos-h5-vehicle-assets-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:oneos-prototype-demo-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】原型演示",
|
||||||
|
"itemKey": "prototypes/oneos-prototype-demo-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:oneos-web-approval-cc-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】我的抄送",
|
||||||
|
"itemKey": "prototypes/oneos-web-approval-cc-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:oneos-web-approval-done-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】我的已办",
|
||||||
|
"itemKey": "prototypes/oneos-web-approval-done-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:oneos-web-approval-initiated-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】我发起的",
|
||||||
|
"itemKey": "prototypes/oneos-web-approval-initiated-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:oneos-web-approval-todo-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】我的待办",
|
||||||
|
"itemKey": "prototypes/oneos-web-approval-todo-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:oneos-web-business-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】业务管理",
|
||||||
|
"itemKey": "prototypes/oneos-web-business-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:oneos-web-data-analysis-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】数据分析",
|
||||||
|
"itemKey": "prototypes/oneos-web-data-analysis-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:oneos-web-finance-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】财务管理(合包)",
|
||||||
|
"itemKey": "prototypes/oneos-web-finance-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:oneos-web-h2-station-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】加氢记录",
|
||||||
|
"itemKey": "prototypes/oneos-web-h2-station-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:oneos-web-h2-station-analysis-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】加氢站分析",
|
||||||
|
"itemKey": "prototypes/oneos-web-h2-station-analysis-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:oneos-web-h2-station-site-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】站点信息",
|
||||||
|
"itemKey": "prototypes/oneos-web-h2-station-site-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:oneos-web-h2-station-stats-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】加氢站数量统计",
|
||||||
|
"itemKey": "prototypes/oneos-web-h2-station-stats-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:oneos-web-h2-station-weekly-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】站点周报统计",
|
||||||
|
"itemKey": "prototypes/oneos-web-h2-station-weekly-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:oneos-web-help-center-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】帮助中心",
|
||||||
|
"itemKey": "prototypes/oneos-web-help-center-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:oneos-web-lease-contract-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】车辆租赁合同",
|
||||||
|
"itemKey": "prototypes/oneos-web-lease-contract-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:oneos-web-ledger-data-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】台账数据",
|
||||||
|
"itemKey": "prototypes/oneos-web-ledger-data-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:oneos-web-ops-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】运维管理",
|
||||||
|
"itemKey": "prototypes/oneos-web-ops-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:oneos-web-procurement-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】采购管理",
|
||||||
|
"itemKey": "prototypes/oneos-web-procurement-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:oneos-web-workbench-new-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】工作台",
|
||||||
|
"itemKey": "prototypes/oneos-web-workbench-new-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:payment-records-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】收款记录",
|
||||||
|
"itemKey": "prototypes/payment-records-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:self-operated-business-ledger-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】物流业务明细",
|
||||||
|
"itemKey": "prototypes/self-operated-business-ledger-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:self-operated-contract-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】自营合同",
|
||||||
|
"itemKey": "prototypes/self-operated-contract-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:self-operated-dispatch-task-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】调度任务",
|
||||||
|
"itemKey": "prototypes/self-operated-dispatch-task-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:supplier-management-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】供应商管理",
|
||||||
|
"itemKey": "prototypes/supplier-management-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:task-work-order-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】任务工单",
|
||||||
|
"itemKey": "prototypes/task-work-order-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:vehicle-fault-handling-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】故障处置",
|
||||||
|
"itemKey": "prototypes/vehicle-fault-handling-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:vehicle-h2-fee-ledger-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】车辆氢费明细",
|
||||||
|
"itemKey": "prototypes/vehicle-h2-fee-ledger-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:vehicle-inspection-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】vehicle inspection",
|
||||||
|
"itemKey": "prototypes/vehicle-inspection-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:vehicle-maintenance-ledger-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】维修保养台账",
|
||||||
|
"itemKey": "prototypes/vehicle-maintenance-ledger-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:vehicle-management-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】车辆资产",
|
||||||
|
"itemKey": "prototypes/vehicle-management-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:vehicle-pickup-receivable-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】提车应收款",
|
||||||
|
"itemKey": "prototypes/vehicle-pickup-receivable-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:vehicle-purchase-contract-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】vehicle purchase contract",
|
||||||
|
"itemKey": "prototypes/vehicle-purchase-contract-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:vehicle-return-settlement-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】还车应结款",
|
||||||
|
"itemKey": "prototypes/vehicle-return-settlement-legacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "item:prototypes:yunxiao-pipeline-handbook-legacy",
|
||||||
|
"kind": "item",
|
||||||
|
"title": "【旧版】云效生产线手册",
|
||||||
|
"itemKey": "prototypes/yunxiao-pipeline-handbook-legacy"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
83
.claude/skills/AutoRDO/SKILL.md
Normal file
83
.claude/skills/AutoRDO/SKILL.md
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
---
|
||||||
|
name: AutoRDO
|
||||||
|
description: >-
|
||||||
|
AutoRDO (Requirement Description Optimization): cleans fragmented chat logs,
|
||||||
|
voice transcripts, oral notes, and feedback ledgers into written title and description;
|
||||||
|
auto-detects 类型/优先级/标签/提交部门/提交人 from content; maps OneOS modules via oneos-domain.md;
|
||||||
|
splits multi-line into multiple results; if any 待确认 exists, MUST switch to Plan mode
|
||||||
|
for choice-based confirmation. Does not change Yunxiao status or create tasks.
|
||||||
|
Pair with YunxiaoPMapp for cloud write; never load yunxiao-requirement-lifecycle.
|
||||||
|
---
|
||||||
|
|
||||||
|
# AutoRDO
|
||||||
|
|
||||||
|
**Requirement Description Optimization**(需求描述优化)。
|
||||||
|
将碎片化、通俗化文字(聊天/录音/反馈台账)在**保留原意**前提下拆解为**标题、描述**,并**自动识别**类型、优先级、标签、提交部门、提交人,供入库写入云效需求。
|
||||||
|
多行/多条独立诉求 → **自动拆成多份**转译结果。
|
||||||
|
|
||||||
|
**强制**:清洗结果中**只要存在任意「待确认」**,Agent **必须立刻** `SwitchMode` → **plan**,逐条用选择题消解;**无需**用户再说「确认待确认」。无待确认则可直接交定稿。
|
||||||
|
|
||||||
|
## 边界(强制)
|
||||||
|
|
||||||
|
| 做 | 不做 |
|
||||||
|
|---|---|
|
||||||
|
| 提炼标题与书面描述;自动识别类型/优先级/标签/提交部门/提交人 | 改云效状态 / 建任务 / **直接**打云效标签 |
|
||||||
|
| 多行/多条 → 多份转译结果 | 写成完整 AutoPRD / 臆造业务结论 |
|
||||||
|
| 有待确认 → 强制 Plan 逐条确认 | 停在初稿等口令;把猜测写入定稿 |
|
||||||
|
| 去除描述**结尾句号** | 加载 `yunxiao-requirement-lifecycle` |
|
||||||
|
|
||||||
|
云效建单与打标由 **`$YunxiaoPMapp`** 负责;本 Skill 只出清洗稿与**推荐元数据**。
|
||||||
|
|
||||||
|
## 何时使用
|
||||||
|
|
||||||
|
- 口令含 `AutoRDO` / `清洗聊天` / `录音整理` / `原始诉求`
|
||||||
|
- 粘贴反馈台账(含部门/优先级/模块列)或口述碎片
|
||||||
|
- YunxiaoPMapp「记录需求」前必须先跑本 Skill(材料为碎片/台账时)
|
||||||
|
|
||||||
|
## 输入
|
||||||
|
|
||||||
|
- 聊天、会议速记、口述、录音转写
|
||||||
|
- **多行/台账**:含反馈人、所属部门、业务模块、优先级、PC或移动端等列时优先采信列值
|
||||||
|
- 确认阶段补充文字
|
||||||
|
|
||||||
|
## 处理规则
|
||||||
|
|
||||||
|
**强制前置**:ONE-OS 材料先 Read [references/oneos-domain.md](references/oneos-domain.md),元数据规则见 [references/meta-fields.md](references/meta-fields.md),再按 [references/rules.md](references/rules.md) 执行。
|
||||||
|
|
||||||
|
1. **多条拆解** → 每条独立成稿
|
||||||
|
2. **OneOS 对齐** → 模块/部门标准名
|
||||||
|
3. **元数据识别** → 类型、优先级、标签、提交部门、提交人(显式列 > 正文标记 > 语义推断;不确定 → 待确认)
|
||||||
|
4. **标题 + 描述转译** → 去口语、去结尾句号
|
||||||
|
5. **有待确认 → 强制 Plan** → 见 [references/confirm-pending.md](references/confirm-pending.md)
|
||||||
|
|
||||||
|
## 输出
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 原始诉求(AutoRDO)
|
||||||
|
|
||||||
|
**标题**:<清晰标题>
|
||||||
|
**类型**:【新增】|【优化】
|
||||||
|
**优先级**:P1-高|P2-中|P3-低
|
||||||
|
**标签**:<标准模块>[, PC端|小程序]
|
||||||
|
**提交部门**:<标准部门名或空>
|
||||||
|
**提交人**:<姓名或空>
|
||||||
|
|
||||||
|
**描述**:
|
||||||
|
<转译正文;无结尾句号>
|
||||||
|
反馈:<有则附日期/禅道/状态/端>
|
||||||
|
|
||||||
|
待确认:
|
||||||
|
- …
|
||||||
|
```
|
||||||
|
|
||||||
|
多条时先写「共 N 条」,再 `### 1` … `### N`。
|
||||||
|
交 YunxiaoPMapp 示例:`记录需求:标题=…;类型=…;优先级=…;标签=…;提交部门=…;提交人=…;描述=…`
|
||||||
|
|
||||||
|
## 口令
|
||||||
|
|
||||||
|
```text
|
||||||
|
AutoRDO:<粘贴聊天或台账行>
|
||||||
|
AutoRDO:录音转写如下 …
|
||||||
|
按下列补充消解待确认:
|
||||||
|
<补充说明>
|
||||||
|
```
|
||||||
4
.claude/skills/AutoRDO/agents/openai.yaml
Normal file
4
.claude/skills/AutoRDO/agents/openai.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
interface:
|
||||||
|
display_name: "AutoRDO"
|
||||||
|
short_description: "清洗诉求并识别类型优先级标签部门提交人"
|
||||||
|
default_prompt: "按 AutoRDO 清洗:先读 oneos-domain.md 与 meta-fields.md;多行拆多条;出标题+描述+类型/优先级/标签/提交部门/提交人。有待确认则同轮强制切 Plan 用选择题消解;不改云效、不直接打标、不贴词典全文。"
|
||||||
126
.claude/skills/AutoRDO/references/confirm-pending.md
Normal file
126
.claude/skills/AutoRDO/references/confirm-pending.md
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
# AutoRDO · 待确认逐条 Plan 确认
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
|
||||||
|
清洗稿中的「待确认」经产品经理**逐条人工确认**后,回填进标题/描述,得到可交 YunxiaoPMapp 的定稿。
|
||||||
|
确认过程**优先选择题**;选项用 [oneos-domain.md](oneos-domain.md) 辅助生成;也支持用补充说明/需求描述文字直接消解待确认点。
|
||||||
|
|
||||||
|
## 何时进入(强制)
|
||||||
|
|
||||||
|
```text
|
||||||
|
清洗初稿产出后:
|
||||||
|
若任一需求含「待确认」→ 同轮必须 SwitchMode → plan
|
||||||
|
若全部无待确认 → 不必进 Plan,初稿即定稿
|
||||||
|
```
|
||||||
|
|
||||||
|
- **触发条件只有一条**:存在待确认(单条或多条中任意一点)
|
||||||
|
- **禁止**要求用户再说「确认待确认」「开始确认」才进 Plan
|
||||||
|
- 用户在 Plan 中可用选择题作答,也可粘贴补充说明消解
|
||||||
|
|
||||||
|
**不进 Plan 的唯一情况**:清洗结果中没有任何「待确认」条目。
|
||||||
|
|
||||||
|
## Plan 门禁(强制)
|
||||||
|
|
||||||
|
1. 清洗初稿写出后(可先展示初稿摘要),**立刻** `SwitchMode` → **plan**,说明:存在待确认,须逐条确认后再回填定稿;本阶段仍**不写云效**
|
||||||
|
2. Plan 列出:待确认的**需求条号**、每条下的待确认点清单、推荐确认方式(选择题 / 文字补充)
|
||||||
|
3. **用户确认 / 批准 Plan / 「执行」之前**:禁止把未确认内容写进定稿描述
|
||||||
|
4. 批准后:按条推进确认 → 回填 → 输出定稿
|
||||||
|
|
||||||
|
## 逐条确认顺序
|
||||||
|
|
||||||
|
```text
|
||||||
|
需求 1 的待确认点 1 → 点 2 → … → 需求 1 定稿片段
|
||||||
|
需求 2 的待确认点 1 → …
|
||||||
|
…
|
||||||
|
全部完成后输出「已确认定稿」全集
|
||||||
|
```
|
||||||
|
|
||||||
|
- **一次只推进一个待确认点**(或同一点下的一组互斥选项),避免一屏堆十几个问题
|
||||||
|
- 多条需求时,Plan 清单可注明建议从第 1 条起;用户可指定跳过或改序
|
||||||
|
- 某条无「待确认」→ 跳过,保留初稿即可
|
||||||
|
|
||||||
|
## 确认方式(优先选择)
|
||||||
|
|
||||||
|
每个待确认点按下列优先级出题:
|
||||||
|
|
||||||
|
| 优先级 | 方式 | 适用 |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | **选择题**(2–5 个互斥选项 + 可选「其他/我补充」) | 模块归属、部门名称、类型/优先级、是否/范围、枚举字段、拆条边界等 |
|
||||||
|
| 2 | **多选** | 明确可多选的范围(如适用端:PC+H5) |
|
||||||
|
| 3 | **文字补充** | 无法枚举、需自由描述字段清单/规则细节时 |
|
||||||
|
|
||||||
|
### 选项如何用 OneOS 词典生成
|
||||||
|
|
||||||
|
先 Read `oneos-domain.md`,再出选项:
|
||||||
|
|
||||||
|
- **模块名不清**:候选 = 词典中相关条线的标准模块名(如还车应结款 / 违章管理 / 还车管理),勿自造模块
|
||||||
|
- **部门/角色口语**:候选 = 第 1 节标准名(业管→业务管理组,安全小组→安全部 等)+「保持单据原文分区名」
|
||||||
|
- **跨条线联动**:选项写清主责模块 vs 联动对象;标题只挂主责,联动写描述
|
||||||
|
- **故事点细节**:仅当材料或用户补充已暗示时,才把词典闭环中的合理分支列为选项;**禁止**把未提及的故事点细节默认选中
|
||||||
|
|
||||||
|
每题结构建议:
|
||||||
|
|
||||||
|
```text
|
||||||
|
【需求 n · 待确认 k】<待确认原文>
|
||||||
|
依据词典,请选择:
|
||||||
|
A. …
|
||||||
|
B. …
|
||||||
|
C. …
|
||||||
|
D. 其他(请补充一句)
|
||||||
|
也可用一段需求描述直接回答本点
|
||||||
|
```
|
||||||
|
|
||||||
|
## 用需求描述补充
|
||||||
|
|
||||||
|
用户可用以下任一方式消解待确认,**不必**每题都点选:
|
||||||
|
|
||||||
|
- 粘贴一段补充说明 / 功能规则 / 字段清单
|
||||||
|
- 回复「按下列描述确认:…」
|
||||||
|
- 对某一待确认点直接写答案句
|
||||||
|
|
||||||
|
Agent 须:
|
||||||
|
|
||||||
|
1. 将补充文字**映射**到对应待确认点(可一次消解多点)
|
||||||
|
2. 写入该条**描述**(书面化、去结尾句号),从「待确认」列表**移除已消解项**
|
||||||
|
3. 补充仍含糊的部分 → 保留或新开「待确认」,继续选择题
|
||||||
|
4. **不**把补充里未说的内容脑补进去
|
||||||
|
|
||||||
|
## 回填定稿规则
|
||||||
|
|
||||||
|
确认完成后,对该条输出「已确认」版本:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
### n(已确认)
|
||||||
|
|
||||||
|
## 原始诉求(AutoRDO)
|
||||||
|
|
||||||
|
**标题**:…
|
||||||
|
|
||||||
|
**描述**:
|
||||||
|
<初稿 + 已确认信息合并;无结尾句号>
|
||||||
|
|
||||||
|
待确认:
|
||||||
|
- (无则写「无」或省略本段)
|
||||||
|
```
|
||||||
|
|
||||||
|
- 标题若因模块/动作确认而需微调,可改,并在确认回合说明改了什么
|
||||||
|
- 未确认点**不得**假装已确认;可标「本条暂缓,待确认仍保留」
|
||||||
|
- 全部条完成后,给总览:已确认条数 / 仍含待确认条数
|
||||||
|
|
||||||
|
## 口令
|
||||||
|
|
||||||
|
```text
|
||||||
|
AutoRDO:<材料> → 有待确认则自动进 Plan
|
||||||
|
按下列补充消解待确认:
|
||||||
|
<粘贴补充说明>
|
||||||
|
第 6 条待确认选 A;第 7 条补充:字段非必填,计入应补汇总
|
||||||
|
```
|
||||||
|
|
||||||
|
(「确认待确认」等口令**不再作为**进 Plan 的前置条件;有待确认即强制进。)
|
||||||
|
|
||||||
|
## 不做
|
||||||
|
|
||||||
|
- 确认阶段仍不改云效、不建任务
|
||||||
|
- 不把 `oneos-domain.md` 全文贴进定稿
|
||||||
|
- 不跳过 Plan 直接把「猜的答案」写进描述
|
||||||
|
- 不等用户额外口令才进 Plan(有待确认必须进)
|
||||||
96
.claude/skills/AutoRDO/references/meta-fields.md
Normal file
96
.claude/skills/AutoRDO/references/meta-fields.md
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
# AutoRDO · 元数据自动识别
|
||||||
|
|
||||||
|
从粘贴内容(台账表格行、聊天、口述)自动识别下列字段,写入每条原始诉求输出;**不**直接改云效打标(打标由 YunxiaoPMapp 执行)。
|
||||||
|
|
||||||
|
## 输出字段
|
||||||
|
|
||||||
|
| 字段 | 说明 | 无依据时 |
|
||||||
|
|---|---|---|
|
||||||
|
| **类型** | `【新增】` / `【优化】`(与云效标题前缀一致) | 默认 `【优化】`,并列入待确认 |
|
||||||
|
| **优先级** | `P1-高` / `P2-中` / `P3-低` | 默认 `P2-中`,高不确定则待确认 |
|
||||||
|
| **标签** | 主模块标签(对齐 `oneos-domain.md` 标准模块名);可附端标签 `PC端` / `小程序` | 仅模块不确定则待确认 |
|
||||||
|
| **提交部门** | 映射到词典标准部门名 | 材料无部门且无法推断 → 待确认或空 |
|
||||||
|
| **提交人** | 反馈人/用户姓名 | 材料无人名 → 空(不臆造) |
|
||||||
|
|
||||||
|
## 识别优先级
|
||||||
|
|
||||||
|
```text
|
||||||
|
1. 显式列/字段(反馈台账:优先级、所属部门、反馈方、业务模块、PC或移动端…)
|
||||||
|
2. 正文中的明确标记(P1、【优化】、@某人、部门署名)
|
||||||
|
3. 语义推断(用词 + oneos-domain 模块/部门)
|
||||||
|
4. 仍不确定 → 待确认(选择题),禁止假装已确认
|
||||||
|
```
|
||||||
|
|
||||||
|
## 类型(【新增】/【优化】)
|
||||||
|
|
||||||
|
| 信号 | 类型 |
|
||||||
|
|---|---|
|
||||||
|
| 新增、增加、支持、允许、增加列/字段/入口、批量导入(首次能力) | 【新增】 |
|
||||||
|
| 优化、调整、修改、放开、更清晰、重构、移动至、改由、精确到、兼容 | 【优化】 |
|
||||||
|
| 台账/口令已写 `【新增】`/`【优化】` | 以显式为准 |
|
||||||
|
| 同时含新增与优化语义 | 以**主诉求**定类型;次要点写在描述 |
|
||||||
|
|
||||||
|
标题可带类型前缀供入库:`【优化】交车管理:…`;若用户只要裸标题,类型仍单独输出字段。
|
||||||
|
|
||||||
|
## 优先级
|
||||||
|
|
||||||
|
| 信号 | 优先级 |
|
||||||
|
|---|---|
|
||||||
|
| 列值 `P1-高` / `P1` / 紧急、阻塞、无法办理、P1 | `P1-高` |
|
||||||
|
| 列值 `P2-中` / `P2` | `P2-中` |
|
||||||
|
| 列值 `P3-低` / `P3` / 文案、置灰、体验微调 | `P3-低` |
|
||||||
|
| 无信号 | 默认 `P2-中` |
|
||||||
|
|
||||||
|
## 标签
|
||||||
|
|
||||||
|
1. **主标签** = 归属标准模块名(`oneos-domain.md`),如 `还车应结款`、`违章管理`、`交车管理`
|
||||||
|
2. 台账「业务模块」列优先;口语映射到标准名(验车管理→验车入库,调拨管理→车辆调拨)
|
||||||
|
3. **端标签**(可选,可多选):材料含 `PC端`/`小程序`/`PC及小程序` 时写入
|
||||||
|
4. 「其他」「全局优化」「小程序审批中心」等非模块名:主标签用最贴近模块或 `系统全局`;勿发明云效不存在的随意标签名
|
||||||
|
5. 输出格式:逗号分隔,如 `还车应结款, PC端`
|
||||||
|
|
||||||
|
## 提交部门
|
||||||
|
|
||||||
|
| 材料常见写法 | 标准输出 |
|
||||||
|
|---|---|
|
||||||
|
| 业务管理部、业管、业务管理 | 业务管理组 |
|
||||||
|
| 运维部、运维 | 运维部 |
|
||||||
|
| 数智中心、数智、信息化 | 数智部 |
|
||||||
|
| 安全部、安全 | 安全部 |
|
||||||
|
| 财务部、财务 | 财务部 |
|
||||||
|
| 法务部、法务 | 法务部 |
|
||||||
|
| 采购部/采购组 | 按词典区分输出 |
|
||||||
|
|
||||||
|
台账「所属部门」列优先;聊天中「我们运维…」可推断,低置信度则待确认。
|
||||||
|
|
||||||
|
## 提交人
|
||||||
|
|
||||||
|
- 台账「反馈方/用户」「反馈人」列 → 原样作为提交人
|
||||||
|
- 聊天 @姓名、署名「张三:」→ 取该名
|
||||||
|
- 多人联合反馈 → 取主反馈人(首列/首个署名);其余可写描述附注
|
||||||
|
- **禁止**用当前对话用户名冒充提交人(除非材料写明)
|
||||||
|
|
||||||
|
## 与描述附注的关系
|
||||||
|
|
||||||
|
- **结构化字段**(类型/优先级/标签/提交部门/提交人)单独成行,供 YunxiaoPMapp 建单口令复用
|
||||||
|
- 禅道编号、处理状态、反馈日期等 → 可放描述末行「反馈:…」附注,不升格为强制字段
|
||||||
|
|
||||||
|
## 输出模板(每条)
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 原始诉求(AutoRDO)
|
||||||
|
|
||||||
|
**标题**:<清晰标题;可选带【新增】/【优化】前缀>
|
||||||
|
**类型**:【新增】|【优化】
|
||||||
|
**优先级**:P1-高|P2-中|P3-低
|
||||||
|
**标签**:<模块>[, PC端|小程序]
|
||||||
|
**提交部门**:<标准部门名或空>
|
||||||
|
**提交人**:<姓名或空>
|
||||||
|
|
||||||
|
**描述**:
|
||||||
|
<转译正文;无结尾句号>
|
||||||
|
反馈:<日期 · 原文部门 · 状态 · 禅道号 · 端 …>(有则写)
|
||||||
|
|
||||||
|
待确认:
|
||||||
|
- …
|
||||||
|
```
|
||||||
399
.claude/skills/AutoRDO/references/oneos-domain.md
Normal file
399
.claude/skills/AutoRDO/references/oneos-domain.md
Normal file
@@ -0,0 +1,399 @@
|
|||||||
|
# ONE-OS 业务领域词典(供 AutoRDO 对齐)
|
||||||
|
|
||||||
|
> 来源:业务条线说明原型 `lease-business-line-overview`
|
||||||
|
> 用途:清洗标题/描述时,优先用下列**标准模块名、部门名、闭环表述**对齐,避免口语臆造模块或错挂条线。
|
||||||
|
> 系统定位:1 套系统 · 5 大业务条线闭环 · 3 大数据底座 · 演进方向为业财一体
|
||||||
|
> **强制**:本文件只用于理解与用词对齐;**禁止**把本词典全文贴进云效描述或 AutoRDO 输出稿。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. 系统总览
|
||||||
|
|
||||||
|
| 维度 | 口径 |
|
||||||
|
|---|---|
|
||||||
|
| 平台名 | ONE-OS(亦写作 OneOS) |
|
||||||
|
| 五大业务条线 | 租赁 · 能源 · 运维 · 安全 · 物流 |
|
||||||
|
| 三大数据底座 | 车辆资产运营情况 · 各业务条线盈亏情况 · 里程调度情况 |
|
||||||
|
| 现阶段 | 业务驱动 · 财务手工维护(收款/付款/核销多人工) |
|
||||||
|
| 演进方向 | 业财闭环一体化(打通财务 YS,「收款记录」「付款记录」与业务台账双向回写) |
|
||||||
|
|
||||||
|
**标题提炼提示**:口述涉及合同/台账/交还车/氢费/证照/调度时,先归入对应条线再落模块名;跨条线联动(如还车应结款联动违章事故)在描述中写明联动对象,标题以主责模块为准。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 业务部门 / 角色词典(标准用词)
|
||||||
|
|
||||||
|
清洗时统一下列名称;同义口语请映射到标准名。
|
||||||
|
|
||||||
|
| 标准名称 | 常见口语/别称 | 主要出现条线 |
|
||||||
|
|---|---|---|
|
||||||
|
| 业务管理组 | 业管、业务管理 | 租赁、运维、安全、物流 |
|
||||||
|
| 业务管理组-能源部 | 能源组、业管能源、业务管理部-能源组 | 能源、租赁还车 |
|
||||||
|
| 业务服务组 | 业务服务 | 物流 |
|
||||||
|
| 业务员 | 业务 | 租赁 |
|
||||||
|
| 调度岗 | 调度 | 物流 |
|
||||||
|
| 法务部 | 法务 | 租赁、运维采购合同 |
|
||||||
|
| 财务部 | 财务 | 租赁评级、能源账户、运维付款/维保、安全违章事故、物流台账 |
|
||||||
|
| 安全部 | 安全 | 租赁评级、证照、安全条线 |
|
||||||
|
| 运维部 | 运维、区域操作员 | 运维全链路、交还车、租赁提车后交车 |
|
||||||
|
| 采购部 | 采购 | 能源加氢站、运维采购合同/验车 |
|
||||||
|
| 采购组 | 采购组 | 供应商管理(能源/运维) |
|
||||||
|
| 数智部 | 数智、信息化 | 合同模板电子化、能源扩展 |
|
||||||
|
| 董事长 | 老板、总 | 非标合同、资产出售过户报废确认 |
|
||||||
|
| 司机 | 提车司机、内部司机 | 交车培训、故障、安全培训 |
|
||||||
|
| 加氢站 / 签约加氢站 | 站点、站方 | 能源 |
|
||||||
|
|
||||||
|
**组织边界提示**
|
||||||
|
|
||||||
|
- 「采购组」侧重供应商主数据;「采购部」侧重站点管理与采购/三方租赁合同。
|
||||||
|
- 「业务管理组」与「业务管理组-能源部」勿混用;氢费、加氢对账默认能源部。
|
||||||
|
- 物流调度明确:**非 TMS**,不做配载与承运商调度。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 功能模块总表(按条线)
|
||||||
|
|
||||||
|
### 2.1 租赁业务条线(6 模块 · 全链路闭环)
|
||||||
|
|
||||||
|
**条线闭环**:客户评级决定是否可签 → 标准模板支撑签约 → 租赁合同进入履约 → 提车应收对齐后交车 → 台账承接租期账单 → 还车应结款会签归档。
|
||||||
|
|
||||||
|
| 步 | 模块名 | 一句话定位 | 责任部门 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 1 | 客户管理 | 准入评级 · 决定能否签约、走哪条流程 | 业务管理组、法务部、财务部、安全部 |
|
||||||
|
| 2 | 标准合同管理 | 模板配置 · 支撑电子合同一键发起 | 法务部、数智部 |
|
||||||
|
| 3 | 租赁合同 | 签约发起 · 标准 / 非标 / 禁止三条路径 | 业务员、法务部 |
|
||||||
|
| 4 | 提车应收款 | 应收生成 · 实收对齐 · 触发交车 | 业务员、法务部、业务管理组、运维部 |
|
||||||
|
| 5 | 租赁业务台账 | 交车后账单 · 周期收费与实收延续 | 运维部、业务员、业务管理组 |
|
||||||
|
| 6 | 还车应结款 | 还车结算 · 多部门会签 · 归档闭环 | 业务管理组、安全部、运维部、业务管理组-能源部 |
|
||||||
|
|
||||||
|
**关键结果标签(客户管理)**:可标准签约 · 可签·走非标 · 禁止签约·高风险
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.2 能源业务条线(6 模块 · 业财闭环)
|
||||||
|
|
||||||
|
**条线闭环**:供应商主数据支撑站点绑定 → 签约站账号与订单主动上报 → 非签约站氢费补录对账 → 客户对账单关联收款 → 加氢记录标记已付款 → 成熟后向采购端与司机端延伸。
|
||||||
|
|
||||||
|
| 步 | 模块名 | 一句话定位 | 责任部门 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 1 | 供应商管理 | 加氢/充电站供应商 · 站点绑定与业财直连 | 采购组、财务部 |
|
||||||
|
| 2 | 加氢站管理 | 签约站 / 非签约站 · 账号、余额与价格 | 采购部、加氢站 |
|
||||||
|
| 3 | 加氢订单 | 主动上报 · PLC 自动采集 · 预约接单 | 签约加氢站、业务管理组-能源部 |
|
||||||
|
| 4 | 车辆氢费明细 | 非签约站补录 · 对账归档 · 余额关联 | 业务管理组-能源部 |
|
||||||
|
| 5 | 氢费账户 | 客户预付款 · 对账单 · 业财收款闭环 | 业务管理组-能源部、财务部 |
|
||||||
|
| 6 | 扩展规划 | 上游采购 · 下游司机服务 | 采购部、业务管理组-能源部、数智部 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.3 运维管理条线(15 模块)
|
||||||
|
|
||||||
|
**主线(main)**:验车入库 → 上牌 → 证照 → 备车 → 交车 → 还车 → 出售/过户/报废出库
|
||||||
|
**并行能力(support)**:供应商、采购合同、替换车、故障、年审、维保、异动、调拨(无严格先后)
|
||||||
|
|
||||||
|
**条线闭环**:供应商与采购合同入库 → 上牌证照与备车整备 → 交车/替换/还车闭环 → 故障与年审维保 → 异动调拨 → 出售/过户/报废审批出库。
|
||||||
|
|
||||||
|
| 步 | 模块名 | 轨道 | 一句话定位 | 责任部门 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| 1 | 供应商管理 | support | 整车厂 / 三方租赁 · 付款底座 | 采购组、财务部 |
|
||||||
|
| 2 | 车辆采购 / 三方租赁合同 | support | 车型数量 · 付款关联 · 验车任务 | 采购部、法务部、财务部 |
|
||||||
|
| 3 | 验车入库 | main | 采购 / 三方来源 · 验完自动入库 | 运维部、采购部 |
|
||||||
|
| 4 | 车辆上牌 | main | 车架号入库 · 完成牌证登记 | 运维部 |
|
||||||
|
| 5 | 证照管理 | main | 一车一档 · 到期待办推送 | 运维部、安全部 |
|
||||||
|
| 6 | 备车管理 | main | 交车前整备 · 随时可交付 | 运维部 |
|
||||||
|
| 7 | 交车管理 | main | 司机培训留痕 · 区域派单 · OCR 比对 · 电子签 | 运维部、业务管理组、司机 |
|
||||||
|
| 8 | 替换车管理 | support | 临时 / 永久替换 · 费用自动核算 | 运维部、业务管理组 |
|
||||||
|
| 9 | 还车管理 | main | 区域派单 · 费用自动计算 · 电子签 | 运维部、业务管理组 |
|
||||||
|
| 10 | 故障管理 | support | AI 助手 + 人工 · 证据链归档 | 运维部、司机 |
|
||||||
|
| 11 | 年审记录 | support | 提前 3 个月 · OCR 刷新证照 | 运维部 |
|
||||||
|
| 12 | 维修与保养记录 | support | 费用汇总 · 业财一体 · 盈亏核算 | 运维部、财务部 |
|
||||||
|
| 13 | 车辆异动 | support | 出库维修 / 年审 / 保养 · 成本归集 | 运维部 |
|
||||||
|
| 14 | 车辆调拨 | support | 跨区调拨 · 运维权转移 | 运维部、业务管理组 |
|
||||||
|
| 15 | 车辆出售、过户、报废 | main | 资产变更审批 · 过程留痕 · 自动出库 | 运维部、董事长、财务部 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.4 安全管理条线(6 模块 · 安全闭环)
|
||||||
|
|
||||||
|
**条线闭环**:司机信息与证照 → 定期培训与资料库学习 → 违规记录关联评级 → 违章/事故登记 → 联动还车应结款与代处理费用。
|
||||||
|
|
||||||
|
| 步 | 模块名 | 一句话定位 | 责任部门 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 1 | 司机管理 | 物流内部司机 · 信息证照一体 | 安全部、业务管理组 |
|
||||||
|
| 2 | 内部司机培训 | 定期安全培训 · 证据链留痕 | 安全部、司机 |
|
||||||
|
| 3 | 安全培训资料库 | 资料上传 · APP / 小程序学习 | 安全部、司机 |
|
||||||
|
| 4 | 违规记录 | 司机违规 · 关联评级 | 安全部、业务管理组 |
|
||||||
|
| 5 | 违章管理 | 分值罚款 · 还车联动 · 代处理 | 安全部、财务部、业务管理组 |
|
||||||
|
| 6 | 事故管理 | 权责划分 · 保险赔付 · 还车联动 | 安全部、财务部、业务管理组 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.5 物流业务条线(3 模块 · 经营闭环)
|
||||||
|
|
||||||
|
**条线闭环**:物流合同生效 → 轻量调度派车(交车后可办结)→ 办结自动生成物流业务明细 → 汇总盈亏 → 汇集项目盈亏表 → 演进关联收款记录完成业财闭环。
|
||||||
|
|
||||||
|
| 步 | 模块名 | 一句话定位 | 责任部门 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 1 | 物流合同 | 关键信息录入 · 业务确认生效 · 可派车 | 业务管理组、业务服务组 |
|
||||||
|
| 2 | 调度任务 | 轻量派车 · 交还车校验 · 办结出车 | 业务服务组、调度岗、运维部 |
|
||||||
|
| 3 | 物流台账 | 任务自动生成 · 补录导入 · 盈亏核算 | 业务服务组、财务部 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.6 三大数据底座(管理决策层,非业务条线)
|
||||||
|
|
||||||
|
| 底座 | 看什么 | 主要数据来源条线 |
|
||||||
|
|---|---|---|
|
||||||
|
| 车辆资产运营情况 | 规模 · 结构 · 健康度 · 品牌型号出勤率下钻省市 | 运维、车辆管理、证照/保险、交车/备车 |
|
||||||
|
| 各业务条线盈亏情况 | 收入 · 成本 · 利润(条线/项目/单车) | 租赁台账、物流台账、氢费账户、收款、维保/事故/违章 |
|
||||||
|
| 里程调度情况 | 里程补贴 · 客户履约 · 智能替换与运维干预 | 车机/GPS/人工里程、客户里程约定、替换车、运维干预 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 流程闭环速查(端到端一句话)
|
||||||
|
|
||||||
|
| 条线 | 闭环一句话 |
|
||||||
|
|---|---|
|
||||||
|
| 租赁 | 客户 → 模板 → 签约 → 提车应收 → 交车 → 台账账单 → 还车应结款归档 |
|
||||||
|
| 能源 | 供应商 → 加氢站 → 订单采集 → 氢费明细 → 客户账户收款 → 记录已付款 |
|
||||||
|
| 运维 | 采购/验车入库 → 牌证备车 → 交还车 → 维保故障 → 异动调拨 → 处置出库 |
|
||||||
|
| 安全 | 司机档案 → 培训资料 → 违规评级 → 违章事故 → 还车应结款费用 |
|
||||||
|
| 物流 | 合同生效 → 调度派车办结 → 台账明细/盈亏 →(演进)收款业财闭环 |
|
||||||
|
| 系统级 | 五条线业务闭环 → 三大数据底座决策 → 打通财务 YS 业财一体 |
|
||||||
|
|
||||||
|
**高频跨模块联动(写描述时勿漏)**
|
||||||
|
|
||||||
|
- 租赁签约路径依赖**客户管理**评级(标准 / 非标 / 禁止)
|
||||||
|
- **提车应收**对齐后触发运维**交车**;交车成功生成**租赁业务台账**
|
||||||
|
- **还车管理**完成后生成**还车应结款**;安全**违章/事故**费用写入应结项
|
||||||
|
- 运维**采购/三方租赁合同**自动生成**验车入库**任务
|
||||||
|
- 物流**调度办结**须车辆已**交车**;办结自动写**物流台账**
|
||||||
|
- 能源签约站**加氢订单**与非签约站**氢费明细**统一进入**氢费账户**对账收款
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 故事点(按模块:起点 → 怎么运作 → 闭环)
|
||||||
|
|
||||||
|
> 结构对齐页面「起点 / 怎么运作 / 闭环」。标题用「模块名 + 核心动作」;描述保留谁发起、关键规则、闭环结果,不升格成完整 PRD。
|
||||||
|
> 下列为各模块业务事实摘要,用于**识别归属与用词**;材料未提及的细节**不得**脑补进描述。
|
||||||
|
|
||||||
|
### 4.1 租赁
|
||||||
|
|
||||||
|
#### 客户管理
|
||||||
|
- **起点**:业务管理组维护客户基础信息,作为后续合同与账单的统一客户主数据
|
||||||
|
- **怎么运作**:法务每 3 个月评估法律风险;财务实时维护财务风险等级;安全实时维护安全风险等级;系统综合形成签约策略
|
||||||
|
- **闭环**:未达禁止标准可签;偏离常规范式走「非标准流程」;达禁止标准禁止新签,现有合同标「高风险」并通知业务跟进或终止
|
||||||
|
|
||||||
|
#### 标准合同管理
|
||||||
|
- **起点**:法务部维护各车型试用/正式等标准模板,明确条款边界与风控要求
|
||||||
|
- **怎么运作**:数智部按模板配置电子合同;条款可设「触发车型」;「风控红线」被改进非标审批;「锁定区域」不可随意改
|
||||||
|
- **闭环**:业务员直选模板走标准流程;触碰红线或锁定区外修改转法务非标审批
|
||||||
|
|
||||||
|
#### 租赁合同
|
||||||
|
- **起点**:业务员选羚牛签约主体与乙方客户;系统按评级判标准/非标/禁止
|
||||||
|
- **怎么运作**:合同要素实时反写电子合同预览;生成电子合同/条款附件/授权委托书;越界转非标;支持续签、转正式、转三方、增值服务、授权委托书、主动终止等
|
||||||
|
- **闭环**:审批通过进入履约并串联提车应收、交车、台账;非标须法务与董事长确认后放行
|
||||||
|
|
||||||
|
#### 提车应收款
|
||||||
|
- **起点**:提交租赁合同审批时,按合同条款自动生成提车应收金额
|
||||||
|
- **怎么运作**:法务在「收款记录」导入到账(后期对接 YS/银企直联);业务/业管关联账单并分配金额;实收对齐后标记完成
|
||||||
|
- **闭环**:应收完成后按约定生成交车任务,属地运维执行交车
|
||||||
|
|
||||||
|
#### 租赁业务台账
|
||||||
|
- **起点**:运维交车成功后自动生成该车租赁账单,应付款日初始「待设置」
|
||||||
|
- **怎么运作**:设置应付款日后生成首期应收;提车实收写入首期;溢出并入第二期减免
|
||||||
|
- **闭环**:持续记录每期应收/实收/状态,支撑租期运营与还车结算
|
||||||
|
|
||||||
|
#### 还车应结款
|
||||||
|
- **起点**:运维完成还车后自动生成还车应结款任务
|
||||||
|
- **怎么运作**:业管、安全、运维、能源各自完成部门审批;汇总应退/应补;应补关联收款记录、应退关联付款记录
|
||||||
|
- **闭环**:业管发起总审批;完成后自动归档,租赁单条业务全链路闭环
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4.2 能源
|
||||||
|
|
||||||
|
#### 供应商管理
|
||||||
|
- **起点**:加氢站/充电站作为供应商纳入统一体系,采购组维护基础信息与结算要素
|
||||||
|
- **怎么运作**:创建站点时绑定供应商;氢费/电费对账支持直连付款;收付款明细关联财务记录;支撑付款/收款申请审批
|
||||||
|
- **闭环**:供应商主数据与站点、对账、财务贯通,打好能源业财基础
|
||||||
|
|
||||||
|
#### 加氢站管理
|
||||||
|
- **起点**:采购部统一管理签约站/非签约站;签约站须关联供应商与系统账号
|
||||||
|
- **怎么运作**:签约站账号登录加氢订单(PC/移动/H5);预付款余额;营业状态;成本价关联氢费记录;能源部形成对账单并发起付款(后期对接 YS)
|
||||||
|
- **闭环**:站点/账号/余额/价格/营业状态集中管理,签约站可自助上报
|
||||||
|
|
||||||
|
#### 加氢订单
|
||||||
|
- **起点**:签约站登录后多渠道上报订单;PLC 站点可自动获取
|
||||||
|
- **怎么运作**:多端快速识别记录;PLC 自动获取;联动「小羚羚」预约接单,司机确认;进入加氢记录供对账
|
||||||
|
- **闭环**:主动上报或自动采集,预约在线闭环,减少手工补录
|
||||||
|
|
||||||
|
#### 车辆氢费明细
|
||||||
|
- **起点**:非签约站氢费由业务管理组-能源部手动维护
|
||||||
|
- **怎么运作**:录入并关联站点/车辆/客户;对账后标「已对账」归档;联动预付款余额与客户能源账户;OCR 与电子围栏辅助核对
|
||||||
|
- **闭环**:签约/非签约氢费统一归集,余额变动可追溯
|
||||||
|
|
||||||
|
#### 氢费账户
|
||||||
|
- **起点**:管理客户氢费预付款余额与客户对账单
|
||||||
|
- **怎么运作**:维护余额变动;生成对账单;关联「收款记录」;收款后加氢记录标「已付款」;支持充值/开票直达财务(替代钉钉,对接 YS)
|
||||||
|
- **闭环**:明细→对账→收款全链路可核对,付款状态与财务实收一致
|
||||||
|
|
||||||
|
#### 扩展规划
|
||||||
|
- **起点**:条线成熟后向上游采购与下游司机服务延伸
|
||||||
|
- **怎么运作**:上游氢气采购;下游外部氢能车司机服务;与现有供应商/站点/订单/账户衔接
|
||||||
|
- **闭环**:覆盖「采购—站点—用氢—结算—司机服务」更大范围生态
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4.3 运维
|
||||||
|
|
||||||
|
#### 供应商管理
|
||||||
|
- **起点**:整车厂、三方租赁企业纳入供应商体系
|
||||||
|
- **怎么运作**:维护档案;为采购/三方租赁合同提供主数据;支撑付款底座
|
||||||
|
- **闭环**:与采购合同、付款记录贯通
|
||||||
|
|
||||||
|
#### 车辆采购 / 三方租赁合同
|
||||||
|
- **起点**:向整车厂/三方租赁厂商发起采购或三方租赁合同
|
||||||
|
- **怎么运作**:创建审批;关联付款记录;按条款自动生成验车任务
|
||||||
|
- **闭环**:合同、付款、验车联动,入库合规入口
|
||||||
|
|
||||||
|
#### 验车入库
|
||||||
|
- **起点**:对采购或三方来源氢能车执行验车
|
||||||
|
- **怎么运作**:接收验车任务;记录过程与问题;验完自动入库
|
||||||
|
- **闭环**:验车结果与合同、库存绑定,来源可审计
|
||||||
|
|
||||||
|
#### 车辆上牌
|
||||||
|
- **起点**:对仅有车架号的新车执行上牌
|
||||||
|
- **怎么运作**:筛选待上牌车;录入/同步牌照;更新库存状态
|
||||||
|
- **闭环**:牌证完整,为证照与交车提供前置条件
|
||||||
|
|
||||||
|
#### 证照管理
|
||||||
|
- **起点**:行驶证、道路运输证、登记证、特种设备证/标识、加氢卡、安全阀、压力表等一车一档
|
||||||
|
- **怎么运作**:维护档案与有效期;临近到期生成年审/等评/换证待办;推送运维/安全
|
||||||
|
- **闭环**:证照全生命周期管理,降低漏办与违规风险
|
||||||
|
|
||||||
|
#### 备车管理
|
||||||
|
- **起点**:日常提前整备,确保交车任务可随时交付
|
||||||
|
- **怎么运作**:按计划/库存策略发起检查;记录整备项与责任人
|
||||||
|
- **闭环**:交车前置完成,提升交付效率与质量一致性
|
||||||
|
|
||||||
|
#### 交车管理
|
||||||
|
- **起点**:承接租赁/物流交车任务,按区域派属地运维;司机先完成在线培训并留痕
|
||||||
|
- **怎么运作**:司机上传身份证/驾驶证/从业资格证、签名与现场拍照;交付证照及保险有效车辆;记录里程/氢量/电量/位置;OCR 胎纹;还车时比对算磨损等费用;E 签宝电子签归档
|
||||||
|
- **闭环**:培训与交车数据完整可查,为还车费用与争议提供依据
|
||||||
|
|
||||||
|
#### 替换车管理
|
||||||
|
- **起点**:因客户或车辆原因发起临时/永久替换
|
||||||
|
- **怎么运作**:选类型与新旧车;完成替换交还;客户原因自动算费用差
|
||||||
|
- **闭环**:过程可追踪、费用可核算,履约不中断
|
||||||
|
|
||||||
|
#### 还车管理
|
||||||
|
- **起点**:处理业务/业管还车任务,按区域派属地运维
|
||||||
|
- **怎么运作**:记录还车时间/里程/氢电量/位置;OCR 胎纹对比算磨损费;按里程与氢电差算费用;E 签宝确认归档
|
||||||
|
- **闭环**:费用依据交还对比自动出具
|
||||||
|
|
||||||
|
#### 故障管理
|
||||||
|
- **起点**:微信 AI 故障助手或人工记录故障关键信息
|
||||||
|
- **怎么运作**:记时间地点车型紧急程度;留存图文视频聊天证据;运维处理至关闭;形成待办统计;沉淀品牌故障类型统计支撑采购论证
|
||||||
|
- **闭环**:全过程留痕,证据链完整
|
||||||
|
|
||||||
|
#### 年审记录
|
||||||
|
- **起点**:按行驶证审验有效期提前 3 个月生成年审任务
|
||||||
|
- **怎么运作**:按车按月归集;完成后 OCR 新行驶证刷新证照;按月量化完成率
|
||||||
|
- **闭环**:任务不遗漏,证照与办理结果同步
|
||||||
|
|
||||||
|
#### 维修与保养记录
|
||||||
|
- **起点**:运维手动维护负责车辆维保记录(首期)
|
||||||
|
- **怎么运作**:配件费/人工费汇总;按承担方(客户/我司)生成客户账单或计入运维成本;计入车辆盈亏
|
||||||
|
- **闭环**:维保成本可追溯可分摊,支撑单车盈亏与对客户计费
|
||||||
|
|
||||||
|
#### 车辆异动
|
||||||
|
- **起点**:因当地维修/年审/保养出库异动,须提前审批
|
||||||
|
- **怎么运作**:记异动前后氢电量里程;异动期间加氢记录归集为异动成本
|
||||||
|
- **闭环**:可审批可计量,避免成本漏记
|
||||||
|
|
||||||
|
#### 车辆调拨
|
||||||
|
- **起点**:车辆从 A 地调至 B 地运营,须提前审批
|
||||||
|
- **怎么运作**:记发起方/费用/运输;接收方确认;运维操作权由 A 转 B
|
||||||
|
- **闭环**:跨区调拨透明,责任属地随车切换
|
||||||
|
|
||||||
|
#### 车辆出售、过户、报废
|
||||||
|
- **起点**:达出售/过户/报废条件发起资产变更,录入交易方价格过户残值等
|
||||||
|
- **怎么运作**:提交申请;董事长确认;运维记录全过程归档;完成后退出运营并出库
|
||||||
|
- **闭环**:处置审批留痕,生命周期闭环至出库归档
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4.4 安全
|
||||||
|
|
||||||
|
#### 司机管理
|
||||||
|
- **起点**:管理物流内部司机,支撑快速选取与档案维护
|
||||||
|
- **怎么运作**:维护基础信息与在职状态;管理驾驶证/从业资格证;与交车、台账联动
|
||||||
|
- **闭环**:主数据统一、证照可查,支撑调度与合规
|
||||||
|
|
||||||
|
#### 内部司机培训
|
||||||
|
- **起点**:定期开展安全培训并形成可追溯记录
|
||||||
|
- **怎么运作**:制定计划组织参训;记录时间内容参训人;形成证据链供交管查询
|
||||||
|
- **闭环**:培训电子归档,随时可调阅
|
||||||
|
|
||||||
|
#### 安全培训资料库
|
||||||
|
- **起点**:安全部上传培训与安全运营资料供司机学习
|
||||||
|
- **怎么运作**:维护课件制度指引;分类发布版本检索;司机经 APP/小程序学习
|
||||||
|
- **闭环**:资料集中更新,移动端可学可查
|
||||||
|
|
||||||
|
#### 违规记录
|
||||||
|
- **起点**:记录内部司机运营违规
|
||||||
|
- **怎么运作**:登记事件类型时间结果;关联司机档案;联动客户安全评级
|
||||||
|
- **闭环**:违规可追踪汇总,支撑选用与评级
|
||||||
|
|
||||||
|
#### 违章管理
|
||||||
|
- **起点**:记录交通违章并与还车应结款联动
|
||||||
|
- **怎么运作**:登记时间地点分值罚款及是否缴纳;未处理纳入还车结算;逾期未缴自动生成代处理费用
|
||||||
|
- **闭环**:违章可查,代处理费用与还车/财务口径一致
|
||||||
|
|
||||||
|
#### 事故管理
|
||||||
|
- **起点**:记录事故信息,支撑定责理赔与还车结算
|
||||||
|
- **怎么运作**:登记权责划分;记保险介入/赔付/上浮;联动还车应结款写入安全费用
|
||||||
|
- **闭环**:登记→赔付→上浮→应结款贯通,费用不遗漏
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4.5 物流
|
||||||
|
|
||||||
|
#### 物流合同
|
||||||
|
- **起点**:创建物流运力服务合同,录客户/车型/车辆数/交车时间地点,上传附件
|
||||||
|
- **怎么运作**:录入项目与合同要素;业务确认生效后可创建轻量调度并提示运维交车
|
||||||
|
- **闭环**:合同成为调度派车与交车的上游凭证
|
||||||
|
|
||||||
|
#### 调度任务
|
||||||
|
- **起点**:在生效合同下创建出车任务,派车派司机;非 TMS
|
||||||
|
- **怎么运作**:选合同、计划出车日、线路、是否多趟与计价口径;未交车须先交车;办结确认实际出车后自动生成物流业务明细一行
|
||||||
|
- **闭环**:出车事实追溯到合同与车牌,驱动台账落账
|
||||||
|
|
||||||
|
#### 物流台账
|
||||||
|
- **起点**:承接调度办结自动生成的出车明细,导入/行编辑补录异常与历史
|
||||||
|
- **怎么运作**:办结写入营收侧并算金额/总成本/盈亏;氢费/ETC 等成本可手工补录;汇集项目盈亏表;演进关联「收款记录」
|
||||||
|
- **闭环**:收入与司机/车辆成本同台账可核对,盈亏可对接财务实收
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. AutoRDO 应用约定
|
||||||
|
|
||||||
|
1. **标题**:优先 `模块标准名:核心动作/结果`(10–30 字),模块名以本词典为准(例:`验车入库:采购与三方租赁合同自动生成验车记录及入库`)
|
||||||
|
2. **条线归属**:一句需求只挂一个主模块;跨条线联动写在描述里,不硬塞进标题
|
||||||
|
3. **部门用词**:口语「业管/能源组/运维」等映射到第 1 节标准名
|
||||||
|
4. **闭环口径**:若材料只讲做到一半,闭环写实际说到的结果,缺的标「待确认」
|
||||||
|
5. **不做**:不把本词典全文贴进云效描述或输出稿;不脑补材料未出现的故事点细节
|
||||||
|
6. **业财关键词**:收款记录、付款记录、对账单、应收/实收、YS、银企直联、E 签宝、小羚羚、PLC——保留原文业务对象名,勿随意改写
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 条线演进(辅助理解,非强制写入描述)
|
||||||
|
|
||||||
|
| 条线 | 现阶段 | 演进方向 |
|
||||||
|
|---|---|---|
|
||||||
|
| 租赁 | 合同电子化 · 业务闭环化 | 移动端商城直连发起合同,后续自动打通 |
|
||||||
|
| 能源 | 手工维护氢费明细 | 签约站主动上报,能源部转为核对确认 |
|
||||||
|
| 运维 | 车辆使用环节闭环 | 入库→运作→出库全链路 |
|
||||||
|
| 安全 | 司机安全全链条 | 与客户安全评级挂钩、事前预判 |
|
||||||
|
| 物流 | 合同 + 调度办结落账 | 成本自动回填、司机在线、关联收款;不做完整 TMS |
|
||||||
|
| 系统 | 业务驱动 · 财务手工 | 打通 YS · 业财一体 |
|
||||||
67
.claude/skills/AutoRDO/references/rules.md
Normal file
67
.claude/skills/AutoRDO/references/rules.md
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# AutoRDO 清洗与拆解细则
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
|
||||||
|
碎片 → 可入库的书面「标题」与「描述」。保留原意;不写成产品 PRD。
|
||||||
|
多行/多条独立输入 → **多份**转译结果(一份需求一份稿)。
|
||||||
|
|
||||||
|
## 必做与精炼规则
|
||||||
|
|
||||||
|
| 规则 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| **多条拆解** | 输入为多条独立诉求时,**先拆后洗**:<br>• **拆分信号**(满足任一即可):换行且每行一句独立诉求;`1. 2. 3.` / `-` / `*` 列表;表格多行;空行分段;「另外」「还有」「第二条」等显式分条<br>• **每条**各自输出一份标题+描述+待确认,**禁止**合并成一条大需求<br>• **不拆**:同一条需求内部的续写、补充说明、功能规则子点(属于描述细节,挂在该条下)<br>• **边界不清**:无法判断是一条还是多条时,在文首标「待确认:拆条边界」,并按最可能的分条给出结果,请用户校对 |
|
||||||
|
| **OneOS 领域对齐** | 涉及 ONE-OS / 羚牛业务时,**先读** [oneos-domain.md](oneos-domain.md):<br>• 部门口语映射到标准名(业管→业务管理组,能源组→业务管理组-能源部 等)<br>• 标题模块名优先用词典标准名(如「验车入库」而非口语「验车管理」——若材料确指该模块)<br>• 跨条线联动写在描述,标题只挂主责模块<br>• **禁止**把词典全文或未在材料中出现的故事点细节写入输出 |
|
||||||
|
| **标题提炼** | 根据材料内容理解,自动概括简炼、清晰的标准需求标题:<br>• **内容理解**:准确识别归属的业务模块与核心动作/诉求(如:`验车入库:采购与三方租赁合同自动生成验车记录及入库`)。<br>• **自然流畅**:表达自然书面化,无需死板强求拼接固定句式;彻底剔除“我们要做一个”、“主要是用于”、“完成之后才能”等口语废话。<br>• **字数适中**:控制在 10-30 字内,能让读者一眼看懂需求核心。 |
|
||||||
|
| **元数据识别** | 详见 [meta-fields.md](meta-fields.md)。从台账列或正文自动识别并输出:<br>• **类型**:`【新增】`/`【优化】`<br>• **优先级**:`P1-高`/`P2-中`/`P3-低`<br>• **标签**:标准模块名(+ 可选 PC端/小程序)<br>• **提交部门**:映射词典标准名(业务管理部→业务管理组,数智中心→数智部 等)<br>• **提交人**:反馈方/用户列或署名<br>• 显式列优先;推断不确定则待确认;**不**直接写云效打标 |
|
||||||
|
| **描述转译** | 原文的转译结果,将口述/碎片材料转译为规范书面表达,保留原意(不改变谁要求什么、约束与例外;不替换成「更优方案」);业财对象名(收款记录、付款记录、YS、E 签宝、小羚羚、PLC 等)按词典保留 |
|
||||||
|
| 书面化 | 口语改成完整句子或清晰短条目;主谓齐全 |
|
||||||
|
| 去口头禅 | 删除:嗯、啊、那个、就是说、然后呢、对对对、你懂吧 等 |
|
||||||
|
| 自我修正 | 以最后一次明确口径为准;若前后矛盾且未决,列入「待确认」 |
|
||||||
|
| 去重复 | 同一意思多轮确认只保留一处;多条拆解时,各条之间不要互相抄写无关内容 |
|
||||||
|
| 轻度格式 | 可用短标题/条目;禁止展开成总览/角色/流程图/故事点等 PRD 结构 |
|
||||||
|
| 去结尾句号 | 描述中每个句子或条目末尾去掉 `。`;保留 `?` `!` 若确为疑问/感叹 |
|
||||||
|
| 待确认 | 材料含糊处写 `待确认:…`,不臆造;**只要存在待确认,同轮强制**进入 [confirm-pending.md](confirm-pending.md) 的 Plan 逐条确认(无需用户再说「确认待确认」) |
|
||||||
|
| **待确认 Plan 确认** | 详见 [confirm-pending.md](confirm-pending.md):<br>• 清洗结果含待确认 → **立刻** `SwitchMode` → plan<br>• 按需求条号**逐点**确认;**优先选择题**(2–5 项 +「其他/我补充」),选项用 `oneos-domain.md` 辅助<br>• 也支持用户粘贴**需求描述/补充说明**一次消解多点<br>• 确认后回填描述并移除已消解项;未确认不得写入定稿 |
|
||||||
|
|
||||||
|
## 多条拆解示例
|
||||||
|
|
||||||
|
**输入(多行):**
|
||||||
|
```text
|
||||||
|
还车应结款生成后自动展示违章事故信息,不必等安全员提交
|
||||||
|
验车完成后才能车辆入库
|
||||||
|
氢费账户对账单要能关联收款记录
|
||||||
|
```
|
||||||
|
|
||||||
|
**输出**:3 份独立的「原始诉求(AutoRDO)」,每份各自标题+描述;不要揉成一条。
|
||||||
|
|
||||||
|
## 标题提炼对比示例
|
||||||
|
|
||||||
|
- ❌ **坏标题(直抄口语/带废话)**:`我们现在要做一个验车管理功能主要是采购合同和三方租赁合同自动形成验车记录验车完成之后才能车辆入库`
|
||||||
|
- ✅ **好标题(自然清晰,覆盖标准模块)**:`验车入库:采购与三方租赁合同自动生成验车记录及入库`(模块名对齐 oneos-domain)
|
||||||
|
|
||||||
|
## 不做
|
||||||
|
|
||||||
|
- 不生成 AutoPRD 十章或「产品说明」
|
||||||
|
- 不写验收清单、故事点、mermaid
|
||||||
|
- 不改云效、不建【交付】/分析/设计
|
||||||
|
- 不加载 `yunxiao-requirement-lifecycle`
|
||||||
|
- 不把多条独立诉求合并成一条「大杂烩」需求
|
||||||
|
|
||||||
|
## 录音
|
||||||
|
|
||||||
|
1. 已有转写 → 按上文清洗转写稿并拆解标题与描述;转写中若含多条独立诉求,同样先拆后洗
|
||||||
|
2. 仅音频 → 回报「请提供转写文本后再 AutoRDO」,停止声称已清洗完成
|
||||||
|
|
||||||
|
## 质量自检
|
||||||
|
|
||||||
|
- [ ] 多行/多条输入时,已按条拆成多份结果(条数与输入独立诉求数一致或已说明待确认边界)
|
||||||
|
- [ ] 已对照 `oneos-domain.md`(ONE-OS 相关材料)
|
||||||
|
- [ ] **标题清晰通顺**(标准模块名 + 核心动作,无死板句式绑定,无口语废话)
|
||||||
|
- [ ] 部门/业财关键词已映射或保留为词典标准口径
|
||||||
|
- [ ] **描述为原文的转译结果**,干系人能认出这是自己说的意思;未脑补词典故事点
|
||||||
|
- [ ] 无口头禅堆砌、无未决矛盾被写成定论
|
||||||
|
- [ ] 描述末尾无 `。`
|
||||||
|
- [ ] 未冒充完整 PRD;未把词典全文写入输出
|
||||||
|
- [ ] 已输出类型/优先级/标签/提交部门/提交人(有依据或已标待确认;未臆造提交人)
|
||||||
|
- [ ] 若存在待确认:已同轮强制进 Plan(未等「确认待确认」口令);优先选择题、选项有词典依据;文字补充已映射到对应点;定稿无未确认臆造
|
||||||
|
- [ ] 若无待确认:未多余进 Plan
|
||||||
113
.claude/skills/YunxiaoPM/SKILL.md
Normal file
113
.claude/skills/YunxiaoPM/SKILL.md
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
---
|
||||||
|
name: YunxiaoPM
|
||||||
|
description: >-
|
||||||
|
产品经理云效(Projex)自动化:记录需求(压缩点选 1a2b3a4d:类型/项目/优先级/标签)、
|
||||||
|
实时点选云效项目、推进 待处理→已确认→分析中→设计中→设计完成→待开发,
|
||||||
|
交付树【交付】ASSOCIATED /【分析】【设计】TASK_SUB,无单快轨与编号直推交棒何斐,
|
||||||
|
创建迭代并挂【交付】(不挂需求)。用户说 YunxiaoPM、YunxiaoPMapp、需求任务、记录需求、受理确认、开始分析、
|
||||||
|
开始设计、设计完成、交棒开发、快轨待开发、编号直推、创建迭代 时使用。
|
||||||
|
不建【开发】/【测试】。凡写云效先 Plan 确认再一口气 apply;禁止对齐
|
||||||
|
yunxiao-requirement-lifecycle。
|
||||||
|
---
|
||||||
|
|
||||||
|
# 需求任务(YunxiaoPM)
|
||||||
|
|
||||||
|
产品部云效自动化。斜杠调起 **`/YunxiaoPM`**;对外中文名 **需求任务**(原名 YunxiaoPMapp)。本 Skill **自洽成篇**;**禁止** fork / include / 「对齐」`yunxiao-requirement-lifecycle`。
|
||||||
|
|
||||||
|
产品经理会话**不要**同时挂载旧 lifecycle Skill,避免双建任务。
|
||||||
|
|
||||||
|
## Plan 模式门禁(强制 · 凡写云效)
|
||||||
|
|
||||||
|
凡会改云效的操作(建单、改状态、建/改任务、打标、传附件、改负责人、建迭代等),Agent **第一步**必须:
|
||||||
|
|
||||||
|
1. `SwitchMode` → **plan**(说明:先对齐参数与执行清单,确认后再一口气 apply)。
|
||||||
|
2. **新建**依赖项目空间时:先按 [references/project-selection.md](references/project-selection.md) **实时拉项目列表并点选(门禁 PJ)**;禁止静默使用 `runtime-ids.json` 默认 `spaceIdentifier`。口令/选项**无法对应**时:**自动重拉项目列表一次**再匹配;仍失败则停请用户重选(禁止第 3 次空转拉取)。
|
||||||
|
3. Plan 写清:**已选项目名 + spaceId**、目标需求/任务**编号**、将改状态、将建/复用的交付·分析·设计编号策略、迭代版本类型(若适用)、§0.1① 占位风险勾选(若适用)、**不会做的事**(不建【开发】/【测试】、不按标题查重)。**记录需求**须按 [compact-select.md](references/compact-select.md) 给出 1–4 题字母表,接受压缩答复如 `1a2b3a4d`。
|
||||||
|
4. **用户确认 / 批准 Plan / 「执行」之前**:禁止 apply;项目未点选同禁。压缩串须先解析回显,再等「执行」。
|
||||||
|
5. 确认后切回 Agent,**同一轮按清单一口气执行到底**,再一次性校验回报;中途缺参才停下。
|
||||||
|
|
||||||
|
**例外(可读可不进 Plan):** 仅查状态 / 为什么没流转 / 给我方案。
|
||||||
|
|
||||||
|
**禁止:** 以「参数已齐」「速度路径」「用户很熟」跳过 Plan;「批准计划」若清单未点齐关键参数(含 **PJ 项目**),仍视为未完成门禁。
|
||||||
|
|
||||||
|
## 真相源模型
|
||||||
|
|
||||||
|
```text
|
||||||
|
需求状态 = 阶段看板唯一真相
|
||||||
|
【交付】 = 每需求最多 1 条容器(ASSOCIATED→需求)
|
||||||
|
【分析】/【设计】 = TASK_SUB→交付(交付「子项」必可见;与 ASSOCIATED 同 create 互斥)
|
||||||
|
【开发】/【测试】 = 不进本 Skill
|
||||||
|
查重/复用唯一渠道 = 任务编号(ONEOS-xx);禁止按标题
|
||||||
|
```
|
||||||
|
|
||||||
|
编号权威:需求描述 `## 工作项编号(系统)`(见 [references/workitem-ids.md](references/workitem-ids.md))。
|
||||||
|
操作顺序:口令显式编号 > 读该区块 > ASSOCIATED/SUB 校验;冲突则停。
|
||||||
|
|
||||||
|
## 外置调用(禁止本 Skill 内嵌对方全文)
|
||||||
|
|
||||||
|
| 时机 | 调用 |
|
||||||
|
|---|---|
|
||||||
|
| 入库清洗聊天/录音 | **`$AutoRDO`**(独立 Skill;路径 `AutoRDO/SKILL.md`;不内嵌清洗细则) |
|
||||||
|
| 设计完成 PRD + 对象存储链接 + 回填【交付】 | **`$oneos-autoprd`(AutoPRD)**;创建【交付】仍占位,设计完成才灌 MD |
|
||||||
|
| 人员 / 状态 / 字段 ID;项目 catalog 仅缓存 | [assets/runtime-ids.json](assets/runtime-ids.json) |
|
||||||
|
| **PJ 云效项目点选**(新建必选;实时列表) | [references/project-selection.md](references/project-selection.md) · [scripts/list_projects.py](scripts/list_projects.py) |
|
||||||
|
| **压缩点选 `1a2b3a4d`**(类型/项目/优先级/标签) | [references/compact-select.md](references/compact-select.md) · [scripts/list_tags.py](scripts/list_tags.py) |
|
||||||
|
| 阶段日历工时 | [references/work-hours.md](references/work-hours.md) + [assets/cn-workday-calendar.json](assets/cn-workday-calendar.json) + [scripts/workday_hours.py](scripts/workday_hours.py) |
|
||||||
|
|
||||||
|
## 路由(按需完整阅读)
|
||||||
|
|
||||||
|
| 场景 | 模块 |
|
||||||
|
|---|---|
|
||||||
|
| 交付树、关联约定、禁止项 | [references/model.md](references/model.md) |
|
||||||
|
| 描述双段 · AutoRDO / 占位 / AutoPRD | [references/description-split.md](references/description-split.md) |
|
||||||
|
| 步骤 0–5 标准路径 | [references/stage-flow.md](references/stage-flow.md) |
|
||||||
|
| 无单快轨到待开发 | [references/fast-track.md](references/fast-track.md) |
|
||||||
|
| 编号直推交棒 | [references/number-push.md](references/number-push.md) |
|
||||||
|
| 交棒门禁 · 回退最小集 | [references/handoff-and-rollback.md](references/handoff-and-rollback.md) |
|
||||||
|
| 计划开始/完成 · 阶段日历工时 | [references/work-hours.md](references/work-hours.md) |
|
||||||
|
| Make 导出 ZIP + 复制截图 | [references/make-export-attach.md](references/make-export-attach.md) |
|
||||||
|
| 创建迭代 · V主.副.子 · 只挂交付 | [references/sprint.md](references/sprint.md) |
|
||||||
|
| 口令面 | [references/commands.md](references/commands.md) |
|
||||||
|
| 记录需求元字段(优先级/标签/提交部门/提交人) | [references/record-meta-fields.md](references/record-meta-fields.md) |
|
||||||
|
| 云效项目点选 PJ | [references/project-selection.md](references/project-selection.md) |
|
||||||
|
| 验收清单 · 回报模板 | [references/acceptance.md](references/acceptance.md) |
|
||||||
|
| 交接契约(开发 Skill 入口) | [references/handoff-contract.md](references/handoff-contract.md) |
|
||||||
|
| 已验证实写 API · 极速建单 | [references/live-api.md](references/live-api.md) · [scripts/live_create_fast.py](scripts/live_create_fast.py) |
|
||||||
|
| 2026-07-23 复盘与耗时对比 | [references/live-perf-2026-07-23.md](references/live-perf-2026-07-23.md) |
|
||||||
|
|
||||||
|
## 口令速查
|
||||||
|
|
||||||
|
```text
|
||||||
|
记录需求:…;项目=(Plan 点选,勿默认);优先级=紧急|高|中|低;标签=…;提交部门=…;提交人=…;推进至=暂不推进|已确认|分析中|设计中|设计完成|待开发|待开发(快轨)
|
||||||
|
受理确认:ONEOS-xx
|
||||||
|
开始分析:ONEOS-xx
|
||||||
|
开始设计:ONEOS-xx;交付任务=…;分析任务=…
|
||||||
|
设计完成:ONEOS-xx;设计任务=…;原型=…
|
||||||
|
交棒开发:ONEOS-xx;交付任务=…
|
||||||
|
快轨待开发:ONEOS-xx
|
||||||
|
编号直推:分析任务=ONEOS-b / 设计任务=ONEOS-c / 交付任务=ONEOS-a
|
||||||
|
创建迭代:版本类型=主|副|子;交付任务=ONEOS-a,ONEOS-b,…;名称前缀=…
|
||||||
|
```
|
||||||
|
|
||||||
|
**PJ 项目**:新建前必须从云效实时列表点选(见 [project-selection.md](references/project-selection.md));口令带项目名仅作预填建议。
|
||||||
|
**压缩点选**:记录需求 Plan 展示 `1.类型 2.项目 3.优先级 4.标签` 字母表;你可回 `1a2b3a4d`(见 [compact-select.md](references/compact-select.md))。标签未命中会自动重拉一次标签候选并重生选项。
|
||||||
|
**记录需求**元字段(优先级/标签/提交部门/提交人):与压缩点选并用;缺项用字母表补齐。见 [references/record-meta-fields.md](references/record-meta-fields.md)。
|
||||||
|
|
||||||
|
后续口令**优先带任务编号**;未带则读「工作项编号(系统)」;仍无则询问;**禁止按标题补全**。
|
||||||
|
|
||||||
|
## 本 Skill 终点
|
||||||
|
|
||||||
|
交棒完成(需求=待开发;【交付】负责人=何斐)后结束。可一句:「请技术经理使用开发 Skill」。
|
||||||
|
例外:交棒后「创建迭代并关联交付」仍属 YunxiaoPM。
|
||||||
|
|
||||||
|
**明确不做:** 创建【开发】/【测试】、挂仓库、开分支、提测、写用例。
|
||||||
|
|
||||||
|
## §0.1 五条补齐(摘要)
|
||||||
|
|
||||||
|
1. **交棒占位**:标准路径下交付仍为 `等待设计任务完成后自动填入` 时**允许**交棒,但 Plan 必须勾选风险,回报首行标红。**快轨**有手工/原型时禁止占位(见 [fast-track.md](references/fast-track.md))。
|
||||||
|
2. **预计工时**:标准路径 = **阶段日历工时**(工作日×8);**快轨待开发**需求默认预计/实际各 **2**。
|
||||||
|
3. **编号真相源**在需求「工作项编号(系统)」;新建后立即 PATCH 该区块。
|
||||||
|
4. **无单快轨**:【设计】描述同步需求;计划起止=当日;TASK_SUB→交付后补 ASSOCIATED→需求;【交付】描述手工同步或 AutoPRD;交付/设计与需求同标签;设计当日完成态。
|
||||||
|
5. **描述双段**不互相覆盖;迭代**只挂【交付】**(需求不挂迭代);回退重做设计则**新开设计编号**,交付计划开始不改。
|
||||||
|
|
||||||
|
细则见各 references。
|
||||||
49
.claude/skills/YunxiaoPM/acceptance.md
Normal file
49
.claude/skills/YunxiaoPM/acceptance.md
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# 验收清单与回报
|
||||||
|
|
||||||
|
## apply 后必须自检
|
||||||
|
|
||||||
|
| # | 项 | 通过标准 |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | 需求编号 | 回报含 ONEOS-xx |
|
||||||
|
| 2 | 任务编号 | 交付/分析/设计凡新建或操作均回报编号;禁止只报标题 |
|
||||||
|
| 3 | 编号区块 | 需求「工作项编号(系统)」与实际一致 |
|
||||||
|
| 4 | ASSOCIATED | **仅交付**详情关联项可见需求(`createWorkitemRelationInfo=ASSOCIATED`;禁止 PARENT 冒充) |
|
||||||
|
| 5 | SUB | **必过**:分析/设计 create 用 `TASK_SUB→交付`(含 `parent`+`parentIdentifier`);交付「子项」tab 须可见。与 ASSOCIATED 同 create 互斥,阶段任务关联项可空(见 live-api.md) |
|
||||||
|
| 6 | 计划开始 | 未误覆盖已有值 |
|
||||||
|
| 7 | 阶段日历工时 | 有计划完成时已写入;脚注存在;回报用语正确 |
|
||||||
|
| 8 | 交棒 | 需求=待开发;交付负责人=何斐(交棒场景) |
|
||||||
|
| 9 | 占位风险 | 交付仍占位时首行标红 |
|
||||||
|
| 10 | 负向 | 本轮**无**【开发】/【测试】任务;未按标题查重 |
|
||||||
|
|
||||||
|
设计完成额外:AutoPRD 段已写;交付非占位(除非失败停下);ZIP+截图已挂或已列出缺项。
|
||||||
|
|
||||||
|
迭代额外:只挂【交付】(需求不挂);版本号符合递增规则。
|
||||||
|
|
||||||
|
## 回报模板(精简)
|
||||||
|
|
||||||
|
```text
|
||||||
|
【YunxiaoPMapp】
|
||||||
|
风险:(若有占位交棒则首行标红)
|
||||||
|
需求:ONEOS-xx | 状态=…
|
||||||
|
交付:ONEOS-a | 负责人=…
|
||||||
|
分析:ONEOS-b | …(无则写无)
|
||||||
|
设计:ONEOS-c | …(无则写无)
|
||||||
|
阶段日历工时:分析 Hh / 设计 Hh(若本轮写入)
|
||||||
|
附件:…(若本轮)
|
||||||
|
迭代:…(若本轮)
|
||||||
|
下一步:请技术经理使用开发 Skill(交棒后)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 适合全自动 vs 人工门禁
|
||||||
|
|
||||||
|
| 适合全自动 | 建议半自动/人工门禁 |
|
||||||
|
|---|---|
|
||||||
|
| 建单、打标签、挂迭代、写描述、建交付树、改状态、交棒负责人、幂等查重 | 受理(已确认)、是否快轨、设计完成是否真可开发、跨需求优先级与迭代容量、回退与取消 |
|
||||||
|
|
||||||
|
## 实写性能(2026-07-23 复盘)
|
||||||
|
|
||||||
|
| 项 | 要求 |
|
||||||
|
|---|---|
|
||||||
|
| 改状态 | 只用 `status/transit`(见 [live-api.md](live-api.md)) |
|
||||||
|
| 改【交付】负责人 | 只用 `PATCH …/{id}` + `propertyKey=assignedTo` |
|
||||||
|
| 极速复测 | `scripts/live_create_fast.py`;默认不开浏览器 |
|
||||||
4
.claude/skills/YunxiaoPM/agents/openai.yaml
Normal file
4
.claude/skills/YunxiaoPM/agents/openai.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
interface:
|
||||||
|
display_name: "需求任务"
|
||||||
|
short_description: "云效:压缩点选记录需求→分析/设计→交棒待开发→挂迭代"
|
||||||
|
default_prompt: "按需求任务(/YunxiaoPM)处理:先 Plan 出压缩点选字母表并确认项目,用户回 1a2b3a4d 与「执行」后再 apply。"
|
||||||
95
.claude/skills/YunxiaoPM/assets/cn-workday-calendar.json
Normal file
95
.claude/skills/YunxiaoPM/assets/cn-workday-calendar.json
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"timezone": "Asia/Shanghai",
|
||||||
|
"note": "法定放假日 holidays;国务院公布的周末调休补班日 workdays_on_weekend。缺年则禁止静默按仅去周末计算。",
|
||||||
|
"source": {
|
||||||
|
"2025": "国办发明电〔2024〕12号 https://www.gov.cn/zhengce/zhengceku/202411/content_6986383.htm",
|
||||||
|
"2026": "国办发明电〔2025〕7号 https://www.gov.cn/zhengce/content/202511/content_7047090.htm"
|
||||||
|
},
|
||||||
|
"years": {
|
||||||
|
"2025": {
|
||||||
|
"holidays": [
|
||||||
|
"2025-01-01",
|
||||||
|
"2025-01-28",
|
||||||
|
"2025-01-29",
|
||||||
|
"2025-01-30",
|
||||||
|
"2025-01-31",
|
||||||
|
"2025-02-01",
|
||||||
|
"2025-02-02",
|
||||||
|
"2025-02-03",
|
||||||
|
"2025-02-04",
|
||||||
|
"2025-04-04",
|
||||||
|
"2025-04-05",
|
||||||
|
"2025-04-06",
|
||||||
|
"2025-05-01",
|
||||||
|
"2025-05-02",
|
||||||
|
"2025-05-03",
|
||||||
|
"2025-05-04",
|
||||||
|
"2025-05-05",
|
||||||
|
"2025-05-31",
|
||||||
|
"2025-06-01",
|
||||||
|
"2025-06-02",
|
||||||
|
"2025-10-01",
|
||||||
|
"2025-10-02",
|
||||||
|
"2025-10-03",
|
||||||
|
"2025-10-04",
|
||||||
|
"2025-10-05",
|
||||||
|
"2025-10-06",
|
||||||
|
"2025-10-07",
|
||||||
|
"2025-10-08"
|
||||||
|
],
|
||||||
|
"workdays_on_weekend": [
|
||||||
|
"2025-01-26",
|
||||||
|
"2025-02-08",
|
||||||
|
"2025-04-27",
|
||||||
|
"2025-09-28",
|
||||||
|
"2025-10-11"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"2026": {
|
||||||
|
"holidays": [
|
||||||
|
"2026-01-01",
|
||||||
|
"2026-01-02",
|
||||||
|
"2026-01-03",
|
||||||
|
"2026-02-15",
|
||||||
|
"2026-02-16",
|
||||||
|
"2026-02-17",
|
||||||
|
"2026-02-18",
|
||||||
|
"2026-02-19",
|
||||||
|
"2026-02-20",
|
||||||
|
"2026-02-21",
|
||||||
|
"2026-02-22",
|
||||||
|
"2026-02-23",
|
||||||
|
"2026-04-04",
|
||||||
|
"2026-04-05",
|
||||||
|
"2026-04-06",
|
||||||
|
"2026-05-01",
|
||||||
|
"2026-05-02",
|
||||||
|
"2026-05-03",
|
||||||
|
"2026-05-04",
|
||||||
|
"2026-05-05",
|
||||||
|
"2026-06-19",
|
||||||
|
"2026-06-20",
|
||||||
|
"2026-06-21",
|
||||||
|
"2026-09-25",
|
||||||
|
"2026-09-26",
|
||||||
|
"2026-09-27",
|
||||||
|
"2026-10-01",
|
||||||
|
"2026-10-02",
|
||||||
|
"2026-10-03",
|
||||||
|
"2026-10-04",
|
||||||
|
"2026-10-05",
|
||||||
|
"2026-10-06",
|
||||||
|
"2026-10-07"
|
||||||
|
],
|
||||||
|
"workdays_on_weekend": [
|
||||||
|
"2026-01-04",
|
||||||
|
"2026-02-14",
|
||||||
|
"2026-02-28",
|
||||||
|
"2026-05-09",
|
||||||
|
"2026-09-20",
|
||||||
|
"2026-10-10"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
221
.claude/skills/YunxiaoPM/assets/runtime-ids.json
Normal file
221
.claude/skills/YunxiaoPM/assets/runtime-ids.json
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"skill": "YunxiaoPM",
|
||||||
|
"verified_at": "2026-07-25",
|
||||||
|
"note": "YunxiaoPM constants. Project space MUST be user-selected (PJ gate); project.spaceIdentifier is last-known cache only — never auto-apply. See references/project-selection.md.",
|
||||||
|
"project": {
|
||||||
|
"selection_mode": "user_pick_required",
|
||||||
|
"name": null,
|
||||||
|
"name_aliases": [
|
||||||
|
"01_ONEOS",
|
||||||
|
"ONEOS",
|
||||||
|
"统一运营管理平台",
|
||||||
|
"统一运营管理平台PC端",
|
||||||
|
"统一运营管理平台 PC 端"
|
||||||
|
],
|
||||||
|
"spaceIdentifier": null,
|
||||||
|
"customCode": null,
|
||||||
|
"spaceType": "Project",
|
||||||
|
"organizationIdentifier": "697c54a19df7fdfa65466405",
|
||||||
|
"default_sprint_name_prefix": "统一运营管理平台PC端",
|
||||||
|
"list_api": "GET /projex/api/workspace/project/search/list",
|
||||||
|
"last_selected": {
|
||||||
|
"name": "01_ONEOS",
|
||||||
|
"spaceIdentifier": "1280be963a5a2cc126a4118dca",
|
||||||
|
"customCode": "ONEOS",
|
||||||
|
"note": "历史常用项;仅作预填建议,禁止未点选即使用"
|
||||||
|
},
|
||||||
|
"refreshed_at": "2026-07-25"
|
||||||
|
},
|
||||||
|
"projects_catalog": [
|
||||||
|
{
|
||||||
|
"name": "05_羚牛碳资产平台",
|
||||||
|
"identifier": "ff104a3bce09463da136a97999",
|
||||||
|
"customCode": "CARBON"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "06_对外客户项目",
|
||||||
|
"identifier": "baca8b4d676c5af67e475caec0",
|
||||||
|
"customCode": "CUST"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "07_LNBOX",
|
||||||
|
"identifier": "35e1e915a052379bbdfb993aac",
|
||||||
|
"customCode": "LNBOX"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "04_AI应用",
|
||||||
|
"identifier": "d9002ea72c6c3a1a97b02be750",
|
||||||
|
"customCode": "AIAPP"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "03_数据中台",
|
||||||
|
"identifier": "a801cef5c9a68fa051c07432c7",
|
||||||
|
"customCode": "DATA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "02_小羚羚APP",
|
||||||
|
"identifier": "db771a2cca07bed43b369af077",
|
||||||
|
"customCode": "XLLAPP"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "01_ONEOS",
|
||||||
|
"identifier": "1280be963a5a2cc126a4118dca",
|
||||||
|
"customCode": "ONEOS"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "敏捷研发示例项目",
|
||||||
|
"identifier": "65eca0c2e16a23939081e19e14",
|
||||||
|
"customCode": "DEMO"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"people": {
|
||||||
|
"wangmian": {
|
||||||
|
"displayName": "王冕",
|
||||||
|
"identifier": "6811df000601d2fea60144a9",
|
||||||
|
"role": "产品创建人/默认负责人"
|
||||||
|
},
|
||||||
|
"hefei": {
|
||||||
|
"displayName": "何斐",
|
||||||
|
"identifier": "695f0400562f09713f9c3a93",
|
||||||
|
"role": "待开发交棒【交付】负责人"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"故障管理": "ceb526a7343995577645317e9a",
|
||||||
|
"还车应结款": "4204960ce658c94b17abb7c5f6",
|
||||||
|
"工作台": "b62d21beac55c0b43389915eab",
|
||||||
|
"交车管理": "b6947b5aca82a8c759612ba039",
|
||||||
|
"合同管理": "23873be81931cb0dc1bf87a456",
|
||||||
|
"安全培训": "76988b5f73ef515de5930d59b9",
|
||||||
|
"证照管理": "11f4c2ec65901a8f3199c81706",
|
||||||
|
"还车管理": "1e0fce2d6929ff4ac13b310e97"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"req": {
|
||||||
|
"待处理": "100005",
|
||||||
|
"已确认": "32",
|
||||||
|
"分析中": "154395",
|
||||||
|
"设计中": "156603",
|
||||||
|
"设计完成": "307012",
|
||||||
|
"待开发": "1582fc929d429111b925309493"
|
||||||
|
},
|
||||||
|
"task": {
|
||||||
|
"待处理": "100005",
|
||||||
|
"已完成": "100014"
|
||||||
|
},
|
||||||
|
"transit_api": "POST /projex/api/workitem/workitem/{id}/status/transit",
|
||||||
|
"fast_handoff_hops": [
|
||||||
|
"设计完成",
|
||||||
|
"待开发"
|
||||||
|
],
|
||||||
|
"note": "见 references/live-api.md;禁止再用 updateStatus"
|
||||||
|
},
|
||||||
|
"workitem_types": {
|
||||||
|
"product_req": {
|
||||||
|
"name": "产品类需求",
|
||||||
|
"category": "Req",
|
||||||
|
"identifier": "9uy29901re573f561d69jn40"
|
||||||
|
},
|
||||||
|
"task": {
|
||||||
|
"name": "任务",
|
||||||
|
"category": "Task",
|
||||||
|
"identifier": "ba102e46bc6a8483d9b7f25c"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"priority": {
|
||||||
|
"紧急": "646004e97f54bb77fec7b455df",
|
||||||
|
"高": "95b89e0a524d9693e1f335ffe5",
|
||||||
|
"中": "fa155d1214f9f8db222d39db3b",
|
||||||
|
"低": "92924feff9c1085891e7511872"
|
||||||
|
},
|
||||||
|
"fields": {
|
||||||
|
"plan_start": {
|
||||||
|
"fieldIdentifier": "79",
|
||||||
|
"name": "计划开始时间",
|
||||||
|
"value_shape": "YYYY-MM-DD HH:mm:ss China wall time preferred; epoch ms string also accepted",
|
||||||
|
"example": "2026-07-27 12:00:00",
|
||||||
|
"update_api": "POST /projex/api/workitem/workitem/field/value/{workitemId} form fieldValueList=JSON"
|
||||||
|
},
|
||||||
|
"plan_end": {
|
||||||
|
"fieldIdentifier": "80",
|
||||||
|
"name": "计划完成时间",
|
||||||
|
"value_shape": "YYYY-MM-DD HH:mm:ss or epoch ms string",
|
||||||
|
"update_api": "POST /projex/api/workitem/workitem/field/value/{workitemId} form fieldValueList=JSON"
|
||||||
|
},
|
||||||
|
"estimated_hours": {
|
||||||
|
"fieldIdentifier": "101586",
|
||||||
|
"name": "预计工时",
|
||||||
|
"note": "不可直接改字段;须工时预估登记",
|
||||||
|
"create_api": "POST /projex/api/workitem/workitem/time/estimate body spentTime,type,recordUserIdentifier,workitemIdentifier",
|
||||||
|
"delete_api": "DELETE /projex/api/workitem/workitem/time/estimate/{workitemId}/{estimateId}",
|
||||||
|
"list_api": "GET /projex/api/workitem/workitem/time/estimate/list?workitemIdentifier="
|
||||||
|
},
|
||||||
|
"actual_hours": {
|
||||||
|
"name": "实际工时",
|
||||||
|
"note": "快轨待开发默认 2",
|
||||||
|
"create_api": "POST /projex/api/workitem/workitem/time body actualTime,type,recordUserIdentifier,workitemIdentifier,gmtStart,gmtEnd (epoch ms string)",
|
||||||
|
"list_api": "GET /projex/api/workitem/workitem/time/list?workitemIdentifier=",
|
||||||
|
"fast_track_default": 2,
|
||||||
|
"verified_at": "2026-07-27",
|
||||||
|
"verified_on": "ONEOS-293"
|
||||||
|
},
|
||||||
|
"fast_track": {
|
||||||
|
"req_estimated_hours": 2,
|
||||||
|
"req_actual_hours": 2,
|
||||||
|
"design_plan_start_end_same_day": true,
|
||||||
|
"design_description": "copy_req_document",
|
||||||
|
"delivery_description": "manual_sync_or_autoprd",
|
||||||
|
"delivery_design_same_tags_as_req": true,
|
||||||
|
"design_associated_to_req_after_task_sub": true,
|
||||||
|
"document_update_api": "PATCH /projex/api/workitem/workitem/{id}/document {content,formatType:RICHTEXT}"
|
||||||
|
},
|
||||||
|
"submit_department": {
|
||||||
|
"fieldIdentifier": "3132597a9718d1c282b7ba5a0c",
|
||||||
|
"name": "提交部门",
|
||||||
|
"format": "string input",
|
||||||
|
"update_api": "POST /projex/api/workitem/workitem/field/value/{workitemId} form fieldValueList=JSON",
|
||||||
|
"verified_at": "2026-07-27",
|
||||||
|
"verified_on": "ONEOS-293"
|
||||||
|
},
|
||||||
|
"submitter": {
|
||||||
|
"fieldIdentifier": "9e01269e96f91fbb97d36bf5b3",
|
||||||
|
"name": "提交人",
|
||||||
|
"format": "string input",
|
||||||
|
"update_api": "POST /projex/api/workitem/workitem/field/value/{workitemId} form fieldValueList=JSON",
|
||||||
|
"verified_at": "2026-07-27",
|
||||||
|
"verified_on": "ONEOS-293"
|
||||||
|
},
|
||||||
|
"tag": {
|
||||||
|
"fieldIdentifier": "tag",
|
||||||
|
"name": "标签",
|
||||||
|
"propertyKey": "tag"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"assignee_rules": {
|
||||||
|
"待开发_交付任务": "hefei",
|
||||||
|
"分析中_交付与分析": "creator",
|
||||||
|
"设计中_设计": "creator"
|
||||||
|
},
|
||||||
|
"relation": {
|
||||||
|
"delivery_to_req": "ASSOCIATED",
|
||||||
|
"stage_to_delivery": "TASK_SUB",
|
||||||
|
"create_field": "createWorkitemRelationInfo",
|
||||||
|
"forbid": [
|
||||||
|
"PARENT_as_关联项",
|
||||||
|
"ASSOCIATED_only_for_stage_tasks_without_TASK_SUB"
|
||||||
|
],
|
||||||
|
"note": "交付必须 ASSOCIATED→需求。分析/设计默认 TASK_SUB→交付(子项 tab)。二者同 create 互斥。见 references/live-api.md"
|
||||||
|
},
|
||||||
|
"delivery_placeholder": "等待设计任务完成后自动填入",
|
||||||
|
"task_title_prefixes": {
|
||||||
|
"delivery": "【交付】",
|
||||||
|
"analysis": "【分析】",
|
||||||
|
"design": "【设计】"
|
||||||
|
},
|
||||||
|
"publish_url": {
|
||||||
|
"shape": "{baseUrl}/{prototype-id}/index.html",
|
||||||
|
"forbid_prototypes_prefix": true,
|
||||||
|
"require_index_html": true
|
||||||
|
}
|
||||||
|
}
|
||||||
317
.claude/skills/YunxiaoPM/docs-YunxiaoPMapp-实现原理-开发Skill对接.md
Normal file
317
.claude/skills/YunxiaoPM/docs-YunxiaoPMapp-实现原理-开发Skill对接.md
Normal file
@@ -0,0 +1,317 @@
|
|||||||
|
# YunxiaoPMapp 实现原理说明
|
||||||
|
|
||||||
|
> 供**开发部门**设计 / 制作「开发侧 Skill」(暂称 **YunxiaoDevapp**)时对齐契约。
|
||||||
|
> 本文描述产品侧 Skill **YunxiaoPMapp** 的模型、边界、数据契约与交棒接口;**不是**对 `yunxiao-requirement-lifecycle` 的兼容说明。
|
||||||
|
> 技能包:https://github.com/15810879921-coder/oneos-pm-skills · `skills/YunxiaoPMapp/`
|
||||||
|
> 文档版本:2026-07-24
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 为什么拆成两个 Skill
|
||||||
|
|
||||||
|
| | YunxiaoPMapp(产品) | 开发 Skill(待建) |
|
||||||
|
|---|---|---|
|
||||||
|
| 职责 | 需求从「待处理」到「待开发」交棒 | 从「待开发」到开发完成 / 提测前 |
|
||||||
|
| 任务类型 | 【交付】【分析】【设计】 | 【开发】(可多条)、可选挂仓库/分支 |
|
||||||
|
| 负责人交接 | 交棒时【交付】→ **何斐** | 拆【开发】子任务并指派研发 |
|
||||||
|
| 明确不做 | 建【开发】/【测试】、开分支、提测 | 不建【分析】/【设计】、不改 AutoRDO 段 |
|
||||||
|
|
||||||
|
**硬规则:** 两个 Skill **禁止互相 include / fork 全文**;只认本文第 6 章「交棒契约」。产品会话与开发会话不要同时挂载旧 `yunxiao-requirement-lifecycle`,避免双建任务树。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 核心真相源(必须先统一)
|
||||||
|
|
||||||
|
```text
|
||||||
|
需求状态 = 阶段看板唯一真相(分析中 / 设计中 / 待开发 …)
|
||||||
|
【交付】任务 = 每需求最多 1 条「交付容器」
|
||||||
|
【分析】【设计】 = 【交付】下的阶段子项(产品侧建)
|
||||||
|
【开发】【测试】 = 开发 / 测试 Skill 建(产品侧永不创建)
|
||||||
|
查重 / 复用 = 只认云效任务编号 ONEOS-xx,禁止按标题
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.1 关系模型(云效)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TB
|
||||||
|
Req["产品类需求 ONEOS-R"]
|
||||||
|
DEL["【交付】ONEOS-a"]
|
||||||
|
AN["【分析】ONEOS-b"]
|
||||||
|
DE["【设计】ONEOS-c"]
|
||||||
|
DEV["【开发】… 开发 Skill"]
|
||||||
|
TEST["【测试】… 测试 Skill"]
|
||||||
|
|
||||||
|
DEL -->|"ASSOCIATED 关联项"| REQ
|
||||||
|
AN -->|"TASK_SUB 子项"| DEL
|
||||||
|
DE -->|"TASK_SUB 子项"| DEL
|
||||||
|
DEV -.->|"建议:SUB→交付 或 ASSOCIATED→需求+交付"| DEL
|
||||||
|
TEST -.->|"测试 Skill"| REQ
|
||||||
|
```
|
||||||
|
|
||||||
|
| 关系 | 谁写 | 验收 |
|
||||||
|
|---|---|---|
|
||||||
|
| `ASSOCIATED` | **仅【交付】→ 需求** | 交付详情「关联项」可见需求 |
|
||||||
|
| `TASK_SUB` | 【分析】/【设计】→【交付】 | 交付详情「子项」可见阶段任务 |
|
||||||
|
| (开发侧建议) | 【开发】→【交付】或需求 | 由开发 Skill 自定,但须可编号查重 |
|
||||||
|
|
||||||
|
**踩坑(已复现):** 对分析/设计只写 `parentIdentifier` + `ASSOCIATED→需求`,交付「子项」会为空。正确:create 时 `createWorkitemRelationInfo=TASK_SUB` + `parent`/`parentIdentifier`=交付。同一 create **只能**带一条关系,ASSOCIATED 与 TASK_SUB 互斥。
|
||||||
|
|
||||||
|
### 2.2 标题只是展示
|
||||||
|
|
||||||
|
- 形式:`【交付】`/`【分析】`/`【设计】` + 需求标题
|
||||||
|
- **不参与查重**;改标题不影响幂等
|
||||||
|
- 开发侧【开发】标题建议 `【开发】` + 范围简述,同样**只认编号**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 编号权威源
|
||||||
|
|
||||||
|
需求描述固定区块(机器可解析):
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 工作项编号(系统)
|
||||||
|
- 交付:ONEOS-a
|
||||||
|
- 分析:ONEOS-b(无则写无)
|
||||||
|
- 设计:ONEOS-c(无则写无)
|
||||||
|
```
|
||||||
|
|
||||||
|
| 规则 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| 新建后立即 PATCH | 只改本区块,不动 AutoRDO / AutoPRD |
|
||||||
|
| 操作顺序 | 口令显式编号 > 读本区块 > ASSOCIATED/SUB 反查 |
|
||||||
|
| 冲突 | 停下人工;**禁止按标题猜** |
|
||||||
|
| 多交付编号 | 停止并列号请人合并 |
|
||||||
|
|
||||||
|
**开发 Skill 入口建议:** 口令必须带 `需求=ONEOS-R` + `交付任务=ONEOS-a`;缺则读本区块;仍无则询问。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 需求描述双段(产品写 · 开发只读)
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 原始诉求(AutoRDO)
|
||||||
|
(聊天/录音清洗稿;设计完成也不删)
|
||||||
|
|
||||||
|
## 产品说明(AutoPRD)
|
||||||
|
(设计完成才灌满;含对象存储预览链接)
|
||||||
|
|
||||||
|
## 工作项编号(系统)
|
||||||
|
- 交付 / 分析 / 设计
|
||||||
|
```
|
||||||
|
|
||||||
|
| 段 | 谁写 | 开发侧用法 |
|
||||||
|
|---|---|---|
|
||||||
|
| AutoRDO | `$AutoRDO` → 产品记需求时 | 占位交棒时**唯一可信**业务原文 |
|
||||||
|
| AutoPRD | `$oneos-autoprd` → 设计完成时 | 正式需求说明;缺则有权要求产品补设计完成 |
|
||||||
|
| 编号区块 | YunxiaoPMapp | 定位交付树 |
|
||||||
|
|
||||||
|
**【交付】描述:** 设计完成前固定占位文案 `等待设计任务完成后自动填入`;设计完成后替换为 AutoPRD 正文。
|
||||||
|
**允许占位交棒**,但产品回报必须标红风险;开发 Skill 应检测占位并提示「材料不齐,可凭 AutoRDO 开工或退回补设计」。
|
||||||
|
|
||||||
|
对象存储预览 URL 形态:`{baseUrl}/{prototype-id}/index.html`(禁止加 `prototypes/` 前缀、禁止去掉 `index.html`)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 产品侧阶段状态机(0→5)
|
||||||
|
|
||||||
|
```text
|
||||||
|
0 创建需求(待处理) ─AutoRDO→ 仅需求,不建任务
|
||||||
|
1 受理确认(已确认) 仍不建任务
|
||||||
|
2 分析中 建【交付】+【分析】
|
||||||
|
3 设计中 建【设计】;收口【分析】计划完成
|
||||||
|
4 设计完成 收口【设计】;AutoPRD+附件;灌【交付】描述
|
||||||
|
5 待开发交棒 ★ 需求→待开发;【交付】负责人→何斐
|
||||||
|
★ = YunxiaoPMapp 终点 / 开发 Skill 起点
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.1 各步要点(开发需知道的副作用)
|
||||||
|
|
||||||
|
| 步骤 | 需求状态 | 任务侧关键动作 |
|
||||||
|
|---|---|---|
|
||||||
|
| 2 分析中 | 分析中 | 新建【交付】ASSOCIATED→需求;描述=占位;计划开始仅空写当日且**此后不可改**;新建【分析】TASK_SUB→交付 |
|
||||||
|
| 3 设计中 | 设计中 | 新建【设计】;【分析】计划完成=当日 + 阶段日历工时 |
|
||||||
|
| 4 设计完成 | 设计完成 | 【设计】完成态;需求+交付挂 ZIP/截图;交付描述换正式说明 |
|
||||||
|
| 5 交棒 | **待开发** | **只改交付负责人→何斐**;不新建分析/设计;不写交付计划完成 |
|
||||||
|
|
||||||
|
### 5.2 两条旁路(仍交到同一终点)
|
||||||
|
|
||||||
|
| 路径 | 前提 | 行为 |
|
||||||
|
|---|---|---|
|
||||||
|
| **无单快轨** | 尚无分析路径 / 明确跳过分析 | 待开发 + 新建交付+设计(设计当日收口);**不建分析**;默认可不跑 AutoPRD |
|
||||||
|
| **编号直推** | 已有分析/设计**编号** | 收口空计划完成 → 待开发 + 交付交棒何斐;不新建冗余单 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 交棒契约(开发 Skill 必须实现)
|
||||||
|
|
||||||
|
### 6.1 入口条件(产品已完成)
|
||||||
|
|
||||||
|
```text
|
||||||
|
需求状态 = 待开发
|
||||||
|
【交付】任务编号 = ONEOS-a(唯一)
|
||||||
|
【交付】负责人 = 何斐
|
||||||
|
【交付】ASSOCIATED → 该需求
|
||||||
|
可选:分析/设计编号在「工作项编号(系统)」中
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2 开发 Skill 建议入口口令
|
||||||
|
|
||||||
|
```text
|
||||||
|
接手开发:需求=ONEOS-R;交付任务=ONEOS-a
|
||||||
|
拆分开发:交付任务=ONEOS-a;范围=前端|后端|…;负责人=…
|
||||||
|
开始开发:开发任务=ONEOS-d
|
||||||
|
开发完成:开发任务=ONEOS-d
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.3 开发 Skill 建议职责边界
|
||||||
|
|
||||||
|
| 应做 | 不应做 |
|
||||||
|
|---|---|
|
||||||
|
| 在【交付】下建一条或多条【开发】(编号幂等) | 再建【分析】/【设计】或第二套【交付】 |
|
||||||
|
| 正式关联:建议 SUB→交付,或同时 ASSOCIATED→需求 | 只按标题「【开发】xxx」查重 |
|
||||||
|
| 挂仓库 / 分支 / MR(按你们 Codeup 规范) | 覆盖需求 AutoRDO 段 |
|
||||||
|
| 改【开发】状态与负责人 | 擅自把需求从待开发退回(除非产品授权回退口令) |
|
||||||
|
| 检测交付描述是否仍为占位并提示 | 假装 AutoPRD 已齐全 |
|
||||||
|
| 全部【开发】完成后通知测试 Skill / 建【测试】 | 在产品 Skill 会话里混跑 |
|
||||||
|
|
||||||
|
### 6.4 共享常量(可引用,勿整包加载)
|
||||||
|
|
||||||
|
路径均在 `skills/YunxiaoPMapp/assets/`:
|
||||||
|
|
||||||
|
| 文件 | 内容 |
|
||||||
|
|---|---|
|
||||||
|
| `runtime-ids.json` | 项目 spaceId、何斐 ID、工作项类型、状态 transit、字段 79/80 |
|
||||||
|
| `cn-workday-calendar.json` | 法定节假日 / 调休(阶段日历工时) |
|
||||||
|
|
||||||
|
开发侧可复制一份到自己的 `assets/`,或只读引用短路径;**不要**把 YunxiaoPMapp 的 references 全文 include 进开发 Skill。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 计划时间与「阶段日历工时」
|
||||||
|
|
||||||
|
产品侧口径(开发侧若写计划时间建议对齐语义):
|
||||||
|
|
||||||
|
| 对象 | 计划开始 | 计划完成 | 预计工时 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 【交付】 | 首次分析中空则写当日,**永不覆盖** | 产品侧不写(留给上线) | 一般不推全周期 |
|
||||||
|
| 【分析】【设计】 | 创建时空则写当日,**永不覆盖** | 阶段收口日 | `工作日×8` |
|
||||||
|
|
||||||
|
```text
|
||||||
|
预计工时 = 阶段日历工时(Lead Time)≠ 人力投入人天
|
||||||
|
算法:起止日含首尾,扣周末与法定假,计入调休补班;×8 小时
|
||||||
|
禁止:(结束−开始+1)×8 的自然日算法
|
||||||
|
```
|
||||||
|
|
||||||
|
脚注固定:`【系统】预计工时=阶段日历工时(工作日×8),非人力投入预估`
|
||||||
|
脚本:`scripts/workday_hours.py`
|
||||||
|
|
||||||
|
**建议:** 开发 Skill 若给【开发】写预计工时,在文档中明确是「人力投入预估」还是「阶段日历工时」,避免与产品侧混称。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Agent 运行时原理(制作 Skill 时照抄模式)
|
||||||
|
|
||||||
|
### 8.1 Plan 门禁
|
||||||
|
|
||||||
|
凡写云效:`SwitchMode → plan` → 用户确认 → 一口气 apply → 一次校验回报。
|
||||||
|
禁止用「参数已齐 / 速度路径」跳过 Plan。
|
||||||
|
|
||||||
|
### 8.2 模块化路由
|
||||||
|
|
||||||
|
`SKILL.md` 只做路由与门禁;细则在 `references/*.md`;常量在 `assets/`;脚本在 `scripts/`。
|
||||||
|
外置能力(AutoRDO、AutoPRD)**调用对方 Skill**,不内嵌对方全文。
|
||||||
|
|
||||||
|
### 8.3 幂等
|
||||||
|
|
||||||
|
```text
|
||||||
|
幂等键 = 项目 + 需求编号 + 任务类型角色(交付/分析/设计/开发…)+ 已登记任务编号
|
||||||
|
命中编号 → 复用并补缺字段;禁止新建第二条同角色主容器(交付唯一)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8.4 验收与回报
|
||||||
|
|
||||||
|
每次 apply 后自检(产品侧清单见 `references/acceptance.md`)。开发侧建议至少回报:
|
||||||
|
|
||||||
|
```text
|
||||||
|
【YunxiaoDevapp】
|
||||||
|
需求:ONEOS-R | 状态=待开发|开发中|…
|
||||||
|
交付:ONEOS-a | 负责人=…
|
||||||
|
开发:ONEOS-d1, ONEOS-d2 | …
|
||||||
|
仓库/分支:…
|
||||||
|
下一步:…
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8.5 已验证写路径(可复用思路)
|
||||||
|
|
||||||
|
| 动作 | 约定(见 live-api.md) |
|
||||||
|
|---|---|
|
||||||
|
| 改状态 | `POST …/status/transit`(勿用错误 updateStatus) |
|
||||||
|
| 改负责人 | `PATCH …/{id}` + `propertyKey=assignedTo` |
|
||||||
|
| 建单关系 | create 带 `createWorkitemRelationInfo` |
|
||||||
|
| 极速复测 | `scripts/live_create_fast.py`(可参考,开发侧另写自己的脚本) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. 回退最小集(开发需配合)
|
||||||
|
|
||||||
|
| 场景 | 产品侧规则 | 开发侧注意 |
|
||||||
|
|---|---|---|
|
||||||
|
| 待开发 → 退回设计中 | 需求回退;交付负责人可改回产品;**交付计划开始不改**;重做设计则**新开设计编号** | 已建【开发】是否取消 / 暂停由开发 Skill 定义;勿静默删编号 |
|
||||||
|
| 设计完成后需求大变 | Plan 问是否回退;更新 AutoPRD;AutoRDO 保留+变更纪要 | 勿覆盖 AutoRDO |
|
||||||
|
| 取消需求 | 任务标取消;不删编号区块 | 同步取消未完成【开发】 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. 建议的「YunxiaoDevapp」目录骨架
|
||||||
|
|
||||||
|
```text
|
||||||
|
YunxiaoDevapp/
|
||||||
|
├── SKILL.md # 门禁 + 路由 + 边界(引用本文契约,不 include PMapp)
|
||||||
|
├── assets/
|
||||||
|
│ └── runtime-ids.json # 可从 PMapp 复制/裁剪
|
||||||
|
├── references/
|
||||||
|
│ ├── model.md # 【开发】与交付/需求的关系约定
|
||||||
|
│ ├── handoff-intake.md # 认交付编号 + 占位检测
|
||||||
|
│ ├── split-dev-tasks.md # 拆前端/后端多【开发】
|
||||||
|
│ ├── codeup.md # 分支 / MR / 关联
|
||||||
|
│ ├── commands.md # 口令面
|
||||||
|
│ └── acceptance.md
|
||||||
|
└── scripts/ # 可选极速 API
|
||||||
|
```
|
||||||
|
|
||||||
|
`SKILL.md` description 建议写明:触发词「接手开发 / 拆分开发 / 开始开发」;**Does NOT create 【分析】/【设计】**;入口条件需求=待开发。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. 对照检查表(开发 Skill 评审用)
|
||||||
|
|
||||||
|
- [ ] 是否只认「需求编号 + 交付任务编号」,禁止标题查重
|
||||||
|
- [ ] 是否拒绝创建第二套【交付】或【分析】【设计】
|
||||||
|
- [ ] 占位交棒时是否提示风险且不假装 PRD 齐全
|
||||||
|
- [ ] 【开发】是否可编号幂等、可挂到交付树
|
||||||
|
- [ ] 是否与 YunxiaoPMapp **会话隔离**(不同 Skill、不同口令)
|
||||||
|
- [ ] 计划开始字段是否遵守「已有值不覆盖」(若沿用同一字段)
|
||||||
|
- [ ] 提测 / 【测试】是否交给测试 Skill,本包边界清晰
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. 相关文档索引
|
||||||
|
|
||||||
|
| 主题 | 路径(仓库内) |
|
||||||
|
|---|---|
|
||||||
|
| Skill 入口 | `skills/YunxiaoPMapp/SKILL.md` |
|
||||||
|
| 交付树模型 | `skills/YunxiaoPMapp/references/model.md` |
|
||||||
|
| 交棒契约 | `skills/YunxiaoPMapp/references/handoff-contract.md` |
|
||||||
|
| 标准路径 0–5 | `skills/YunxiaoPMapp/references/stage-flow.md` |
|
||||||
|
| 交棒门禁 / 回退 | `skills/YunxiaoPMapp/references/handoff-and-rollback.md` |
|
||||||
|
| 描述双段 | `skills/YunxiaoPMapp/references/description-split.md` |
|
||||||
|
| 编号区块 | `skills/YunxiaoPMapp/references/workitem-ids.md` |
|
||||||
|
| 快轨 / 编号直推 | `references/fast-track.md` · `number-push.md` |
|
||||||
|
| 工时算法 | `references/work-hours.md` |
|
||||||
|
| 实写 API | `references/live-api.md` |
|
||||||
|
|
||||||
|
安装产品 Skill:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx skills add 15810879921-coder/oneos-pm-skills --skill YunxiaoPMapp -a cursor -g -y
|
||||||
|
```
|
||||||
179
.claude/skills/YunxiaoPM/docs-产品部流转流程图.md
Normal file
179
.claude/skills/YunxiaoPM/docs-产品部流转流程图.md
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
# 产品部流转:YunxiaoPMapp(到交棒为止)
|
||||||
|
|
||||||
|
> 用途:先把**产品部**在云效上的工作流转说清楚;开发 / 测试 / 发版不在本 Skill 内,仅在文末标出交接点。
|
||||||
|
> 依据:`references/stage-flow.md` · `model.md` · `fast-track.md` · `handoff-contract.md`
|
||||||
|
> 日期:2026-07-24
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 产品部管到哪里
|
||||||
|
|
||||||
|
```text
|
||||||
|
产品部(YunxiaoPMapp)终点 = 需求状态「待开发」+【交付】负责人「何斐」
|
||||||
|
之后 = 请技术经理使用开发 Skill(不建【开发】/【测试】)
|
||||||
|
```
|
||||||
|
|
||||||
|
| 谁 | 做什么 | 不做什么 |
|
||||||
|
|---|---|---|
|
||||||
|
| 产品 / YunxiaoPMapp | 建需求、打标签、建【交付】【分析】【设计】、推进状态、设计完成灌 AutoPRD、交棒 | 建【开发】【测试】、开分支、提测、发版 |
|
||||||
|
| 技术经理(接手) | 从「待开发」起拆开发 | 不改写 AutoRDO;不新建第二套【交付】 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 总览流程图(标准路径)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TB
|
||||||
|
subgraph inputs [材料入口]
|
||||||
|
Chat[聊天/录音/口述]
|
||||||
|
AutoRDO["$AutoRDO 清洗"]
|
||||||
|
Proto[原型页 Make]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph pm [产品部 · YunxiaoPMapp]
|
||||||
|
S0["0 创建需求\n状态=待处理\n只写 AutoRDO\n不建任务"]
|
||||||
|
S1["1 受理确认\n状态=已确认\n仍不建任务"]
|
||||||
|
S2["2 分析中\n建【交付】+【分析】"]
|
||||||
|
S3["3 设计中\n建【设计】\n收口【分析】"]
|
||||||
|
S4["4 设计完成\n收口【设计】\nAutoPRD+附件\n灌【交付】描述"]
|
||||||
|
S5["5 待开发交棒\n交付负责人→何斐\n★ 产品终点"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph after [产品之后 · 不在本 Skill]
|
||||||
|
Dev["开发 Skill\n拆【开发】…"]
|
||||||
|
Test["测试 Skill"]
|
||||||
|
Rel["发版"]
|
||||||
|
end
|
||||||
|
|
||||||
|
Chat --> AutoRDO --> S0
|
||||||
|
Proto -.-> S4
|
||||||
|
S0 --> S1 --> S2 --> S3 --> S4 --> S5
|
||||||
|
S5 -->|"交棒契约:需求编号+交付编号"| Dev
|
||||||
|
Dev --> Test --> Rel
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 各步说明(产品侧)
|
||||||
|
|
||||||
|
| 步骤 | 需求状态 | 云效任务动作 | 描述写什么 | 口令示例 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| 0 创建 | 待处理 | 无 | `## 原始诉求(AutoRDO)`;编号区块待建 | `记录需求:…;推进至=暂不推进` |
|
||||||
|
| 1 受理 | 已确认 | 仍无 | 不动 | `受理确认:ONEOS-xx` |
|
||||||
|
| 2 分析中 | 分析中 | 新建【交付】ASSOCIATED→需求;新建【分析】TASK_SUB→交付 | 交付=占位文案 | `开始分析:ONEOS-xx` |
|
||||||
|
| 3 设计中 | 设计中 | 新建【设计】TASK_SUB→交付;分析计划完成=当日+阶段日历工时 | — | `开始设计:ONEOS-xx;交付=…;分析=…` |
|
||||||
|
| 4 设计完成 | 设计完成 | 设计完成态;需求+交付挂 ZIP/截图;交付描述换 AutoPRD | `$oneos-autoprd` 灌 `## 产品说明` | `设计完成:ONEOS-xx;设计=…;原型=…` |
|
||||||
|
| 5 交棒 | **待开发** | **只**把【交付】负责人改为何斐 | 若仍占位须标红风险 | `交棒开发:ONEOS-xx;交付=…` |
|
||||||
|
|
||||||
|
**编号权威:** 需求描述 `## 工作项编号(系统)`(交付 / 分析 / 设计)。后续口令优先带 `ONEOS-xx`,禁止按标题查重。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 交付树(产品建出来的结构)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TB
|
||||||
|
REQ["产品类需求 ONEOS-R\n状态=阶段真相"]
|
||||||
|
DEL["【交付】ONEOS-a\nASSOCIATED→需求"]
|
||||||
|
AN["【分析】ONEOS-b"]
|
||||||
|
DE["【设计】ONEOS-c"]
|
||||||
|
|
||||||
|
DEL -->|"关联项 ASSOCIATED"| REQ
|
||||||
|
AN -->|"子项 TASK_SUB"| DEL
|
||||||
|
DE -->|"子项 TASK_SUB"| DEL
|
||||||
|
```
|
||||||
|
|
||||||
|
验收口诀:
|
||||||
|
- 打开【交付】→「关联项」能看到需求
|
||||||
|
- 打开【交付】→「子项」能看到分析/设计(必须 `TASK_SUB`,不能只写 parentIdentifier)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 两条旁路(仍交到同一终点)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
subgraph standard [标准]
|
||||||
|
A1[分析中] --> A2[设计中] --> A3[设计完成] --> A4[待开发]
|
||||||
|
end
|
||||||
|
subgraph fast [无单快轨]
|
||||||
|
B1[待处理/已确认等] --> B2["待开发\n建交付+设计当日收口\n不建分析"]
|
||||||
|
end
|
||||||
|
subgraph push [编号直推]
|
||||||
|
C1[已有分析/设计编号] --> C2[收口空计划完成] --> C3[待开发+交棒何斐]
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
| 路径 | 何时用 | 注意 |
|
||||||
|
|---|---|---|
|
||||||
|
| 标准 0→5 | 正常产品节奏 | 设计完成才灌 AutoPRD |
|
||||||
|
| 快轨 | 明确跳过分析、急交棒 | 默认可不跑 AutoPRD;交付常占位→回报标红 |
|
||||||
|
| 编号直推 | 树上已有阶段任务编号 | 不新建冗余单;只认编号 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 产品部人机边界(Plan 门禁)
|
||||||
|
|
||||||
|
```text
|
||||||
|
凡写云效:Plan 对齐 → 人确认 → 一口气 apply → 一次校验回报
|
||||||
|
```
|
||||||
|
|
||||||
|
| 适合全自动 | 建议人点一下 |
|
||||||
|
|---|---|
|
||||||
|
| 建单、打标、建树、改状态、交棒负责人、幂等复用 | 优先级、标签、是否快轨、设计是否真可开发、占位是否接受交棒 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 交棒给下游时交出什么
|
||||||
|
|
||||||
|
产品回报至少包含:
|
||||||
|
|
||||||
|
```text
|
||||||
|
【YunxiaoPMapp】
|
||||||
|
风险:(占位交棒则首行标红)
|
||||||
|
需求:ONEOS-R | 状态=待开发
|
||||||
|
交付:ONEOS-a | 负责人=何斐
|
||||||
|
分析:ONEOS-b 或 无
|
||||||
|
设计:ONEOS-c 或 快轨占位说明
|
||||||
|
下一步:请技术经理使用开发 Skill
|
||||||
|
```
|
||||||
|
|
||||||
|
下游入口条件见 `references/handoff-contract.md`:认 **需求编号 + 交付任务编号**。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 和全链路的关系(本文件边界)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
PM[产品部本文] --> Handoff[待开发交棒]
|
||||||
|
Handoff --> Dev[开发]
|
||||||
|
Dev --> QA[测试]
|
||||||
|
QA --> Rel[发版]
|
||||||
|
```
|
||||||
|
|
||||||
|
全链路(含谢佳伟 / 时生亮)见仓库原型:
|
||||||
|
`src/prototypes/yunxiao-pipeline-handbook/`
|
||||||
|
产品 Skill 对接开发说明:
|
||||||
|
`docs-YunxiaoPMapp-实现原理-开发Skill对接.md`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. 相关 references
|
||||||
|
|
||||||
|
| 主题 | 路径 |
|
||||||
|
|---|---|
|
||||||
|
| 标准 0–5 | `references/stage-flow.md` |
|
||||||
|
| 交付树 / 子项 | `references/model.md` |
|
||||||
|
| 快轨 | `references/fast-track.md` |
|
||||||
|
| 编号直推 | `references/number-push.md` |
|
||||||
|
| 交棒门禁 | `references/handoff-and-rollback.md` |
|
||||||
|
| 交棒契约 | `references/handoff-contract.md` |
|
||||||
|
| 口令 | `references/commands.md` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 延伸阅读
|
||||||
|
|
||||||
|
- 四角色泳道(产品/开发/测试/发版):`docs-四角色泳道流程图.md`
|
||||||
|
- 开发侧草案:`docs-开发侧流转草案.md`
|
||||||
318
.claude/skills/YunxiaoPM/docs-全流程分步说明.md
Normal file
318
.claude/skills/YunxiaoPM/docs-全流程分步说明.md
Normal file
@@ -0,0 +1,318 @@
|
|||||||
|
# 全流程分步说明:产品 → 开发 → 测试 → 发版
|
||||||
|
|
||||||
|
> 把整条链路拆成**按顺序执行的步骤**,每步说清:谁做、做什么、云效上变成什么、下一步谁接。
|
||||||
|
> 读完应能照着口令/动作走完一轮(标准路径)。
|
||||||
|
> 日期:2026-07-24
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 先记住三件事
|
||||||
|
|
||||||
|
1. **需求状态 = 阶段真相**
|
||||||
|
看需求状态就知道现在卡在哪一段(分析中 / 待开发 / 开发中 / 待测试…)。
|
||||||
|
2. **每条需求只有 1 个【交付】容器**
|
||||||
|
分析、设计、开发、测试都挂在这个交付下面(子项),不要再建第二个【交付】。
|
||||||
|
3. **编号说话,不靠标题查**
|
||||||
|
口令尽量带 `ONEOS-xx`;改标题不影响关联。
|
||||||
|
|
||||||
|
```text
|
||||||
|
需求(状态主轴)
|
||||||
|
└─【交付】(容器,关联到需求)
|
||||||
|
├─【分析】【设计】 ← 产品建
|
||||||
|
├─【开发】… ← 开发建
|
||||||
|
└─【测试】 ← 开发提测时建
|
||||||
|
【发版】另建,挂迭代 + 范围内需求
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 总步骤一览(共 18 步)
|
||||||
|
|
||||||
|
| 阶段 | 步骤 | 一句话 |
|
||||||
|
|---|---|---|
|
||||||
|
| **产品** | 1~6 | 从记诉求到交棒给何斐 |
|
||||||
|
| **开发** | 7~12 | 从拆任务到提测 |
|
||||||
|
| **测试** | 13~15 | 从接测到测试完成 |
|
||||||
|
| **发版** | 16~17 | 从建发版到发布结果 |
|
||||||
|
| **收口** | 18 | 产品验收关闭 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 阶段 A|产品(步骤 1~6)
|
||||||
|
|
||||||
|
### 步骤 1|记录需求
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 产品 / AI(YunxiaoPMapp) |
|
||||||
|
| **做什么** | 把聊天、录音、口述先洗成 AutoRDO,再建一条**产品类需求** |
|
||||||
|
| **需求状态** | **待处理** |
|
||||||
|
| **云效任务** | 不建任何任务 |
|
||||||
|
| **描述里写** | `## 原始诉求(AutoRDO)`;编号区先空着 |
|
||||||
|
| **口令例** | `记录需求:…;推进至=暂不推进` |
|
||||||
|
| **为什么** | 先落盘,避免口头需求丢;还没确认值不值得做 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 步骤 2|受理确认
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 产品 |
|
||||||
|
| **做什么** | 确认要做:定优先级、打标签(从云效标签里点选) |
|
||||||
|
| **需求状态** | **已确认** |
|
||||||
|
| **云效任务** | 仍不建任务 |
|
||||||
|
| **口令例** | `受理确认:ONEOS-xx` |
|
||||||
|
| **为什么** | 和「还没想清楚」的待处理分开;确认后才进分析/设计 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 步骤 3|开始分析
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 产品 / AI |
|
||||||
|
| **做什么** | ① 建 **【交付】**(整条需求的唯一容器,关联到需求)② 建 **【分析】**(挂在交付**子项**下) |
|
||||||
|
| **需求状态** | **分析中** |
|
||||||
|
| **云效任务** | 【交付】+【分析】 |
|
||||||
|
| **口令例** | `开始分析:ONEOS-xx` |
|
||||||
|
| **验收** | 打开【交付】→「关联项」有需求;「子项」有【分析】 |
|
||||||
|
| **为什么** | 分析要有落点;后续设计/开发/测试都挂同一棵树 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 步骤 4|开始设计
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 产品 / AI |
|
||||||
|
| **做什么** | 建 **【设计】**(子项挂交付);收口【分析】计划时间 |
|
||||||
|
| **需求状态** | **设计中** |
|
||||||
|
| **云效任务** | 新增【设计】 |
|
||||||
|
| **口令例** | `开始设计:ONEOS-xx;交付=…;分析=…` |
|
||||||
|
| **为什么** | 进入原型/方案设计;分析阶段收口 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 步骤 5|设计完成
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 产品 / AI |
|
||||||
|
| **做什么** | 收口【设计】;跑 AutoPRD,把**产品说明**灌进【交付】描述;挂原型 ZIP/截图等附件 |
|
||||||
|
| **需求状态** | **设计完成** |
|
||||||
|
| **口令例** | `设计完成:ONEOS-xx;设计=…;原型=…` |
|
||||||
|
| **为什么** | 开发接手时看的是【交付】里的产品说明,不是聊天记录 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 步骤 6|交棒开发(产品终点)
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 产品 / AI |
|
||||||
|
| **做什么** | 需求改为待开发;**【交付】负责人改为何斐**(不新建开发/测试任务) |
|
||||||
|
| **需求状态** | **待开发** ★ |
|
||||||
|
| **交出什么** | 需求编号 +【交付】编号 |
|
||||||
|
| **口令例** | `交棒开发:ONEOS-xx;交付=…` |
|
||||||
|
| **为什么** | 产品部到此结束;技术经理从这里拆开发 |
|
||||||
|
|
||||||
|
> 旁路:急单可用**快轨**(跳过分析、直接待开发),仍交到同一终点「待开发 + 交付→何斐」。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 阶段 B|开发(步骤 7~12)
|
||||||
|
|
||||||
|
### 步骤 7|分配开发任务
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 开发主管何斐 / 开发 Skill |
|
||||||
|
| **做什么** | 输入**交付任务编号** → 自动建 **【开发】**;标题=`【开发】`+需求标题;**描述人工补**;指定开发人;自动写计划时间 |
|
||||||
|
| **关联** | 子项挂【交付】;关联项挂需求 |
|
||||||
|
| **需求状态** | 仍为 **待开发**(确认即可,一般不用再改) |
|
||||||
|
| **口令例** | `分配任务:交付=ONEOS-a;开发人=张三` |
|
||||||
|
| **为什么** | 一条需求可拆多个开发任务;都挂在同一交付下 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 步骤 8|开始开发
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 开发人员 |
|
||||||
|
| **做什么** | 口令带上**开发任务编号** |
|
||||||
|
| **开发任务** | → **处理中** |
|
||||||
|
| **需求状态** | → **开发中** |
|
||||||
|
| **口令例** | `开始开发:ONEOS-d` |
|
||||||
|
| **为什么** | 看板一眼能看出「正在写代码」 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 步骤 9|写代码 / 提 MR
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 开发人员 |
|
||||||
|
| **做什么** | 按【交付】里的产品说明实现;分支/MR 建议挂上开发任务编号与需求编号 |
|
||||||
|
| **需求状态** | 仍为 **开发中** |
|
||||||
|
| **为什么** | 代码可追溯到哪条开发任务、哪条需求 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 步骤 10|AI 自测门禁(开发侧草案)
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | AI(开发完成后触发) |
|
||||||
|
| **做什么** | 找与**需求同标题**的测试计划 → 按用例自测 → 不过则自动提缺陷(标题含开发任务编号)并尝试修复,直到本计划用例全过 |
|
||||||
|
| **需求状态** | 仍为 **开发中**(未全过前) |
|
||||||
|
| **为什么** | 在正式提测前先挡住明显问题(属草案,规则可再收紧) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 步骤 11|开发任务完成
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 系统 / AI(用例全过之后) |
|
||||||
|
| **做什么** | 该条【开发】标为**已完成** |
|
||||||
|
| **需求状态** | → **开发完成**(若有多条开发,建议等**全部**完成再改,避免过早) |
|
||||||
|
| **为什么** | 标记「代码+门禁」这一段结束 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 步骤 12|完成开发 · 正式提测
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 开发人员(自测也完成) |
|
||||||
|
| **做什么** | 口令「完成开发」→ 自动建 **【测试】**(标题=`【测试】`+任务名);子项挂【交付】;建议再关联需求;指派测试(如谢佳伟) |
|
||||||
|
| **需求状态** | → **待测试** ★ |
|
||||||
|
| **口令例** | `完成开发:ONEOS-d` |
|
||||||
|
| **为什么** | 开发交棒给测试;测试侧开始接单 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 阶段 C|测试(步骤 13~15)
|
||||||
|
|
||||||
|
### 步骤 13|接测试任务
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 测试(谢佳伟等) |
|
||||||
|
| **做什么** | 打开【测试】任务;确认关联的需求与交付;准备/核对测试计划与用例包(建议按**需求编号**分包,比「同标题」更稳) |
|
||||||
|
| **需求状态** | **待测试** → 开始执行后改为 **测试中** |
|
||||||
|
| **为什么** | 正式测试以计划用例为准,不靠口头「测过了」 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 步骤 14|执行用例 · 缺陷回流
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 测试执行;失败时回流开发修 |
|
||||||
|
| **做什么** | 按用例执行;失败建缺陷 → 开发修复 → 再测 |
|
||||||
|
| **需求状态** | **测试中** |
|
||||||
|
| **为什么** | 质量关口;未绿不能进发版 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 步骤 15|测试完成
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 测试 / AI 辅助判定 |
|
||||||
|
| **做什么** | **本需求**相关用例全绿 →【测试】收口;通知发版对接人 |
|
||||||
|
| **需求状态** | → **测试完成** ★ |
|
||||||
|
| **注意** | 只卡本需求,不卡同迭代里别的需求 |
|
||||||
|
| **为什么** | 发版范围以「测试完成」的需求为准 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 阶段 D|发版(步骤 16~17)
|
||||||
|
|
||||||
|
### 步骤 16|建发版任务
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 发版对接人(时生亮)· 手工或 AI |
|
||||||
|
| **做什么** | 建 **【发版】**;关联**迭代** + 本期内要上的需求(建议再挂交付/测试);汇总更新说明 |
|
||||||
|
| **需求状态** | 进入发布流程时 → **发布中** |
|
||||||
|
| **为什么** | 一次发版可能含多条需求;要有明确范围清单 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 步骤 17|发布结果回写
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 发版对接人 / 流水线 |
|
||||||
|
| **做什么** | 执行发布 |
|
||||||
|
| **结果** | 成功 → **发布完成**;失败 → **发布失败**(可重试再进发布中) |
|
||||||
|
| **为什么** | 成败要回写云效,避免「以为发了其实没发」 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 阶段 E|收口(步骤 18)
|
||||||
|
|
||||||
|
### 步骤 18|业务验收 · 关闭
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 产品 |
|
||||||
|
| **做什么** | 业务验收通过后,关闭需求,并收口【交付】 |
|
||||||
|
| **需求状态** | → **已关闭** |
|
||||||
|
| **为什么** | 全链路结束;树上任务与需求一致收口 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 状态主链(串起来看)
|
||||||
|
|
||||||
|
```text
|
||||||
|
待处理 → 已确认 → 分析中 → 设计中 → 设计完成
|
||||||
|
→ 待开发 ← 产品交棒给何斐
|
||||||
|
→ 开发中 → 开发完成
|
||||||
|
→ 待测试 → 测试中 → 测试完成
|
||||||
|
→ 发布中 → 发布完成(或发布失败可重试)
|
||||||
|
→ 已关闭 ← 产品验收关单
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四个交棒口(最重要)
|
||||||
|
|
||||||
|
| 交棒 | 交出人 | 接棒人 | 交出物 | 状态落点 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| ① 产品→开发 | 产品 | 何斐 | 需求号 + 交付号 | 待开发 |
|
||||||
|
| ② 开发→测试 | 开发人 | 测试 | 【测试】任务已建好 | 待测试 |
|
||||||
|
| ③ 测试→发版 | 测试 | 发版 | 本需求用例全绿 | 测试完成 |
|
||||||
|
| ④ 发版→产品 | 发版 | 产品 | 发布完成 / 更新说明 | 发布完成 → 已关闭 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 谁在什么时候动(对照表)
|
||||||
|
|
||||||
|
| 步骤 | 产品 | 开发主管 | 开发人 | 测试 | 发版 |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| 1~2 记需求/确认 | ● | | | | |
|
||||||
|
| 3~5 分析设计 | ● | | | | |
|
||||||
|
| 6 交棒 | ● | 接 | | | |
|
||||||
|
| 7 分配任务 | | ● | | | |
|
||||||
|
| 8~9 开始写码 | | | ● | | |
|
||||||
|
| 10~11 AI门禁/完成任务 | | | ●/AI | | |
|
||||||
|
| 12 提测 | | | ● | 接 | |
|
||||||
|
| 13~15 测试 | | | 修缺陷 | ● | |
|
||||||
|
| 16~17 发版 | | | | | ● |
|
||||||
|
| 18 关闭 | ● | | | | |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 相关文档
|
||||||
|
|
||||||
|
| 文档 | 用途 |
|
||||||
|
|---|---|
|
||||||
|
| `docs-四角色泳道流程图.md` | 泳道图总览 |
|
||||||
|
| `docs-产品部流转流程图.md` | 产品 1~6 细规 |
|
||||||
|
| `docs-开发侧流转草案.md` | 开发 7~12 细规与待拍板 |
|
||||||
|
| `yunxiao-pipeline-handbook` | 云效规则与配置 |
|
||||||
181
.claude/skills/YunxiaoPM/docs-四角色泳道流程图.md
Normal file
181
.claude/skills/YunxiaoPM/docs-四角色泳道流程图.md
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
# 四角色泳道图:产品 · 开发 · 测试 · 发版
|
||||||
|
|
||||||
|
> 用途:一张图看清从建需求到发版关闭,四条泳道各自做什么、在哪交棒。
|
||||||
|
> 依据:产品部流转 · 开发侧草案 · 生产线手册(测试/发版)
|
||||||
|
> 日期:2026-07-24
|
||||||
|
> 说明:开发泳道含「AI 用例门禁」草案;测试泳道为正式提测后的人/计划执行。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 泳道总览(推荐主图)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TB
|
||||||
|
subgraph PM["泳道① 产品"]
|
||||||
|
direction TB
|
||||||
|
P0["建需求 · 待处理<br/>只写 AutoRDO"]
|
||||||
|
P1["受理确认 · 已确认"]
|
||||||
|
P2["分析中<br/>建【交付】+【分析】"]
|
||||||
|
P3["设计中<br/>建【设计】"]
|
||||||
|
P4["设计完成<br/>AutoPRD 灌交付"]
|
||||||
|
P5["交棒 · 待开发<br/>交付负责人→何斐"]
|
||||||
|
P6["业务验收后<br/>关闭需求+交付"]
|
||||||
|
P0 --> P1 --> P2 --> P3 --> P4 --> P5
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph DEV["泳道② 开发"]
|
||||||
|
direction TB
|
||||||
|
D1["何斐:分配任务<br/>建【开发】SUB→交付"]
|
||||||
|
D2["开发人:开始开发<br/>任务处理中 · 需求开发中"]
|
||||||
|
D3["写代码 / 提 MR"]
|
||||||
|
D4["AI 按同标题测试计划自测<br/>不过→提缺陷并修"]
|
||||||
|
D5["开发任务已完成<br/>需求→开发完成"]
|
||||||
|
D6["完成开发(含自测)<br/>建【测试】· 需求待测试"]
|
||||||
|
D1 --> D2 --> D3 --> D4 --> D5 --> D6
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph QA["泳道③ 测试"]
|
||||||
|
direction TB
|
||||||
|
T1["接【测试】任务<br/>需求=待测试"]
|
||||||
|
T2["建/挂测试计划与用例<br/>(建议按需求编号分包)"]
|
||||||
|
T3["测试中 · 执行用例"]
|
||||||
|
T4["缺陷回流开发修复"]
|
||||||
|
T5["本需求用例全绿<br/>需求→测试完成"]
|
||||||
|
T1 --> T2 --> T3
|
||||||
|
T3 -.->|失败| T4
|
||||||
|
T4 -.->|再测| T3
|
||||||
|
T3 -->|通过| T5
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph REL["泳道④ 发版"]
|
||||||
|
direction TB
|
||||||
|
R1["建【发版】任务<br/>挂迭代+范围内需求"]
|
||||||
|
R2["汇总更新说明"]
|
||||||
|
R3["发布中"]
|
||||||
|
R4{"发布结果"}
|
||||||
|
R5["发布完成"]
|
||||||
|
R6["发布失败 · 可重试"]
|
||||||
|
R1 --> R2 --> R3 --> R4
|
||||||
|
R4 -->|成功| R5
|
||||||
|
R4 -->|失败| R6
|
||||||
|
R6 -.-> R3
|
||||||
|
end
|
||||||
|
|
||||||
|
P5 -->|"交棒契约<br/>需求编号+交付编号"| D1
|
||||||
|
D6 -->|"提测<br/>【测试】已挂交付"| T1
|
||||||
|
T5 -->|"交棒发版"| R1
|
||||||
|
R5 -->|"业务可验收"| P6
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 横向时间轴版(谁在哪一阶段动)
|
||||||
|
|
||||||
|
从左到右是需求状态主链;上下是四个角色。空格表示该角色此阶段无主动动作。
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
subgraph S_PM["产品阶段"]
|
||||||
|
direction TB
|
||||||
|
sp0["待处理→已确认"]
|
||||||
|
sp1["分析/设计/设计完成"]
|
||||||
|
sp2["待开发交棒"]
|
||||||
|
sp3["已关闭"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph S_DEV["开发阶段"]
|
||||||
|
direction TB
|
||||||
|
sd0["拆【开发】"]
|
||||||
|
sd1["开发中"]
|
||||||
|
sd2["AI门禁→开发完成"]
|
||||||
|
sd3["建【测试】→待测试"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph S_QA["测试阶段"]
|
||||||
|
direction TB
|
||||||
|
sq0["待测试"]
|
||||||
|
sq1["测试中"]
|
||||||
|
sq2["测试完成"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph S_REL["发版阶段"]
|
||||||
|
direction TB
|
||||||
|
sr0["建【发版】"]
|
||||||
|
sr1["发布中"]
|
||||||
|
sr2["完成/失败"]
|
||||||
|
end
|
||||||
|
|
||||||
|
sp0 --> sp1 --> sp2
|
||||||
|
sp2 --> sd0 --> sd1 --> sd2 --> sd3
|
||||||
|
sd3 --> sq0 --> sq1 --> sq2
|
||||||
|
sq2 --> sr0 --> sr1 --> sr2
|
||||||
|
sr2 --> sp3
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 交接点一览
|
||||||
|
|
||||||
|
| # | 从 → 到 | 交出什么 | 需求状态落点 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 1 | 产品 → 开发 | 需求编号 +【交付】编号;交付负责人=何斐 | **待开发** |
|
||||||
|
| 2 | 开发 → 测试 | 【测试】任务(子项挂交付);用例计划可先备好 | **待测试** |
|
||||||
|
| 3 | 测试 → 发版 | 本需求用例全绿;范围内需求清单 | **测试完成** |
|
||||||
|
| 4 | 发版 → 产品 | 发布完成证据 / 更新说明 | **发布完成** → 产品关单 **已关闭** |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 各泳道职责边界(一句话)
|
||||||
|
|
||||||
|
| 角色 | 管什么 | 不管什么 |
|
||||||
|
|---|---|---|
|
||||||
|
| **产品** | 建需求、【交付】【分析】【设计】、AutoPRD、交棒待开发、验收关闭 | 不建【开发】【测试】【发版】、不开分支 |
|
||||||
|
| **开发** | 拆【开发】、写码、AI 自测门禁、建【测试】提测 | 不改写产品 AutoRDO;不建第二套【交付】 |
|
||||||
|
| **测试** | 接【测试】、跑计划用例、缺陷回流、判测试完成 | 不擅自改需求状态到开发中;不建【发版】(可催) |
|
||||||
|
| **发版** | 建【发版】、挂迭代与范围、发布与回写成败 | 不替代测试判绿;不关闭需求(交给产品) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 云效工作项树(跨角色)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TB
|
||||||
|
REQ["需求 · 状态=阶段真相"]
|
||||||
|
DEL["【交付】ASSOCIATED→需求"]
|
||||||
|
AN["【分析】"]
|
||||||
|
DE["【设计】"]
|
||||||
|
DV["【开发】"]
|
||||||
|
TE["【测试】"]
|
||||||
|
RE["【发版】ASSOCIATED→迭代/需求"]
|
||||||
|
|
||||||
|
DEL --> REQ
|
||||||
|
AN -->|TASK_SUB| DEL
|
||||||
|
DE -->|TASK_SUB| DEL
|
||||||
|
DV -->|TASK_SUB| DEL
|
||||||
|
TE -->|TASK_SUB| DEL
|
||||||
|
DV -.->|ASSOCIATED| REQ
|
||||||
|
TE -.->|ASSOCIATED| REQ
|
||||||
|
RE -.->|关联范围| REQ
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 典型负责人(手册约定,可按项目改)
|
||||||
|
|
||||||
|
| 泳道 | 典型对接人 |
|
||||||
|
|---|---|
|
||||||
|
| 产品 | 王冕 · YunxiaoPMapp / AI |
|
||||||
|
| 开发 | 何斐(拆任务)→ 王雨昊 / 李振等(执行) |
|
||||||
|
| 测试 | 谢佳伟 |
|
||||||
|
| 发版 | 时生亮 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 相关文档
|
||||||
|
|
||||||
|
| 文档 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| `docs-全流程分步说明.md` | **整条链路逐步说明(推荐先读)** |
|
||||||
|
| `docs-产品部流转流程图.md` | 产品 0→5 细图 |
|
||||||
|
| `docs-开发侧流转草案.md` | 开发 D1–D5 细图 |
|
||||||
|
| `yunxiao-pipeline-handbook` | 全链路配置与规则 |
|
||||||
230
.claude/skills/YunxiaoPM/docs-开发侧流转草案.md
Normal file
230
.claude/skills/YunxiaoPM/docs-开发侧流转草案.md
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
# 开发侧流转草案(产品交棒之后)
|
||||||
|
|
||||||
|
> 来源:产品经理口述规则整理(2026-07-24)
|
||||||
|
> 上游终点:产品部 `docs-产品部流转流程图.md` → 需求=**待开发**,【交付】负责人=**何斐**
|
||||||
|
> 本文件目标:把「何斐拆任务 → 开发执行 → AI 用例门禁 → 提测」画清,供后续 **YunxiaoDevapp** Skill 定稿
|
||||||
|
> 状态:**草案**(文末有待拍板项)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 总览流程图
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TB
|
||||||
|
subgraph handoff [产品已交棒]
|
||||||
|
Ready["需求=待开发\n【交付】负责人=何斐"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph d1 [D1 分配开发]
|
||||||
|
Assign["何斐:分配任务 + 交付任务编号"]
|
||||||
|
CreateDev["自动建【开发】+需求标题\n描述人工补\n指定开发人\n写计划时间"]
|
||||||
|
Link["子项 TASK_SUB→交付\n关联项 ASSOCIATED→需求"]
|
||||||
|
StReady["需求保持/确认为 待开发"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph d2 [D2 开始开发]
|
||||||
|
Start["开发人:开始开发 + 开发任务编号"]
|
||||||
|
DevDoing["开发任务→处理中"]
|
||||||
|
ReqDoing["需求→开发中"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph d3 [D3 AI 用例门禁]
|
||||||
|
CodeDone["代码开发完成触发"]
|
||||||
|
FindPlan["按需求同标题找测试计划"]
|
||||||
|
AITest["AI 按用例自测"]
|
||||||
|
Fail["未通过→自动提缺陷\n标题含开发任务编号\nAI 写标题描述"]
|
||||||
|
Fix["自动修复→再测"]
|
||||||
|
PassGate["用例全部通过"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph d4 [D4 开发任务完成]
|
||||||
|
DevDone["该条【开发】→已完成"]
|
||||||
|
ReqDevDone["需求→开发完成"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph d5 [D5 完成开发·提测]
|
||||||
|
Finish["开发人:完成开发\n含自测完成"]
|
||||||
|
CreateTest["自动建【测试】+任务名\n子项→交付"]
|
||||||
|
PendingTest["需求→待测试"]
|
||||||
|
end
|
||||||
|
|
||||||
|
Ready --> Assign --> CreateDev --> Link --> StReady
|
||||||
|
StReady --> Start --> DevDoing --> ReqDoing
|
||||||
|
ReqDoing --> CodeDone --> FindPlan --> AITest
|
||||||
|
AITest -->|未通过| Fail --> Fix --> AITest
|
||||||
|
AITest -->|全通过| PassGate --> DevDone --> ReqDevDone
|
||||||
|
ReqDevDone --> Finish --> CreateTest --> PendingTest
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 分步说明(按你的 5 条)
|
||||||
|
|
||||||
|
### D1|何斐分配任务
|
||||||
|
|
||||||
|
| 项 | 规则 |
|
||||||
|
|---|---|
|
||||||
|
| 触发 | Skill 口令:`分配任务` + **交付任务编号** |
|
||||||
|
| 新建 | 【开发】任务;标题 = `【开发】` + **需求标题** |
|
||||||
|
| 描述 | **人工添加**(Skill 不代写正文,或只留空模板) |
|
||||||
|
| 负责人 | 口令指定开发人员 |
|
||||||
|
| 计划时间 | **自动创建**计划开始/计划完成(算法待定:阶段日历工时 or 人力预估,见待拍板) |
|
||||||
|
| 关联 | **子项** `TASK_SUB` →【交付】;**关联项** `ASSOCIATED` → 需求 |
|
||||||
|
| 需求状态 | 改为 / 确认为 **待开发**(见待拍板:与产品交棒是否重复) |
|
||||||
|
|
||||||
|
### D2|开始开发
|
||||||
|
|
||||||
|
| 项 | 规则 |
|
||||||
|
|---|---|
|
||||||
|
| 触发 | `开始开发` + **开发任务编号** |
|
||||||
|
| 开发任务 | → **处理中** |
|
||||||
|
| 需求 | → **开发中**(有 ≥1 条开发进入处理中即可,或本条触发即改,见待拍板) |
|
||||||
|
|
||||||
|
### D3|代码完成后 · AI 按测试计划自测
|
||||||
|
|
||||||
|
| 项 | 规则 |
|
||||||
|
|---|---|
|
||||||
|
| 触发 | 「代码开发完成」(MR 合并 / 口令 / Webhook,触发源待定) |
|
||||||
|
| 找计划 | **自动寻找与需求同标题的测试计划** |
|
||||||
|
| 执行 | AI 按该计划中用例自行测试 |
|
||||||
|
| 失败 | 自动提缺陷:标题含 **开发任务编号** + AI 生成标题/描述;再自动修复,循环直到用例全过 |
|
||||||
|
|
||||||
|
### D4|用例全通过
|
||||||
|
|
||||||
|
| 项 | 规则 |
|
||||||
|
|---|---|
|
||||||
|
| 该条【开发】 | → **已完成** |
|
||||||
|
| 需求 | → **开发完成** |
|
||||||
|
|
||||||
|
### D5|开发人「完成开发」(自测也完成)
|
||||||
|
|
||||||
|
| 项 | 规则 |
|
||||||
|
|---|---|
|
||||||
|
| 触发 | `完成开发` +(建议带)开发任务编号 |
|
||||||
|
| 新建 | 【测试】任务;标题 = `【测试】` + 任务名称(建议=需求标题) |
|
||||||
|
| 关联 | 子项 →【交付】(建议同时 ASSOCIATED→需求) |
|
||||||
|
| 需求 | → **待测试** |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 与产品部的衔接
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
PM["产品 YunxiaoPMapp\n待开发 + 交付→何斐"] --> DevSkill["开发 Skill 草案\n本文 D1–D5"]
|
||||||
|
DevSkill --> QA["测试执行人/Skill\n待测试之后"]
|
||||||
|
```
|
||||||
|
|
||||||
|
| 上游已具备 | 开发侧依赖 |
|
||||||
|
|---|---|
|
||||||
|
| 需求编号 +【交付】编号 | D1 入口只认编号,不按标题拆第二套交付 |
|
||||||
|
| 交付 ASSOCIATED→需求 | D1 开发任务再 ASSOCIATED→需求、SUB→交付 |
|
||||||
|
| 产品不建【开发】【测试】 | 仅开发 Skill 建这两类 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 待拍板(建议你先定这几条)
|
||||||
|
|
||||||
|
### 4.1 状态顺序是否自洽
|
||||||
|
|
||||||
|
你现在的顺序是:
|
||||||
|
|
||||||
|
```text
|
||||||
|
D3 AI 用例全过 → 开发任务已完成 + 需求「开发完成」
|
||||||
|
D5 完成开发 → 建【测试】+ 需求「待测试」
|
||||||
|
```
|
||||||
|
|
||||||
|
与现有手册常见顺序对比:
|
||||||
|
|
||||||
|
```text
|
||||||
|
手册常见:开发人完成自测 → 待测试 →(测试执行)→ 测试完成
|
||||||
|
你草案: AI 先跑测试计划用例过关 → 开发完成 → 人再点完成开发 → 待测试
|
||||||
|
```
|
||||||
|
|
||||||
|
需要确认:
|
||||||
|
1. D3 的「测试计划」是 **开发自测门禁**,正式【测试】任务仍留给谢佳伟?
|
||||||
|
2. 还是 D3 已等同正式测试,那 D5 再建【测试】是否重复?
|
||||||
|
|
||||||
|
### 4.2 「需求→待开发」写在 D1
|
||||||
|
|
||||||
|
产品交棒时需求**已经是待开发**。D1 再改一次通常多余。建议改为:
|
||||||
|
- D1 **校验**需求已是待开发;若不是则停下或只允许从设计完成快轨补交棒
|
||||||
|
- 有开发任务进入处理中时,需求才变为 **开发中**(即你的 D2)
|
||||||
|
|
||||||
|
### 4.3 「与需求同标题的测试计划」
|
||||||
|
|
||||||
|
标题易改、易撞名。更稳的是:
|
||||||
|
- 测试计划关联 **需求编号 / 迭代**,或
|
||||||
|
- 用例包命名 `CP-{需求编号}-…`
|
||||||
|
|
||||||
|
否则同名需求/改标题会导致找错计划。
|
||||||
|
|
||||||
|
### 4.4 AI 自动提缺陷并自动修复
|
||||||
|
|
||||||
|
风险高:无上限循环、误报、改回旧逻辑。建议门禁:
|
||||||
|
- 最多 N 轮;失败转人工
|
||||||
|
- 缺陷必须关联 **开发任务编号 + 需求编号 + 用例 ID**
|
||||||
|
- 与「防回归」清单联动,禁止静默改无关模块
|
||||||
|
|
||||||
|
### 4.5 多条【开发】时需求状态
|
||||||
|
|
||||||
|
| 场景 | 建议 |
|
||||||
|
|---|---|
|
||||||
|
| 任一条开始开发 | 需求 → 开发中 |
|
||||||
|
| 需求 → 开发完成 | **全部**未取消【开发】均为已完成(与手册 Y21 一致) |
|
||||||
|
| 需求 → 待测试 | 全部【开发】完成后,由末位「完成开发」或系统自动建【测试】 |
|
||||||
|
|
||||||
|
你原文 D4 写「该条」通过就把需求改成开发完成——多开发人并行时会过早。建议改成「全员开发任务完成」。
|
||||||
|
|
||||||
|
### 4.6 关联写法(与产品侧一致)
|
||||||
|
|
||||||
|
同一 create 只能带一条 `createWorkitemRelationInfo`:
|
||||||
|
- 优先保证【开发】/【测试】**子项挂在交付**(交付详情「子项」可见)
|
||||||
|
- ASSOCIATED→需求若同 create 互斥,需约定:先 SUB,再补 ASSOCIATED,或 OpenAPI 双挂
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 建议口令面(草案)
|
||||||
|
|
||||||
|
```text
|
||||||
|
分配任务:交付任务=ONEOS-a;开发人=张三,李四;计划开始=…;计划完成=…
|
||||||
|
开始开发:开发任务=ONEOS-d
|
||||||
|
代码完成:开发任务=ONEOS-d → 触发 AI 用例门禁(或 Webhook)
|
||||||
|
完成开发:开发任务=ONEOS-d → 建【测试】;需求→待测试
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 推荐定稿后的状态主链(供你勾选)
|
||||||
|
|
||||||
|
**方案 A(贴近你原文,AI 测作开发门禁)**
|
||||||
|
|
||||||
|
```text
|
||||||
|
待开发 → 开发中 →(AI 用例门禁)→ 开发完成 → 待测试 → 测试中 → 测试完成 → …
|
||||||
|
```
|
||||||
|
|
||||||
|
**方案 B(贴近现有生产线手册)**
|
||||||
|
|
||||||
|
```text
|
||||||
|
待开发 → 开发中 → 开发完成(人自测+MR)→ 待测试 → 测试中(人/AI 跑计划)→ 测试完成 → …
|
||||||
|
```
|
||||||
|
|
||||||
|
AI 跑测试计划放在 **待测试之后**,与【测试】任务负责人(如谢佳伟)对齐。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 下一步
|
||||||
|
|
||||||
|
1. 你拍板:**方案 A 或 B**,以及多【开发】时「开发完成 / 待测试」的聚合规则
|
||||||
|
2. 我按定稿输出 `YunxiaoDevapp` 的 `SKILL.md` 骨架 + 与产品交棒契约对齐段落
|
||||||
|
3. 再补一版「仅开发侧」验收清单(10 条以内)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 相关文档
|
||||||
|
|
||||||
|
| 文档 | 路径 |
|
||||||
|
|---|---|
|
||||||
|
| 产品部流转 | `docs-产品部流转流程图.md` |
|
||||||
|
| 产品↔开发契约 | `docs-YunxiaoPMapp-实现原理-开发Skill对接.md` |
|
||||||
|
| 全链路手册 | `src/prototypes/yunxiao-pipeline-handbook/` |
|
||||||
47
.claude/skills/YunxiaoPM/fast-track.md
Normal file
47
.claude/skills/YunxiaoPM/fast-track.md
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# 无单快轨到待开发
|
||||||
|
|
||||||
|
适用:口令明确「快轨」或「推进至待开发」且当前需求尚无标准分析路径任务(或用户确认跳过分析)。
|
||||||
|
|
||||||
|
## 动作表
|
||||||
|
|
||||||
|
| 对象 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| 需求 | 状态 → **待开发**;**预计工时=2**、**实际工时=2**(覆盖同日 8h 日历工时默认);标签按口令;更新编号区块 |
|
||||||
|
| 【交付】 | 无则新建;ASSOCIATED→需求(勿用 PARENT);负责人→何斐;**计划开始=创建当日**(`79`);**不写**计划完成;**描述双路径**(见下);**标签与需求相同**;更新编号区块 |
|
||||||
|
| 【设计】 | **必须新建**;**TASK_SUB→交付**(交付「子项」须可见);**描述=复制需求当前描述正文**;计划开始/完成均=当日(create 后 `field/value` 写 `79`+`80`);任务→完成态;**标签与需求相同**;建后再尝试 **ASSOCIATED→原始需求**(Cookie 常失败,见 live-api;失败须标红,**子项优先于关联项**);更新编号区块 |
|
||||||
|
| 【分析】 | **禁止创建** |
|
||||||
|
|
||||||
|
## 交付描述双路径(A1)
|
||||||
|
|
||||||
|
| 口令/材料 | 【交付】描述 |
|
||||||
|
|---|---|
|
||||||
|
| **手工描述**(无指定原型) | 同步需求当前手工/AutoRDO 正文(与设计一致可复制 document) |
|
||||||
|
| **指定原型页面** | 调用 `$oneos-autoprd`,从原型生成 AutoPRD「产品说明」写入【交付】 |
|
||||||
|
| 既无手工可同步正文、又无原型 | 才允许占位 `等待设计任务完成后自动填入`,Plan 勾选交棒占位风险,回报首行标红 |
|
||||||
|
|
||||||
|
有手工或原型时**禁止**交棒占位。
|
||||||
|
|
||||||
|
## AutoPRD
|
||||||
|
|
||||||
|
- 快轨默认可不跑 AutoPRD;**例外**:口令指定原型 → 交付走 AutoPRD 路径(上表)。
|
||||||
|
- 口令同时「设计完成 + 原型」时仍按步骤 4 灌需求产品说明段。
|
||||||
|
|
||||||
|
## 查重
|
||||||
|
|
||||||
|
只认任务编号。已有分析单不得因「快轨」被删除。
|
||||||
|
|
||||||
|
## 回报必含
|
||||||
|
|
||||||
|
- 需求 / 交付 / 设计编号
|
||||||
|
- 「快轨:未建分析;设计已同步需求描述并当日收口」
|
||||||
|
- 交付描述来源:手工同步 / AutoPRD / 占位(若占位则首行标红)
|
||||||
|
- 需求预计工时=2、实际工时=2
|
||||||
|
- 设计关联项含需求编号;交付子项含设计编号
|
||||||
|
|
||||||
|
## 与标准 / 编号直推对比
|
||||||
|
|
||||||
|
```text
|
||||||
|
标准:分析中→交付+分析 → 设计中→设计+收口分析 → 设计完成→收口设计 → 待开发交棒
|
||||||
|
快轨(无既有阶段单):→ 待开发:新建交付+设计+交棒何斐(无分析;设计当日收口;需求工时 2+2)
|
||||||
|
编号直推:已有分析/设计编号 → 收口空计划完成 → 待开发+交付交棒(不新建冗余单)
|
||||||
|
```
|
||||||
242
.claude/skills/YunxiaoPM/live-api.md
Normal file
242
.claude/skills/YunxiaoPM/live-api.md
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
# 云效实写 API(YunxiaoPMapp 已验证)
|
||||||
|
|
||||||
|
`verified_at`: 2026-07-25 · **项目须门禁 PJ 点选**(见 [project-selection.md](project-selection.md));历史验证样本项目为 `01_ONEOS` / 原「统一运营管理平台」(`last_selected.spaceIdentifier` 见 `assets/runtime-ids.json`,禁止未点选即使用)。
|
||||||
|
|
||||||
|
本文件只记**已跑通**的写法;禁止再盲试 `updateStatus` / 错误 `updateFieldValue` POST。
|
||||||
|
|
||||||
|
## 认证
|
||||||
|
|
||||||
|
- Cookie:Chrome 域 `.aliyun.com` / `devops.aliyun.com`(`browser_cookie3` 或 Playwright storage)
|
||||||
|
- Header:`x-xsrf-token` = cookie `XSRF-TOKEN`(URL 解码后)
|
||||||
|
- `Origin` / `Referer`:`https://devops.aliyun.com`
|
||||||
|
|
||||||
|
## 建单
|
||||||
|
|
||||||
|
`POST|PUT /projex/api/workitem/workitem?_input_charset=utf-8`
|
||||||
|
|
||||||
|
创建响应 `result.identifier` / `serialNumber` 即编号真相;**禁止按标题查重**。
|
||||||
|
|
||||||
|
## 改负责人(已通)
|
||||||
|
|
||||||
|
```http
|
||||||
|
PATCH /projex/api/workitem/workitem/{id}?_input_charset=utf-8
|
||||||
|
{"propertyKey":"assignedTo","propertyValue":"<userId>","operateType":"COVER"}
|
||||||
|
```
|
||||||
|
|
||||||
|
交棒:【交付】`propertyValue` = 何斐 ID。
|
||||||
|
|
||||||
|
## 打标签(已通)
|
||||||
|
|
||||||
|
```http
|
||||||
|
PATCH /projex/api/workitem/workitem/{id}?_input_charset=utf-8
|
||||||
|
{"workitemIdentifier":"{id}","propertyKey":"tag","propertyValue":"<tagId>[,<tagId>]","operateType":"COVER"}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 改状态(已通 · 唯一推荐)
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /projex/api/workitem/workitem/{id}/status/transit?_input_charset=utf-8
|
||||||
|
{"fromStatus":"<当前status.identifier>","toStatus":"<目标status.identifier>"}
|
||||||
|
```
|
||||||
|
|
||||||
|
成功:`code=200` 且 `result=true`。失败时 `errorMsg` 含「不能流转」。
|
||||||
|
|
||||||
|
### 需求状态 ID(本项目)
|
||||||
|
|
||||||
|
| 显示名 | identifier |
|
||||||
|
|---|---|
|
||||||
|
| 待处理 | `100005` |
|
||||||
|
| 已确认 | `32` |
|
||||||
|
| 分析中 | `154395` |
|
||||||
|
| 设计中 | `156603` |
|
||||||
|
| 设计完成 | `307012` |
|
||||||
|
| 待开发 | `1582fc929d429111b925309493` |
|
||||||
|
|
||||||
|
### 任务状态 ID
|
||||||
|
|
||||||
|
| 显示名 | identifier |
|
||||||
|
|---|---|
|
||||||
|
| 待处理 | `100005` |
|
||||||
|
| 已完成 | `100014` |
|
||||||
|
|
||||||
|
### 极速交棒跳转(工作流允许)
|
||||||
|
|
||||||
|
从「待处理」菜单可见直达「设计完成」;推荐最少跳:
|
||||||
|
|
||||||
|
```text
|
||||||
|
待处理 → 设计完成 → 待开发
|
||||||
|
```
|
||||||
|
|
||||||
|
标准路径若需看板留痕,可走完整链:已确认→分析中→设计中→设计完成→待开发(仍用本 API,勿开 UI)。
|
||||||
|
|
||||||
|
### 禁止(已证伪)
|
||||||
|
|
||||||
|
| 写法 | 结果 |
|
||||||
|
|---|---|
|
||||||
|
| `PATCH …/updateStatus` + `statusIdentifier` | `400 不能为空` |
|
||||||
|
| `PATCH …/{id}` + `propertyKey=status` | `property not found` |
|
||||||
|
| Playwright 点左侧/列表上的状态色块(`x<1100`) | 假成功、状态不落库 |
|
||||||
|
|
||||||
|
仅当 `status/transit` 不可用时,才用 UI:右侧详情状态钮(`getBoundingClientRect().x > 1100`)+ `.next-menu-item`。
|
||||||
|
|
||||||
|
## 计划开始/完成 · 提交部门/人 · 预计工时(2026-07-27 修订)
|
||||||
|
|
||||||
|
**通用字段写入(已通):**
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /projex/api/workitem/workitem/field/value/{workitemId}?_input_charset=utf-8
|
||||||
|
Content-Type: application/x-www-form-urlencoded
|
||||||
|
|
||||||
|
fieldValueList=[{"fieldIdentifier":"79","value":"2026-07-27 12:00:00"},{"fieldIdentifier":"3132597a9718d1c282b7ba5a0c","value":"业务管理部"},{"fieldIdentifier":"9e01269e96f91fbb97d36bf5b3","value":"何苗苗"}]
|
||||||
|
```
|
||||||
|
|
||||||
|
| 字段 | fieldIdentifier | value |
|
||||||
|
|---|---|---|
|
||||||
|
| 计划开始 | `79` | `YYYY-MM-DD HH:mm:ss`(推荐正午)或 epoch ms 字符串 |
|
||||||
|
| 计划完成 | `80` | 同上 |
|
||||||
|
| 提交部门 | `3132597a9718d1c282b7ba5a0c` | 纯文本 |
|
||||||
|
| 提交人 | `9e01269e96f91fbb97d36bf5b3` | 纯文本 |
|
||||||
|
|
||||||
|
**预计工时 `101586`:禁止直接改字段**(报「不可直接修改」)。须登记:
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /projex/api/workitem/workitem/time/estimate?_input_charset=utf-8
|
||||||
|
{"workitemIdentifier":"<id>","spentTime":8,"type":"develop","description":"阶段日历工时","recordUserIdentifier":"<userId>","forCreate":false,"containsRestDay":false}
|
||||||
|
```
|
||||||
|
|
||||||
|
删除多余预估:`DELETE /projex/api/workitem/workitem/time/estimate/{workitemId}/{estimateId}`
|
||||||
|
列表:`GET …/time/estimate/list?workitemIdentifier=`
|
||||||
|
|
||||||
|
旧写法 `PATCH …/updateWorkitemFieldValue` 对上述自定义字段常 `400 不能为空`,勿再优先使用。
|
||||||
|
|
||||||
|
## 父子 / 子项 / 关联项(已通 · 2026-07-23 修订 · 子项优先)
|
||||||
|
|
||||||
|
### 关联项(【交付】强制 · ASSOCIATED)
|
||||||
|
|
||||||
|
任务详情「关联项」只认 `ASSOCIATED`。**仅【交付】**建单时 `createWorkitemRelationInfo` 必须指向**需求**:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"createWorkitemRelationInfo": {
|
||||||
|
"relatedWorkitemIdentifier": "<需求id>",
|
||||||
|
"relatedToRelationIdentifier": "ASSOCIATED"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
校验:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /projex/api/workitem/v2/workitem/{交付id}/relation/workitem/list/by-relation-category?category=ASSOCIATED&isForward=true
|
||||||
|
```
|
||||||
|
|
||||||
|
`result` 含该需求即通过。
|
||||||
|
|
||||||
|
### 禁止(关联项)
|
||||||
|
|
||||||
|
| 写法 | 结果 |
|
||||||
|
|---|---|
|
||||||
|
| `relatedToRelationIdentifier=PARENT` 把交付挂需求 | 详情可能有 parent,**关联项仍为空** |
|
||||||
|
| 分析/设计只用 `ASSOCIATED→需求` + `parentIdentifier` | 关联项可能有,**交付子项仍为空**(ONEOS-246/247) |
|
||||||
|
| 建后再 `POST …/relation/record` 补关系 | Cookie 路径下常报「不能关联相同的工作项」 |
|
||||||
|
| `createWorkitemRelationList` | 不落 ASSOCIATED |
|
||||||
|
|
||||||
|
### 子项(【分析】/【设计】强制 · TASK_SUB)
|
||||||
|
|
||||||
|
「子项」页读 `PARENT_SUB` / `TASK_SUB`,分析/设计**必须**:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"parent": "<交付id>",
|
||||||
|
"parentIdentifier": "<交付id>",
|
||||||
|
"createWorkitemRelationInfo": {
|
||||||
|
"relatedWorkitemIdentifier": "<交付id>",
|
||||||
|
"relatedToRelationIdentifier": "TASK_SUB"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
同一 create 只能带一条 `createWorkitemRelationInfo`。
|
||||||
|
`ASSOCIATED→需求` 与 `TASK_SUB→交付` **不能同时写**。
|
||||||
|
|
||||||
|
**产品优先级:交付「子项」tab > 阶段任务「关联项」。**
|
||||||
|
交付本身仍必须 `ASSOCIATED→需求`。标准路径下分析/设计的「关联项」允许为空。
|
||||||
|
|
||||||
|
**无单快轨例外(设计双挂):** create 用 `TASK_SUB→交付` 后,须再补 **ASSOCIATED→原始需求**,使设计详情「关联项」可见需求。
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /projex/api/workitem/workitem/{设计id}/relation/record?_input_charset=utf-8
|
||||||
|
{"relationIdentifier":"ASSOCIATED","toWorkitemIdentifier":"<需求id>"}
|
||||||
|
```
|
||||||
|
|
||||||
|
**已证伪(Cookie · 2026-07-27):** 凡工作项**已创建**后再 `relation/record` 补挂(含 ASSOCIATED / TASK_SUB),常报「不能关联相同的工作项」;与是否已有父项无关。`createWorkitemRelationList` 亦不落 ASSOCIATED。
|
||||||
|
**可行路径:**
|
||||||
|
|
||||||
|
| 目标 | 做法 |
|
||||||
|
|---|---|
|
||||||
|
| 交付「子项」可见设计(优先) | create 带 `TASK_SUB→交付` |
|
||||||
|
| 设计「关联项」可见需求 | create 带 `ASSOCIATED→需求`(与上互斥,同 create 只能一条) |
|
||||||
|
| 双挂 | 需个人 `x-yunxiao-token` OpenAPI;Cookie 路径**不得**声称成功 |
|
||||||
|
|
||||||
|
产品默认:**子项优先**;关联项失败须在回报中标红并列出缺项。
|
||||||
|
|
||||||
|
校验子项:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /projex/api/workitem/v2/workitem/{交付id}/relation/workitem/list/by-relation-category?category=PARENT_SUB&isForward=true
|
||||||
|
```
|
||||||
|
|
||||||
|
结果须含对应分析/设计 identifier。
|
||||||
|
|
||||||
|
校验设计关联项:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /projex/api/workitem/v2/workitem/{设计id}/relation/workitem/list/by-relation-category?category=ASSOCIATED&isForward=true
|
||||||
|
```
|
||||||
|
|
||||||
|
`result` 须含原始需求 identifier。
|
||||||
|
|
||||||
|
### 无单快轨字段默认(2026-07-27)
|
||||||
|
|
||||||
|
| 对象 | 规则 |
|
||||||
|
|---|---|
|
||||||
|
| 【设计】描述 | 复制需求 document HTML |
|
||||||
|
| 【设计】`79`/`80` | 当日 `12:00:00` / `23:59:59`,create 后 `field/value`(勿 create 同时带 79+80) |
|
||||||
|
| 【交付】描述 | 手工同步需求正文,或原型→AutoPRD;禁止无故占位 |
|
||||||
|
| 【交付】`79` | 创建当日;不写 `80` |
|
||||||
|
| 【交付】/【设计】标签 | 与需求相同,`PATCH propertyKey=tag` |
|
||||||
|
| 需求预计工时 | `time/estimate` **spentTime=2**(先删多余预估) |
|
||||||
|
| 需求实际工时 | `POST …/workitem/time`,body 用 **`actualTime`**(非 spentTime)+ `gmtStart`/`gmtEnd` epoch ms 字符串;见 `runtime-ids.json` `fields.actual_hours` |
|
||||||
|
| 描述更新 | `PATCH …/workitem/{id}/document`,`{"content":"<html>","formatType":"RICHTEXT"}` |
|
||||||
|
|
||||||
|
## 迭代挂接(已通 · 2026-07-27 · 只挂交付)
|
||||||
|
|
||||||
|
创建迭代:`POST /projex/api/workspace/sprint`(必填 `staffIds`;可写 `capacityHours`)。
|
||||||
|
|
||||||
|
挂【交付】到迭代:
|
||||||
|
|
||||||
|
```http
|
||||||
|
PATCH /projex/api/workitem/workitem/{交付id}?_input_charset=utf-8
|
||||||
|
{"workitemIdentifier":"{交付id}","propertyKey":"sprint","propertyValue":"{sprintId}","operateType":"COVER"}
|
||||||
|
```
|
||||||
|
|
||||||
|
清空误挂(如需求):`propertyValue:""` + `operateType:"COVER"`。
|
||||||
|
|
||||||
|
**校验**必须读 `/extra`(详情主接口常不含 sprint 字段,禁止据此判失败):
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /projex/api/workitem/workitem/{id}/extra?_input_charset=utf-8
|
||||||
|
→ result.sprint[].identifier / name
|
||||||
|
```
|
||||||
|
|
||||||
|
产品规则:**只挂【交付】**;需求 / 分析 / 设计默认不挂(除非口令显式)。
|
||||||
|
|
||||||
|
### 极速建单注意
|
||||||
|
|
||||||
|
1. Cookie 只刷一次;全程纯 HTTP,默认**不开浏览器**。
|
||||||
|
2. 交付建完后,【分析】与【设计】**并行**创建(均 TASK_SUB→交付);标准/快轨两树可并行。
|
||||||
|
3. 状态用 `transit` + **本地追踪 fromStatus**(禁止每次 GET);负责人在交棒场景下**创建时即何斐**。
|
||||||
|
4. 建单 `fieldValueList` 可带计划开始 `79`;**不要**在 create 同时写 `79+80`(同日会 400)。
|
||||||
|
5. 标签必须 PATCH(create 带 tag 不落库);可与建子任务重叠;快轨交付/设计须与需求同标签。
|
||||||
|
6. `requests.Session` keep-alive;**禁止**对共享 opener 加全局锁。
|
||||||
|
7. 脚本入口:`scripts/live_create_fast.py`(v5:快轨描述/计划/标签/工时 2+2/设计 ASSOCIATED 补挂)。
|
||||||
660
.claude/skills/YunxiaoPM/live_create_fast.py
Normal file
660
.claude/skills/YunxiaoPM/live_create_fast.py
Normal file
@@ -0,0 +1,660 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""YunxiaoPM 极速真实建单 v5:快轨描述/计划/标签/工时 2+2/设计 ASSOCIATED 补挂。"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import urllib.parse
|
||||||
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||||
|
from datetime import datetime, timedelta, timezone
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
try:
|
||||||
|
import browser_cookie3
|
||||||
|
except ImportError: # pragma: no cover
|
||||||
|
browser_cookie3 = None
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
RUNTIME = json.loads((ROOT / "assets" / "runtime-ids.json").read_text())
|
||||||
|
STATUS = RUNTIME["status"]["req"]
|
||||||
|
TASK_STATUS = RUNTIME["status"]["task"]
|
||||||
|
FAST = RUNTIME.get("fields", {}).get("fast_track") or {}
|
||||||
|
|
||||||
|
SPACE = (
|
||||||
|
RUNTIME.get("project", {}).get("spaceIdentifier")
|
||||||
|
or (RUNTIME.get("project", {}).get("last_selected") or {}).get("spaceIdentifier")
|
||||||
|
)
|
||||||
|
if not SPACE:
|
||||||
|
raise RuntimeError(
|
||||||
|
"未选定项目 spaceIdentifier:须先走门禁 PJ 点选,或设置 runtime project.last_selected"
|
||||||
|
)
|
||||||
|
REQ_TYPE = RUNTIME["workitem_types"]["product_req"]["identifier"]
|
||||||
|
TASK_TYPE = RUNTIME["workitem_types"]["task"]["identifier"]
|
||||||
|
HEFEI = RUNTIME["people"]["hefei"]["identifier"]
|
||||||
|
WANG = RUNTIME["people"].get("wangmian", {}).get("identifier", "6811df000601d2fea60144a9")
|
||||||
|
PRI = RUNTIME["priority"]["中"]
|
||||||
|
TAG_FAULT = RUNTIME.get("tags", {}).get("故障管理", "ceb526a7343995577645317e9a")
|
||||||
|
PLACEHOLDER = RUNTIME["delivery_placeholder"]
|
||||||
|
PROTO = "https://prototype.lnoneos.com/vehicle-fault-handling/index.html"
|
||||||
|
TZ = timezone(timedelta(hours=8))
|
||||||
|
TODAY = datetime.now(TZ).strftime("%Y-%m-%d")
|
||||||
|
NOON = f"{TODAY} 12:00:00"
|
||||||
|
EOD = f"{TODAY} 23:59:59"
|
||||||
|
NOON_MS = str(
|
||||||
|
int(datetime.now(TZ).replace(hour=12, minute=0, second=0, microsecond=0).timestamp() * 1000)
|
||||||
|
)
|
||||||
|
START_MS = str(
|
||||||
|
int(datetime.now(TZ).replace(hour=9, minute=0, second=0, microsecond=0).timestamp() * 1000)
|
||||||
|
)
|
||||||
|
END_MS = str(
|
||||||
|
int(datetime.now(TZ).replace(hour=11, minute=0, second=0, microsecond=0).timestamp() * 1000)
|
||||||
|
)
|
||||||
|
FAST_EST = int(FAST.get("req_estimated_hours", 2))
|
||||||
|
FAST_ACT = int(FAST.get("req_actual_hours", 2))
|
||||||
|
|
||||||
|
PENDING = STATUS["待处理"]
|
||||||
|
DESIGN_DONE = STATUS["设计完成"]
|
||||||
|
PENDING_DEV = STATUS["待开发"]
|
||||||
|
TASK_DONE = TASK_STATUS["已完成"]
|
||||||
|
|
||||||
|
_COOKIE = ""
|
||||||
|
_XSRF = ""
|
||||||
|
|
||||||
|
|
||||||
|
def load_auth() -> None:
|
||||||
|
global _COOKIE, _XSRF
|
||||||
|
jar: dict[str, str] = {}
|
||||||
|
if browser_cookie3:
|
||||||
|
for domain in (".aliyun.com", "devops.aliyun.com", ".devops.aliyun.com"):
|
||||||
|
try:
|
||||||
|
for c in browser_cookie3.chrome(domain_name=domain):
|
||||||
|
jar[c.name] = c.value
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if not jar:
|
||||||
|
p = Path("/tmp/yunxiao_cookies.json")
|
||||||
|
if p.exists():
|
||||||
|
raw = json.loads(p.read_text())
|
||||||
|
jar = (
|
||||||
|
raw
|
||||||
|
if isinstance(raw, dict) and "XSRF-TOKEN" in raw
|
||||||
|
else {c["name"]: c["value"] for c in raw.get("cookies", [])}
|
||||||
|
)
|
||||||
|
_COOKIE = "; ".join(f"{k}={v}" for k, v in jar.items())
|
||||||
|
x = jar.get("XSRF-TOKEN", "")
|
||||||
|
_XSRF = urllib.parse.unquote(x) if "%" in x else x
|
||||||
|
if not _XSRF:
|
||||||
|
raise RuntimeError("缺少 XSRF-TOKEN:请先在 Chrome 登录 devops.aliyun.com")
|
||||||
|
|
||||||
|
|
||||||
|
def session() -> requests.Session:
|
||||||
|
s = requests.Session()
|
||||||
|
s.headers.update(
|
||||||
|
{
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Cookie": _COOKIE,
|
||||||
|
"x-xsrf-token": _XSRF,
|
||||||
|
"X-XSRF-TOKEN": _XSRF,
|
||||||
|
"Origin": "https://devops.aliyun.com",
|
||||||
|
"Referer": f"https://devops.aliyun.com/projex/project/{SPACE}/req",
|
||||||
|
"accept": "application/json",
|
||||||
|
"User-Agent": "YunxiaoPM-live_create_fast/5.0",
|
||||||
|
"Connection": "keep-alive",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def api(s: requests.Session, method: str, url: str, body: Any = None) -> dict:
|
||||||
|
r = s.request(method, url, json=body, timeout=60)
|
||||||
|
try:
|
||||||
|
return r.json()
|
||||||
|
except Exception:
|
||||||
|
r.raise_for_status()
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def create(s: requests.Session, payload: dict) -> dict:
|
||||||
|
url = "https://devops.aliyun.com/projex/api/workitem/workitem?_input_charset=utf-8"
|
||||||
|
j = api(s, "POST", url, payload)
|
||||||
|
r = j.get("result") or {}
|
||||||
|
if j.get("code") == 200 and isinstance(r, dict) and r.get("identifier"):
|
||||||
|
return r
|
||||||
|
j = api(s, "PUT", url, payload)
|
||||||
|
r = j.get("result") or {}
|
||||||
|
if j.get("code") == 200 and isinstance(r, dict) and r.get("identifier"):
|
||||||
|
return r
|
||||||
|
raise RuntimeError(f"create failed: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def get(s: requests.Session, wid: str) -> dict:
|
||||||
|
return api(
|
||||||
|
s,
|
||||||
|
"GET",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/{wid}?_input_charset=utf-8",
|
||||||
|
)["result"]
|
||||||
|
|
||||||
|
|
||||||
|
def apply_tag(s: requests.Session, wid: str, tag_id: str = TAG_FAULT) -> None:
|
||||||
|
j = api(
|
||||||
|
s,
|
||||||
|
"PATCH",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/{wid}?_input_charset=utf-8",
|
||||||
|
{
|
||||||
|
"workitemIdentifier": wid,
|
||||||
|
"propertyKey": "tag",
|
||||||
|
"propertyValue": tag_id,
|
||||||
|
"operateType": "COVER",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if j.get("code") != 200:
|
||||||
|
raise RuntimeError(f"tag failed {wid}: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def set_document(s: requests.Session, wid: str, html: str) -> None:
|
||||||
|
j = api(
|
||||||
|
s,
|
||||||
|
"PATCH",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/{wid}/document?_input_charset=utf-8",
|
||||||
|
{"content": html, "formatType": "RICHTEXT"},
|
||||||
|
)
|
||||||
|
if j.get("code") != 200 or j.get("errorMsg"):
|
||||||
|
raise RuntimeError(f"document failed {wid}: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def set_fields(s: requests.Session, wid: str, pairs: list[tuple[str, str]]) -> None:
|
||||||
|
data = urllib.parse.urlencode(
|
||||||
|
{
|
||||||
|
"fieldValueList": json.dumps(
|
||||||
|
[{"fieldIdentifier": k, "value": v} for k, v in pairs], ensure_ascii=False
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
r = s.post(
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/field/value/{wid}?_input_charset=utf-8",
|
||||||
|
data=data,
|
||||||
|
headers={"Content-Type": "application/x-www-form-urlencoded"},
|
||||||
|
timeout=60,
|
||||||
|
)
|
||||||
|
j = r.json()
|
||||||
|
if j.get("code") != 200:
|
||||||
|
raise RuntimeError(f"field/value failed {wid}: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def set_estimate_hours(s: requests.Session, wid: str, hours: int, user: str = WANG) -> None:
|
||||||
|
est = api(
|
||||||
|
s,
|
||||||
|
"GET",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/time/estimate/list?workitemIdentifier={wid}",
|
||||||
|
).get("result") or []
|
||||||
|
for row in est:
|
||||||
|
eid = row.get("identifier")
|
||||||
|
if eid:
|
||||||
|
api(
|
||||||
|
s,
|
||||||
|
"DELETE",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/time/estimate/{wid}/{eid}",
|
||||||
|
)
|
||||||
|
j = api(
|
||||||
|
s,
|
||||||
|
"POST",
|
||||||
|
"https://devops.aliyun.com/projex/api/workitem/workitem/time/estimate?_input_charset=utf-8",
|
||||||
|
{
|
||||||
|
"workitemIdentifier": wid,
|
||||||
|
"spentTime": hours,
|
||||||
|
"type": "develop",
|
||||||
|
"description": "快轨默认预计工时",
|
||||||
|
"recordUserIdentifier": user,
|
||||||
|
"forCreate": False,
|
||||||
|
"containsRestDay": False,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if j.get("code") != 200:
|
||||||
|
raise RuntimeError(f"estimate failed {wid}: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def set_actual_hours(s: requests.Session, wid: str, hours: int, user: str = WANG) -> None:
|
||||||
|
j = api(
|
||||||
|
s,
|
||||||
|
"POST",
|
||||||
|
"https://devops.aliyun.com/projex/api/workitem/workitem/time?_input_charset=utf-8",
|
||||||
|
{
|
||||||
|
"workitemIdentifier": wid,
|
||||||
|
"actualTime": hours,
|
||||||
|
"type": "develop",
|
||||||
|
"description": "快轨默认实际工时",
|
||||||
|
"recordUserIdentifier": user,
|
||||||
|
"gmtStart": START_MS,
|
||||||
|
"gmtEnd": END_MS,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if j.get("code") != 200 or not j.get("result"):
|
||||||
|
raise RuntimeError(f"actual time failed {wid}: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def try_associate_to_req(s: requests.Session, stage_id: str, req_id: str) -> bool:
|
||||||
|
"""建后补 ASSOCIATED→需求。Cookie 下常失败,成功返回 True。"""
|
||||||
|
bodies = [
|
||||||
|
{"relationIdentifier": "ASSOCIATED", "toWorkitemIdentifier": req_id},
|
||||||
|
{
|
||||||
|
"relationIdentifier": "ASSOCIATED",
|
||||||
|
"fromWorkitemIdentifier": stage_id,
|
||||||
|
"toWorkitemIdentifier": req_id,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
for body in bodies:
|
||||||
|
for url in (
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/{stage_id}/relation/record?_input_charset=utf-8",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/v2/workitem/{stage_id}/relation/record?_input_charset=utf-8",
|
||||||
|
):
|
||||||
|
j = api(s, "POST", url, body)
|
||||||
|
if j.get("code") == 200 and j.get("result") not in (None, False):
|
||||||
|
if not (isinstance(j.get("result"), dict) and j["result"].get("status") in (404, 405)):
|
||||||
|
rows = list_associated(s, stage_id)
|
||||||
|
if req_id in {r.get("identifier") for r in rows}:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def transit(s: requests.Session, wid: str, from_status: str, to_status: str) -> None:
|
||||||
|
if from_status == to_status:
|
||||||
|
return
|
||||||
|
j = api(
|
||||||
|
s,
|
||||||
|
"POST",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/{wid}/status/transit?_input_charset=utf-8",
|
||||||
|
{"fromStatus": from_status, "toStatus": to_status},
|
||||||
|
)
|
||||||
|
if not (j.get("code") == 200 and j.get("result") is True):
|
||||||
|
raise RuntimeError(f"transit {wid} {from_status}->{to_status}: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def md_to_html(md: str) -> str:
|
||||||
|
parts = []
|
||||||
|
for line in md.splitlines():
|
||||||
|
if line.startswith("## "):
|
||||||
|
parts.append(f"<h2>{line[3:]}</h2>")
|
||||||
|
elif line.startswith("### "):
|
||||||
|
parts.append(f"<h3>{line[4:]}</h3>")
|
||||||
|
elif line.startswith("- "):
|
||||||
|
parts.append(f"<p>• {line[2:]}</p>")
|
||||||
|
elif line.strip():
|
||||||
|
parts.append(f"<p>{line}</p>")
|
||||||
|
return "".join(parts)
|
||||||
|
|
||||||
|
|
||||||
|
def req_document_html(s: requests.Session, rid: str) -> str:
|
||||||
|
w = get(s, rid)
|
||||||
|
return ((w.get("document") or {}).get("content") or w.get("description") or "").strip()
|
||||||
|
|
||||||
|
|
||||||
|
def req_payload(subject: str, html: str) -> dict:
|
||||||
|
return {
|
||||||
|
"subject": subject,
|
||||||
|
"description": html,
|
||||||
|
"formatType": "RICHTEXT",
|
||||||
|
"document": {"content": html, "formatType": "RICHTEXT"},
|
||||||
|
"spaceIdentifier": SPACE,
|
||||||
|
"space": SPACE,
|
||||||
|
"spaceType": "Project",
|
||||||
|
"workitemTypeIdentifier": REQ_TYPE,
|
||||||
|
"workitemType": REQ_TYPE,
|
||||||
|
"categoryIdentifier": "Req",
|
||||||
|
"category": "Req",
|
||||||
|
"assignedTo": WANG,
|
||||||
|
"fieldValueList": [
|
||||||
|
{"fieldIdentifier": "priority", "value": PRI},
|
||||||
|
{"fieldIdentifier": "assignedTo", "value": WANG},
|
||||||
|
],
|
||||||
|
"attachmentIdList": [],
|
||||||
|
"cloneFrom": None,
|
||||||
|
"createWorkitemRelationList": [],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def task_payload(
|
||||||
|
subject: str,
|
||||||
|
html: str,
|
||||||
|
assignee: str,
|
||||||
|
*,
|
||||||
|
plan_start: bool = True,
|
||||||
|
associated_req: str | None = None,
|
||||||
|
parent_delivery: str | None = None,
|
||||||
|
) -> dict:
|
||||||
|
fvl = [
|
||||||
|
{"fieldIdentifier": "priority", "value": PRI},
|
||||||
|
{"fieldIdentifier": "assignedTo", "value": assignee},
|
||||||
|
]
|
||||||
|
if plan_start:
|
||||||
|
fvl.append({"fieldIdentifier": "79", "value": NOON_MS})
|
||||||
|
payload: dict[str, Any] = {
|
||||||
|
"subject": subject,
|
||||||
|
"description": html,
|
||||||
|
"formatType": "RICHTEXT",
|
||||||
|
"spaceIdentifier": SPACE,
|
||||||
|
"space": SPACE,
|
||||||
|
"spaceType": "Project",
|
||||||
|
"workitemTypeIdentifier": TASK_TYPE,
|
||||||
|
"workitemType": TASK_TYPE,
|
||||||
|
"categoryIdentifier": "Task",
|
||||||
|
"category": "Task",
|
||||||
|
"assignedTo": assignee,
|
||||||
|
"fieldValueList": fvl,
|
||||||
|
"attachmentIdList": [],
|
||||||
|
"cloneFrom": None,
|
||||||
|
}
|
||||||
|
if parent_delivery:
|
||||||
|
payload["parent"] = parent_delivery
|
||||||
|
payload["parentIdentifier"] = parent_delivery
|
||||||
|
payload["createWorkitemRelationInfo"] = {
|
||||||
|
"relatedWorkitemIdentifier": parent_delivery,
|
||||||
|
"relatedToRelationIdentifier": "TASK_SUB",
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
if not associated_req:
|
||||||
|
raise ValueError("associated_req required for delivery: ASSOCIATED→需求")
|
||||||
|
payload["createWorkitemRelationInfo"] = {
|
||||||
|
"relatedWorkitemIdentifier": associated_req,
|
||||||
|
"relatedToRelationIdentifier": "ASSOCIATED",
|
||||||
|
}
|
||||||
|
return payload
|
||||||
|
|
||||||
|
|
||||||
|
def list_associated(s: requests.Session, wid: str) -> list[dict]:
|
||||||
|
j = api(
|
||||||
|
s,
|
||||||
|
"GET",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/v2/workitem/{wid}/relation/workitem/list/by-relation-category?category=ASSOCIATED&isForward=true",
|
||||||
|
)
|
||||||
|
return j.get("result") or []
|
||||||
|
|
||||||
|
|
||||||
|
def assert_associated_to_req(s: requests.Session, wid: str, req_id: str, label: str) -> None:
|
||||||
|
rows = list_associated(s, wid)
|
||||||
|
ids = {r.get("identifier") for r in rows}
|
||||||
|
if req_id not in ids:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"{label} 关联项未挂需求:期望 {req_id},实际 {[r.get('serialNumber') for r in rows]}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
AUTO_RDO = """## 原始诉求(AutoRDO)
|
||||||
|
|
||||||
|
运维需在故障处置页承接机器人上报的故障,完成处置、挂起与归档,并保留证据链;工作台相关统计口径需与处置页一致
|
||||||
|
|
||||||
|
待确认:
|
||||||
|
- 本期是否含真实短信/邮件通道(现口径一般为演示模板)
|
||||||
|
|
||||||
|
## 工作项编号(系统)
|
||||||
|
- 交付:待建
|
||||||
|
- 分析:待建
|
||||||
|
- 设计:待建
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def summarize_from_create(w: dict, *, status: str, assignee_name: str) -> dict:
|
||||||
|
return {
|
||||||
|
"serial": w.get("serialNumber"),
|
||||||
|
"id": w.get("identifier"),
|
||||||
|
"subject": w.get("subject"),
|
||||||
|
"status": status,
|
||||||
|
"assignee": assignee_name,
|
||||||
|
"parent": w.get("parentIdentifier"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def build_normal() -> dict:
|
||||||
|
t0 = time.perf_counter()
|
||||||
|
s = session()
|
||||||
|
title = "【新增】故障处置(YunxiaoPMapp标准·极速v2)"
|
||||||
|
req = create(s, req_payload(title, md_to_html(AUTO_RDO + f"\n原型:{PROTO}\n")))
|
||||||
|
rid = req["identifier"]
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=2) as pool:
|
||||||
|
f_tag_r = pool.submit(apply_tag, session(), rid)
|
||||||
|
f_deliv = pool.submit(
|
||||||
|
create,
|
||||||
|
session(),
|
||||||
|
task_payload(
|
||||||
|
f"【交付】{title}",
|
||||||
|
f"<p>{PLACEHOLDER}</p>",
|
||||||
|
HEFEI,
|
||||||
|
associated_req=rid,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
deliv = f_deliv.result()
|
||||||
|
f_tag_r.result()
|
||||||
|
did = deliv["identifier"]
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=3) as pool:
|
||||||
|
f_tag_d = pool.submit(apply_tag, session(), did)
|
||||||
|
f_ana = pool.submit(
|
||||||
|
create,
|
||||||
|
session(),
|
||||||
|
task_payload(
|
||||||
|
f"【分析】{title}",
|
||||||
|
"<p>分析阶段:故障处置台账、挂起归档与证据链。</p>",
|
||||||
|
WANG,
|
||||||
|
associated_req=rid,
|
||||||
|
parent_delivery=did,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
f_des = pool.submit(
|
||||||
|
create,
|
||||||
|
session(),
|
||||||
|
task_payload(
|
||||||
|
f"【设计】{title}",
|
||||||
|
f"<p>设计阶段:对齐原型 {PROTO}</p>",
|
||||||
|
WANG,
|
||||||
|
associated_req=rid,
|
||||||
|
parent_delivery=did,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
ana = f_ana.result()
|
||||||
|
des = f_des.result()
|
||||||
|
f_tag_d.result()
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=3) as pool:
|
||||||
|
list(
|
||||||
|
as_completed(
|
||||||
|
[
|
||||||
|
pool.submit(transit, session(), rid, PENDING, DESIGN_DONE),
|
||||||
|
pool.submit(transit, session(), ana["identifier"], PENDING, TASK_DONE),
|
||||||
|
pool.submit(transit, session(), des["identifier"], PENDING, TASK_DONE),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
transit(s, rid, DESIGN_DONE, PENDING_DEV)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"path": "normal",
|
||||||
|
"elapsed_s": round(time.perf_counter() - t0, 3),
|
||||||
|
"req": summarize_from_create(req, status="待开发", assignee_name="王冕"),
|
||||||
|
"delivery": summarize_from_create(deliv, status="待处理", assignee_name="何斐"),
|
||||||
|
"analysis": summarize_from_create(ana, status="已完成", assignee_name="王冕"),
|
||||||
|
"design": summarize_from_create(des, status="已完成", assignee_name="王冕"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def build_fast(
|
||||||
|
*,
|
||||||
|
tag_id: str = TAG_FAULT,
|
||||||
|
has_prototype: bool = True,
|
||||||
|
delivery_html: str | None = None,
|
||||||
|
) -> dict:
|
||||||
|
"""无单快轨。
|
||||||
|
|
||||||
|
- 设计描述 = 需求 document
|
||||||
|
- 交付描述 = 手工同步需求正文(无原型)或传入 AutoPRD HTML;禁止无故占位
|
||||||
|
- 设计 79/80=当日;交付 79=当日
|
||||||
|
- 需求/交付/设计同标签
|
||||||
|
- 需求预计/实际工时各 2
|
||||||
|
- 设计 TASK_SUB→交付后尝试 ASSOCIATED→需求
|
||||||
|
"""
|
||||||
|
t0 = time.perf_counter()
|
||||||
|
s = session()
|
||||||
|
title = "【新增】故障处置(YunxiaoPM快轨·极速v5)"
|
||||||
|
req_html = md_to_html(AUTO_RDO + (f"\n原型:{PROTO}\n" if has_prototype else "\n"))
|
||||||
|
req = create(s, req_payload(title, req_html))
|
||||||
|
rid = req["identifier"]
|
||||||
|
# 以落库 document 为准(与手动建需后读需求一致)
|
||||||
|
req_html = req_document_html(s, rid) or req_html
|
||||||
|
|
||||||
|
if delivery_html:
|
||||||
|
deliv_html = delivery_html
|
||||||
|
desc_source = "autoprd"
|
||||||
|
elif req_html.strip():
|
||||||
|
deliv_html = req_html
|
||||||
|
desc_source = "manual_sync"
|
||||||
|
else:
|
||||||
|
deliv_html = f"<p>{PLACEHOLDER}</p>"
|
||||||
|
desc_source = "placeholder"
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=2) as pool:
|
||||||
|
f_tag_r = pool.submit(apply_tag, session(), rid, tag_id)
|
||||||
|
f_deliv = pool.submit(
|
||||||
|
create,
|
||||||
|
session(),
|
||||||
|
task_payload(
|
||||||
|
f"【交付】{title}",
|
||||||
|
deliv_html,
|
||||||
|
HEFEI,
|
||||||
|
associated_req=rid,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
deliv = f_deliv.result()
|
||||||
|
f_tag_r.result()
|
||||||
|
did = deliv["identifier"]
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=2) as pool:
|
||||||
|
f_tag_d = pool.submit(apply_tag, session(), did, tag_id)
|
||||||
|
f_des = pool.submit(
|
||||||
|
create,
|
||||||
|
session(),
|
||||||
|
task_payload(
|
||||||
|
f"【设计】{title}",
|
||||||
|
req_html,
|
||||||
|
WANG,
|
||||||
|
parent_delivery=did,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
des = f_des.result()
|
||||||
|
f_tag_d.result()
|
||||||
|
des_id = des["identifier"]
|
||||||
|
apply_tag(s, des_id, tag_id)
|
||||||
|
|
||||||
|
# 计划时间:设计起止当日;交付开始当日(create 已带 79,再 field/value 加固)
|
||||||
|
set_fields(s, des_id, [("79", NOON), ("80", EOD)])
|
||||||
|
set_fields(s, did, [("79", NOON)])
|
||||||
|
|
||||||
|
# 设计关联项补挂需求(可能失败,回报 risk)
|
||||||
|
design_assoc_ok = try_associate_to_req(s, des_id, rid)
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=2) as pool:
|
||||||
|
list(
|
||||||
|
as_completed(
|
||||||
|
[
|
||||||
|
pool.submit(transit, session(), rid, PENDING, DESIGN_DONE),
|
||||||
|
pool.submit(transit, session(), des_id, PENDING, TASK_DONE),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
transit(s, rid, DESIGN_DONE, PENDING_DEV)
|
||||||
|
|
||||||
|
set_estimate_hours(s, rid, FAST_EST)
|
||||||
|
set_actual_hours(s, rid, FAST_ACT)
|
||||||
|
|
||||||
|
risk = None
|
||||||
|
if desc_source == "placeholder":
|
||||||
|
risk = "交付描述仍为占位"
|
||||||
|
if not design_assoc_ok:
|
||||||
|
risk = (risk + ";" if risk else "") + "设计 ASSOCIATED→需求补挂失败(Cookie),须 UI/OpenAPI 兜底"
|
||||||
|
|
||||||
|
return {
|
||||||
|
"path": "fast",
|
||||||
|
"elapsed_s": round(time.perf_counter() - t0, 3),
|
||||||
|
"req": summarize_from_create(req, status="待开发", assignee_name="王冕"),
|
||||||
|
"delivery": summarize_from_create(deliv, status="待处理", assignee_name="何斐"),
|
||||||
|
"design": summarize_from_create(des, status="已完成", assignee_name="王冕"),
|
||||||
|
"analysis": None,
|
||||||
|
"delivery_desc_source": desc_source,
|
||||||
|
"design_associated_ok": design_assoc_ok,
|
||||||
|
"risk": risk,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
auth0 = time.perf_counter()
|
||||||
|
load_auth()
|
||||||
|
auth_s = round(time.perf_counter() - auth0, 3)
|
||||||
|
|
||||||
|
wall0 = time.perf_counter()
|
||||||
|
with ThreadPoolExecutor(max_workers=2) as pool:
|
||||||
|
f_fast = pool.submit(build_fast)
|
||||||
|
f_normal = pool.submit(build_normal)
|
||||||
|
fast = f_fast.result()
|
||||||
|
normal = f_normal.result()
|
||||||
|
build_s = round(time.perf_counter() - wall0, 3)
|
||||||
|
|
||||||
|
s = session()
|
||||||
|
assert_associated_to_req(s, normal["delivery"]["id"], normal["req"]["id"], "normal.delivery")
|
||||||
|
assert_associated_to_req(s, fast["delivery"]["id"], fast["req"]["id"], "fast.delivery")
|
||||||
|
|
||||||
|
def assert_sub(delivery_id: str, child_id: str, label: str) -> None:
|
||||||
|
rows = api(
|
||||||
|
s,
|
||||||
|
"GET",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/v2/workitem/{delivery_id}/relation/workitem/list/by-relation-category?category=PARENT_SUB&isForward=true",
|
||||||
|
).get("result") or []
|
||||||
|
ids = {r.get("identifier") for r in rows}
|
||||||
|
if child_id not in ids:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"{label} 未出现在交付子项:期望 {child_id},实际 {[r.get('serialNumber') for r in rows]}"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert_sub(normal["delivery"]["id"], normal["analysis"]["id"], "normal.analysis")
|
||||||
|
assert_sub(normal["delivery"]["id"], normal["design"]["id"], "normal.design")
|
||||||
|
assert_sub(fast["delivery"]["id"], fast["design"]["id"], "fast.design")
|
||||||
|
verify = {
|
||||||
|
"normal_req": get(s, normal["req"]["id"])["status"]["displayName"],
|
||||||
|
"fast_req": get(s, fast["req"]["id"])["status"]["displayName"],
|
||||||
|
"normal_delivery_assignee": (
|
||||||
|
get(s, normal["delivery"]["id"]).get("assignedTo") or {}
|
||||||
|
).get("displayName"),
|
||||||
|
"fast_delivery_assignee": (get(s, fast["delivery"]["id"]).get("assignedTo") or {}).get(
|
||||||
|
"displayName"
|
||||||
|
),
|
||||||
|
"delivery_associated_ok": True,
|
||||||
|
"stage_tasks_as_sub_ok": True,
|
||||||
|
"fast_design_associated_ok": fast.get("design_associated_ok"),
|
||||||
|
}
|
||||||
|
out = {
|
||||||
|
"normal": normal,
|
||||||
|
"fast": fast,
|
||||||
|
"verify": verify,
|
||||||
|
"auth_elapsed_s": auth_s,
|
||||||
|
"wall_elapsed_s": build_s,
|
||||||
|
"created_at": datetime.now(TZ).isoformat(),
|
||||||
|
"mode": "live_create_fast_v5_fast_track_rules",
|
||||||
|
"opts": {
|
||||||
|
"create_includes_plan_start": True,
|
||||||
|
"skip_plan_end_on_create": True,
|
||||||
|
"tracked_transit_no_get": True,
|
||||||
|
"delivery_assignee_hefei_at_create": True,
|
||||||
|
"overlap_tag_with_create": True,
|
||||||
|
"fast_req_hours": f"{FAST_EST}+{FAST_ACT}",
|
||||||
|
"relation": "delivery ASSOCIATED→req; analysis/design TASK_SUB→delivery; design post ASSOCIATED→req",
|
||||||
|
"http": "requests.Session keep-alive",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
Path("/tmp/yunxiao_pmapp_fast_v2_result.json").write_text(
|
||||||
|
json.dumps(out, ensure_ascii=False, indent=2)
|
||||||
|
)
|
||||||
|
print(json.dumps(out, ensure_ascii=False, indent=2))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
60
.claude/skills/YunxiaoPM/model.md
Normal file
60
.claude/skills/YunxiaoPM/model.md
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
# 交付树模型与关联约定
|
||||||
|
|
||||||
|
## 真相源
|
||||||
|
|
||||||
|
```text
|
||||||
|
需求状态 = 阶段看板唯一真相(分析中/设计中/待开发…)
|
||||||
|
【交付】任务 = 该需求的交付容器(每需求最多 1 条)
|
||||||
|
【分析】/【设计】 = YunxiaoPMapp 在交付下建的阶段子项
|
||||||
|
【开发】/【测试】 = 另属开发 Skill / 测试 Skill,不进本包
|
||||||
|
ASSOCIATED = 横向挂钩(【交付】 ↔ 需求)
|
||||||
|
SUB / TASK_SUB = 纵向拆解(交付 → 分析/设计)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 关系验收
|
||||||
|
|
||||||
|
| 关系 | 用在哪里 | 验收 | 优先级 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| ASSOCIATED | **仅【交付】** ↔ 需求 | 交付详情「关联项」能看到需求(**强制**) | 交付必过 |
|
||||||
|
| TASK_SUB | 【分析】/【设计】 → 【交付】 | 交付详情「子项」能看到阶段任务(**强制**) | 阶段任务必过 |
|
||||||
|
|
||||||
|
建单规则(Cookie 路径 · 同一 create 只能一条 `createWorkitemRelationInfo`):
|
||||||
|
|
||||||
|
| 对象 | `createWorkitemRelationInfo` | 另写字段 |
|
||||||
|
|---|---|---|
|
||||||
|
| 【交付】 | `ASSOCIATED` → 需求 | — |
|
||||||
|
| 【分析】/【设计】 | `TASK_SUB` → 交付 | `parent` + `parentIdentifier` = 交付 |
|
||||||
|
|
||||||
|
**禁止**对分析/设计只写 `parentIdentifier` + `ASSOCIATED→需求`:关联项可能有,但交付「子项」仍为空(ONEOS-246/247 已复现)。
|
||||||
|
勿用 `PARENT` 冒充关联项。细则见 [live-api.md](live-api.md)。
|
||||||
|
|
||||||
|
## 禁止
|
||||||
|
|
||||||
|
| 禁止 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| 创建或描述【开发】/【测试】 | 口令与回报均不出现 |
|
||||||
|
| 分析/设计未挂成交付子项(无 TASK_SUB) | 交付「子项」为 0,交棒验收失败 |
|
||||||
|
| 用任务名称/标题做唯一性或查重 | 不得 `subject` 匹配复用 |
|
||||||
|
| 同一需求认定多个交付任务编号 | 列出编号请人合并后再继续 |
|
||||||
|
| 功能模块标签用「分析/设计/交付」 | 模块标签打在需求(可选交付)上 |
|
||||||
|
|
||||||
|
## 任务标题(仅展示)
|
||||||
|
|
||||||
|
- 【交付】+ 需求标题
|
||||||
|
- 【分析】+ 需求标题
|
||||||
|
- 【设计】+ 需求标题
|
||||||
|
|
||||||
|
标题可改,**不参与查重**。
|
||||||
|
|
||||||
|
## 任务编号唯一性
|
||||||
|
|
||||||
|
**唯一允许的查重/复用渠道:云效任务编号**(如 `ONEOS-99` / `serialNumber`)。
|
||||||
|
|
||||||
|
| 场景 | 正确 | 错误 |
|
||||||
|
|---|---|---|
|
||||||
|
| 首次创建【交付】 | 建单成功后回报并写入「工作项编号(系统)」 | 下次用标题搜 |
|
||||||
|
| 复用【交付】 | 口令或编号区块带 `交付任务=ONEOS-xx` | list 后按 subject 相等 |
|
||||||
|
| 判断是否已有交付 | 编号区块或交付 ASSOCIATED 编号集合 | 数【交付】开头标题 |
|
||||||
|
| 分析/设计幂等 | 仅已登记编号 | 按【分析】+需求标题 |
|
||||||
|
|
||||||
|
按编号命中则复用;**计划开始已有值禁止改写**。
|
||||||
49
.claude/skills/YunxiaoPM/references/acceptance.md
Normal file
49
.claude/skills/YunxiaoPM/references/acceptance.md
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# 验收清单与回报
|
||||||
|
|
||||||
|
## apply 后必须自检
|
||||||
|
|
||||||
|
| # | 项 | 通过标准 |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | 需求编号 | 回报含 ONEOS-xx |
|
||||||
|
| 2 | 任务编号 | 交付/分析/设计凡新建或操作均回报编号;禁止只报标题 |
|
||||||
|
| 3 | 编号区块 | 需求「工作项编号(系统)」与实际一致 |
|
||||||
|
| 4 | ASSOCIATED | **仅交付**详情关联项可见需求(`createWorkitemRelationInfo=ASSOCIATED`;禁止 PARENT 冒充) |
|
||||||
|
| 5 | SUB | **必过**:分析/设计 create 用 `TASK_SUB→交付`(含 `parent`+`parentIdentifier`);交付「子项」tab 须可见。与 ASSOCIATED 同 create 互斥,阶段任务关联项可空(见 live-api.md) |
|
||||||
|
| 6 | 计划开始 | 未误覆盖已有值 |
|
||||||
|
| 7 | 阶段日历工时 | 有计划完成时已写入;脚注存在;回报用语正确 |
|
||||||
|
| 8 | 交棒 | 需求=待开发;交付负责人=何斐(交棒场景) |
|
||||||
|
| 9 | 占位风险 | 交付仍占位时首行标红 |
|
||||||
|
| 10 | 负向 | 本轮**无**【开发】/【测试】任务;未按标题查重 |
|
||||||
|
|
||||||
|
设计完成额外:AutoPRD 段已写;交付非占位(除非失败停下);ZIP+截图已挂或已列出缺项。
|
||||||
|
|
||||||
|
迭代额外:只挂【交付】(需求不挂);版本号符合递增规则。
|
||||||
|
|
||||||
|
## 回报模板(精简)
|
||||||
|
|
||||||
|
```text
|
||||||
|
【YunxiaoPM】
|
||||||
|
风险:(若有占位交棒则首行标红)
|
||||||
|
需求:ONEOS-xx | 状态=…
|
||||||
|
交付:ONEOS-a | 负责人=…
|
||||||
|
分析:ONEOS-b | …(无则写无)
|
||||||
|
设计:ONEOS-c | …(无则写无)
|
||||||
|
阶段日历工时:分析 Hh / 设计 Hh(若本轮写入)
|
||||||
|
附件:…(若本轮)
|
||||||
|
迭代:…(若本轮)
|
||||||
|
下一步:请技术经理使用开发 Skill(交棒后)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 适合全自动 vs 人工门禁
|
||||||
|
|
||||||
|
| 适合全自动 | 建议半自动/人工门禁 |
|
||||||
|
|---|---|
|
||||||
|
| 建单、打标签、挂迭代、写描述、建交付树、改状态、交棒负责人、幂等查重 | **PJ 云效项目点选**、受理(已确认)、是否快轨、设计完成是否真可开发、跨需求优先级与迭代容量、回退与取消 |
|
||||||
|
|
||||||
|
## 实写性能(2026-07-23 复盘)
|
||||||
|
|
||||||
|
| 项 | 要求 |
|
||||||
|
|---|---|
|
||||||
|
| 改状态 | 只用 `status/transit`(见 [live-api.md](live-api.md)) |
|
||||||
|
| 改【交付】负责人 | 只用 `PATCH …/{id}` + `propertyKey=assignedTo` |
|
||||||
|
| 极速复测 | `scripts/live_create_fast.py`;默认不开浏览器 |
|
||||||
22
.claude/skills/YunxiaoPM/references/commands.md
Normal file
22
.claude/skills/YunxiaoPM/references/commands.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# 口令面
|
||||||
|
|
||||||
|
```text
|
||||||
|
记录需求:…;项目=(必选·Plan 点选);优先级=紧急|高|中|低;标签=…;提交部门=…;提交人=…;推进至=暂不推进|已确认|分析中|设计中|设计完成|待开发|待开发(快轨)
|
||||||
|
受理确认:ONEOS-xx
|
||||||
|
开始分析:ONEOS-xx → 【交付】+【分析】并回报编号
|
||||||
|
开始设计:ONEOS-xx;交付任务=…;分析任务=… → 【设计】+收口分析
|
||||||
|
设计完成:ONEOS-xx;设计任务=…;原型=…
|
||||||
|
交棒开发:ONEOS-xx;交付任务=… → 待开发 + 该编号负责人=何斐
|
||||||
|
快轨待开发:ONEOS-xx → 待开发 +【交付】+【设计】(无【分析】)+ 交付负责人=何斐
|
||||||
|
编号直推:分析任务=ONEOS-b / 设计任务=ONEOS-c → 收口未完成计划完成 + 需求待开发 + 交付交棒何斐
|
||||||
|
创建迭代:版本类型=主|副|子;交付任务=ONEOS-a,ONEOS-b,…;名称前缀=…
|
||||||
|
AutoRDO:…(粘贴聊天/附录音)→ 再记录需求
|
||||||
|
```
|
||||||
|
|
||||||
|
版本自动规则:取同前缀下最大 `Vx.y.z`(旧 `Vx.y` 视为 `Vx.y.0`)再按主/副/子递增;迭代名=`{前缀}{新版本}`。
|
||||||
|
|
||||||
|
**PJ 项目**:新建需求/迭代前须点选云效项目(实时列表);禁止默认直指。见 [project-selection.md](project-selection.md)。
|
||||||
|
|
||||||
|
后续推进口令**优先显式带任务编号**;未带则读「工作项编号(系统)」;仍无则询问;**禁止按标题补全**。
|
||||||
|
|
||||||
|
YunxiaoPM 回报止于交棒;可一句「请技术经理使用开发 Skill」。
|
||||||
95
.claude/skills/YunxiaoPM/references/compact-select.md
Normal file
95
.claude/skills/YunxiaoPM/references/compact-select.md
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
# 压缩点选(`1a2b3a4d`)
|
||||||
|
|
||||||
|
记录需求 Plan **默认**用编号题 + 字母选项;用户可用一行压缩答复确认。
|
||||||
|
|
||||||
|
## Plan 展示模板
|
||||||
|
|
||||||
|
```text
|
||||||
|
请回复压缩点选,例:1a2b3a4d
|
||||||
|
(数字=题号,字母=选项;大小写不敏感;可写 1A2B3A4D)
|
||||||
|
|
||||||
|
1. 类型
|
||||||
|
A. 新增
|
||||||
|
B. 优化
|
||||||
|
|
||||||
|
2. 项目(云效实时列表;建议项可标★)
|
||||||
|
A. 01_ONEOS(ONEOS)★
|
||||||
|
B. 02_小羚羚APP(XLLAPP)
|
||||||
|
C. …
|
||||||
|
|
||||||
|
3. 优先级
|
||||||
|
A. 紧急
|
||||||
|
B. 高
|
||||||
|
C. 中
|
||||||
|
D. 低
|
||||||
|
|
||||||
|
4. 标签(云效候选;建议项可标★)
|
||||||
|
A. 故障管理★
|
||||||
|
B. 还车应结款
|
||||||
|
C. …
|
||||||
|
```
|
||||||
|
|
||||||
|
可选续题(口令已齐则可写入清单、压缩串可不含):
|
||||||
|
|
||||||
|
```text
|
||||||
|
5. 推进至 …
|
||||||
|
6. 迭代 …
|
||||||
|
```
|
||||||
|
|
||||||
|
## 解析规则
|
||||||
|
|
||||||
|
| 规则 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| 形态 | `(题号)(字母)` 连续拼接,如 `1a2b3a4d` |
|
||||||
|
| 题号 | `1`=类型 `2`=项目 `3`=优先级 `4`=标签;可扩展 `5` `6` |
|
||||||
|
| 字母 | `a`→第 1 项 … `z`→第 26 项;超出选项数 → 非法,停 |
|
||||||
|
| 缺题 | 该题若口令已唯一预填且列表唯一命中,可用预填;否则停并追问缺题 |
|
||||||
|
| 多答同题 | 后写覆盖先写 |
|
||||||
|
| 非法字符 | 停,重贴模板 |
|
||||||
|
|
||||||
|
解析成功后 Plan 回显人话确认一行,例如:
|
||||||
|
|
||||||
|
```text
|
||||||
|
已解析 1a2b3a4d → 类型=新增;项目=02_小羚羚APP;优先级=紧急;标签=(D 项名)
|
||||||
|
确认后回复「执行」
|
||||||
|
```
|
||||||
|
|
||||||
|
用户再回「执行」才 apply(仍守 Plan 门禁)。
|
||||||
|
|
||||||
|
## 与口令预填
|
||||||
|
|
||||||
|
口令已写 `类型:新增;项目:01_ONEOS;优先级:高;标签:故障管理` 时:
|
||||||
|
|
||||||
|
- 对应选项标 ★,并给出**建议压缩串**(如 `1a2a3b4a`),用户可直接改字母或整段重答。
|
||||||
|
- **不得**因有预填而跳过展示字母表;压缩确认(或逐题点选)仍是门禁。
|
||||||
|
|
||||||
|
## 标签未命中 → 自动重拉一次候选并重生选项
|
||||||
|
|
||||||
|
「标签无法对应」:口令标签名在**当前标签候选**中 0 命中(或多命中无法唯一)。
|
||||||
|
|
||||||
|
| 步骤 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| 1 | **自动重拉一次**标签候选(见下「标签候选来源」;强制刷新,不用旧缓存) |
|
||||||
|
| 2 | 用新列表**重新生成 4.A/B/C…** 选择项 |
|
||||||
|
| 3 | 回报:`已自动重拉标签列表(因无法对应)`;请用户重答 `4x` 或整串 |
|
||||||
|
| 4 | 仍无法对应 → 停;**禁止**第 3 次空转;**禁止**猜 tagId |
|
||||||
|
|
||||||
|
> 说明:此处重拉的是**标签候选列表**,不是项目列表。项目无法对应仍走 [project-selection.md](project-selection.md) 的「自动重拉一次」。
|
||||||
|
|
||||||
|
### 标签候选来源(当前已验证路径)
|
||||||
|
|
||||||
|
1. `runtime-ids.json` → `tags`
|
||||||
|
2. 目标项目(或预填项目)下近期工作项 `tag` 字段聚合去重
|
||||||
|
3. 重拉 = 再请求工作项列表聚合 + 合并 runtime;命中后可回写 `tags` 缓存
|
||||||
|
|
||||||
|
(专用 `tag/list` Cookie API 尚未稳定;有稳定端点后改写入 `live-api.md` 并切换。)
|
||||||
|
|
||||||
|
## 项目列表顺序
|
||||||
|
|
||||||
|
生成 2. 选项时:口令预填/建议项目置 **A** 并标 ★,其余按云效返回顺序接 B/C/…。
|
||||||
|
|
||||||
|
## Agent 义务
|
||||||
|
|
||||||
|
1. 记录需求进 Plan 时必须输出本模板(至少 1–4 题)。
|
||||||
|
2. 收到压缩串先解析回显,再等「执行」。
|
||||||
|
3. 标签/项目无法对应:各自动重拉**一次**并刷新对应题选项。
|
||||||
69
.claude/skills/YunxiaoPM/references/description-split.md
Normal file
69
.claude/skills/YunxiaoPM/references/description-split.md
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
# 需求描述 vs 交付描述
|
||||||
|
|
||||||
|
两类描述职责不同;禁止混写;禁止建【交付】时把 AutoPRD 六大块提前塞进交付描述。
|
||||||
|
|
||||||
|
## A. 需求描述 · AutoRDO 清洗
|
||||||
|
|
||||||
|
| 项 | 规则 |
|
||||||
|
|---|---|
|
||||||
|
| 触发 | 对话建需求 / 碎片材料入库 |
|
||||||
|
| 调用 | **必须**使用独立 Skill「**`$AutoRDO`**」(`AutoRDO/SKILL.md`;本 Skill 不内嵌清洗细则) |
|
||||||
|
| 输入 | 聊天记录、录音、口述材料 |
|
||||||
|
| 处理 | 保留原意;书面化;去口头禅;**去除结尾句号**(细则在 AutoRDO `references/rules.md`) |
|
||||||
|
| 输出 | 写入 `## 原始诉求(AutoRDO)` |
|
||||||
|
| 不做 | 本阶段不写 AutoPRD 六大块;不要求已有原型;不覆盖已有「产品说明」 |
|
||||||
|
|
||||||
|
口令:`AutoRDO:…` → 确认后 `记录需求:【新增】标题;描述=整理稿;推进至=…`
|
||||||
|
|
||||||
|
## B. 交付描述
|
||||||
|
|
||||||
|
### B1. 标准路径(分析中起建交付)
|
||||||
|
|
||||||
|
| 时机 | 【交付】描述 |
|
||||||
|
|---|---|
|
||||||
|
| 首次创建起至设计完成前 | 固定文案:`等待设计任务完成后自动填入` |
|
||||||
|
| 设计完成时 | 用 AutoPRD「产品说明」正文替换占位 |
|
||||||
|
|
||||||
|
### B2. 无单快轨建交付(覆盖 B1)
|
||||||
|
|
||||||
|
| 口令/材料 | 【交付】描述 |
|
||||||
|
|---|---|
|
||||||
|
| 手工描述(无指定原型) | **同步需求**当前手工/AutoRDO 正文;禁止占位 |
|
||||||
|
| 指定原型页面 | `$oneos-autoprd` 从原型生成写入;禁止占位 |
|
||||||
|
| 既无正文又无原型 | 才允许占位并标红风险 |
|
||||||
|
|
||||||
|
快轨【设计】描述始终复制需求当前描述正文(见 [fast-track.md](fast-track.md))。
|
||||||
|
|
||||||
|
## C. 需求描述双段模板(不可互相覆盖)
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 原始诉求(AutoRDO)
|
||||||
|
(清洗稿;设计完成也不删除)
|
||||||
|
|
||||||
|
## 产品说明(AutoPRD)
|
||||||
|
(六大块+对象存储链接;未设计完成前可无此节或写「待设计完成后填入」)
|
||||||
|
|
||||||
|
## 工作项编号(系统)
|
||||||
|
- 交付:…
|
||||||
|
- 分析:…
|
||||||
|
- 设计:…
|
||||||
|
```
|
||||||
|
|
||||||
|
## D. 设计完成 · AutoPRD + 附件
|
||||||
|
|
||||||
|
前提:设计任务完成且已关联对应原型页。
|
||||||
|
|
||||||
|
1. 调用 **`$oneos-autoprd`(AutoPRD)**,产出并落盘 `.spec/requirements-prd.md` + 标注同步:
|
||||||
|
- 对象存储预览链接:`{baseUrl}/{prototype-id}/index.html`(禁止加 `prototypes/` 前缀、禁止去掉 `index.html`)
|
||||||
|
- 产品说明 Markdown(总览/角色/流程/状态/风险/交付等,见 AutoPRD 模板)
|
||||||
|
2. 写入需求 `## 产品说明(AutoPRD)`;**禁止覆盖** `## 原始诉求(AutoRDO)` / `## 工作项编号(系统)`。
|
||||||
|
3. 【交付】描述:按**交付任务编号**用产品说明正文**替换**占位(细则见 AutoPRD `references/yunxiao-delivery-sync.md`);可附「原始诉求见需求描述」。**创建【交付】时不得提前灌 MD。**
|
||||||
|
4. 附件(需求 +【交付】均挂;失败则不得声称成功):
|
||||||
|
- Make「导出 HTML(含源码)」ZIP → [make-export-attach.md](make-export-attach.md)
|
||||||
|
- Make「复制截图」全交互页 → 同上
|
||||||
|
|
||||||
|
缺原型 / AutoPRD 失败 / 导出或截图失败 → **不得**报到设计完成并宣称附件齐全;停下并列出缺项。
|
||||||
|
|
||||||
|
执行顺序:先 AutoPRD 落盘与附件就绪 → 再改需求/交付描述与设计计划完成 → 最后改需求状态。
|
||||||
|
|
||||||
|
**禁止**加载 `yunxiao-requirement-lifecycle`;阶段任务树只由本 Skill(YunxiaoPMapp)创建。
|
||||||
47
.claude/skills/YunxiaoPM/references/fast-track.md
Normal file
47
.claude/skills/YunxiaoPM/references/fast-track.md
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# 无单快轨到待开发
|
||||||
|
|
||||||
|
适用:口令明确「快轨」或「推进至待开发」且当前需求尚无标准分析路径任务(或用户确认跳过分析)。
|
||||||
|
|
||||||
|
## 动作表
|
||||||
|
|
||||||
|
| 对象 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| 需求 | 状态 → **待开发**;**预计工时=2**、**实际工时=2**(覆盖同日 8h 日历工时默认);标签按口令;更新编号区块 |
|
||||||
|
| 【交付】 | 无则新建;ASSOCIATED→需求(勿用 PARENT);负责人→何斐;**计划开始=创建当日**(`79`);**不写**计划完成;**描述双路径**(见下);**标签与需求相同**;更新编号区块 |
|
||||||
|
| 【设计】 | **必须新建**;**TASK_SUB→交付**(交付「子项」须可见);**描述=复制需求当前描述正文**;计划开始/完成均=当日(create 后 `field/value` 写 `79`+`80`);任务→完成态;**标签与需求相同**;建后再尝试 **ASSOCIATED→原始需求**(Cookie 常失败,见 live-api;失败须标红,**子项优先于关联项**);更新编号区块 |
|
||||||
|
| 【分析】 | **禁止创建** |
|
||||||
|
|
||||||
|
## 交付描述双路径(A1)
|
||||||
|
|
||||||
|
| 口令/材料 | 【交付】描述 |
|
||||||
|
|---|---|
|
||||||
|
| **手工描述**(无指定原型) | 同步需求当前手工/AutoRDO 正文(与设计一致可复制 document) |
|
||||||
|
| **指定原型页面** | 调用 `$oneos-autoprd`,从原型生成 AutoPRD「产品说明」写入【交付】 |
|
||||||
|
| 既无手工可同步正文、又无原型 | 才允许占位 `等待设计任务完成后自动填入`,Plan 勾选交棒占位风险,回报首行标红 |
|
||||||
|
|
||||||
|
有手工或原型时**禁止**交棒占位。
|
||||||
|
|
||||||
|
## AutoPRD
|
||||||
|
|
||||||
|
- 快轨默认可不跑 AutoPRD;**例外**:口令指定原型 → 交付走 AutoPRD 路径(上表)。
|
||||||
|
- 口令同时「设计完成 + 原型」时仍按步骤 4 灌需求产品说明段。
|
||||||
|
|
||||||
|
## 查重
|
||||||
|
|
||||||
|
只认任务编号。已有分析单不得因「快轨」被删除。
|
||||||
|
|
||||||
|
## 回报必含
|
||||||
|
|
||||||
|
- 需求 / 交付 / 设计编号
|
||||||
|
- 「快轨:未建分析;设计已同步需求描述并当日收口」
|
||||||
|
- 交付描述来源:手工同步 / AutoPRD / 占位(若占位则首行标红)
|
||||||
|
- 需求预计工时=2、实际工时=2
|
||||||
|
- 设计关联项含需求编号;交付子项含设计编号
|
||||||
|
|
||||||
|
## 与标准 / 编号直推对比
|
||||||
|
|
||||||
|
```text
|
||||||
|
标准:分析中→交付+分析 → 设计中→设计+收口分析 → 设计完成→收口设计 → 待开发交棒
|
||||||
|
快轨(无既有阶段单):→ 待开发:新建交付+设计+交棒何斐(无分析;设计当日收口;需求工时 2+2)
|
||||||
|
编号直推:已有分析/设计编号 → 收口空计划完成 → 待开发+交付交棒(不新建冗余单)
|
||||||
|
```
|
||||||
20
.claude/skills/YunxiaoPM/references/handoff-and-rollback.md
Normal file
20
.claude/skills/YunxiaoPM/references/handoff-and-rollback.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# 交棒门禁与回退最小集
|
||||||
|
|
||||||
|
## 交棒门禁(待开发)
|
||||||
|
|
||||||
|
| 情形 | 规则 |
|
||||||
|
|---|---|
|
||||||
|
| 【交付】描述已是 AutoPRD 正式说明(非占位) | 允许交棒;Plan 正常列交付任务编号 + 负责人→何斐 |
|
||||||
|
| 【交付】描述仍为 `等待设计任务完成后自动填入` | **仍允许交棒**,但 Plan **必须**勾选风险项「交付描述仍为占位,技术侧仅可凭需求 AutoRDO 稿理解」;回报**首行标红**该风险;**禁止**静默交棒假装材料齐全 |
|
||||||
|
| 口令同时带原型且要求设计完成 | 先走步骤 4(AutoPRD+附件)成功,再交棒,不再勾占位风险 |
|
||||||
|
|
||||||
|
## 回退 / 变更(最小集 · 兼容计划开始不篡改)
|
||||||
|
|
||||||
|
| 场景 | 规则 |
|
||||||
|
|---|---|
|
||||||
|
| 待开发 → 退回设计中 | 需求状态回退;【交付】负责人可改回创建人/产品;**交付计划开始不改**;若需重做设计 → **新开**设计任务编号(旧设计保持已收口,不改其计划开始);更新「工作项编号(系统)」中的设计编号为新号 |
|
||||||
|
| 设计完成后需求大变 | 不自动改状态;Plan 询问是否回退设计中并新开设计编号;更新 AutoPRD 段;AutoRDO 段保留并追加「变更纪要」 |
|
||||||
|
| 取消需求 | 关联任务标取消/废止;不删编号区块;不改已写计划开始 |
|
||||||
|
| 度量含义 | 交付计划开始保留 = 全周期仍从首次开工起算;回退重做会拉长日历工时——回报注明「含回退重做」 |
|
||||||
|
|
||||||
|
凡写云效的回退仍须走 Plan 门禁。
|
||||||
14
.claude/skills/YunxiaoPM/references/handoff-contract.md
Normal file
14
.claude/skills/YunxiaoPM/references/handoff-contract.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# 交接契约(开发 Skill 入口)
|
||||||
|
|
||||||
|
YunxiaoPMapp 与开发 Skill **不要**互相 include 全文;仅认下列契约。
|
||||||
|
|
||||||
|
```text
|
||||||
|
PM 完成交棒 → 需求=待开发;【交付】任务编号=ONEOS-xx;负责人=何斐;ASSOCIATED 需求
|
||||||
|
若交付描述仍为占位 → 回报已标红风险
|
||||||
|
开发 Skill 入口 → 认「需求编号 + 交付任务编号」
|
||||||
|
占位时只可信需求「原始诉求(AutoRDO)」并有权要求产品补设计完成
|
||||||
|
```
|
||||||
|
|
||||||
|
共享常量(项目 ID、何斐 ID、节假日日历)可引用本 Skill 的 `assets/` 短路径,勿加载整份对方规则。
|
||||||
|
|
||||||
|
测试 Skill 另开;本契约不覆盖提测/缺陷。
|
||||||
242
.claude/skills/YunxiaoPM/references/live-api.md
Normal file
242
.claude/skills/YunxiaoPM/references/live-api.md
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
# 云效实写 API(YunxiaoPMapp 已验证)
|
||||||
|
|
||||||
|
`verified_at`: 2026-07-25 · **项目须门禁 PJ 点选**(见 [project-selection.md](project-selection.md));历史验证样本项目为 `01_ONEOS` / 原「统一运营管理平台」(`last_selected.spaceIdentifier` 见 `assets/runtime-ids.json`,禁止未点选即使用)。
|
||||||
|
|
||||||
|
本文件只记**已跑通**的写法;禁止再盲试 `updateStatus` / 错误 `updateFieldValue` POST。
|
||||||
|
|
||||||
|
## 认证
|
||||||
|
|
||||||
|
- Cookie:Chrome 域 `.aliyun.com` / `devops.aliyun.com`(`browser_cookie3` 或 Playwright storage)
|
||||||
|
- Header:`x-xsrf-token` = cookie `XSRF-TOKEN`(URL 解码后)
|
||||||
|
- `Origin` / `Referer`:`https://devops.aliyun.com`
|
||||||
|
|
||||||
|
## 建单
|
||||||
|
|
||||||
|
`POST|PUT /projex/api/workitem/workitem?_input_charset=utf-8`
|
||||||
|
|
||||||
|
创建响应 `result.identifier` / `serialNumber` 即编号真相;**禁止按标题查重**。
|
||||||
|
|
||||||
|
## 改负责人(已通)
|
||||||
|
|
||||||
|
```http
|
||||||
|
PATCH /projex/api/workitem/workitem/{id}?_input_charset=utf-8
|
||||||
|
{"propertyKey":"assignedTo","propertyValue":"<userId>","operateType":"COVER"}
|
||||||
|
```
|
||||||
|
|
||||||
|
交棒:【交付】`propertyValue` = 何斐 ID。
|
||||||
|
|
||||||
|
## 打标签(已通)
|
||||||
|
|
||||||
|
```http
|
||||||
|
PATCH /projex/api/workitem/workitem/{id}?_input_charset=utf-8
|
||||||
|
{"workitemIdentifier":"{id}","propertyKey":"tag","propertyValue":"<tagId>[,<tagId>]","operateType":"COVER"}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 改状态(已通 · 唯一推荐)
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /projex/api/workitem/workitem/{id}/status/transit?_input_charset=utf-8
|
||||||
|
{"fromStatus":"<当前status.identifier>","toStatus":"<目标status.identifier>"}
|
||||||
|
```
|
||||||
|
|
||||||
|
成功:`code=200` 且 `result=true`。失败时 `errorMsg` 含「不能流转」。
|
||||||
|
|
||||||
|
### 需求状态 ID(本项目)
|
||||||
|
|
||||||
|
| 显示名 | identifier |
|
||||||
|
|---|---|
|
||||||
|
| 待处理 | `100005` |
|
||||||
|
| 已确认 | `32` |
|
||||||
|
| 分析中 | `154395` |
|
||||||
|
| 设计中 | `156603` |
|
||||||
|
| 设计完成 | `307012` |
|
||||||
|
| 待开发 | `1582fc929d429111b925309493` |
|
||||||
|
|
||||||
|
### 任务状态 ID
|
||||||
|
|
||||||
|
| 显示名 | identifier |
|
||||||
|
|---|---|
|
||||||
|
| 待处理 | `100005` |
|
||||||
|
| 已完成 | `100014` |
|
||||||
|
|
||||||
|
### 极速交棒跳转(工作流允许)
|
||||||
|
|
||||||
|
从「待处理」菜单可见直达「设计完成」;推荐最少跳:
|
||||||
|
|
||||||
|
```text
|
||||||
|
待处理 → 设计完成 → 待开发
|
||||||
|
```
|
||||||
|
|
||||||
|
标准路径若需看板留痕,可走完整链:已确认→分析中→设计中→设计完成→待开发(仍用本 API,勿开 UI)。
|
||||||
|
|
||||||
|
### 禁止(已证伪)
|
||||||
|
|
||||||
|
| 写法 | 结果 |
|
||||||
|
|---|---|
|
||||||
|
| `PATCH …/updateStatus` + `statusIdentifier` | `400 不能为空` |
|
||||||
|
| `PATCH …/{id}` + `propertyKey=status` | `property not found` |
|
||||||
|
| Playwright 点左侧/列表上的状态色块(`x<1100`) | 假成功、状态不落库 |
|
||||||
|
|
||||||
|
仅当 `status/transit` 不可用时,才用 UI:右侧详情状态钮(`getBoundingClientRect().x > 1100`)+ `.next-menu-item`。
|
||||||
|
|
||||||
|
## 计划开始/完成 · 提交部门/人 · 预计工时(2026-07-27 修订)
|
||||||
|
|
||||||
|
**通用字段写入(已通):**
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /projex/api/workitem/workitem/field/value/{workitemId}?_input_charset=utf-8
|
||||||
|
Content-Type: application/x-www-form-urlencoded
|
||||||
|
|
||||||
|
fieldValueList=[{"fieldIdentifier":"79","value":"2026-07-27 12:00:00"},{"fieldIdentifier":"3132597a9718d1c282b7ba5a0c","value":"业务管理部"},{"fieldIdentifier":"9e01269e96f91fbb97d36bf5b3","value":"何苗苗"}]
|
||||||
|
```
|
||||||
|
|
||||||
|
| 字段 | fieldIdentifier | value |
|
||||||
|
|---|---|---|
|
||||||
|
| 计划开始 | `79` | `YYYY-MM-DD HH:mm:ss`(推荐正午)或 epoch ms 字符串 |
|
||||||
|
| 计划完成 | `80` | 同上 |
|
||||||
|
| 提交部门 | `3132597a9718d1c282b7ba5a0c` | 纯文本 |
|
||||||
|
| 提交人 | `9e01269e96f91fbb97d36bf5b3` | 纯文本 |
|
||||||
|
|
||||||
|
**预计工时 `101586`:禁止直接改字段**(报「不可直接修改」)。须登记:
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /projex/api/workitem/workitem/time/estimate?_input_charset=utf-8
|
||||||
|
{"workitemIdentifier":"<id>","spentTime":8,"type":"develop","description":"阶段日历工时","recordUserIdentifier":"<userId>","forCreate":false,"containsRestDay":false}
|
||||||
|
```
|
||||||
|
|
||||||
|
删除多余预估:`DELETE /projex/api/workitem/workitem/time/estimate/{workitemId}/{estimateId}`
|
||||||
|
列表:`GET …/time/estimate/list?workitemIdentifier=`
|
||||||
|
|
||||||
|
旧写法 `PATCH …/updateWorkitemFieldValue` 对上述自定义字段常 `400 不能为空`,勿再优先使用。
|
||||||
|
|
||||||
|
## 父子 / 子项 / 关联项(已通 · 2026-07-23 修订 · 子项优先)
|
||||||
|
|
||||||
|
### 关联项(【交付】强制 · ASSOCIATED)
|
||||||
|
|
||||||
|
任务详情「关联项」只认 `ASSOCIATED`。**仅【交付】**建单时 `createWorkitemRelationInfo` 必须指向**需求**:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"createWorkitemRelationInfo": {
|
||||||
|
"relatedWorkitemIdentifier": "<需求id>",
|
||||||
|
"relatedToRelationIdentifier": "ASSOCIATED"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
校验:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /projex/api/workitem/v2/workitem/{交付id}/relation/workitem/list/by-relation-category?category=ASSOCIATED&isForward=true
|
||||||
|
```
|
||||||
|
|
||||||
|
`result` 含该需求即通过。
|
||||||
|
|
||||||
|
### 禁止(关联项)
|
||||||
|
|
||||||
|
| 写法 | 结果 |
|
||||||
|
|---|---|
|
||||||
|
| `relatedToRelationIdentifier=PARENT` 把交付挂需求 | 详情可能有 parent,**关联项仍为空** |
|
||||||
|
| 分析/设计只用 `ASSOCIATED→需求` + `parentIdentifier` | 关联项可能有,**交付子项仍为空**(ONEOS-246/247) |
|
||||||
|
| 建后再 `POST …/relation/record` 补关系 | Cookie 路径下常报「不能关联相同的工作项」 |
|
||||||
|
| `createWorkitemRelationList` | 不落 ASSOCIATED |
|
||||||
|
|
||||||
|
### 子项(【分析】/【设计】强制 · TASK_SUB)
|
||||||
|
|
||||||
|
「子项」页读 `PARENT_SUB` / `TASK_SUB`,分析/设计**必须**:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"parent": "<交付id>",
|
||||||
|
"parentIdentifier": "<交付id>",
|
||||||
|
"createWorkitemRelationInfo": {
|
||||||
|
"relatedWorkitemIdentifier": "<交付id>",
|
||||||
|
"relatedToRelationIdentifier": "TASK_SUB"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
同一 create 只能带一条 `createWorkitemRelationInfo`。
|
||||||
|
`ASSOCIATED→需求` 与 `TASK_SUB→交付` **不能同时写**。
|
||||||
|
|
||||||
|
**产品优先级:交付「子项」tab > 阶段任务「关联项」。**
|
||||||
|
交付本身仍必须 `ASSOCIATED→需求`。标准路径下分析/设计的「关联项」允许为空。
|
||||||
|
|
||||||
|
**无单快轨例外(设计双挂):** create 用 `TASK_SUB→交付` 后,须再补 **ASSOCIATED→原始需求**,使设计详情「关联项」可见需求。
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /projex/api/workitem/workitem/{设计id}/relation/record?_input_charset=utf-8
|
||||||
|
{"relationIdentifier":"ASSOCIATED","toWorkitemIdentifier":"<需求id>"}
|
||||||
|
```
|
||||||
|
|
||||||
|
**已证伪(Cookie · 2026-07-27):** 凡工作项**已创建**后再 `relation/record` 补挂(含 ASSOCIATED / TASK_SUB),常报「不能关联相同的工作项」;与是否已有父项无关。`createWorkitemRelationList` 亦不落 ASSOCIATED。
|
||||||
|
**可行路径:**
|
||||||
|
|
||||||
|
| 目标 | 做法 |
|
||||||
|
|---|---|
|
||||||
|
| 交付「子项」可见设计(优先) | create 带 `TASK_SUB→交付` |
|
||||||
|
| 设计「关联项」可见需求 | create 带 `ASSOCIATED→需求`(与上互斥,同 create 只能一条) |
|
||||||
|
| 双挂 | 需个人 `x-yunxiao-token` OpenAPI;Cookie 路径**不得**声称成功 |
|
||||||
|
|
||||||
|
产品默认:**子项优先**;关联项失败须在回报中标红并列出缺项。
|
||||||
|
|
||||||
|
校验子项:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /projex/api/workitem/v2/workitem/{交付id}/relation/workitem/list/by-relation-category?category=PARENT_SUB&isForward=true
|
||||||
|
```
|
||||||
|
|
||||||
|
结果须含对应分析/设计 identifier。
|
||||||
|
|
||||||
|
校验设计关联项:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /projex/api/workitem/v2/workitem/{设计id}/relation/workitem/list/by-relation-category?category=ASSOCIATED&isForward=true
|
||||||
|
```
|
||||||
|
|
||||||
|
`result` 须含原始需求 identifier。
|
||||||
|
|
||||||
|
### 无单快轨字段默认(2026-07-27)
|
||||||
|
|
||||||
|
| 对象 | 规则 |
|
||||||
|
|---|---|
|
||||||
|
| 【设计】描述 | 复制需求 document HTML |
|
||||||
|
| 【设计】`79`/`80` | 当日 `12:00:00` / `23:59:59`,create 后 `field/value`(勿 create 同时带 79+80) |
|
||||||
|
| 【交付】描述 | 手工同步需求正文,或原型→AutoPRD;禁止无故占位 |
|
||||||
|
| 【交付】`79` | 创建当日;不写 `80` |
|
||||||
|
| 【交付】/【设计】标签 | 与需求相同,`PATCH propertyKey=tag` |
|
||||||
|
| 需求预计工时 | `time/estimate` **spentTime=2**(先删多余预估) |
|
||||||
|
| 需求实际工时 | `POST …/workitem/time`,body 用 **`actualTime`**(非 spentTime)+ `gmtStart`/`gmtEnd` epoch ms 字符串;见 `runtime-ids.json` `fields.actual_hours` |
|
||||||
|
| 描述更新 | `PATCH …/workitem/{id}/document`,`{"content":"<html>","formatType":"RICHTEXT"}` |
|
||||||
|
|
||||||
|
## 迭代挂接(已通 · 2026-07-27 · 只挂交付)
|
||||||
|
|
||||||
|
创建迭代:`POST /projex/api/workspace/sprint`(必填 `staffIds`;可写 `capacityHours`)。
|
||||||
|
|
||||||
|
挂【交付】到迭代:
|
||||||
|
|
||||||
|
```http
|
||||||
|
PATCH /projex/api/workitem/workitem/{交付id}?_input_charset=utf-8
|
||||||
|
{"workitemIdentifier":"{交付id}","propertyKey":"sprint","propertyValue":"{sprintId}","operateType":"COVER"}
|
||||||
|
```
|
||||||
|
|
||||||
|
清空误挂(如需求):`propertyValue:""` + `operateType:"COVER"`。
|
||||||
|
|
||||||
|
**校验**必须读 `/extra`(详情主接口常不含 sprint 字段,禁止据此判失败):
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /projex/api/workitem/workitem/{id}/extra?_input_charset=utf-8
|
||||||
|
→ result.sprint[].identifier / name
|
||||||
|
```
|
||||||
|
|
||||||
|
产品规则:**只挂【交付】**;需求 / 分析 / 设计默认不挂(除非口令显式)。
|
||||||
|
|
||||||
|
### 极速建单注意
|
||||||
|
|
||||||
|
1. Cookie 只刷一次;全程纯 HTTP,默认**不开浏览器**。
|
||||||
|
2. 交付建完后,【分析】与【设计】**并行**创建(均 TASK_SUB→交付);标准/快轨两树可并行。
|
||||||
|
3. 状态用 `transit` + **本地追踪 fromStatus**(禁止每次 GET);负责人在交棒场景下**创建时即何斐**。
|
||||||
|
4. 建单 `fieldValueList` 可带计划开始 `79`;**不要**在 create 同时写 `79+80`(同日会 400)。
|
||||||
|
5. 标签必须 PATCH(create 带 tag 不落库);可与建子任务重叠;快轨交付/设计须与需求同标签。
|
||||||
|
6. `requests.Session` keep-alive;**禁止**对共享 opener 加全局锁。
|
||||||
|
7. 脚本入口:`scripts/live_create_fast.py`(v5:快轨描述/计划/标签/工时 2+2/设计 ASSOCIATED 补挂)。
|
||||||
59
.claude/skills/YunxiaoPM/references/live-perf-2026-07-23.md
Normal file
59
.claude/skills/YunxiaoPM/references/live-perf-2026-07-23.md
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
# 2026-07-23 真实建单复盘与极速优化
|
||||||
|
|
||||||
|
## 测试结论
|
||||||
|
|
||||||
|
标准 + 快轨均可建到「待开发」交棒;交付树、标签「故障管理」、快轨无【分析】均正确。
|
||||||
|
|
||||||
|
| 轮次 | 编号 |
|
||||||
|
|---|---|
|
||||||
|
| 第一轮(探测+UI) | ONEOS-141~147 |
|
||||||
|
| 极速 v1 | ONEOS-148~154 |
|
||||||
|
| 极速 v2 | ONEOS-164~177(含中间探针) |
|
||||||
|
|
||||||
|
## 过程问题(已修)
|
||||||
|
|
||||||
|
| # | 问题 | 根因 | 修复 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 1 | 状态改不动 / 假成功 | 误用 `updateStatus`;UI 点列表区 | `POST …/status/transit` |
|
||||||
|
| 2 | 负责人改不成 | `updateFieldValue` 错 | `PATCH …/{id}` + `assignedTo` |
|
||||||
|
| 3 | 状态 ID 不全 | 未抓网络 | 写入 `runtime-ids.json` |
|
||||||
|
| 4 | 极慢 | Playwright + 串行探测 | 纯 HTTP + 并行 |
|
||||||
|
| 5 | v1 仍偏慢 | 多余 GET、串行 PATCH 计划、交棒再改负责人 | 见下节 v2 |
|
||||||
|
|
||||||
|
## 性能对比
|
||||||
|
|
||||||
|
| 口径 | 优化前(第一轮) | 极速 v1 | 极速 v2(本轮) |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 会话墙钟 | ≈ **17.9 分钟** | — | — |
|
||||||
|
| 两路径并行建单墙钟 | ≈4.1 分钟自动化 | **4.4 s** | **2.2 s** |
|
||||||
|
| 标准单路径 | 失败反复 | 3.7 s | **2.2 s** |
|
||||||
|
| 快轨单路径 | 失败反复 | 3.7 s | **2.1 s** |
|
||||||
|
| 浏览器 | 多次 | 无 | 无 |
|
||||||
|
|
||||||
|
相对第一轮会话 ≈ **490×**;相对 v1 再快约 **2×**。
|
||||||
|
|
||||||
|
## v2 压榨点(已落地)
|
||||||
|
|
||||||
|
1. `status/transit` **本地追踪** `fromStatus`,跳过每次 GET。
|
||||||
|
2. 建单 `fieldValueList` 带**计划开始(79)**;计划完成不在 create 写(同日会 400)。
|
||||||
|
3. 【交付】创建时负责人直接 **何斐**(省 PATCH)。
|
||||||
|
4. `requests.Session` keep-alive;**去掉全局锁**(否则并行失效)。
|
||||||
|
5. 打标签与建子任务 **重叠**;两路径并行。
|
||||||
|
6. 交棒后汇总用创建响应,校验 GET 移出主路径计时。
|
||||||
|
|
||||||
|
## 探针结论(未采用)
|
||||||
|
|
||||||
|
| 尝试 | 结果 |
|
||||||
|
|---|---|
|
||||||
|
| create `fieldValueList` 带 tag | 建单成功但标签不落库 → 仍须 PATCH |
|
||||||
|
| create 同时写 79+80 | `400 计划…转化异常` |
|
||||||
|
| urllib 全局 lock + 单 opener | 并行被串行化,单路径 ≈4 s |
|
||||||
|
|
||||||
|
## 仍可再压(收益变小)
|
||||||
|
|
||||||
|
1. 标签 API 若将来支持 create 落库,可再少 2~4 次 PATCH。
|
||||||
|
2. HTTP/2 或连接预热(DNS/TLS 复用到进程级)。
|
||||||
|
3. 业务允许「建单即待开发」且平台支持初始状态 → 少 2 次 transit。
|
||||||
|
4. 计划完成改为交棒后异步补写(当前故意跳过)。
|
||||||
|
|
||||||
|
脚本:`scripts/live_create_fast.py`(mode=`live_create_fast_v2`)。
|
||||||
53
.claude/skills/YunxiaoPM/references/make-export-attach.md
Normal file
53
.claude/skills/YunxiaoPM/references/make-export-attach.md
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# Make 导出与截图附件
|
||||||
|
|
||||||
|
设计完成(步骤 4)且已关联原型页时:需求与【交付】均挂附件。任一侧失败 → 不得声称设计完成附件齐全。
|
||||||
|
|
||||||
|
## 1. 导出 HTML(含源码)ZIP
|
||||||
|
|
||||||
|
与 Make「发布 → 导出 HTML(含源码)」对齐。
|
||||||
|
|
||||||
|
优先本地 Make Admin:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET {adminOrigin}/api/export-html?path={prototypePath}&projectId={projectId}&includeSource=true
|
||||||
|
```
|
||||||
|
|
||||||
|
| 参数 | 要求 |
|
||||||
|
|---|---|
|
||||||
|
| `path` | 原型路径(如 `prototypes/oneos-h5-vehicle-assets`) |
|
||||||
|
| `includeSource` | **必须** `true` |
|
||||||
|
| 响应 | ZIP(`PK` 头);文件名建议 `{prototype-id}-html-source.zip` |
|
||||||
|
|
||||||
|
失败时:提示用户在 Make 客户端对该原型执行「发布 → 导出 HTML(含源码)」,把 ZIP 路径发回。
|
||||||
|
**禁止**用「仅对象存储链接」冒充已附带源码包。
|
||||||
|
|
||||||
|
## 2. 复制截图(全交互页)
|
||||||
|
|
||||||
|
1. Make「发布 → **复制截图**」(或等价:导出该原型主界面及所有交互页截图)。
|
||||||
|
2. 上传到需求附件与【交付】附件。
|
||||||
|
3. 缺页/失败 → 列出缺项,不得报成功。
|
||||||
|
|
||||||
|
## 3. 挂载范围
|
||||||
|
|
||||||
|
同一 ZIP / 同一批截图:
|
||||||
|
|
||||||
|
1. 上传到需求 identifier
|
||||||
|
2. 上传到【交付】任务 identifier
|
||||||
|
|
||||||
|
优先 API;未知 upload 端点时用已登录浏览器在详情页「附件」上传。
|
||||||
|
|
||||||
|
## 4. 与对象存储的关系
|
||||||
|
|
||||||
|
| 产物 | 用途 |
|
||||||
|
|---|---|
|
||||||
|
| `{baseUrl}/{id}/index.html` | AutoPRD 描述内可点预览链接 |
|
||||||
|
| 导出 ZIP(含源码) | 附件,供开发离线打开 |
|
||||||
|
| 交互页截图 | 附件,供评审/开发对照 |
|
||||||
|
|
||||||
|
三者职责不同,不可互相替代。
|
||||||
|
|
||||||
|
## 负向
|
||||||
|
|
||||||
|
- 不得导出错误原型页(须 Plan 确认原型路径/名称)。
|
||||||
|
- 不得把别的需求的旧 ZIP 复用到新需求。
|
||||||
|
- 快轨交棒默认不跑本附件流程(除非口令同时设计完成+原型)。
|
||||||
60
.claude/skills/YunxiaoPM/references/model.md
Normal file
60
.claude/skills/YunxiaoPM/references/model.md
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
# 交付树模型与关联约定
|
||||||
|
|
||||||
|
## 真相源
|
||||||
|
|
||||||
|
```text
|
||||||
|
需求状态 = 阶段看板唯一真相(分析中/设计中/待开发…)
|
||||||
|
【交付】任务 = 该需求的交付容器(每需求最多 1 条)
|
||||||
|
【分析】/【设计】 = YunxiaoPMapp 在交付下建的阶段子项
|
||||||
|
【开发】/【测试】 = 另属开发 Skill / 测试 Skill,不进本包
|
||||||
|
ASSOCIATED = 横向挂钩(【交付】 ↔ 需求)
|
||||||
|
SUB / TASK_SUB = 纵向拆解(交付 → 分析/设计)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 关系验收
|
||||||
|
|
||||||
|
| 关系 | 用在哪里 | 验收 | 优先级 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| ASSOCIATED | **仅【交付】** ↔ 需求 | 交付详情「关联项」能看到需求(**强制**) | 交付必过 |
|
||||||
|
| TASK_SUB | 【分析】/【设计】 → 【交付】 | 交付详情「子项」能看到阶段任务(**强制**) | 阶段任务必过 |
|
||||||
|
|
||||||
|
建单规则(Cookie 路径 · 同一 create 只能一条 `createWorkitemRelationInfo`):
|
||||||
|
|
||||||
|
| 对象 | `createWorkitemRelationInfo` | 另写字段 |
|
||||||
|
|---|---|---|
|
||||||
|
| 【交付】 | `ASSOCIATED` → 需求 | — |
|
||||||
|
| 【分析】/【设计】 | `TASK_SUB` → 交付 | `parent` + `parentIdentifier` = 交付 |
|
||||||
|
|
||||||
|
**禁止**对分析/设计只写 `parentIdentifier` + `ASSOCIATED→需求`:关联项可能有,但交付「子项」仍为空(ONEOS-246/247 已复现)。
|
||||||
|
勿用 `PARENT` 冒充关联项。细则见 [live-api.md](live-api.md)。
|
||||||
|
|
||||||
|
## 禁止
|
||||||
|
|
||||||
|
| 禁止 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| 创建或描述【开发】/【测试】 | 口令与回报均不出现 |
|
||||||
|
| 分析/设计未挂成交付子项(无 TASK_SUB) | 交付「子项」为 0,交棒验收失败 |
|
||||||
|
| 用任务名称/标题做唯一性或查重 | 不得 `subject` 匹配复用 |
|
||||||
|
| 同一需求认定多个交付任务编号 | 列出编号请人合并后再继续 |
|
||||||
|
| 功能模块标签用「分析/设计/交付」 | 模块标签打在需求(可选交付)上 |
|
||||||
|
|
||||||
|
## 任务标题(仅展示)
|
||||||
|
|
||||||
|
- 【交付】+ 需求标题
|
||||||
|
- 【分析】+ 需求标题
|
||||||
|
- 【设计】+ 需求标题
|
||||||
|
|
||||||
|
标题可改,**不参与查重**。
|
||||||
|
|
||||||
|
## 任务编号唯一性
|
||||||
|
|
||||||
|
**唯一允许的查重/复用渠道:云效任务编号**(如 `ONEOS-99` / `serialNumber`)。
|
||||||
|
|
||||||
|
| 场景 | 正确 | 错误 |
|
||||||
|
|---|---|---|
|
||||||
|
| 首次创建【交付】 | 建单成功后回报并写入「工作项编号(系统)」 | 下次用标题搜 |
|
||||||
|
| 复用【交付】 | 口令或编号区块带 `交付任务=ONEOS-xx` | list 后按 subject 相等 |
|
||||||
|
| 判断是否已有交付 | 编号区块或交付 ASSOCIATED 编号集合 | 数【交付】开头标题 |
|
||||||
|
| 分析/设计幂等 | 仅已登记编号 | 按【分析】+需求标题 |
|
||||||
|
|
||||||
|
按编号命中则复用;**计划开始已有值禁止改写**。
|
||||||
35
.claude/skills/YunxiaoPM/references/number-push.md
Normal file
35
.claude/skills/YunxiaoPM/references/number-push.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# 编号直推到待开发
|
||||||
|
|
||||||
|
适用:标准路径已建过【分析】和/或【设计】,用**任务编号**一口气推到待开发交棒。
|
||||||
|
|
||||||
|
## 入口(只认编号)
|
||||||
|
|
||||||
|
```text
|
||||||
|
交棒开发:需求=ONEOS-xx;交付任务=ONEOS-a;分析任务=ONEOS-b;设计任务=ONEOS-c
|
||||||
|
交棒开发:分析任务=ONEOS-b → 由分析 ASSOCIATED/SUB 反查需求与交付
|
||||||
|
交棒开发:设计任务=ONEOS-c → 同上反查
|
||||||
|
```
|
||||||
|
|
||||||
|
禁止用标题猜。编号对不上关联树 → 停下列出关联,不瞎改。
|
||||||
|
|
||||||
|
## 动作表
|
||||||
|
|
||||||
|
| 对象 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| 需求 | 状态 → **待开发**(按云效连跳) |
|
||||||
|
| 【交付】 | **必须**用交付任务编号定位;负责人→何斐;不改计划开始;不写计划完成;描述仍占位则保持(除非同时设计完成+原型+AutoPRD) |
|
||||||
|
| 【分析】 | 若有编号:计划完成若为空 → 写当日并推工时;**不新建**第二条 |
|
||||||
|
| 【设计】 | 若有编号:计划完成若为空 → 写当日并推工时;**不新建**第二条 |
|
||||||
|
| 仅有分析、尚无设计 | **不强制补建【设计】**(与无单快轨区分);回报注明「无设计任务编号」 |
|
||||||
|
| 仅有设计、无分析 | 收口设计 + 交棒;**不补建分析** |
|
||||||
|
|
||||||
|
## 与无单快轨区别
|
||||||
|
|
||||||
|
| | 无单快轨 | 编号直推 |
|
||||||
|
|---|---|---|
|
||||||
|
| 前提 | 尚无分析/设计阶段单(或明确跳过分析) | 已有分析和/或设计**任务编号** |
|
||||||
|
| 【分析】 | 禁止创建 | 有编号则收口,无则不建 |
|
||||||
|
| 【设计】 | 必须新建且当日收口 | 有编号则收口;仅分析无设计时不强制新建 |
|
||||||
|
| 定位 | 新建后登记编号 | **仅任务编号**定位/反查 |
|
||||||
|
|
||||||
|
仍不创建【开发】/【测试】。交棒占位风险见 [handoff-and-rollback.md](handoff-and-rollback.md)。
|
||||||
73
.claude/skills/YunxiaoPM/references/project-selection.md
Normal file
73
.claude/skills/YunxiaoPM/references/project-selection.md
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
# 门禁 PJ · 云效项目选择(强制点选)
|
||||||
|
|
||||||
|
凡 **新建需求 / 新建任务树 / 创建迭代 / 其它写入依赖 `spaceIdentifier`** 的操作,项目必须由用户从云效实时列表**点选**。禁止静默使用 `runtime-ids.json` 里的默认 `project.spaceIdentifier`。
|
||||||
|
|
||||||
|
## 何时触发
|
||||||
|
|
||||||
|
| 场景 | 是否必须选项目 |
|
||||||
|
|---|---|
|
||||||
|
| 记录需求 / 无单快轨新建 | **必须** |
|
||||||
|
| 创建迭代(新挂项目空间) | **必须**(与需求同项目时沿用已锁定项,仍须在 Plan 写出项目名+ID) |
|
||||||
|
| 仅推进已有编号(受理确认、开始分析…) | **不必重选**;以该编号所在项目为准,Plan 写出项目名 |
|
||||||
|
| 只读查询 | 不强制 |
|
||||||
|
|
||||||
|
## 执行顺序(建单前)
|
||||||
|
|
||||||
|
1. **实时拉取**云效项目列表(Cookie + XSRF):
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /projex/api/workspace/project/search/list
|
||||||
|
?category=Project&scope=all&toPage=1&pageSize=100
|
||||||
|
&conditions={"conditionGroups":[[]]}
|
||||||
|
&extraConditions=…(可与页面一致:当前用户参与 + public)
|
||||||
|
&orderBy={"fieldIdentifier":"gmtCreate","format":"input","order":"desc","className":"date"}
|
||||||
|
&_input_charset=utf-8
|
||||||
|
```
|
||||||
|
|
||||||
|
2. 将结果整理为单选列表:`{name}({customCode})`;选项 id 用 `identifier`(spaceId)。
|
||||||
|
3. **AskQuestion / Plan 单选**「PJ. 云效项目」;未点选 → **禁止 create**。
|
||||||
|
4. 「批准 Plan」≠ 已选项目;Plan 里仍是空选项或写「默认 01_ONEOS」而未点选 → 停。
|
||||||
|
5. 用户点选后:本轮 apply 全程使用该 `spaceIdentifier`;回报写清项目名 + customCode + spaceId。
|
||||||
|
6. 拉取成功后可回写 `assets/runtime-ids.json` → `projects_catalog`(缓存);**缓存不得当作已选项**。
|
||||||
|
|
||||||
|
## 无法对应 → 自动重拉一次
|
||||||
|
|
||||||
|
「无法对应」任一成立即触发:
|
||||||
|
|
||||||
|
| # | 情形 |
|
||||||
|
|---|---|
|
||||||
|
| 1 | 口令/预填的项目名、customCode、别名在**当前列表**中 0 命中 |
|
||||||
|
| 2 | 口令给出的 spaceId / identifier 不在当前列表 |
|
||||||
|
| 3 | 用户点选的选项 id 在 apply 前校验时已不在列表(列表过期) |
|
||||||
|
| 4 | 仅命中 `projects_catalog` 缓存、与本次实时列表不一致 |
|
||||||
|
| 5 | 首次拉取失败后改用了缓存,用户按缓存点选后 create 报项目/空间无效 |
|
||||||
|
|
||||||
|
**动作(固定一次):**
|
||||||
|
|
||||||
|
1. **立即再调一次**同一 `project/search/list`(强制网络,不用缓存)。
|
||||||
|
2. 用新列表重新做匹配 / 刷新 Plan 单选选项;可回写 `projects_catalog`。
|
||||||
|
3. 回报注明:`已自动重拉项目列表(因无法对应)`。
|
||||||
|
4. **仍无法对应** → 停,展示最新列表请用户重选;**禁止**再自动拉第 3 次;**禁止**猜一个 spaceId 继续建单。
|
||||||
|
|
||||||
|
匹配规则(名/码):忽略大小写;`name` 全等或包含;`customCode` 全等;`name_aliases` 全等。多命中视为无法唯一对应 → 重拉后仍多命中则请用户点选,不自动选定。
|
||||||
|
|
||||||
|
## 禁止
|
||||||
|
|
||||||
|
- 未询问就写入 `project.spaceIdentifier`(即便 catalog 标了 `suggested`)
|
||||||
|
- 按口令里的「统一运营管理平台」字符串静默映射而不展示列表点选(口令仅作**预填建议**,仍须用户确认点选)
|
||||||
|
- API 失败时擅自沿用上次默认;应展示 `projects_catalog` 缓存并标明「离线缓存,请确认」,仍须点选;用户确认后若仍无法对应 → 走上一节「自动重拉一次」
|
||||||
|
- 多项目并行建单却共用一个未确认的 spaceId
|
||||||
|
- 「无法对应」时循环重拉超过 1 次,或跳过点选直接建单
|
||||||
|
|
||||||
|
## 口令预填
|
||||||
|
|
||||||
|
```text
|
||||||
|
记录需求:…;项目=01_ONEOS;…
|
||||||
|
```
|
||||||
|
|
||||||
|
若口令已含项目名/编号前缀且在实时列表中**唯一命中**:Plan 可预勾该选项,但仍须用户确认;0 命中或多命中 → **先自动重拉一次**再匹配;仍 0/多 → 不预勾,只展示最新列表。
|
||||||
|
|
||||||
|
## 脚本
|
||||||
|
|
||||||
|
`scripts/list_projects.py`:stdout JSON `projects[]`。
|
||||||
|
带查询时:`python3 scripts/list_projects.py --match '01_ONEOS'` —— 0 命中/多命中则自动重拉一次再匹配(`refetched: true`)。
|
||||||
58
.claude/skills/YunxiaoPM/references/record-meta-fields.md
Normal file
58
.claude/skills/YunxiaoPM/references/record-meta-fields.md
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# 记录需求 · 元字段(优先级 / 标签 / 提交部门 / 提交人)
|
||||||
|
|
||||||
|
建单前消费网页 / AutoRDO / 口令中的四类元信息。细则与 `assets/runtime-ids.json` 对齐;**禁止臆造未验证的 fieldIdentifier**。
|
||||||
|
|
||||||
|
## 口令形态
|
||||||
|
|
||||||
|
```text
|
||||||
|
记录需求:…;优先级=紧急|高|中|低;标签=…;提交部门=…;提交人=…;推进至=…
|
||||||
|
```
|
||||||
|
|
||||||
|
四字段均可选出现;网页或 AutoRDO 提示里已带的值与口令等价。
|
||||||
|
|
||||||
|
## Plan 是否追问
|
||||||
|
|
||||||
|
记录需求 **一律**走 [compact-select.md](compact-select.md) 字母表(类型/项目/优先级/标签),即使用户口令已写齐;给出建议压缩串,等用户回 `1a2b3a4d`(或改字母)并「执行」。
|
||||||
|
|
||||||
|
| 条件 | 行为 |
|
||||||
|
|---|---|
|
||||||
|
| 口令已含类型/项目/优先级/标签 | 对应选项标 ★ + 建议压缩串;**仍须**压缩确认或显式点选 |
|
||||||
|
| 标签名 0 命中 / 多命中 | **自动重拉一次**标签候选并重生 4.A/B/C…;仍失败则停 |
|
||||||
|
| 仅缺提交部门/提交人 | 压缩 1–4 确认后,缺则追问或写入描述页脚 |
|
||||||
|
| 仅缺「推进至」等 | 按既有口令规则;可作 5. 题字母表 |
|
||||||
|
|
||||||
|
## 写入策略
|
||||||
|
|
||||||
|
### 优先级(已验证)
|
||||||
|
|
||||||
|
- 映射:`runtime-ids.json` → `priority`(紧急 / 高 / 中 / 低)。
|
||||||
|
- create 时写入 `fieldIdentifier: "priority"`(与 [live-api.md](live-api.md) / `live_create_fast.py` 一致)。
|
||||||
|
- 未给优先级时:Plan 追问;脚本默认「中」仅作既有兜底,口令/网页有值时以用户值为准。
|
||||||
|
|
||||||
|
### 标签(已验证)
|
||||||
|
|
||||||
|
- 映射:`runtime-ids.json` → `tags`(按显示名取 tagId)。
|
||||||
|
- 标签须 **PATCH** `propertyKey: "tag"`(create 带 tag 不落库)。
|
||||||
|
- 口令/网页给出的标签名若不在候选:按 [compact-select.md](compact-select.md) **自动重拉一次**标签列表并重生选项;仍无则停在 Plan,勿猜 ID。
|
||||||
|
|
||||||
|
### 提交部门 / 提交人(已验证 · 2026-07-27 · ONEOS-293)
|
||||||
|
|
||||||
|
| 字段 | fieldIdentifier |
|
||||||
|
|---|---|
|
||||||
|
| 提交部门 | `3132597a9718d1c282b7ba5a0c` |
|
||||||
|
| 提交人 | `9e01269e96f91fbb97d36bf5b3` |
|
||||||
|
|
||||||
|
| 规则 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| **写入** | `POST /projex/api/workitem/workitem/field/value/{workitemId}`,`Content-Type: application/x-www-form-urlencoded`,参数 `fieldValueList` = JSON 数组字符串 `[{"fieldIdentifier","value"}]` |
|
||||||
|
| **形态** | 均为普通文本 input(非人员选择器);口令值原样写入 |
|
||||||
|
| **页脚** | 仍可在描述页脚重复一份,便于检索;**不能替代**字段写入 |
|
||||||
|
| **计划开始** | 字段 `79`,同一 `field/value` API;推荐 `YYYY-MM-DD 12:00:00`。快轨:【交付】/【设计】创建当日写入;【设计】另写计划完成 `80`=`当日 23:59:59` |
|
||||||
|
| **预计工时** | 字段 `101586` **禁止**直接 PATCH;用 `POST …/time/estimate`(`spentTime`)登记;删多余用 `DELETE …/time/estimate/{workitemId}/{estimateId}` |
|
||||||
|
| **实际工时** | `POST …/workitem/time`,body **`actualTime`**(非 spentTime)+ `gmtStart`/`gmtEnd`(epoch ms 字符串);快轨待开发需求默认 **2** |
|
||||||
|
| **描述更新** | `PATCH …/workitem/{id}/document`,`{"content","formatType":"RICHTEXT"}` |
|
||||||
|
| **快轨标签** | 【交付】【设计】建单后 `PATCH propertyKey=tag`,`propertyValue` 与需求 tagId 一致(多标签逗号拼接) |
|
||||||
|
|
||||||
|
## 与描述双段的关系
|
||||||
|
|
||||||
|
页脚元信息写在「原始诉求」段末或整篇描述末尾均可,**不得覆盖** `## 产品说明(AutoPRD)` / `## 工作项编号(系统)` 区块(见 [description-split.md](description-split.md))。
|
||||||
63
.claude/skills/YunxiaoPM/references/sprint.md
Normal file
63
.claude/skills/YunxiaoPM/references/sprint.md
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# 创建迭代并关联交付
|
||||||
|
|
||||||
|
产品经理可将已交棒(或已有编号)的多条【交付】任务打进同一云效迭代。
|
||||||
|
|
||||||
|
## 口令
|
||||||
|
|
||||||
|
```text
|
||||||
|
创建迭代:版本类型=副;交付任务=ONEOS-a,ONEOS-b,ONEOS-c;名称前缀=统一运营管理平台PC端
|
||||||
|
创建迭代:版本类型=子;交付任务=ONEOS-99;名称前缀=统一运营管理平台PC端
|
||||||
|
```
|
||||||
|
|
||||||
|
| 参数 | 规则 |
|
||||||
|
|---|---|
|
||||||
|
| 交付任务 | **1..N 个任务编号**(逗号分隔);禁止用标题凑数 |
|
||||||
|
| 版本类型 | 主 / 副 / 子;未点选则停下询问,禁止默认猜 |
|
||||||
|
| 名称前缀 | 可选;缺省 `统一运营管理平台PC端`。最终名=`{前缀}{版本号}` |
|
||||||
|
|
||||||
|
## 版本号 `V{主}.{副}.{子}`
|
||||||
|
|
||||||
|
| 版本类型 | 含义 | 递增 |
|
||||||
|
|---|---|---|
|
||||||
|
| **主** | 功能重制 | 主+1,副→0,子→0(V1.3.2→V2.0.0) |
|
||||||
|
| **副** | 新功能上线 | 副+1,子→0(V1.3.2→V1.4.0) |
|
||||||
|
| **子** | bug/优化 | 子+1(V1.3.2→V1.3.3) |
|
||||||
|
|
||||||
|
### 取基线再递增
|
||||||
|
|
||||||
|
1. 拉取当前项目云效迭代列表。
|
||||||
|
2. 从迭代**名称**解析 `V数字.数字.数字`;旧名 `V数字.数字` 视为 `.0`。
|
||||||
|
3. 同名称前缀内取**最大**版本为基线(主→副→子比较);避免 PC 与小程序串号。
|
||||||
|
4. 按用户点选类型递增,写入新迭代名称。
|
||||||
|
5. 无一可解析版本:基线 `V0.0.0` 再递增(主→V1.0.0,副→V0.1.0,子→V0.0.1);或口令显式给起始版本。
|
||||||
|
|
||||||
|
禁止:手填与规则冲突的版本号却声称自动生成;禁止用交付标题推断版本类型。
|
||||||
|
|
||||||
|
## 创建与关联
|
||||||
|
|
||||||
|
| 步骤 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| 1 | 算出新版本 → 拼迭代全名 |
|
||||||
|
| 2 | 创建迭代(起止日期口令未给则询问或用项目默认,禁止瞎填) |
|
||||||
|
| 3 | **只挂【交付】**:N 个交付任务挂迭代;交付失败不得报完成 |
|
||||||
|
| 4 | 幂等:同名迭代已存在 → 不新建,补挂尚未关联的交付,回报「复用迭代」 |
|
||||||
|
| 5 | 回报:迭代名、版本号、identifier、已关联交付编号、失败编号 |
|
||||||
|
|
||||||
|
**禁止**把需求挂进迭代(需求侧「迭代」字段保持空)。不挂【分析】/【设计】除非口令显式点名。
|
||||||
|
**不**在本步创建【开发】/【测试】。仍须 Plan 门禁。
|
||||||
|
|
||||||
|
### 挂接 API(已通 · 校验走 `/extra`)
|
||||||
|
|
||||||
|
```http
|
||||||
|
PATCH /projex/api/workitem/workitem/{交付id}?_input_charset=utf-8
|
||||||
|
{"workitemIdentifier":"{交付id}","propertyKey":"sprint","propertyValue":"{sprintId}","operateType":"COVER"}
|
||||||
|
```
|
||||||
|
|
||||||
|
校验(详情主接口**不**含 sprint,勿用其判空):
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /projex/api/workitem/workitem/{id}/extra?_input_charset=utf-8
|
||||||
|
→ result.sprint[].identifier
|
||||||
|
```
|
||||||
|
|
||||||
|
清空误挂的需求迭代:同上 PATCH,`propertyValue:""` + `operateType:"COVER"`(或 `CLEAR`)。
|
||||||
63
.claude/skills/YunxiaoPM/references/stage-flow.md
Normal file
63
.claude/skills/YunxiaoPM/references/stage-flow.md
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# 标准路径:待处理 → 待开发交棒
|
||||||
|
|
||||||
|
人员/状态等常量见 [../assets/runtime-ids.json](../assets/runtime-ids.json)。**项目空间**须按 [project-selection.md](project-selection.md) 点选,禁止默认直指。查重只用任务编号。
|
||||||
|
|
||||||
|
## 步骤 0|创建需求
|
||||||
|
|
||||||
|
| 云效动作 | 落地 |
|
||||||
|
|---|---|
|
||||||
|
| 新建产品类需求 | POST 建单;标题 `【新增】`/`【优化】` |
|
||||||
|
| 需求描述 | **先** AutoRDO 清洗再写入 `## 原始诉求(AutoRDO)`;本步不写 AutoPRD |
|
||||||
|
| 默认状态 | **待处理**;不建任务、不改负责人 |
|
||||||
|
| 可选推进 | 口令点选目标状态;未选则停在待处理 |
|
||||||
|
|
||||||
|
## 步骤 1|受理 → 已确认
|
||||||
|
|
||||||
|
| 云效动作 | 落地 |
|
||||||
|
|---|---|
|
||||||
|
| 状态 | 待处理 → **已确认** |
|
||||||
|
| 任务 | **仍不建**交付/分析/设计 |
|
||||||
|
|
||||||
|
若用户只「创建」未受理:只提示「受理后请推进至已确认」,不自动跳。
|
||||||
|
|
||||||
|
## 步骤 2|分析中
|
||||||
|
|
||||||
|
| 对象 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| 【交付】 | 无则新建;标题 `【交付】`+需求标题;**ASSOCIATED→需求**(勿用 PARENT);负责人=创建人/产品;**计划开始仅空时写当日**;不写计划完成;描述=`等待设计任务完成后自动填入`;更新编号区块 |
|
||||||
|
| 【分析】 | 新建;**TASK_SUB→交付**(`parent`+`parentIdentifier`+`createWorkitemRelationInfo=TASK_SUB`);交付「子项」须可见;计划开始=当日(仅空时);负责人默认可=创建人;更新编号区块 |
|
||||||
|
|
||||||
|
| 需求 | 状态=`分析中` |
|
||||||
|
|
||||||
|
## 步骤 3|设计中
|
||||||
|
|
||||||
|
| 对象 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| 【交付】 | 已存在则按编号复用;没有则补建;**不改交付计划开始**;不写交付计划完成 |
|
||||||
|
| 【设计】 | 新建;**TASK_SUB→交付**(同分析);计划开始=当日(仅空时);更新编号区块 |
|
||||||
|
| 【分析】 | **计划完成**=状态更新日;推算阶段日历工时(见 work-hours) |
|
||||||
|
| 需求 | 状态=`设计中` |
|
||||||
|
|
||||||
|
## 步骤 4|设计完成
|
||||||
|
|
||||||
|
| 对象 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| 【设计】 | 计划完成=当日;推算工时;任务→完成态 |
|
||||||
|
| 需求 | AutoPRD 写入 `## 产品说明`;挂 ZIP+截图;状态=`设计完成` |
|
||||||
|
| 【交付】 | 不换负责人;不改计划开始;不写计划完成;描述改为 AutoPRD 正文;同样挂附件 |
|
||||||
|
|
||||||
|
顺序与失败门禁见 [description-split.md](description-split.md)。
|
||||||
|
|
||||||
|
## 步骤 5|待开发交棒(本 Skill 终点 · 标准路径)
|
||||||
|
|
||||||
|
| 对象 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| 需求 | 状态=`待开发` |
|
||||||
|
| 【交付】 | 按**任务编号**定位;**负责人→何斐**;不改计划开始;不写计划完成 |
|
||||||
|
| 【分析】/【设计】 | 不新建;不改已有计划开始;前序未收口按步骤 3/4 处理 |
|
||||||
|
|
||||||
|
执行 [handoff-and-rollback.md](handoff-and-rollback.md) §交棒门禁。
|
||||||
|
|
||||||
|
**不做:** 【开发】/【测试】、仓库、分支、提测。
|
||||||
|
|
||||||
|
快轨 / 编号直推见专文。创建迭代见 [sprint.md](sprint.md)。
|
||||||
73
.claude/skills/YunxiaoPM/references/work-hours.md
Normal file
73
.claude/skills/YunxiaoPM/references/work-hours.md
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
# 计划时间与阶段日历工时
|
||||||
|
|
||||||
|
适用于【交付】/【分析】/【设计】统一口径。
|
||||||
|
|
||||||
|
## 用途
|
||||||
|
|
||||||
|
| 对象 | 计划开始→计划完成 |
|
||||||
|
|---|---|
|
||||||
|
| 【交付】 | 需求开工→上线全周期(本 Skill **不**写交付计划完成;上线由后续段) |
|
||||||
|
| 【分析】 | 分析阶段时长 |
|
||||||
|
| 【设计】 | 设计阶段时长 |
|
||||||
|
|
||||||
|
## 计划开始(不可篡改)
|
||||||
|
|
||||||
|
| 对象 | 首次写入 | 之后 |
|
||||||
|
|---|---|---|
|
||||||
|
| 【交付】 | 首次进入分析中且字段为空 → 当日 | **禁止覆盖** |
|
||||||
|
| 【分析】 | 首次创建且为空 → 当日 | **禁止覆盖** |
|
||||||
|
| 【设计】 | 首次创建且为空 → 当日 | **禁止覆盖** |
|
||||||
|
|
||||||
|
日期写入形态:中国时区正午 epoch ms 字符串,见 [../assets/runtime-ids.json](../assets/runtime-ids.json) `fields.plan_start`。
|
||||||
|
|
||||||
|
## 计划完成
|
||||||
|
|
||||||
|
| 环节 | 写计划完成的对象 |
|
||||||
|
|---|---|
|
||||||
|
| 推进到设计中 | 【分析】= 状态更新日 |
|
||||||
|
| 推进到设计完成 | 【设计】= 状态更新日 |
|
||||||
|
| 无单快轨建设计 | 【设计】= 当日(同轮收口) |
|
||||||
|
| 编号直推收口 | 口令涉及的分析/设计若计划完成为空 → 当日 |
|
||||||
|
| 上线/关闭 | 【交付】计划完成(**本 Skill 暂不写**) |
|
||||||
|
|
||||||
|
## 预计工时 = 阶段日历工时(Lead Time)
|
||||||
|
|
||||||
|
有计划完成且已有计划开始时,写入该对象云效「预计工时」:
|
||||||
|
|
||||||
|
```text
|
||||||
|
workdays = 0
|
||||||
|
从计划开始日到计划完成日(含首尾)逐日:
|
||||||
|
周六或周日 → 跳过(除非该日是调休补班)
|
||||||
|
法定放假日 → 跳过
|
||||||
|
调休补班日(含周末上班)→ 计入
|
||||||
|
其余周一~周五 → 计入
|
||||||
|
预计工时(小时) = workdays × 8
|
||||||
|
```
|
||||||
|
|
||||||
|
**禁止**用「(结束日 − 开始日 + 1)× 8」日历天数算法。
|
||||||
|
|
||||||
|
### 语义与脚注(强制)
|
||||||
|
|
||||||
|
- 正式名称:**阶段日历工时**,**不是**投入人天/排期负荷。
|
||||||
|
- 任务描述末尾固定脚注:
|
||||||
|
`【系统】预计工时=阶段日历工时(工作日×8),非人力投入预估`
|
||||||
|
- 回报写「阶段日历工时 Hh」,**禁止**写「需投入 Hh」。
|
||||||
|
- 本 Skill **不自动写**「人力投入预估」。
|
||||||
|
|
||||||
|
### 日历数据源
|
||||||
|
|
||||||
|
- 使用 [../assets/cn-workday-calendar.json](../assets/cn-workday-calendar.json)(按自然年;跨年须覆盖起止两侧年份)。
|
||||||
|
- 缺当年日历 → **停下**提示补日历;**禁止**静默按「仅去周末」算完并报成功。
|
||||||
|
- 计算脚本:[../scripts/workday_hours.py](../scripts/workday_hours.py)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 scripts/workday_hours.py 2026-03-06 2026-03-09
|
||||||
|
```
|
||||||
|
|
||||||
|
缺计划开始则只写结束、不推工时,回报提示。
|
||||||
|
|
||||||
|
## 示例
|
||||||
|
|
||||||
|
- 开始=周五、结束=下周一(无节假日)→ 五+一 → 16h
|
||||||
|
- 区间全在法定放假内 → 0h
|
||||||
|
- 某周日为调休补班且落在区间内 → 该日计入 8h
|
||||||
22
.claude/skills/YunxiaoPM/references/workitem-ids.md
Normal file
22
.claude/skills/YunxiaoPM/references/workitem-ids.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# 工作项编号(系统)
|
||||||
|
|
||||||
|
## 权威源
|
||||||
|
|
||||||
|
需求描述固定区块(机器可解析;人工只读即可):
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 工作项编号(系统)
|
||||||
|
- 交付:ONEOS-xx
|
||||||
|
- 分析:ONEOS-yy(无则写无)
|
||||||
|
- 设计:ONEOS-zz(无则写无)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 规则
|
||||||
|
|
||||||
|
1. **禁止**仅靠本地会话映射当唯一真相。
|
||||||
|
2. 每次新建/登记交付·分析·设计编号后,**立即 PATCH 更新该区块**(只改本区块,不动 AutoRDO / AutoPRD 正文)。
|
||||||
|
3. 操作顺序:口令显式编号 > 读本区块 > ASSOCIATED/SUB 反查校验。
|
||||||
|
4. 三者冲突 → 停下人工;**仍禁止按标题猜**。
|
||||||
|
5. 本地缓存仅加速,启动以云效该区块为准。
|
||||||
|
6. 区块出现两个交付编号 → 停止并列号请人合并。
|
||||||
|
7. 取消需求:关联任务标取消/废止;**不删**本区块(留痕)。
|
||||||
221
.claude/skills/YunxiaoPM/runtime-ids.json
Normal file
221
.claude/skills/YunxiaoPM/runtime-ids.json
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"skill": "YunxiaoPM",
|
||||||
|
"verified_at": "2026-07-25",
|
||||||
|
"note": "YunxiaoPM constants. Project space MUST be user-selected (PJ gate); project.spaceIdentifier is last-known cache only — never auto-apply. See references/project-selection.md.",
|
||||||
|
"project": {
|
||||||
|
"selection_mode": "user_pick_required",
|
||||||
|
"name": null,
|
||||||
|
"name_aliases": [
|
||||||
|
"01_ONEOS",
|
||||||
|
"ONEOS",
|
||||||
|
"统一运营管理平台",
|
||||||
|
"统一运营管理平台PC端",
|
||||||
|
"统一运营管理平台 PC 端"
|
||||||
|
],
|
||||||
|
"spaceIdentifier": null,
|
||||||
|
"customCode": null,
|
||||||
|
"spaceType": "Project",
|
||||||
|
"organizationIdentifier": "697c54a19df7fdfa65466405",
|
||||||
|
"default_sprint_name_prefix": "统一运营管理平台PC端",
|
||||||
|
"list_api": "GET /projex/api/workspace/project/search/list",
|
||||||
|
"last_selected": {
|
||||||
|
"name": "01_ONEOS",
|
||||||
|
"spaceIdentifier": "1280be963a5a2cc126a4118dca",
|
||||||
|
"customCode": "ONEOS",
|
||||||
|
"note": "历史常用项;仅作预填建议,禁止未点选即使用"
|
||||||
|
},
|
||||||
|
"refreshed_at": "2026-07-25"
|
||||||
|
},
|
||||||
|
"projects_catalog": [
|
||||||
|
{
|
||||||
|
"name": "05_羚牛碳资产平台",
|
||||||
|
"identifier": "ff104a3bce09463da136a97999",
|
||||||
|
"customCode": "CARBON"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "06_对外客户项目",
|
||||||
|
"identifier": "baca8b4d676c5af67e475caec0",
|
||||||
|
"customCode": "CUST"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "07_LNBOX",
|
||||||
|
"identifier": "35e1e915a052379bbdfb993aac",
|
||||||
|
"customCode": "LNBOX"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "04_AI应用",
|
||||||
|
"identifier": "d9002ea72c6c3a1a97b02be750",
|
||||||
|
"customCode": "AIAPP"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "03_数据中台",
|
||||||
|
"identifier": "a801cef5c9a68fa051c07432c7",
|
||||||
|
"customCode": "DATA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "02_小羚羚APP",
|
||||||
|
"identifier": "db771a2cca07bed43b369af077",
|
||||||
|
"customCode": "XLLAPP"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "01_ONEOS",
|
||||||
|
"identifier": "1280be963a5a2cc126a4118dca",
|
||||||
|
"customCode": "ONEOS"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "敏捷研发示例项目",
|
||||||
|
"identifier": "65eca0c2e16a23939081e19e14",
|
||||||
|
"customCode": "DEMO"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"people": {
|
||||||
|
"wangmian": {
|
||||||
|
"displayName": "王冕",
|
||||||
|
"identifier": "6811df000601d2fea60144a9",
|
||||||
|
"role": "产品创建人/默认负责人"
|
||||||
|
},
|
||||||
|
"hefei": {
|
||||||
|
"displayName": "何斐",
|
||||||
|
"identifier": "695f0400562f09713f9c3a93",
|
||||||
|
"role": "待开发交棒【交付】负责人"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"故障管理": "ceb526a7343995577645317e9a",
|
||||||
|
"还车应结款": "4204960ce658c94b17abb7c5f6",
|
||||||
|
"工作台": "b62d21beac55c0b43389915eab",
|
||||||
|
"交车管理": "b6947b5aca82a8c759612ba039",
|
||||||
|
"合同管理": "23873be81931cb0dc1bf87a456",
|
||||||
|
"安全培训": "76988b5f73ef515de5930d59b9",
|
||||||
|
"证照管理": "11f4c2ec65901a8f3199c81706",
|
||||||
|
"还车管理": "1e0fce2d6929ff4ac13b310e97"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"req": {
|
||||||
|
"待处理": "100005",
|
||||||
|
"已确认": "32",
|
||||||
|
"分析中": "154395",
|
||||||
|
"设计中": "156603",
|
||||||
|
"设计完成": "307012",
|
||||||
|
"待开发": "1582fc929d429111b925309493"
|
||||||
|
},
|
||||||
|
"task": {
|
||||||
|
"待处理": "100005",
|
||||||
|
"已完成": "100014"
|
||||||
|
},
|
||||||
|
"transit_api": "POST /projex/api/workitem/workitem/{id}/status/transit",
|
||||||
|
"fast_handoff_hops": [
|
||||||
|
"设计完成",
|
||||||
|
"待开发"
|
||||||
|
],
|
||||||
|
"note": "见 references/live-api.md;禁止再用 updateStatus"
|
||||||
|
},
|
||||||
|
"workitem_types": {
|
||||||
|
"product_req": {
|
||||||
|
"name": "产品类需求",
|
||||||
|
"category": "Req",
|
||||||
|
"identifier": "9uy29901re573f561d69jn40"
|
||||||
|
},
|
||||||
|
"task": {
|
||||||
|
"name": "任务",
|
||||||
|
"category": "Task",
|
||||||
|
"identifier": "ba102e46bc6a8483d9b7f25c"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"priority": {
|
||||||
|
"紧急": "646004e97f54bb77fec7b455df",
|
||||||
|
"高": "95b89e0a524d9693e1f335ffe5",
|
||||||
|
"中": "fa155d1214f9f8db222d39db3b",
|
||||||
|
"低": "92924feff9c1085891e7511872"
|
||||||
|
},
|
||||||
|
"fields": {
|
||||||
|
"plan_start": {
|
||||||
|
"fieldIdentifier": "79",
|
||||||
|
"name": "计划开始时间",
|
||||||
|
"value_shape": "YYYY-MM-DD HH:mm:ss China wall time preferred; epoch ms string also accepted",
|
||||||
|
"example": "2026-07-27 12:00:00",
|
||||||
|
"update_api": "POST /projex/api/workitem/workitem/field/value/{workitemId} form fieldValueList=JSON"
|
||||||
|
},
|
||||||
|
"plan_end": {
|
||||||
|
"fieldIdentifier": "80",
|
||||||
|
"name": "计划完成时间",
|
||||||
|
"value_shape": "YYYY-MM-DD HH:mm:ss or epoch ms string",
|
||||||
|
"update_api": "POST /projex/api/workitem/workitem/field/value/{workitemId} form fieldValueList=JSON"
|
||||||
|
},
|
||||||
|
"estimated_hours": {
|
||||||
|
"fieldIdentifier": "101586",
|
||||||
|
"name": "预计工时",
|
||||||
|
"note": "不可直接改字段;须工时预估登记",
|
||||||
|
"create_api": "POST /projex/api/workitem/workitem/time/estimate body spentTime,type,recordUserIdentifier,workitemIdentifier",
|
||||||
|
"delete_api": "DELETE /projex/api/workitem/workitem/time/estimate/{workitemId}/{estimateId}",
|
||||||
|
"list_api": "GET /projex/api/workitem/workitem/time/estimate/list?workitemIdentifier="
|
||||||
|
},
|
||||||
|
"actual_hours": {
|
||||||
|
"name": "实际工时",
|
||||||
|
"note": "快轨待开发默认 2",
|
||||||
|
"create_api": "POST /projex/api/workitem/workitem/time body actualTime,type,recordUserIdentifier,workitemIdentifier,gmtStart,gmtEnd (epoch ms string)",
|
||||||
|
"list_api": "GET /projex/api/workitem/workitem/time/list?workitemIdentifier=",
|
||||||
|
"fast_track_default": 2,
|
||||||
|
"verified_at": "2026-07-27",
|
||||||
|
"verified_on": "ONEOS-293"
|
||||||
|
},
|
||||||
|
"fast_track": {
|
||||||
|
"req_estimated_hours": 2,
|
||||||
|
"req_actual_hours": 2,
|
||||||
|
"design_plan_start_end_same_day": true,
|
||||||
|
"design_description": "copy_req_document",
|
||||||
|
"delivery_description": "manual_sync_or_autoprd",
|
||||||
|
"delivery_design_same_tags_as_req": true,
|
||||||
|
"design_associated_to_req_after_task_sub": true,
|
||||||
|
"document_update_api": "PATCH /projex/api/workitem/workitem/{id}/document {content,formatType:RICHTEXT}"
|
||||||
|
},
|
||||||
|
"submit_department": {
|
||||||
|
"fieldIdentifier": "3132597a9718d1c282b7ba5a0c",
|
||||||
|
"name": "提交部门",
|
||||||
|
"format": "string input",
|
||||||
|
"update_api": "POST /projex/api/workitem/workitem/field/value/{workitemId} form fieldValueList=JSON",
|
||||||
|
"verified_at": "2026-07-27",
|
||||||
|
"verified_on": "ONEOS-293"
|
||||||
|
},
|
||||||
|
"submitter": {
|
||||||
|
"fieldIdentifier": "9e01269e96f91fbb97d36bf5b3",
|
||||||
|
"name": "提交人",
|
||||||
|
"format": "string input",
|
||||||
|
"update_api": "POST /projex/api/workitem/workitem/field/value/{workitemId} form fieldValueList=JSON",
|
||||||
|
"verified_at": "2026-07-27",
|
||||||
|
"verified_on": "ONEOS-293"
|
||||||
|
},
|
||||||
|
"tag": {
|
||||||
|
"fieldIdentifier": "tag",
|
||||||
|
"name": "标签",
|
||||||
|
"propertyKey": "tag"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"assignee_rules": {
|
||||||
|
"待开发_交付任务": "hefei",
|
||||||
|
"分析中_交付与分析": "creator",
|
||||||
|
"设计中_设计": "creator"
|
||||||
|
},
|
||||||
|
"relation": {
|
||||||
|
"delivery_to_req": "ASSOCIATED",
|
||||||
|
"stage_to_delivery": "TASK_SUB",
|
||||||
|
"create_field": "createWorkitemRelationInfo",
|
||||||
|
"forbid": [
|
||||||
|
"PARENT_as_关联项",
|
||||||
|
"ASSOCIATED_only_for_stage_tasks_without_TASK_SUB"
|
||||||
|
],
|
||||||
|
"note": "交付必须 ASSOCIATED→需求。分析/设计默认 TASK_SUB→交付(子项 tab)。二者同 create 互斥。见 references/live-api.md"
|
||||||
|
},
|
||||||
|
"delivery_placeholder": "等待设计任务完成后自动填入",
|
||||||
|
"task_title_prefixes": {
|
||||||
|
"delivery": "【交付】",
|
||||||
|
"analysis": "【分析】",
|
||||||
|
"design": "【设计】"
|
||||||
|
},
|
||||||
|
"publish_url": {
|
||||||
|
"shape": "{baseUrl}/{prototype-id}/index.html",
|
||||||
|
"forbid_prototypes_prefix": true,
|
||||||
|
"require_index_html": true
|
||||||
|
}
|
||||||
|
}
|
||||||
227
.claude/skills/YunxiaoPM/scripts/list_projects.py
Normal file
227
.claude/skills/YunxiaoPM/scripts/list_projects.py
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""拉取云效项目列表(供 YunxiaoPMapp 门禁 PJ 点选)。stdout = JSON。
|
||||||
|
|
||||||
|
无法对应时自动重拉一次:
|
||||||
|
python3 scripts/list_projects.py --match '01_ONEOS'
|
||||||
|
python3 scripts/list_projects.py --match-id 1280be963a5a2cc126a4118dca
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import urllib.parse
|
||||||
|
from datetime import datetime, timedelta, timezone
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
RUNTIME = json.loads((ROOT / "assets" / "runtime-ids.json").read_text())
|
||||||
|
ORG = RUNTIME.get("project", {}).get("organizationIdentifier", "697c54a19df7fdfa65466405")
|
||||||
|
WANG = RUNTIME.get("people", {}).get("wangmian", {}).get("identifier", "6811df000601d2fea60144a9")
|
||||||
|
ALIASES = [a.lower() for a in (RUNTIME.get("project", {}).get("name_aliases") or [])]
|
||||||
|
TZ = timezone(timedelta(hours=8))
|
||||||
|
|
||||||
|
|
||||||
|
def load_jar() -> dict[str, str]:
|
||||||
|
jar: dict[str, str] = {}
|
||||||
|
try:
|
||||||
|
import browser_cookie3
|
||||||
|
|
||||||
|
for domain in (".aliyun.com", "devops.aliyun.com", ".devops.aliyun.com"):
|
||||||
|
try:
|
||||||
|
for c in browser_cookie3.chrome(domain_name=domain):
|
||||||
|
jar[c.name] = c.value
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if not jar.get("XSRF-TOKEN"):
|
||||||
|
p = Path("/tmp/yunxiao_cookies.json")
|
||||||
|
if p.exists():
|
||||||
|
raw = json.loads(p.read_text())
|
||||||
|
jar = (
|
||||||
|
raw
|
||||||
|
if isinstance(raw, dict) and "XSRF-TOKEN" in raw
|
||||||
|
else {c["name"]: c["value"] for c in raw.get("cookies", [])}
|
||||||
|
)
|
||||||
|
if not jar.get("XSRF-TOKEN"):
|
||||||
|
raise RuntimeError("缺少 XSRF-TOKEN:请先在 Chrome 登录 devops.aliyun.com")
|
||||||
|
return jar
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_projects() -> list[dict[str, Any]]:
|
||||||
|
jar = load_jar()
|
||||||
|
x = jar.get("XSRF-TOKEN", "")
|
||||||
|
xsrf = urllib.parse.unquote(x) if "%" in x else x
|
||||||
|
cookie = "; ".join(f"{k}={v}" for k, v in jar.items())
|
||||||
|
headers = {
|
||||||
|
"Cookie": cookie,
|
||||||
|
"x-xsrf-token": xsrf,
|
||||||
|
"X-XSRF-TOKEN": xsrf,
|
||||||
|
"Origin": "https://devops.aliyun.com",
|
||||||
|
"Referer": "https://devops.aliyun.com/projex",
|
||||||
|
"accept": "application/json",
|
||||||
|
}
|
||||||
|
extra = json.dumps(
|
||||||
|
{
|
||||||
|
"conditionGroups": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"className": "user",
|
||||||
|
"fieldIdentifier": "users",
|
||||||
|
"format": "multiList",
|
||||||
|
"operator": "CONTAINS",
|
||||||
|
"value": [WANG],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"className": "string",
|
||||||
|
"fieldIdentifier": "scope",
|
||||||
|
"format": "list",
|
||||||
|
"operator": "CONTAINS",
|
||||||
|
"value": ["public"],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
]
|
||||||
|
},
|
||||||
|
separators=(",", ":"),
|
||||||
|
)
|
||||||
|
params = {
|
||||||
|
"extraConditions": extra,
|
||||||
|
"conditions": json.dumps({"conditionGroups": [[]]}, separators=(",", ":")),
|
||||||
|
"orderBy": json.dumps(
|
||||||
|
{
|
||||||
|
"fieldIdentifier": "gmtCreate",
|
||||||
|
"format": "input",
|
||||||
|
"order": "desc",
|
||||||
|
"className": "date",
|
||||||
|
},
|
||||||
|
separators=(",", ":"),
|
||||||
|
),
|
||||||
|
"scope": "all",
|
||||||
|
"category": "Project",
|
||||||
|
"toPage": 1,
|
||||||
|
"pageSize": 100,
|
||||||
|
"_input_charset": "utf-8",
|
||||||
|
}
|
||||||
|
r = requests.get(
|
||||||
|
"https://devops.aliyun.com/projex/api/workspace/project/search/list",
|
||||||
|
headers=headers,
|
||||||
|
params=params,
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
|
r.raise_for_status()
|
||||||
|
rows = r.json().get("result") or []
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"name": p.get("name"),
|
||||||
|
"identifier": p.get("identifier"),
|
||||||
|
"customCode": p.get("customCode"),
|
||||||
|
"logicalStatus": p.get("logicalStatus"),
|
||||||
|
"status": (p.get("status") or {}).get("displayName"),
|
||||||
|
"scope": p.get("scope"),
|
||||||
|
}
|
||||||
|
for p in rows
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def match_projects(
|
||||||
|
projects: list[dict[str, Any]],
|
||||||
|
*,
|
||||||
|
query: str | None = None,
|
||||||
|
space_id: str | None = None,
|
||||||
|
) -> list[dict[str, Any]]:
|
||||||
|
if space_id:
|
||||||
|
sid = space_id.strip()
|
||||||
|
return [p for p in projects if p.get("identifier") == sid]
|
||||||
|
if not query:
|
||||||
|
return []
|
||||||
|
q = query.strip().lower()
|
||||||
|
hits: list[dict[str, Any]] = []
|
||||||
|
for p in projects:
|
||||||
|
name = (p.get("name") or "").lower()
|
||||||
|
code = (p.get("customCode") or "").lower()
|
||||||
|
if q == name or q == code or q in name or name in q:
|
||||||
|
hits.append(p)
|
||||||
|
continue
|
||||||
|
if q in ALIASES and (code == "oneos" or "oneos" in name or "运营" in name):
|
||||||
|
hits.append(p)
|
||||||
|
# de-dupe by identifier
|
||||||
|
seen: set[str] = set()
|
||||||
|
out: list[dict[str, Any]] = []
|
||||||
|
for p in hits:
|
||||||
|
i = p.get("identifier") or ""
|
||||||
|
if i in seen:
|
||||||
|
continue
|
||||||
|
seen.add(i)
|
||||||
|
out.append(p)
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def list_projects(
|
||||||
|
*,
|
||||||
|
match: str | None = None,
|
||||||
|
match_id: str | None = None,
|
||||||
|
) -> dict:
|
||||||
|
projects = fetch_projects()
|
||||||
|
payload: dict[str, Any] = {
|
||||||
|
"fetched_at": datetime.now(TZ).isoformat(),
|
||||||
|
"organizationIdentifier": ORG,
|
||||||
|
"count": len(projects),
|
||||||
|
"projects": projects,
|
||||||
|
"selection_required": True,
|
||||||
|
"refetched": False,
|
||||||
|
"note": "禁止默认直指;须 AskQuestion/Plan 点选后再写入 spaceIdentifier",
|
||||||
|
}
|
||||||
|
if not match and not match_id:
|
||||||
|
return payload
|
||||||
|
|
||||||
|
hits = match_projects(projects, query=match, space_id=match_id)
|
||||||
|
if len(hits) == 1:
|
||||||
|
payload["matches"] = hits
|
||||||
|
payload["match_status"] = "unique"
|
||||||
|
return payload
|
||||||
|
|
||||||
|
# 无法对应(0 或多)→ 自动重拉一次
|
||||||
|
projects2 = fetch_projects()
|
||||||
|
hits2 = match_projects(projects2, query=match, space_id=match_id)
|
||||||
|
payload["projects"] = projects2
|
||||||
|
payload["count"] = len(projects2)
|
||||||
|
payload["refetched"] = True
|
||||||
|
payload["refetch_reason"] = "无法对应" if len(hits) != 1 else "unexpected"
|
||||||
|
if len(hits) == 0:
|
||||||
|
payload["refetch_reason"] = "首次0命中"
|
||||||
|
elif len(hits) > 1:
|
||||||
|
payload["refetch_reason"] = "首次多命中"
|
||||||
|
payload["matches"] = hits2
|
||||||
|
if len(hits2) == 1:
|
||||||
|
payload["match_status"] = "unique_after_refetch"
|
||||||
|
elif len(hits2) == 0:
|
||||||
|
payload["match_status"] = "none_after_refetch"
|
||||||
|
payload["note"] = "已自动重拉一次仍无法对应;请用户从最新列表点选;禁止再拉第3次"
|
||||||
|
else:
|
||||||
|
payload["match_status"] = "ambiguous_after_refetch"
|
||||||
|
payload["note"] = "已自动重拉一次仍多命中;请用户点选;禁止自动选定"
|
||||||
|
payload["fetched_at"] = datetime.now(TZ).isoformat()
|
||||||
|
return payload
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
ap = argparse.ArgumentParser(description="YunxiaoPMapp 项目列表 / 匹配(无法对应则重拉一次)")
|
||||||
|
ap.add_argument("--match", help="按项目名或 customCode 匹配")
|
||||||
|
ap.add_argument("--match-id", help="按 spaceIdentifier 匹配")
|
||||||
|
args = ap.parse_args()
|
||||||
|
print(
|
||||||
|
json.dumps(
|
||||||
|
list_projects(match=args.match, match_id=args.match_id),
|
||||||
|
ensure_ascii=False,
|
||||||
|
indent=2,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
190
.claude/skills/YunxiaoPM/scripts/list_tags.py
Normal file
190
.claude/skills/YunxiaoPM/scripts/list_tags.py
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""标签候选列表(聚合工作项 tag + runtime);未命中可 --match 后自动重拉一次。"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import urllib.parse
|
||||||
|
from datetime import datetime, timedelta, timezone
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
RUNTIME = json.loads((ROOT / "assets" / "runtime-ids.json").read_text())
|
||||||
|
TZ = timezone(timedelta(hours=8))
|
||||||
|
|
||||||
|
|
||||||
|
def load_jar() -> dict[str, str]:
|
||||||
|
jar: dict[str, str] = {}
|
||||||
|
try:
|
||||||
|
import browser_cookie3
|
||||||
|
|
||||||
|
for domain in (".aliyun.com", "devops.aliyun.com", ".devops.aliyun.com"):
|
||||||
|
try:
|
||||||
|
for c in browser_cookie3.chrome(domain_name=domain):
|
||||||
|
jar[c.name] = c.value
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if not jar.get("XSRF-TOKEN"):
|
||||||
|
p = Path("/tmp/yunxiao_cookies.json")
|
||||||
|
if p.exists():
|
||||||
|
raw = json.loads(p.read_text())
|
||||||
|
jar = (
|
||||||
|
raw
|
||||||
|
if isinstance(raw, dict) and "XSRF-TOKEN" in raw
|
||||||
|
else {c["name"]: c["value"] for c in raw.get("cookies", [])}
|
||||||
|
)
|
||||||
|
if not jar.get("XSRF-TOKEN"):
|
||||||
|
raise RuntimeError("缺少 XSRF-TOKEN")
|
||||||
|
return jar
|
||||||
|
|
||||||
|
|
||||||
|
def session() -> requests.Session:
|
||||||
|
jar = load_jar()
|
||||||
|
x = jar.get("XSRF-TOKEN", "")
|
||||||
|
xsrf = urllib.parse.unquote(x) if "%" in x else x
|
||||||
|
s = requests.Session()
|
||||||
|
s.headers.update(
|
||||||
|
{
|
||||||
|
"Cookie": "; ".join(f"{k}={v}" for k, v in jar.items()),
|
||||||
|
"x-xsrf-token": xsrf,
|
||||||
|
"X-XSRF-TOKEN": xsrf,
|
||||||
|
"Origin": "https://devops.aliyun.com",
|
||||||
|
"Referer": "https://devops.aliyun.com/projex",
|
||||||
|
"accept": "application/json",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_tags(space_id: str) -> list[dict[str, str]]:
|
||||||
|
s = session()
|
||||||
|
by_id: dict[str, str] = {}
|
||||||
|
for name, tid in (RUNTIME.get("tags") or {}).items():
|
||||||
|
by_id[tid] = name
|
||||||
|
body = {
|
||||||
|
"spaceIdentifier": space_id,
|
||||||
|
"spaceType": "Project",
|
||||||
|
"category": "Req",
|
||||||
|
"toPage": 1,
|
||||||
|
"pageSize": 100,
|
||||||
|
"conditions": json.dumps({"conditionGroups": [[]]}),
|
||||||
|
}
|
||||||
|
rows = (
|
||||||
|
s.post(
|
||||||
|
"https://devops.aliyun.com/projex/api/workitem/workitem/list?_input_charset=utf-8",
|
||||||
|
json=body,
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
|
.json()
|
||||||
|
.get("result")
|
||||||
|
or []
|
||||||
|
)
|
||||||
|
for row in rows:
|
||||||
|
for t in row.get("tag") or []:
|
||||||
|
tid = t.get("identifier")
|
||||||
|
name = t.get("name") or t.get("displayName")
|
||||||
|
if tid and name:
|
||||||
|
by_id[tid] = name
|
||||||
|
# Task 再扫一页,补标签
|
||||||
|
body["category"] = "Task"
|
||||||
|
rows = (
|
||||||
|
s.post(
|
||||||
|
"https://devops.aliyun.com/projex/api/workitem/workitem/list?_input_charset=utf-8",
|
||||||
|
json=body,
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
|
.json()
|
||||||
|
.get("result")
|
||||||
|
or []
|
||||||
|
)
|
||||||
|
for row in rows:
|
||||||
|
for t in row.get("tag") or []:
|
||||||
|
tid = t.get("identifier")
|
||||||
|
name = t.get("name") or t.get("displayName")
|
||||||
|
if tid and name:
|
||||||
|
by_id[tid] = name
|
||||||
|
return [{"name": n, "identifier": i} for i, n in sorted(by_id.items(), key=lambda x: x[1])]
|
||||||
|
|
||||||
|
|
||||||
|
def match_tags(tags: list[dict[str, str]], query: str) -> list[dict[str, str]]:
|
||||||
|
q = query.strip().lower()
|
||||||
|
hits = []
|
||||||
|
for t in tags:
|
||||||
|
name = (t.get("name") or "").lower()
|
||||||
|
if q == name or q in name or name in q:
|
||||||
|
hits.append(t)
|
||||||
|
return hits
|
||||||
|
|
||||||
|
|
||||||
|
def list_tags(*, space_id: str, match: str | None = None, prefer: str | None = None) -> dict[str, Any]:
|
||||||
|
tags = fetch_tags(space_id)
|
||||||
|
# prefer 置顶
|
||||||
|
if prefer:
|
||||||
|
prefer_l = prefer.strip().lower()
|
||||||
|
tags = sorted(
|
||||||
|
tags,
|
||||||
|
key=lambda t: (0 if (t.get("name") or "").lower() == prefer_l else 1, t.get("name") or ""),
|
||||||
|
)
|
||||||
|
out: dict[str, Any] = {
|
||||||
|
"fetched_at": datetime.now(TZ).isoformat(),
|
||||||
|
"spaceIdentifier": space_id,
|
||||||
|
"count": len(tags),
|
||||||
|
"tags": tags,
|
||||||
|
"refetched": False,
|
||||||
|
"note": "标签未命中须自动重拉一次并重生 4.A/B/C 选项;见 compact-select.md",
|
||||||
|
}
|
||||||
|
if not match:
|
||||||
|
return out
|
||||||
|
hits = match_tags(tags, match)
|
||||||
|
if len(hits) == 1:
|
||||||
|
out["matches"] = hits
|
||||||
|
out["match_status"] = "unique"
|
||||||
|
return out
|
||||||
|
# 无法对应 → 重拉一次
|
||||||
|
tags2 = fetch_tags(space_id)
|
||||||
|
if prefer:
|
||||||
|
prefer_l = prefer.strip().lower()
|
||||||
|
tags2 = sorted(
|
||||||
|
tags2,
|
||||||
|
key=lambda t: (0 if (t.get("name") or "").lower() == prefer_l else 1, t.get("name") or ""),
|
||||||
|
)
|
||||||
|
hits2 = match_tags(tags2, match)
|
||||||
|
out["tags"] = tags2
|
||||||
|
out["count"] = len(tags2)
|
||||||
|
out["refetched"] = True
|
||||||
|
out["refetch_reason"] = "首次0命中" if len(hits) == 0 else "首次多命中"
|
||||||
|
out["matches"] = hits2
|
||||||
|
if len(hits2) == 1:
|
||||||
|
out["match_status"] = "unique_after_refetch"
|
||||||
|
elif len(hits2) == 0:
|
||||||
|
out["match_status"] = "none_after_refetch"
|
||||||
|
out["note"] = "已自动重拉标签列表仍无法对应;请用户点选 4.x;禁止再拉第3次"
|
||||||
|
else:
|
||||||
|
out["match_status"] = "ambiguous_after_refetch"
|
||||||
|
out["fetched_at"] = datetime.now(TZ).isoformat()
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
ap = argparse.ArgumentParser()
|
||||||
|
ap.add_argument("--space", required=True, help="spaceIdentifier")
|
||||||
|
ap.add_argument("--match", help="标签名")
|
||||||
|
ap.add_argument("--prefer", help="置顶标签名")
|
||||||
|
args = ap.parse_args()
|
||||||
|
print(
|
||||||
|
json.dumps(
|
||||||
|
list_tags(space_id=args.space, match=args.match, prefer=args.prefer),
|
||||||
|
ensure_ascii=False,
|
||||||
|
indent=2,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
660
.claude/skills/YunxiaoPM/scripts/live_create_fast.py
Normal file
660
.claude/skills/YunxiaoPM/scripts/live_create_fast.py
Normal file
@@ -0,0 +1,660 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""YunxiaoPM 极速真实建单 v5:快轨描述/计划/标签/工时 2+2/设计 ASSOCIATED 补挂。"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import urllib.parse
|
||||||
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||||
|
from datetime import datetime, timedelta, timezone
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
try:
|
||||||
|
import browser_cookie3
|
||||||
|
except ImportError: # pragma: no cover
|
||||||
|
browser_cookie3 = None
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
RUNTIME = json.loads((ROOT / "assets" / "runtime-ids.json").read_text())
|
||||||
|
STATUS = RUNTIME["status"]["req"]
|
||||||
|
TASK_STATUS = RUNTIME["status"]["task"]
|
||||||
|
FAST = RUNTIME.get("fields", {}).get("fast_track") or {}
|
||||||
|
|
||||||
|
SPACE = (
|
||||||
|
RUNTIME.get("project", {}).get("spaceIdentifier")
|
||||||
|
or (RUNTIME.get("project", {}).get("last_selected") or {}).get("spaceIdentifier")
|
||||||
|
)
|
||||||
|
if not SPACE:
|
||||||
|
raise RuntimeError(
|
||||||
|
"未选定项目 spaceIdentifier:须先走门禁 PJ 点选,或设置 runtime project.last_selected"
|
||||||
|
)
|
||||||
|
REQ_TYPE = RUNTIME["workitem_types"]["product_req"]["identifier"]
|
||||||
|
TASK_TYPE = RUNTIME["workitem_types"]["task"]["identifier"]
|
||||||
|
HEFEI = RUNTIME["people"]["hefei"]["identifier"]
|
||||||
|
WANG = RUNTIME["people"].get("wangmian", {}).get("identifier", "6811df000601d2fea60144a9")
|
||||||
|
PRI = RUNTIME["priority"]["中"]
|
||||||
|
TAG_FAULT = RUNTIME.get("tags", {}).get("故障管理", "ceb526a7343995577645317e9a")
|
||||||
|
PLACEHOLDER = RUNTIME["delivery_placeholder"]
|
||||||
|
PROTO = "https://prototype.lnoneos.com/vehicle-fault-handling/index.html"
|
||||||
|
TZ = timezone(timedelta(hours=8))
|
||||||
|
TODAY = datetime.now(TZ).strftime("%Y-%m-%d")
|
||||||
|
NOON = f"{TODAY} 12:00:00"
|
||||||
|
EOD = f"{TODAY} 23:59:59"
|
||||||
|
NOON_MS = str(
|
||||||
|
int(datetime.now(TZ).replace(hour=12, minute=0, second=0, microsecond=0).timestamp() * 1000)
|
||||||
|
)
|
||||||
|
START_MS = str(
|
||||||
|
int(datetime.now(TZ).replace(hour=9, minute=0, second=0, microsecond=0).timestamp() * 1000)
|
||||||
|
)
|
||||||
|
END_MS = str(
|
||||||
|
int(datetime.now(TZ).replace(hour=11, minute=0, second=0, microsecond=0).timestamp() * 1000)
|
||||||
|
)
|
||||||
|
FAST_EST = int(FAST.get("req_estimated_hours", 2))
|
||||||
|
FAST_ACT = int(FAST.get("req_actual_hours", 2))
|
||||||
|
|
||||||
|
PENDING = STATUS["待处理"]
|
||||||
|
DESIGN_DONE = STATUS["设计完成"]
|
||||||
|
PENDING_DEV = STATUS["待开发"]
|
||||||
|
TASK_DONE = TASK_STATUS["已完成"]
|
||||||
|
|
||||||
|
_COOKIE = ""
|
||||||
|
_XSRF = ""
|
||||||
|
|
||||||
|
|
||||||
|
def load_auth() -> None:
|
||||||
|
global _COOKIE, _XSRF
|
||||||
|
jar: dict[str, str] = {}
|
||||||
|
if browser_cookie3:
|
||||||
|
for domain in (".aliyun.com", "devops.aliyun.com", ".devops.aliyun.com"):
|
||||||
|
try:
|
||||||
|
for c in browser_cookie3.chrome(domain_name=domain):
|
||||||
|
jar[c.name] = c.value
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if not jar:
|
||||||
|
p = Path("/tmp/yunxiao_cookies.json")
|
||||||
|
if p.exists():
|
||||||
|
raw = json.loads(p.read_text())
|
||||||
|
jar = (
|
||||||
|
raw
|
||||||
|
if isinstance(raw, dict) and "XSRF-TOKEN" in raw
|
||||||
|
else {c["name"]: c["value"] for c in raw.get("cookies", [])}
|
||||||
|
)
|
||||||
|
_COOKIE = "; ".join(f"{k}={v}" for k, v in jar.items())
|
||||||
|
x = jar.get("XSRF-TOKEN", "")
|
||||||
|
_XSRF = urllib.parse.unquote(x) if "%" in x else x
|
||||||
|
if not _XSRF:
|
||||||
|
raise RuntimeError("缺少 XSRF-TOKEN:请先在 Chrome 登录 devops.aliyun.com")
|
||||||
|
|
||||||
|
|
||||||
|
def session() -> requests.Session:
|
||||||
|
s = requests.Session()
|
||||||
|
s.headers.update(
|
||||||
|
{
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Cookie": _COOKIE,
|
||||||
|
"x-xsrf-token": _XSRF,
|
||||||
|
"X-XSRF-TOKEN": _XSRF,
|
||||||
|
"Origin": "https://devops.aliyun.com",
|
||||||
|
"Referer": f"https://devops.aliyun.com/projex/project/{SPACE}/req",
|
||||||
|
"accept": "application/json",
|
||||||
|
"User-Agent": "YunxiaoPM-live_create_fast/5.0",
|
||||||
|
"Connection": "keep-alive",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def api(s: requests.Session, method: str, url: str, body: Any = None) -> dict:
|
||||||
|
r = s.request(method, url, json=body, timeout=60)
|
||||||
|
try:
|
||||||
|
return r.json()
|
||||||
|
except Exception:
|
||||||
|
r.raise_for_status()
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def create(s: requests.Session, payload: dict) -> dict:
|
||||||
|
url = "https://devops.aliyun.com/projex/api/workitem/workitem?_input_charset=utf-8"
|
||||||
|
j = api(s, "POST", url, payload)
|
||||||
|
r = j.get("result") or {}
|
||||||
|
if j.get("code") == 200 and isinstance(r, dict) and r.get("identifier"):
|
||||||
|
return r
|
||||||
|
j = api(s, "PUT", url, payload)
|
||||||
|
r = j.get("result") or {}
|
||||||
|
if j.get("code") == 200 and isinstance(r, dict) and r.get("identifier"):
|
||||||
|
return r
|
||||||
|
raise RuntimeError(f"create failed: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def get(s: requests.Session, wid: str) -> dict:
|
||||||
|
return api(
|
||||||
|
s,
|
||||||
|
"GET",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/{wid}?_input_charset=utf-8",
|
||||||
|
)["result"]
|
||||||
|
|
||||||
|
|
||||||
|
def apply_tag(s: requests.Session, wid: str, tag_id: str = TAG_FAULT) -> None:
|
||||||
|
j = api(
|
||||||
|
s,
|
||||||
|
"PATCH",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/{wid}?_input_charset=utf-8",
|
||||||
|
{
|
||||||
|
"workitemIdentifier": wid,
|
||||||
|
"propertyKey": "tag",
|
||||||
|
"propertyValue": tag_id,
|
||||||
|
"operateType": "COVER",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if j.get("code") != 200:
|
||||||
|
raise RuntimeError(f"tag failed {wid}: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def set_document(s: requests.Session, wid: str, html: str) -> None:
|
||||||
|
j = api(
|
||||||
|
s,
|
||||||
|
"PATCH",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/{wid}/document?_input_charset=utf-8",
|
||||||
|
{"content": html, "formatType": "RICHTEXT"},
|
||||||
|
)
|
||||||
|
if j.get("code") != 200 or j.get("errorMsg"):
|
||||||
|
raise RuntimeError(f"document failed {wid}: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def set_fields(s: requests.Session, wid: str, pairs: list[tuple[str, str]]) -> None:
|
||||||
|
data = urllib.parse.urlencode(
|
||||||
|
{
|
||||||
|
"fieldValueList": json.dumps(
|
||||||
|
[{"fieldIdentifier": k, "value": v} for k, v in pairs], ensure_ascii=False
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
r = s.post(
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/field/value/{wid}?_input_charset=utf-8",
|
||||||
|
data=data,
|
||||||
|
headers={"Content-Type": "application/x-www-form-urlencoded"},
|
||||||
|
timeout=60,
|
||||||
|
)
|
||||||
|
j = r.json()
|
||||||
|
if j.get("code") != 200:
|
||||||
|
raise RuntimeError(f"field/value failed {wid}: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def set_estimate_hours(s: requests.Session, wid: str, hours: int, user: str = WANG) -> None:
|
||||||
|
est = api(
|
||||||
|
s,
|
||||||
|
"GET",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/time/estimate/list?workitemIdentifier={wid}",
|
||||||
|
).get("result") or []
|
||||||
|
for row in est:
|
||||||
|
eid = row.get("identifier")
|
||||||
|
if eid:
|
||||||
|
api(
|
||||||
|
s,
|
||||||
|
"DELETE",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/time/estimate/{wid}/{eid}",
|
||||||
|
)
|
||||||
|
j = api(
|
||||||
|
s,
|
||||||
|
"POST",
|
||||||
|
"https://devops.aliyun.com/projex/api/workitem/workitem/time/estimate?_input_charset=utf-8",
|
||||||
|
{
|
||||||
|
"workitemIdentifier": wid,
|
||||||
|
"spentTime": hours,
|
||||||
|
"type": "develop",
|
||||||
|
"description": "快轨默认预计工时",
|
||||||
|
"recordUserIdentifier": user,
|
||||||
|
"forCreate": False,
|
||||||
|
"containsRestDay": False,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if j.get("code") != 200:
|
||||||
|
raise RuntimeError(f"estimate failed {wid}: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def set_actual_hours(s: requests.Session, wid: str, hours: int, user: str = WANG) -> None:
|
||||||
|
j = api(
|
||||||
|
s,
|
||||||
|
"POST",
|
||||||
|
"https://devops.aliyun.com/projex/api/workitem/workitem/time?_input_charset=utf-8",
|
||||||
|
{
|
||||||
|
"workitemIdentifier": wid,
|
||||||
|
"actualTime": hours,
|
||||||
|
"type": "develop",
|
||||||
|
"description": "快轨默认实际工时",
|
||||||
|
"recordUserIdentifier": user,
|
||||||
|
"gmtStart": START_MS,
|
||||||
|
"gmtEnd": END_MS,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if j.get("code") != 200 or not j.get("result"):
|
||||||
|
raise RuntimeError(f"actual time failed {wid}: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def try_associate_to_req(s: requests.Session, stage_id: str, req_id: str) -> bool:
|
||||||
|
"""建后补 ASSOCIATED→需求。Cookie 下常失败,成功返回 True。"""
|
||||||
|
bodies = [
|
||||||
|
{"relationIdentifier": "ASSOCIATED", "toWorkitemIdentifier": req_id},
|
||||||
|
{
|
||||||
|
"relationIdentifier": "ASSOCIATED",
|
||||||
|
"fromWorkitemIdentifier": stage_id,
|
||||||
|
"toWorkitemIdentifier": req_id,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
for body in bodies:
|
||||||
|
for url in (
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/{stage_id}/relation/record?_input_charset=utf-8",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/v2/workitem/{stage_id}/relation/record?_input_charset=utf-8",
|
||||||
|
):
|
||||||
|
j = api(s, "POST", url, body)
|
||||||
|
if j.get("code") == 200 and j.get("result") not in (None, False):
|
||||||
|
if not (isinstance(j.get("result"), dict) and j["result"].get("status") in (404, 405)):
|
||||||
|
rows = list_associated(s, stage_id)
|
||||||
|
if req_id in {r.get("identifier") for r in rows}:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def transit(s: requests.Session, wid: str, from_status: str, to_status: str) -> None:
|
||||||
|
if from_status == to_status:
|
||||||
|
return
|
||||||
|
j = api(
|
||||||
|
s,
|
||||||
|
"POST",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/{wid}/status/transit?_input_charset=utf-8",
|
||||||
|
{"fromStatus": from_status, "toStatus": to_status},
|
||||||
|
)
|
||||||
|
if not (j.get("code") == 200 and j.get("result") is True):
|
||||||
|
raise RuntimeError(f"transit {wid} {from_status}->{to_status}: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def md_to_html(md: str) -> str:
|
||||||
|
parts = []
|
||||||
|
for line in md.splitlines():
|
||||||
|
if line.startswith("## "):
|
||||||
|
parts.append(f"<h2>{line[3:]}</h2>")
|
||||||
|
elif line.startswith("### "):
|
||||||
|
parts.append(f"<h3>{line[4:]}</h3>")
|
||||||
|
elif line.startswith("- "):
|
||||||
|
parts.append(f"<p>• {line[2:]}</p>")
|
||||||
|
elif line.strip():
|
||||||
|
parts.append(f"<p>{line}</p>")
|
||||||
|
return "".join(parts)
|
||||||
|
|
||||||
|
|
||||||
|
def req_document_html(s: requests.Session, rid: str) -> str:
|
||||||
|
w = get(s, rid)
|
||||||
|
return ((w.get("document") or {}).get("content") or w.get("description") or "").strip()
|
||||||
|
|
||||||
|
|
||||||
|
def req_payload(subject: str, html: str) -> dict:
|
||||||
|
return {
|
||||||
|
"subject": subject,
|
||||||
|
"description": html,
|
||||||
|
"formatType": "RICHTEXT",
|
||||||
|
"document": {"content": html, "formatType": "RICHTEXT"},
|
||||||
|
"spaceIdentifier": SPACE,
|
||||||
|
"space": SPACE,
|
||||||
|
"spaceType": "Project",
|
||||||
|
"workitemTypeIdentifier": REQ_TYPE,
|
||||||
|
"workitemType": REQ_TYPE,
|
||||||
|
"categoryIdentifier": "Req",
|
||||||
|
"category": "Req",
|
||||||
|
"assignedTo": WANG,
|
||||||
|
"fieldValueList": [
|
||||||
|
{"fieldIdentifier": "priority", "value": PRI},
|
||||||
|
{"fieldIdentifier": "assignedTo", "value": WANG},
|
||||||
|
],
|
||||||
|
"attachmentIdList": [],
|
||||||
|
"cloneFrom": None,
|
||||||
|
"createWorkitemRelationList": [],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def task_payload(
|
||||||
|
subject: str,
|
||||||
|
html: str,
|
||||||
|
assignee: str,
|
||||||
|
*,
|
||||||
|
plan_start: bool = True,
|
||||||
|
associated_req: str | None = None,
|
||||||
|
parent_delivery: str | None = None,
|
||||||
|
) -> dict:
|
||||||
|
fvl = [
|
||||||
|
{"fieldIdentifier": "priority", "value": PRI},
|
||||||
|
{"fieldIdentifier": "assignedTo", "value": assignee},
|
||||||
|
]
|
||||||
|
if plan_start:
|
||||||
|
fvl.append({"fieldIdentifier": "79", "value": NOON_MS})
|
||||||
|
payload: dict[str, Any] = {
|
||||||
|
"subject": subject,
|
||||||
|
"description": html,
|
||||||
|
"formatType": "RICHTEXT",
|
||||||
|
"spaceIdentifier": SPACE,
|
||||||
|
"space": SPACE,
|
||||||
|
"spaceType": "Project",
|
||||||
|
"workitemTypeIdentifier": TASK_TYPE,
|
||||||
|
"workitemType": TASK_TYPE,
|
||||||
|
"categoryIdentifier": "Task",
|
||||||
|
"category": "Task",
|
||||||
|
"assignedTo": assignee,
|
||||||
|
"fieldValueList": fvl,
|
||||||
|
"attachmentIdList": [],
|
||||||
|
"cloneFrom": None,
|
||||||
|
}
|
||||||
|
if parent_delivery:
|
||||||
|
payload["parent"] = parent_delivery
|
||||||
|
payload["parentIdentifier"] = parent_delivery
|
||||||
|
payload["createWorkitemRelationInfo"] = {
|
||||||
|
"relatedWorkitemIdentifier": parent_delivery,
|
||||||
|
"relatedToRelationIdentifier": "TASK_SUB",
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
if not associated_req:
|
||||||
|
raise ValueError("associated_req required for delivery: ASSOCIATED→需求")
|
||||||
|
payload["createWorkitemRelationInfo"] = {
|
||||||
|
"relatedWorkitemIdentifier": associated_req,
|
||||||
|
"relatedToRelationIdentifier": "ASSOCIATED",
|
||||||
|
}
|
||||||
|
return payload
|
||||||
|
|
||||||
|
|
||||||
|
def list_associated(s: requests.Session, wid: str) -> list[dict]:
|
||||||
|
j = api(
|
||||||
|
s,
|
||||||
|
"GET",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/v2/workitem/{wid}/relation/workitem/list/by-relation-category?category=ASSOCIATED&isForward=true",
|
||||||
|
)
|
||||||
|
return j.get("result") or []
|
||||||
|
|
||||||
|
|
||||||
|
def assert_associated_to_req(s: requests.Session, wid: str, req_id: str, label: str) -> None:
|
||||||
|
rows = list_associated(s, wid)
|
||||||
|
ids = {r.get("identifier") for r in rows}
|
||||||
|
if req_id not in ids:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"{label} 关联项未挂需求:期望 {req_id},实际 {[r.get('serialNumber') for r in rows]}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
AUTO_RDO = """## 原始诉求(AutoRDO)
|
||||||
|
|
||||||
|
运维需在故障处置页承接机器人上报的故障,完成处置、挂起与归档,并保留证据链;工作台相关统计口径需与处置页一致
|
||||||
|
|
||||||
|
待确认:
|
||||||
|
- 本期是否含真实短信/邮件通道(现口径一般为演示模板)
|
||||||
|
|
||||||
|
## 工作项编号(系统)
|
||||||
|
- 交付:待建
|
||||||
|
- 分析:待建
|
||||||
|
- 设计:待建
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def summarize_from_create(w: dict, *, status: str, assignee_name: str) -> dict:
|
||||||
|
return {
|
||||||
|
"serial": w.get("serialNumber"),
|
||||||
|
"id": w.get("identifier"),
|
||||||
|
"subject": w.get("subject"),
|
||||||
|
"status": status,
|
||||||
|
"assignee": assignee_name,
|
||||||
|
"parent": w.get("parentIdentifier"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def build_normal() -> dict:
|
||||||
|
t0 = time.perf_counter()
|
||||||
|
s = session()
|
||||||
|
title = "【新增】故障处置(YunxiaoPMapp标准·极速v2)"
|
||||||
|
req = create(s, req_payload(title, md_to_html(AUTO_RDO + f"\n原型:{PROTO}\n")))
|
||||||
|
rid = req["identifier"]
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=2) as pool:
|
||||||
|
f_tag_r = pool.submit(apply_tag, session(), rid)
|
||||||
|
f_deliv = pool.submit(
|
||||||
|
create,
|
||||||
|
session(),
|
||||||
|
task_payload(
|
||||||
|
f"【交付】{title}",
|
||||||
|
f"<p>{PLACEHOLDER}</p>",
|
||||||
|
HEFEI,
|
||||||
|
associated_req=rid,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
deliv = f_deliv.result()
|
||||||
|
f_tag_r.result()
|
||||||
|
did = deliv["identifier"]
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=3) as pool:
|
||||||
|
f_tag_d = pool.submit(apply_tag, session(), did)
|
||||||
|
f_ana = pool.submit(
|
||||||
|
create,
|
||||||
|
session(),
|
||||||
|
task_payload(
|
||||||
|
f"【分析】{title}",
|
||||||
|
"<p>分析阶段:故障处置台账、挂起归档与证据链。</p>",
|
||||||
|
WANG,
|
||||||
|
associated_req=rid,
|
||||||
|
parent_delivery=did,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
f_des = pool.submit(
|
||||||
|
create,
|
||||||
|
session(),
|
||||||
|
task_payload(
|
||||||
|
f"【设计】{title}",
|
||||||
|
f"<p>设计阶段:对齐原型 {PROTO}</p>",
|
||||||
|
WANG,
|
||||||
|
associated_req=rid,
|
||||||
|
parent_delivery=did,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
ana = f_ana.result()
|
||||||
|
des = f_des.result()
|
||||||
|
f_tag_d.result()
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=3) as pool:
|
||||||
|
list(
|
||||||
|
as_completed(
|
||||||
|
[
|
||||||
|
pool.submit(transit, session(), rid, PENDING, DESIGN_DONE),
|
||||||
|
pool.submit(transit, session(), ana["identifier"], PENDING, TASK_DONE),
|
||||||
|
pool.submit(transit, session(), des["identifier"], PENDING, TASK_DONE),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
transit(s, rid, DESIGN_DONE, PENDING_DEV)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"path": "normal",
|
||||||
|
"elapsed_s": round(time.perf_counter() - t0, 3),
|
||||||
|
"req": summarize_from_create(req, status="待开发", assignee_name="王冕"),
|
||||||
|
"delivery": summarize_from_create(deliv, status="待处理", assignee_name="何斐"),
|
||||||
|
"analysis": summarize_from_create(ana, status="已完成", assignee_name="王冕"),
|
||||||
|
"design": summarize_from_create(des, status="已完成", assignee_name="王冕"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def build_fast(
|
||||||
|
*,
|
||||||
|
tag_id: str = TAG_FAULT,
|
||||||
|
has_prototype: bool = True,
|
||||||
|
delivery_html: str | None = None,
|
||||||
|
) -> dict:
|
||||||
|
"""无单快轨。
|
||||||
|
|
||||||
|
- 设计描述 = 需求 document
|
||||||
|
- 交付描述 = 手工同步需求正文(无原型)或传入 AutoPRD HTML;禁止无故占位
|
||||||
|
- 设计 79/80=当日;交付 79=当日
|
||||||
|
- 需求/交付/设计同标签
|
||||||
|
- 需求预计/实际工时各 2
|
||||||
|
- 设计 TASK_SUB→交付后尝试 ASSOCIATED→需求
|
||||||
|
"""
|
||||||
|
t0 = time.perf_counter()
|
||||||
|
s = session()
|
||||||
|
title = "【新增】故障处置(YunxiaoPM快轨·极速v5)"
|
||||||
|
req_html = md_to_html(AUTO_RDO + (f"\n原型:{PROTO}\n" if has_prototype else "\n"))
|
||||||
|
req = create(s, req_payload(title, req_html))
|
||||||
|
rid = req["identifier"]
|
||||||
|
# 以落库 document 为准(与手动建需后读需求一致)
|
||||||
|
req_html = req_document_html(s, rid) or req_html
|
||||||
|
|
||||||
|
if delivery_html:
|
||||||
|
deliv_html = delivery_html
|
||||||
|
desc_source = "autoprd"
|
||||||
|
elif req_html.strip():
|
||||||
|
deliv_html = req_html
|
||||||
|
desc_source = "manual_sync"
|
||||||
|
else:
|
||||||
|
deliv_html = f"<p>{PLACEHOLDER}</p>"
|
||||||
|
desc_source = "placeholder"
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=2) as pool:
|
||||||
|
f_tag_r = pool.submit(apply_tag, session(), rid, tag_id)
|
||||||
|
f_deliv = pool.submit(
|
||||||
|
create,
|
||||||
|
session(),
|
||||||
|
task_payload(
|
||||||
|
f"【交付】{title}",
|
||||||
|
deliv_html,
|
||||||
|
HEFEI,
|
||||||
|
associated_req=rid,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
deliv = f_deliv.result()
|
||||||
|
f_tag_r.result()
|
||||||
|
did = deliv["identifier"]
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=2) as pool:
|
||||||
|
f_tag_d = pool.submit(apply_tag, session(), did, tag_id)
|
||||||
|
f_des = pool.submit(
|
||||||
|
create,
|
||||||
|
session(),
|
||||||
|
task_payload(
|
||||||
|
f"【设计】{title}",
|
||||||
|
req_html,
|
||||||
|
WANG,
|
||||||
|
parent_delivery=did,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
des = f_des.result()
|
||||||
|
f_tag_d.result()
|
||||||
|
des_id = des["identifier"]
|
||||||
|
apply_tag(s, des_id, tag_id)
|
||||||
|
|
||||||
|
# 计划时间:设计起止当日;交付开始当日(create 已带 79,再 field/value 加固)
|
||||||
|
set_fields(s, des_id, [("79", NOON), ("80", EOD)])
|
||||||
|
set_fields(s, did, [("79", NOON)])
|
||||||
|
|
||||||
|
# 设计关联项补挂需求(可能失败,回报 risk)
|
||||||
|
design_assoc_ok = try_associate_to_req(s, des_id, rid)
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=2) as pool:
|
||||||
|
list(
|
||||||
|
as_completed(
|
||||||
|
[
|
||||||
|
pool.submit(transit, session(), rid, PENDING, DESIGN_DONE),
|
||||||
|
pool.submit(transit, session(), des_id, PENDING, TASK_DONE),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
transit(s, rid, DESIGN_DONE, PENDING_DEV)
|
||||||
|
|
||||||
|
set_estimate_hours(s, rid, FAST_EST)
|
||||||
|
set_actual_hours(s, rid, FAST_ACT)
|
||||||
|
|
||||||
|
risk = None
|
||||||
|
if desc_source == "placeholder":
|
||||||
|
risk = "交付描述仍为占位"
|
||||||
|
if not design_assoc_ok:
|
||||||
|
risk = (risk + ";" if risk else "") + "设计 ASSOCIATED→需求补挂失败(Cookie),须 UI/OpenAPI 兜底"
|
||||||
|
|
||||||
|
return {
|
||||||
|
"path": "fast",
|
||||||
|
"elapsed_s": round(time.perf_counter() - t0, 3),
|
||||||
|
"req": summarize_from_create(req, status="待开发", assignee_name="王冕"),
|
||||||
|
"delivery": summarize_from_create(deliv, status="待处理", assignee_name="何斐"),
|
||||||
|
"design": summarize_from_create(des, status="已完成", assignee_name="王冕"),
|
||||||
|
"analysis": None,
|
||||||
|
"delivery_desc_source": desc_source,
|
||||||
|
"design_associated_ok": design_assoc_ok,
|
||||||
|
"risk": risk,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
auth0 = time.perf_counter()
|
||||||
|
load_auth()
|
||||||
|
auth_s = round(time.perf_counter() - auth0, 3)
|
||||||
|
|
||||||
|
wall0 = time.perf_counter()
|
||||||
|
with ThreadPoolExecutor(max_workers=2) as pool:
|
||||||
|
f_fast = pool.submit(build_fast)
|
||||||
|
f_normal = pool.submit(build_normal)
|
||||||
|
fast = f_fast.result()
|
||||||
|
normal = f_normal.result()
|
||||||
|
build_s = round(time.perf_counter() - wall0, 3)
|
||||||
|
|
||||||
|
s = session()
|
||||||
|
assert_associated_to_req(s, normal["delivery"]["id"], normal["req"]["id"], "normal.delivery")
|
||||||
|
assert_associated_to_req(s, fast["delivery"]["id"], fast["req"]["id"], "fast.delivery")
|
||||||
|
|
||||||
|
def assert_sub(delivery_id: str, child_id: str, label: str) -> None:
|
||||||
|
rows = api(
|
||||||
|
s,
|
||||||
|
"GET",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/v2/workitem/{delivery_id}/relation/workitem/list/by-relation-category?category=PARENT_SUB&isForward=true",
|
||||||
|
).get("result") or []
|
||||||
|
ids = {r.get("identifier") for r in rows}
|
||||||
|
if child_id not in ids:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"{label} 未出现在交付子项:期望 {child_id},实际 {[r.get('serialNumber') for r in rows]}"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert_sub(normal["delivery"]["id"], normal["analysis"]["id"], "normal.analysis")
|
||||||
|
assert_sub(normal["delivery"]["id"], normal["design"]["id"], "normal.design")
|
||||||
|
assert_sub(fast["delivery"]["id"], fast["design"]["id"], "fast.design")
|
||||||
|
verify = {
|
||||||
|
"normal_req": get(s, normal["req"]["id"])["status"]["displayName"],
|
||||||
|
"fast_req": get(s, fast["req"]["id"])["status"]["displayName"],
|
||||||
|
"normal_delivery_assignee": (
|
||||||
|
get(s, normal["delivery"]["id"]).get("assignedTo") or {}
|
||||||
|
).get("displayName"),
|
||||||
|
"fast_delivery_assignee": (get(s, fast["delivery"]["id"]).get("assignedTo") or {}).get(
|
||||||
|
"displayName"
|
||||||
|
),
|
||||||
|
"delivery_associated_ok": True,
|
||||||
|
"stage_tasks_as_sub_ok": True,
|
||||||
|
"fast_design_associated_ok": fast.get("design_associated_ok"),
|
||||||
|
}
|
||||||
|
out = {
|
||||||
|
"normal": normal,
|
||||||
|
"fast": fast,
|
||||||
|
"verify": verify,
|
||||||
|
"auth_elapsed_s": auth_s,
|
||||||
|
"wall_elapsed_s": build_s,
|
||||||
|
"created_at": datetime.now(TZ).isoformat(),
|
||||||
|
"mode": "live_create_fast_v5_fast_track_rules",
|
||||||
|
"opts": {
|
||||||
|
"create_includes_plan_start": True,
|
||||||
|
"skip_plan_end_on_create": True,
|
||||||
|
"tracked_transit_no_get": True,
|
||||||
|
"delivery_assignee_hefei_at_create": True,
|
||||||
|
"overlap_tag_with_create": True,
|
||||||
|
"fast_req_hours": f"{FAST_EST}+{FAST_ACT}",
|
||||||
|
"relation": "delivery ASSOCIATED→req; analysis/design TASK_SUB→delivery; design post ASSOCIATED→req",
|
||||||
|
"http": "requests.Session keep-alive",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
Path("/tmp/yunxiao_pmapp_fast_v2_result.json").write_text(
|
||||||
|
json.dumps(out, ensure_ascii=False, indent=2)
|
||||||
|
)
|
||||||
|
print(json.dumps(out, ensure_ascii=False, indent=2))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
92
.claude/skills/YunxiaoPM/scripts/workday_hours.py
Executable file
92
.claude/skills/YunxiaoPM/scripts/workday_hours.py
Executable file
@@ -0,0 +1,92 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Compute YunxiaoPMapp stage calendar hours = workdays × 8.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python3 workday_hours.py YYYY-MM-DD YYYY-MM-DD
|
||||||
|
python3 workday_hours.py YYYY-MM-DD YYYY-MM-DD --calendar /path/to/cn-workday-calendar.json
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from datetime import date, datetime, timedelta
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def parse_day(s: str) -> date:
|
||||||
|
return datetime.strptime(s, "%Y-%m-%d").date()
|
||||||
|
|
||||||
|
|
||||||
|
def load_calendar(path: Path) -> dict:
|
||||||
|
data = json.loads(path.read_text(encoding="utf-8"))
|
||||||
|
years = data.get("years") or {}
|
||||||
|
holidays: set[str] = set()
|
||||||
|
makeup: set[str] = set()
|
||||||
|
for _y, block in years.items():
|
||||||
|
holidays.update(block.get("holidays") or [])
|
||||||
|
makeup.update(block.get("workdays_on_weekend") or [])
|
||||||
|
return {"holidays": holidays, "makeup": makeup, "years": set(years.keys())}
|
||||||
|
|
||||||
|
|
||||||
|
def ensure_years_covered(start: date, end: date, years: set[str]) -> None:
|
||||||
|
y = start.year
|
||||||
|
while y <= end.year:
|
||||||
|
if str(y) not in years:
|
||||||
|
raise SystemExit(
|
||||||
|
f"缺少 {y} 年日历:请在 assets/cn-workday-calendar.json 补全后再计算。"
|
||||||
|
"禁止仅去周末静默估算。"
|
||||||
|
)
|
||||||
|
y += 1
|
||||||
|
|
||||||
|
|
||||||
|
def is_workday(d: date, holidays: set[str], makeup: set[str]) -> bool:
|
||||||
|
key = d.isoformat()
|
||||||
|
if key in holidays:
|
||||||
|
return False
|
||||||
|
if key in makeup:
|
||||||
|
return True
|
||||||
|
return d.weekday() < 5 # Mon=0 .. Fri=4
|
||||||
|
|
||||||
|
|
||||||
|
def count_workdays(start: date, end: date, holidays: set[str], makeup: set[str]) -> int:
|
||||||
|
if end < start:
|
||||||
|
raise SystemExit("结束日早于开始日")
|
||||||
|
n = 0
|
||||||
|
cur = start
|
||||||
|
while cur <= end:
|
||||||
|
if is_workday(cur, holidays, makeup):
|
||||||
|
n += 1
|
||||||
|
cur += timedelta(days=1)
|
||||||
|
return n
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
parser = argparse.ArgumentParser(description="阶段日历工时 = 工作日×8")
|
||||||
|
parser.add_argument("start", help="计划开始 YYYY-MM-DD")
|
||||||
|
parser.add_argument("end", help="计划完成 YYYY-MM-DD")
|
||||||
|
parser.add_argument(
|
||||||
|
"--calendar",
|
||||||
|
default=str(Path(__file__).resolve().parent.parent / "assets" / "cn-workday-calendar.json"),
|
||||||
|
help="日历 JSON 路径",
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
start = parse_day(args.start)
|
||||||
|
end = parse_day(args.end)
|
||||||
|
cal = load_calendar(Path(args.calendar))
|
||||||
|
ensure_years_covered(start, end, cal["years"])
|
||||||
|
days = count_workdays(start, end, cal["holidays"], cal["makeup"])
|
||||||
|
hours = days * 8
|
||||||
|
out = {
|
||||||
|
"start": start.isoformat(),
|
||||||
|
"end": end.isoformat(),
|
||||||
|
"workdays": days,
|
||||||
|
"stage_calendar_hours": hours,
|
||||||
|
"label": "阶段日历工时(工作日×8),非人力投入预估",
|
||||||
|
}
|
||||||
|
print(json.dumps(out, ensure_ascii=False, indent=2))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
63
.claude/skills/YunxiaoPM/stage-flow.md
Normal file
63
.claude/skills/YunxiaoPM/stage-flow.md
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# 标准路径:待处理 → 待开发交棒
|
||||||
|
|
||||||
|
项目常量见 [../assets/runtime-ids.json](../assets/runtime-ids.json)。查重只用任务编号。
|
||||||
|
|
||||||
|
## 步骤 0|创建需求
|
||||||
|
|
||||||
|
| 云效动作 | 落地 |
|
||||||
|
|---|---|
|
||||||
|
| 新建产品类需求 | POST 建单;标题 `【新增】`/`【优化】` |
|
||||||
|
| 需求描述 | **先** AutoRDO 清洗再写入 `## 原始诉求(AutoRDO)`;本步不写 AutoPRD |
|
||||||
|
| 默认状态 | **待处理**;不建任务、不改负责人 |
|
||||||
|
| 可选推进 | 口令点选目标状态;未选则停在待处理 |
|
||||||
|
|
||||||
|
## 步骤 1|受理 → 已确认
|
||||||
|
|
||||||
|
| 云效动作 | 落地 |
|
||||||
|
|---|---|
|
||||||
|
| 状态 | 待处理 → **已确认** |
|
||||||
|
| 任务 | **仍不建**交付/分析/设计 |
|
||||||
|
|
||||||
|
若用户只「创建」未受理:只提示「受理后请推进至已确认」,不自动跳。
|
||||||
|
|
||||||
|
## 步骤 2|分析中
|
||||||
|
|
||||||
|
| 对象 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| 【交付】 | 无则新建;标题 `【交付】`+需求标题;**ASSOCIATED→需求**(勿用 PARENT);负责人=创建人/产品;**计划开始仅空时写当日**;不写计划完成;描述=`等待设计任务完成后自动填入`;更新编号区块 |
|
||||||
|
| 【分析】 | 新建;**TASK_SUB→交付**(`parent`+`parentIdentifier`+`createWorkitemRelationInfo=TASK_SUB`);交付「子项」须可见;计划开始=当日(仅空时);负责人默认可=创建人;更新编号区块 |
|
||||||
|
|
||||||
|
| 需求 | 状态=`分析中` |
|
||||||
|
|
||||||
|
## 步骤 3|设计中
|
||||||
|
|
||||||
|
| 对象 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| 【交付】 | 已存在则按编号复用;没有则补建;**不改交付计划开始**;不写交付计划完成 |
|
||||||
|
| 【设计】 | 新建;**TASK_SUB→交付**(同分析);计划开始=当日(仅空时);更新编号区块 |
|
||||||
|
| 【分析】 | **计划完成**=状态更新日;推算阶段日历工时(见 work-hours) |
|
||||||
|
| 需求 | 状态=`设计中` |
|
||||||
|
|
||||||
|
## 步骤 4|设计完成
|
||||||
|
|
||||||
|
| 对象 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| 【设计】 | 计划完成=当日;推算工时;任务→完成态 |
|
||||||
|
| 需求 | AutoPRD 写入 `## 产品说明`;挂 ZIP+截图;状态=`设计完成` |
|
||||||
|
| 【交付】 | 不换负责人;不改计划开始;不写计划完成;描述改为 AutoPRD 正文;同样挂附件 |
|
||||||
|
|
||||||
|
顺序与失败门禁见 [description-split.md](description-split.md)。
|
||||||
|
|
||||||
|
## 步骤 5|待开发交棒(本 Skill 终点 · 标准路径)
|
||||||
|
|
||||||
|
| 对象 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| 需求 | 状态=`待开发` |
|
||||||
|
| 【交付】 | 按**任务编号**定位;**负责人→何斐**;不改计划开始;不写计划完成 |
|
||||||
|
| 【分析】/【设计】 | 不新建;不改已有计划开始;前序未收口按步骤 3/4 处理 |
|
||||||
|
|
||||||
|
执行 [handoff-and-rollback.md](handoff-and-rollback.md) §交棒门禁。
|
||||||
|
|
||||||
|
**不做:** 【开发】/【测试】、仓库、分支、提测。
|
||||||
|
|
||||||
|
快轨 / 编号直推见专文。创建迭代见 [sprint.md](sprint.md)。
|
||||||
@@ -1,146 +1,108 @@
|
|||||||
---
|
---
|
||||||
name: oneos-autoprd
|
name: oneos-autoprd
|
||||||
description: >-
|
description: >-
|
||||||
Generates and keeps in sync OneOS AutoPRD (PM-facing requirements) plus Axhub
|
OneOS AutoPRD: generates PM-facing requirements (总览/目标/边界/角色/用户故事
|
||||||
Make annotation directory Markdown/PRD; on 需求定稿/定稿/确认定稿/本次定稿 appends
|
起点→运作→闭环/故事点/正逆向/流程图/关键逻辑/状态/风险/交付) and syncs Axhub Make
|
||||||
functional release changelog below the PRD since last baseline. When a Yunxiao
|
annotation PRD. On 需求定稿/本轮定稿 appends functional changelog with auto
|
||||||
requirement advances to 分析中/设计中/待开发, creates a same-titled linked task
|
V主.副.子 (user 主/副/子 override wins). With YunxiaoPMapp design-complete,
|
||||||
(tag+create-time follow the requirement; 分析中/设计中 assignee=creator, 待开发
|
writes Markdown into 【交付】 by task number (not at create; placeholder until then).
|
||||||
assignee=何斐). Use eagerly for prototypes, AutoPRD, or Yunxiao requirement
|
Use for AutoPRD, prototypes, 产品说明, 本轮定稿. Never create same-titled stage
|
||||||
description/更新内容/stage advance—do not skip annotation sync, 定稿 changelog,
|
tasks; never load yunxiao-requirement-lifecycle—cloud combo is YunxiaoPMapp only.
|
||||||
or stage-task creation.
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# OneOS AutoPRD
|
# AutoPRD(oneos-autoprd)
|
||||||
|
|
||||||
为 OneOS 业务模块生成**产品经理可读、可评审、可排期**的需求说明,并**自动挂到 Axhub Make 标注工具 → 原型目录**。
|
为 OneOS 业务模块生成**产品经理可读、可评审、可排期**的需求说明,并**自动挂到 Axhub Make 标注工具 → 原型目录**。
|
||||||
|
|
||||||
另支持:**需求定稿**时汇总功能/逻辑变更记录;与云效组合时提供「需求说明 + 更新内容」;需求进入**分析中 / 设计中 / 待开发**时**自动创建与需求同名的关联任务**(规则见下,写在本 Skill,不改云效 Skill)。
|
另支持:**本轮定稿 / 需求定稿**时汇总功能变更并**自动递增 PRD 版本号**;与 **`$YunxiaoPMapp`** 组合时,在**设计完成**(或显式同步交付)把 Markdown 写入【交付】任务描述。
|
||||||
|
|
||||||
颗粒度对齐「保险采购」全模块 PRD:讲清做什么、谁用、故事点、正逆向、流程图与关键业务逻辑;**不写**表结构、接口、字段代码名、文件路径、实现清单。
|
**禁止加载** `yunxiao-requirement-lifecycle`。云效状态机与【交付】/【分析】/【设计】树**只**由 YunxiaoPMapp 负责;本 Skill **不**建同名无前缀阶段任务。
|
||||||
|
|
||||||
|
颗粒度:讲清做什么、谁用、故事点、正逆向、流程图与关键业务逻辑;**不写**表结构、接口、字段代码名、文件路径、实现清单。
|
||||||
|
|
||||||
## 何时使用(含自动触发)
|
## 何时使用(含自动触发)
|
||||||
|
|
||||||
**主动调用时**
|
**主动调用**
|
||||||
|
|
||||||
- AutoPRD、OneOS 需求说明、整模块 PRD、故事点 + 流程图
|
- AutoPRD、OneOS 需求说明、整模块 PRD、故事点 + 流程图、产品说明
|
||||||
|
|
||||||
**改原型时必须自动跟进(全局规则)**
|
**改原型时必须自动跟进**
|
||||||
|
|
||||||
- 正在修改 `src/prototypes/<id>/` 下页面、交互、文案、判定、验收相关内容
|
- 修改 `src/prototypes/<id>/` 下页面、交互、文案、判定、验收相关内容
|
||||||
- 同一轮交付内同步更新 PRD Markdown + 标注目录,不得只改代码
|
- 同一轮同步更新 PRD Markdown + 标注目录;**纯样式且无产品语义变化可跳过全量重写**
|
||||||
|
|
||||||
**需求定稿时(强制)**
|
**需求定稿时(强制)**
|
||||||
|
|
||||||
- 用户回复含:`需求定稿` / `定稿` / `确认定稿` / `本次定稿`
|
- 关键字:`需求定稿` / `定稿` / `确认定稿` / `本次定稿` / **`本轮定稿`**
|
||||||
- 执行 [references/release-changelog.md](references/release-changelog.md):写第 10 章 + 更新基线
|
- 执行 [references/release-changelog.md](references/release-changelog.md):第 10 章 + `prdVersion` 基线
|
||||||
|
|
||||||
**云效建需求 / 完善需求时(强制组合)**
|
**与 YunxiaoPMapp 组合(强制 · 唯一云效组合)**
|
||||||
|
|
||||||
- 与 `$yunxiao-requirement-lifecycle` 一起使用时:先跑本 Skill,再写云效描述
|
- 设计完成或完善「产品说明」:先本 Skill 落盘 MD,再由 YunxiaoPMapp / 本 Skill 按 [yunxiao-description.md](references/yunxiao-description.md) 写入需求 `## 产品说明(AutoPRD)`(**不覆盖** `## 原始诉求(AutoRDO)` / `## 工作项编号(系统)`)
|
||||||
- **需求说明** ← PRD 正文(或浓缩交付口径 + 关键章节)
|
- **创建【交付】时不写 PRD 正文**(占位由 YunxiaoPMapp 写入);设计完成或口令「同步交付说明」时按 [yunxiao-delivery-sync.md](references/yunxiao-delivery-sync.md) 用任务**编号**回填【交付】
|
||||||
- **更新内容** ← 第 10 章中**自上次定稿以来**的条目(无增量则「首版定稿 / 本轮无功能增量」)
|
- 入库前聊天/录音清洗:先 `$AutoRDO`,再 YunxiaoPMapp 记录需求
|
||||||
|
|
||||||
**云效需求推进至分析中 / 设计中 / 待开发时(强制)**
|
|
||||||
|
|
||||||
- 无论口令来自本 Skill 还是云效 Skill,只要本轮把需求推到上述状态,就执行 [references/yunxiao-stage-tasks.md](references/yunxiao-stage-tasks.md)
|
|
||||||
- 自动建**与需求同名**的任务并正式关联;标签与创建时间口径沿用需求;分析中/设计中负责人=创建人,待开发负责人=**何斐**
|
|
||||||
|
|
||||||
不要用本 Skill 替代:需求探索访谈、设计比稿、纯样式微调(无产品语义变化时可跳过全量重写)。
|
|
||||||
|
|
||||||
## 工作流
|
## 工作流
|
||||||
|
|
||||||
### 主流程(写/同步 PRD)
|
### 主流程(写/同步 PRD)
|
||||||
|
|
||||||
1. **定模块**:确认 OneOS 模块名与 `src/prototypes/<prototype-id>/`。
|
1. **定模块**:OneOS 模块名与 `src/prototypes/<prototype-id>/`。
|
||||||
2. **读上下文(只取产品语义)**
|
2. **读上下文(只取产品语义)**
|
||||||
- 用户说明、已确认口径、原型标注、`.spec/`、业务条线说明(`lines.ts`)
|
- 用户说明、已确认口径、原型标注、`.spec/`、业务条线说明(`lines.ts`)
|
||||||
- 忽略实现细节;字段名/接口改写成业务语言。
|
- 忽略实现细节;字段名/接口改写成业务语言。
|
||||||
3. **收敛边界**:做什么 / 不做什么、外部依赖、与其它模块关系。
|
3. **收敛边界**:做什么 / 不做什么、外部依赖、与其它模块关系。
|
||||||
4. **按模板成文**:下方「输出结构」;缺关键信息最多问 1~2 个问题,其余写「假设」。
|
4. **按模板成文**:见「输出结构」与 [references/template.md](references/template.md)。
|
||||||
5. **落盘 + 标注同步(强制)** — 见 [references/annotation-sync.md](references/annotation-sync.md)。
|
5. **落盘 + 标注同步(强制)** — [references/annotation-sync.md](references/annotation-sync.md)。
|
||||||
|
|
||||||
| 顺序 | 动作 |
|
| 顺序 | 动作 |
|
||||||
|------|------|
|
|------|------|
|
||||||
| A | 写/更新 `src/prototypes/<id>/.spec/requirements-prd.md` |
|
| A | 写/更新 `src/prototypes/<id>/.spec/requirements-prd.md` |
|
||||||
| B | 写/更新 `src/resources/prd/<id>-autoprd.md` |
|
| B | 写/更新 `src/resources/prd/<id>-autoprd.md` |
|
||||||
| C | 更新 `annotation-source.json` **顶层** `directory.nodes`(PRD 全文 + 推荐分章);禁止只写 `data.directory` |
|
| C | 更新 `annotation-source.json` **顶层** `directory.nodes`(PRD 全文 + 推荐分章) |
|
||||||
| D | 若存在 `scripts/sync-annotation-directory.mjs`,执行之 |
|
| D | 若存在 `scripts/sync-annotation-directory.mjs`,执行之 |
|
||||||
|
|
||||||
6. **交付说明**:路径、标注目录入口、故事点合计、开放问题/假设。
|
6. **交付说明**:路径、标注入口、故事点合计、开放问题/假设。
|
||||||
|
|
||||||
### 定稿流程(关键字触发)
|
### 定稿流程
|
||||||
|
|
||||||
见 [references/release-changelog.md](references/release-changelog.md)。摘要:
|
见 [references/release-changelog.md](references/release-changelog.md)。含自动 `V主.副.子`;**用户显式指定主/副/子时以用户为准**。
|
||||||
|
|
||||||
1. 读 PRD + `.spec/autoprd-baseline.json`
|
### 云效需求「产品说明」(与 YunxiaoPMapp 双段模板)
|
||||||
2. 汇总自上次定稿以来的**功能/逻辑**变更(排除样式/UI/表结构)
|
|
||||||
3. 追加到 `## 10. 功能变更记录`(最新在上)
|
|
||||||
4. 更新基线 JSON + 标注目录
|
|
||||||
5. 若同时发云效:本次定稿块 →「更新内容」;旧段 →「更新内容·历史」
|
|
||||||
|
|
||||||
### 云效交接格式(给 yunxiao skill 直接粘贴)
|
见 [references/yunxiao-description.md](references/yunxiao-description.md)。
|
||||||
|
|
||||||
```markdown
|
### 云效【交付】回填(设计完成 · 非创建时)
|
||||||
## 原型链接
|
|
||||||
<对象存储或预览 URL>
|
|
||||||
|
|
||||||
## 需求说明
|
见 [references/yunxiao-delivery-sync.md](references/yunxiao-delivery-sync.md)。
|
||||||
<AutoPRD 正文或交付口径 + 必要章节>
|
|
||||||
|
|
||||||
## 更新内容
|
|
||||||
<第 10 章本次定稿块;无则「首版定稿」或「本轮无功能/逻辑增量」>
|
|
||||||
|
|
||||||
## 更新内容·历史
|
|
||||||
<以往更新内容倒序,勿删除>
|
|
||||||
```
|
|
||||||
|
|
||||||
### 云效阶段任务(状态推进时强制)
|
|
||||||
|
|
||||||
见 [references/yunxiao-stage-tasks.md](references/yunxiao-stage-tasks.md)。摘要:
|
|
||||||
|
|
||||||
| 需求状态 | 任务标签 | 负责人 | 标题 |
|
|
||||||
|----------|----------|--------|------|
|
|
||||||
| 分析中 | 分析 | 需求创建人 | 与需求同名 |
|
|
||||||
| 设计中 | 设计 | 需求创建人 | 与需求同名 |
|
|
||||||
| 待开发 | 交付(或开发) | 何斐 | 与需求同名 |
|
|
||||||
|
|
||||||
正式关联需求;创建时间口径沿用需求;同阶段未取消任务不重复建。
|
|
||||||
|
|
||||||
## 写作硬约束
|
## 写作硬约束
|
||||||
|
|
||||||
**必须写**
|
**必须写(映射用户概要)**
|
||||||
|
|
||||||
- 一句话定位 + 目标 / 非目标
|
| 概要能力 | 落在章节 |
|
||||||
- 模块边界(含 mermaid 总览更好)
|
|---|---|
|
||||||
- 角色与目标(角色名优先对齐业务条线说明)
|
| 总览 | §1 一句话与目标 |
|
||||||
- **用户故事**(业务条线说明口径)+ Epic 级**故事点(SP)**粗估
|
| 目标 / 边界 | §1–2 |
|
||||||
- 分功能**正向**与**逆向/边界**
|
| 角色 | §3 |
|
||||||
- 至少 1~2 个 **mermaid** 流程图
|
| 用户故事(起点→运作→闭环)+ 故事点 | §4 |
|
||||||
- **关键业务逻辑**(业务话)
|
| 正逆向流程 | §5 |
|
||||||
- 验收清单 + 「交付口径」一段话
|
| 关键逻辑 / 状态 / 风险 | §6(及验收相关) |
|
||||||
- 定稿后:**功能变更记录**(第 10 章)
|
| 流程图 | §7 |
|
||||||
|
| 交付 | §9 交付口径 |
|
||||||
|
| 定稿变更 | §10 |
|
||||||
|
|
||||||
|
另:验收清单 §8;对象存储预览链接形态 `{baseUrl}/{prototype-id}/index.html`(禁止加 `prototypes/` 前缀、禁止去掉 `index.html`)。
|
||||||
|
|
||||||
**禁止写**
|
**禁止写**
|
||||||
|
|
||||||
- 数据库表、字段名、接口路径、代码路径、组件名、存储 key
|
- 数据库表、字段名、接口路径、代码路径、组件名、存储 key
|
||||||
- 研发实现指令(可写「正式环境由审批中心回写」这类业务依赖)
|
- 变更记录里的样式/UI/表结构优化
|
||||||
- 在变更记录里写样式/UI/表结构优化
|
- 引导加载 `yunxiao-requirement-lifecycle` 或「同名阶段任务」建单
|
||||||
|
|
||||||
## 用户故事口径(强制 · 对齐业务条线说明)
|
## 用户故事口径(强制 · 对齐业务条线说明)
|
||||||
|
|
||||||
真相源:原型 **业务条线说明**(`lease-business-line-overview` / `lines.ts`)。
|
真相源:业务条线说明(`lease-business-line-overview` / `lines.ts`)。
|
||||||
每条能力用「责任部门 → **起点** → **怎么运作** → **闭环**」叙述;**不要**用「作为…我希望…」宽表作主叙述。
|
主叙述:**起点 → 怎么运作 → 闭环**(不要用「作为…我希望…」宽表作主叙述)。
|
||||||
|
|
||||||
| 块 | 写什么 |
|
|
||||||
|----|--------|
|
|
||||||
| 角色 | 谁负责、谁协同 |
|
|
||||||
| 起点 | 谁在什么前提下启动 |
|
|
||||||
| 怎么运作 | 有序步骤,含跨角色协作 |
|
|
||||||
| 关键结果 | 可选标签 |
|
|
||||||
| 闭环 | 业务终点与可追溯性 |
|
|
||||||
|
|
||||||
可选:`US-xx`、压缩句「作为…我想…以便…」、规模 S/M/L 或 SP(仅排期,不替代主叙述)。
|
|
||||||
|
|
||||||
## 输出结构
|
## 输出结构
|
||||||
|
|
||||||
@@ -158,26 +120,27 @@ description: >-
|
|||||||
## 7. 总览流程图
|
## 7. 总览流程图
|
||||||
## 8. 验收清单
|
## 8. 验收清单
|
||||||
## 9. 交付口径
|
## 9. 交付口径
|
||||||
## 10. 功能变更记录 ← 定稿后维护;日常改原型不强制每改必写
|
## 10. 功能变更记录 ← 定稿维护;含 V主.副.子
|
||||||
```
|
```
|
||||||
|
|
||||||
## 质量自检
|
## 质量自检
|
||||||
|
|
||||||
- [ ] 产品经理不看代码也能评审
|
- [ ] 产品经理不看代码也能评审
|
||||||
- [ ] 用户故事为起点 / 怎么运作 / 闭环
|
- [ ] 用户故事为起点 / 怎么运作 / 闭环
|
||||||
- [ ] `.spec/requirements-prd.md` 已更新
|
- [ ] `.spec/requirements-prd.md` + 标注目录已同步
|
||||||
- [ ] 标注目录「产品需求说明(PRD)」已同步且正文一致
|
- [ ] 定稿时:第 10 章含版本号 + `autoprd-baseline.json` 含 `prdVersion`
|
||||||
- [ ] 定稿时:第 10 章 + `autoprd-baseline.json` 已更新
|
- [ ] 与 YunxiaoPMapp 设计完成:【交付】按**编号**回填,创建时未提前灌 MD
|
||||||
- [ ] 推进至分析中/设计中/待开发时:同名任务已创建或复用,正式关联,负责人正确
|
- [ ] 全文无 `yunxiao-requirement-lifecycle` 引导;无同名阶段任务建单
|
||||||
- [ ] 无表结构 / 接口 / 代码路径;变更记录无样式/UI 废话
|
- [ ] 变更记录无样式/UI/表结构废话
|
||||||
|
|
||||||
## 参考
|
## 参考
|
||||||
|
|
||||||
- 定稿变更日志:[references/release-changelog.md](references/release-changelog.md)
|
- 定稿与版本:[references/release-changelog.md](references/release-changelog.md)
|
||||||
- 云效阶段任务:[references/yunxiao-stage-tasks.md](references/yunxiao-stage-tasks.md)
|
- 云效产品说明:[references/yunxiao-description.md](references/yunxiao-description.md)
|
||||||
- 标注同步细则:[references/annotation-sync.md](references/annotation-sync.md)
|
- 【交付】回填:[references/yunxiao-delivery-sync.md](references/yunxiao-delivery-sync.md)
|
||||||
- 章节模板:[references/template.md](references/template.md)
|
- 标注同步:[references/annotation-sync.md](references/annotation-sync.md)
|
||||||
|
- 模板:[references/template.md](references/template.md)
|
||||||
- 故事示例:[references/granularity-example.md](references/granularity-example.md)
|
- 故事示例:[references/granularity-example.md](references/granularity-example.md)
|
||||||
- 业务条线:`src/prototypes/lease-business-line-overview/lines.ts`
|
- 业务条线:`src/prototypes/lease-business-line-overview/lines.ts`
|
||||||
- 复杂判定规格:配合项目规则 `business-logic-documentation`
|
- 云效组合(唯一):`$YunxiaoPMapp`
|
||||||
- 云效组合:`$yunxiao-requirement-lifecycle`(建需求时先本 Skill)
|
- 入库清洗:`$AutoRDO`
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# 功能变更记录(定稿触发)
|
# 功能变更记录(定稿触发)+ PRD 版本号
|
||||||
|
|
||||||
用户回复**需求定稿关键字**后,必须生成「自上次定稿以来」的功能变更日志,追加到 PRD **最下方**,并更新定稿基线。
|
用户回复**定稿关键字**后,必须生成「自上次定稿以来」的功能变更日志,追加到 PRD **最下方**,按规则递增 **`prdVersion`(V主.副.子)**,并更新定稿基线。
|
||||||
|
|
||||||
## 触发关键字(命中任一)
|
## 触发关键字(命中任一)
|
||||||
|
|
||||||
`需求定稿` · `定稿` · `确认定稿` · `本次定稿`
|
`需求定稿` · `定稿` · `确认定稿` · `本次定稿` · **`本轮定稿`**
|
||||||
|
|
||||||
(可带模块名,如「保险采购需求定稿」。)
|
(可带模块名,如「保险采购本轮定稿」。可附带 `版本类型=主|副|子`。)
|
||||||
|
|
||||||
## 写什么 / 不写什么
|
## 写什么 / 不写什么
|
||||||
|
|
||||||
@@ -16,44 +16,57 @@
|
|||||||
| 变更了什么业务逻辑 / 流程 / 验收口径 | 「优化了哪些表」「改了哪些字段/接口」 |
|
| 变更了什么业务逻辑 / 流程 / 验收口径 | 「优化了哪些表」「改了哪些字段/接口」 |
|
||||||
| 用户可感知的交互结果变化 | 纯样式、动效、无语义文案微调 |
|
| 用户可感知的交互结果变化 | 纯样式、动效、无语义文案微调 |
|
||||||
|
|
||||||
条目口吻示例:
|
## 版本号 `V{主}.{副}.{子}`
|
||||||
|
|
||||||
- 「识别失败」:失败数可点击查看失败文件与原因;仅失败时也可打开明细
|
基线字段 `prdVersion`(无则视为 `V0.0.0`)。有功能/逻辑增量时递增;**无增量则版本号不变**。
|
||||||
- 「比价单」:审批通过后仍须在保单管理另行录入正式保单(强调不自动同步)
|
|
||||||
|
### 判定优先级
|
||||||
|
|
||||||
|
1. **用户覆盖(优先)**
|
||||||
|
口令或对话显式指定「主 / 副 / 子」→ **以用户为准**,不再自动改判。
|
||||||
|
定稿块首行写:`判定=用户指定·主`(或副/子)。
|
||||||
|
|
||||||
|
2. **自动判定(用户未指定时)**
|
||||||
|
- **主+1**(副→0,子→0):跨模块边界变化、主流程/状态机重做、角色权限模型大改、验收口径整体推翻等「大改动」≥1 条主导。
|
||||||
|
- **副+1**(子→0):能力增删改、逻辑/文案产品语义变化、故事点级功能优化(**默认多数定稿**)。
|
||||||
|
- **子+1**:仅小幅逻辑澄清;若用户明确「本轮定稿」且变更非空且未指定类型 → **至少副+1**(不用子)。
|
||||||
|
- 定稿块首行写:`判定=主:…` / `判定=副:…` / `判定=子:…`(须写依据,禁止无依据猜)。
|
||||||
|
|
||||||
|
3. **无功能增量**
|
||||||
|
版本号不变;正文写「本轮无功能/逻辑增量(仅样式或未达产品语义变更)」或「首版定稿」(无基线且首版可落到 `V1.0.0` 若视为首次发布——首版有实质内容时用主从 `V0.0.0`→`V1.0.0`)。
|
||||||
|
|
||||||
## 落点
|
## 落点
|
||||||
|
|
||||||
1. **PRD 文末章节**(强制)
|
1. **PRD 文末章节**
|
||||||
`src/prototypes/<id>/.spec/requirements-prd.md` → `## 10. 功能变更记录`
|
`src/prototypes/<id>/.spec/requirements-prd.md` → `## 10. 功能变更记录`
|
||||||
新定稿块插在该章**最上方**(倒序:最新在上);历史块保留。
|
新定稿块插在该章**最上方**。
|
||||||
|
|
||||||
2. **定稿基线**(强制)
|
2. **定稿基线**
|
||||||
`src/prototypes/<id>/.spec/autoprd-baseline.json`
|
`src/prototypes/<id>/.spec/autoprd-baseline.json`
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"prototypeId": "insurance-procurement",
|
"prototypeId": "insurance-procurement",
|
||||||
|
"prdVersion": "V1.2.0",
|
||||||
"lastConfirmedAt": "2026-07-21T12:00:00+08:00",
|
"lastConfirmedAt": "2026-07-21T12:00:00+08:00",
|
||||||
"lastConfirmedLabel": "定稿 · 2026-07-21",
|
"lastConfirmedLabel": "定稿 · V1.2.0 · 2026-07-21",
|
||||||
"summaryBullets": ["…", "…"]
|
"summaryBullets": ["…", "…"]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
3. **标注目录**:同步更新「产品需求说明(PRD)」全文节点;若有「PRD 分章」,增加或更新「功能变更记录」分章。
|
3. **标注目录**:同步「产品需求说明(PRD)」全文节点。
|
||||||
|
|
||||||
4. **云效交接**(若本轮同时走云效):把**本次定稿块**正文作为需求描述「更新内容」;旧「更新内容」挪到「更新内容·历史」。
|
4. **云效**(若本轮走 YunxiaoPMapp):按 [yunxiao-description.md](yunxiao-description.md) 更新需求产品说明;**禁止**加载 `yunxiao-requirement-lifecycle`。
|
||||||
|
|
||||||
## 定稿工作流
|
## 定稿工作流
|
||||||
|
|
||||||
1. 确认 `<prototype-id>`(从对话 / 打开文件 / 用户指名推断)。
|
1. 确认 `<prototype-id>`。
|
||||||
2. 读现有 PRD 与 `autoprd-baseline.json`(无基线则本轮视为**首版定稿**)。
|
2. 读 PRD 与 `autoprd-baseline.json`(无基线 → 首版;`prdVersion` 缺省 `V0.0.0`)。
|
||||||
3. 收集自 `lastConfirmedAt` 以来的产品语义变更:
|
3. 收集自 `lastConfirmedAt` 以来的产品语义变更;过滤样式/表结构。
|
||||||
对话确认口径 → 批注/操作说明 → PRD 新旧差异 →(可选)相关提交说明。
|
4. 判定版本类型(用户指定优先)→ 计算新 `prdVersion`。
|
||||||
过滤掉样式/表结构类改动。
|
5. 追加 `### 定稿 · V{x.y.z} · YYYY-MM-DD`(首行判定理由 + 条目)。
|
||||||
4. 若无功能增量:仍写定稿块,正文为「本轮无功能/逻辑增量(仅样式或未达产品语义变更)」或「首版定稿」。
|
6. 更新基线 JSON;annotation-sync。
|
||||||
5. 追加 `### 定稿 · YYYY-MM-DD` + 条目列表到第 10 章顶部。
|
7. 回报:新版本号、判定理由、条目数、PRD 路径。
|
||||||
6. 更新 `autoprd-baseline.json`;执行 annotation-sync。
|
|
||||||
7. 向用户回报:基线时间、条目数、PRD 路径;若需发云效,提示可用口令。
|
|
||||||
|
|
||||||
## PRD 章节格式
|
## PRD 章节格式
|
||||||
|
|
||||||
@@ -62,17 +75,21 @@
|
|||||||
|
|
||||||
> 产品经理原型发版记录。仅记功能与业务逻辑变更;不含样式/UI/表结构。
|
> 产品经理原型发版记录。仅记功能与业务逻辑变更;不含样式/UI/表结构。
|
||||||
|
|
||||||
### 定稿 · 2026-07-21
|
### 定稿 · V1.2.0 · 2026-07-21
|
||||||
|
|
||||||
- 「能力名」:做了什么 / 逻辑如何变
|
判定=副:新增比价失败明细可点开
|
||||||
|
|
||||||
|
- 「识别失败」:失败数可点击查看失败文件与原因
|
||||||
- …
|
- …
|
||||||
|
|
||||||
### 定稿 · 2026-07-10
|
### 定稿 · V1.1.0 · 2026-07-10
|
||||||
|
|
||||||
|
判定=用户指定·副
|
||||||
|
|
||||||
- …
|
- …
|
||||||
```
|
```
|
||||||
|
|
||||||
## 与日常改原型的关系
|
## 与日常改原型的关系
|
||||||
|
|
||||||
- **改原型过程中**:按 AutoPRD 主流程增量更新第 1–9 章;**不必**每改一次就写第 10 章。
|
- **改原型过程中**:增量更新第 1–9 章;**不必**每改一次写第 10 章。
|
||||||
- **用户说定稿时**:才汇总写入第 10 章并刷新基线。
|
- **用户说定稿时**:才汇总第 10 章并刷新版本与基线。
|
||||||
|
|||||||
@@ -2,6 +2,22 @@
|
|||||||
|
|
||||||
复制下列结构填写。方括号为占位。**第 4 章用户故事必须用业务条线说明口径。**
|
复制下列结构填写。方括号为占位。**第 4 章用户故事必须用业务条线说明口径。**
|
||||||
|
|
||||||
|
## 概要能力 → 章节映射
|
||||||
|
|
||||||
|
| 用户概要 | 本模板位置 |
|
||||||
|
|---|---|
|
||||||
|
| 总览 | §1 一句话与目标 |
|
||||||
|
| 目标 / 边界 | §1–2 |
|
||||||
|
| 角色 | §3 |
|
||||||
|
| 用户故事(起点→运作→闭环)/ 故事点 | §4 |
|
||||||
|
| 正逆向流程 | §5 |
|
||||||
|
| 状态 / 风险 / 关键逻辑 | §6(可分小节写状态机与风险) |
|
||||||
|
| 流程图 | §7 |
|
||||||
|
| 交付 | §9 |
|
||||||
|
| 定稿变更与版本 | §10(见 release-changelog) |
|
||||||
|
|
||||||
|
状态与风险也可在 §6 下设 `### 状态` / `### 风险` 短节,避免另起大结构推翻存量 PRD。
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
# <模块名> · 产品需求说明(全模块)
|
# <模块名> · 产品需求说明(全模块)
|
||||||
|
|
||||||
@@ -110,7 +126,9 @@ flowchart TB
|
|||||||
> 产品经理原型发版记录。仅记功能与业务逻辑变更;不含样式/UI/表结构。
|
> 产品经理原型发版记录。仅记功能与业务逻辑变更;不含样式/UI/表结构。
|
||||||
> 由「需求定稿」关键字触发追加;日常改原型不强制每改必写。详见 [release-changelog.md](release-changelog.md)。
|
> 由「需求定稿」关键字触发追加;日常改原型不强制每改必写。详见 [release-changelog.md](release-changelog.md)。
|
||||||
|
|
||||||
### 定稿 · YYYY-MM-DD
|
### 定稿 · V{x.y.z} · YYYY-MM-DD
|
||||||
|
|
||||||
|
判定=<主|副|子|用户指定·…>:<一行依据>
|
||||||
|
|
||||||
- 「<能力名>」:<做了什么 / 逻辑如何变>
|
- 「<能力名>」:<做了什么 / 逻辑如何变>
|
||||||
- …
|
- …
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# 【交付】任务描述回填(设计完成 · 按编号)
|
||||||
|
|
||||||
|
与 **`$YunxiaoPMapp`** 组合。创建【交付】时描述保持占位 `等待设计任务完成后自动填入`;**本文件只在设计完成(或显式同步)时**把 AutoPRD Markdown 写入【交付】。
|
||||||
|
|
||||||
|
**禁止**按任务标题查找交付;**禁止**加载 `yunxiao-requirement-lifecycle`。
|
||||||
|
|
||||||
|
## 触发时机
|
||||||
|
|
||||||
|
| 时机 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| YunxiaoPMapp **设计完成**且 AutoPRD 落盘成功 | 必须回填【交付】描述 |
|
||||||
|
| 口令 `同步交付说明:交付任务=ONEOS-xx`(或需求编号可反查交付) | 按编号回填 |
|
||||||
|
| 仅创建【交付】 / 分析中 / 设计中尚未设计完成 | **不**写 PRD 正文 |
|
||||||
|
|
||||||
|
## 前置
|
||||||
|
|
||||||
|
1. 已有【交付】任务编号:口令显式 > 需求 `## 工作项编号(系统)` > ASSOCIATED 反查校验。
|
||||||
|
2. 冲突或缺少编号 → 停下询问;禁止按 `【交付】`+标题猜。
|
||||||
|
3. 本地已有 `requirements-prd.md`(或本轮刚生成)。
|
||||||
|
|
||||||
|
## 写入内容
|
||||||
|
|
||||||
|
- 用与需求「产品说明(AutoPRD)」一致的正文**替换**占位文案。
|
||||||
|
- 推荐:原型链接 + `requirements-prd.md` 全文(或 YunxiaoPMapp 约定的产品说明正文)。
|
||||||
|
- 可附一句:`原始诉求见需求描述「原始诉求(AutoRDO)」`。
|
||||||
|
- 不要删除或改写需求侧 AutoRDO 段(本步骤只改**任务**描述)。
|
||||||
|
|
||||||
|
## 执行顺序(设计完成组合)
|
||||||
|
|
||||||
|
```text
|
||||||
|
1. AutoPRD 落盘 MD + 标注同步
|
||||||
|
2. 更新需求「产品说明(AutoPRD)」
|
||||||
|
3. 按交付任务编号 PATCH 任务描述(替换占位)
|
||||||
|
4. 附件(ZIP/截图)由 YunxiaoPMapp make-export 流程负责;本文件不替代附件
|
||||||
|
5. 任一步失败 → 不得声称交付说明已更新 / 设计完成材料齐全
|
||||||
|
```
|
||||||
|
|
||||||
|
## 回报
|
||||||
|
|
||||||
|
- 交付任务编号、是否已替换占位、MD 路径
|
||||||
|
- 失败时列出缺项(无编号 / 无 MD / 写入失败)
|
||||||
|
|
||||||
|
## 负向
|
||||||
|
|
||||||
|
- 创建交付当下灌入未完成的 PRD
|
||||||
|
- 按标题 list 复用「像交付的任务」
|
||||||
|
- 引导旧 lifecycle 建同名任务
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
# 云效需求描述:产品说明(对接 YunxiaoPMapp)
|
||||||
|
|
||||||
|
发云效 / 完善需求描述时,与 **`$YunxiaoPMapp`** 双段模板对齐。
|
||||||
|
**禁止加载** `yunxiao-requirement-lifecycle`。
|
||||||
|
|
||||||
|
## 需求描述固定结构(不可互相覆盖)
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 原始诉求(AutoRDO)
|
||||||
|
(由 AutoRDO 清洗;设计完成也不删除;本 Skill 不覆盖本段)
|
||||||
|
|
||||||
|
## 产品说明(AutoPRD)
|
||||||
|
(本 Skill 写入:原型链接 + requirements-prd 正文或等价产品说明)
|
||||||
|
|
||||||
|
## 工作项编号(系统)
|
||||||
|
(由 YunxiaoPMapp 维护;本 Skill 不改本段)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 产品说明段推荐拼装
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 产品说明(AutoPRD)
|
||||||
|
|
||||||
|
### 原型链接
|
||||||
|
<{baseUrl}/{prototype-id}/index.html;禁止加 prototypes/ 前缀;禁止去掉 index.html>
|
||||||
|
无则写「待发布」
|
||||||
|
|
||||||
|
### 需求说明
|
||||||
|
<src/prototypes/<id>/.spec/requirements-prd.md 全文原样粘贴;禁止摘要顶替>
|
||||||
|
|
||||||
|
### 更新内容
|
||||||
|
<第 10 章最新定稿块;无则「首版定稿」或「本轮无功能/逻辑增量」>
|
||||||
|
|
||||||
|
### 更新内容·历史
|
||||||
|
<旧更新内容倒序;勿删>
|
||||||
|
```
|
||||||
|
|
||||||
|
若 YunxiaoPMapp 本轮只要求「产品说明」短写:至少包含原型链接 + MD 全文或与交付回填一致的正文;**仍禁止**覆盖 AutoRDO / 工作项编号段。
|
||||||
|
|
||||||
|
## 真相源文件
|
||||||
|
|
||||||
|
1. `src/prototypes/<prototype-id>/.spec/requirements-prd.md`(主)
|
||||||
|
2. 否则 `src/resources/prd/<prototype-id>-autoprd.md`
|
||||||
|
|
||||||
|
先 Read 文件再写入;不要凭记忆重写。
|
||||||
|
|
||||||
|
## 执行步骤
|
||||||
|
|
||||||
|
1. 确认 prototype-id 与需求编号(若写云效)。
|
||||||
|
2. 读 MD 全文。
|
||||||
|
3. PATCH/更新需求描述时**只改**「产品说明(AutoPRD)」相关内容;保留原始诉求与工作项编号。
|
||||||
|
4. 若同时设计完成:按 [yunxiao-delivery-sync.md](yunxiao-delivery-sync.md) 回填【交付】。
|
||||||
|
5. 回报:需求编号、MD 路径、是否全文写入、是否已回填交付编号。
|
||||||
|
|
||||||
|
## 禁止
|
||||||
|
|
||||||
|
- 只用第 9 章摘要顶替全文(除非用户只要链接)
|
||||||
|
- 二次删减章节、去掉 mermaid/表格却声称全文已写
|
||||||
|
- 创建【交付】时灌入 PRD(须等设计完成;见交付回填)
|
||||||
|
- 引用或配合 `yunxiao-requirement-lifecycle`
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
# 云效阶段任务自动创建(AutoPRD 负责)
|
|
||||||
|
|
||||||
本规则写在 **oneos-autoprd**,不依赖改写 `yunxiao-requirement-lifecycle`。
|
|
||||||
凡本 Skill 参与的云效操作中,需求推进到下列状态时,**同一轮必须**建同名任务并正式关联需求。
|
|
||||||
|
|
||||||
## 触发状态
|
|
||||||
|
|
||||||
| 需求推进至 | 任务标签(右侧基础字段) | 负责人 | 任务标题 |
|
|
||||||
|------------|--------------------------|--------|----------|
|
|
||||||
| **分析中** | `分析` | **需求创建人**姓名 | 与需求标题**完全同名** |
|
|
||||||
| **设计中** | `设计` | **需求创建人**姓名 | 与需求标题**完全同名** |
|
|
||||||
| **待开发** | `交付`(若项目无「交付」标签则用 `开发`) | **何斐** | 与需求标题**完全同名** |
|
|
||||||
|
|
||||||
## 强制字段与关系
|
|
||||||
|
|
||||||
1. **正式关联需求**:父子或关联项;只挂标题不算关联。创建后必须在界面上能看到需求 ↔ 任务关系。
|
|
||||||
2. **标签**:写入任务「标签」基础字段(见上表);标题前缀不能代替标签。
|
|
||||||
3. **创建时间沿用需求**:任务的创建时间(及标签侧可见的创建时间口径)尽量与**需求创建时间**一致。
|
|
||||||
- 平台允许改创建时间 / 用 API 指定时:写成需求的创建时间。
|
|
||||||
- 平台不允许:在任务描述首行注明 `创建时间口径=需求创建时间(YYYY-MM-DD HH:mm)`,并在回报里说明「平台限制未改系统创建时间」。
|
|
||||||
4. **幂等**:同一需求、同一阶段标签下,已存在**未取消**且已正式关联的同名任务 → **不新建**,只校验负责人/标签/关联是否正确,缺则补齐。
|
|
||||||
5. **顺序**:先确认需求已进入目标状态(或本轮动作将写入该状态),再创建/补齐任务;回报时给出任务编号与链接。
|
|
||||||
|
|
||||||
## 执行步骤(apply 时)
|
|
||||||
|
|
||||||
```text
|
|
||||||
1. 读取需求:标题、创建人、创建时间、当前/目标状态、已关联任务列表
|
|
||||||
2. 按上表确定本轮阶段标签与负责人
|
|
||||||
3. 查重(需求ID + 阶段标签 + 未取消)
|
|
||||||
4. 无则创建:标题=需求标题;标签=阶段标签;负责人=上表;创建时间口径=需求创建时间;正式关联需求
|
|
||||||
5. 有则校验并修补标签/负责人/关联
|
|
||||||
6. 回报:需求状态、任务编号、负责人、是否新建/复用
|
|
||||||
```
|
|
||||||
|
|
||||||
## 不在本规则内
|
|
||||||
|
|
||||||
- 不自动建「测试 / 发版」任务(除非用户另行要求)。
|
|
||||||
- 不因样式类 PRD 变更触发建任务;仅**需求状态**进入分析中/设计中/待开发时触发。
|
|
||||||
- 云效生命周期细则、流水线、缺陷闭环仍可由 `$yunxiao-requirement-lifecycle` 配合执行;**本建任务逻辑以 AutoPRD 本文为准**。
|
|
||||||
|
|
||||||
## 与定稿 / 需求说明的关系
|
|
||||||
|
|
||||||
- 写「需求说明 / 更新内容」仍按 AutoPRD 主流程与定稿流程。
|
|
||||||
- 推进到待开发且需要描述时:先 AutoPRD 文档,再改状态,再按本文件建任务(负责人何斐)。
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
description: 改原型跟进 AutoPRD;定稿写功能变更;云效建需求先跑 AutoPRD;状态推进建同名任务
|
description: 改原型跟进 AutoPRD;定稿写功能变更与版本号;云效仅与 YunxiaoPMapp 组合;禁止旧 lifecycle 同名任务
|
||||||
alwaysApply: true
|
alwaysApply: true
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -7,7 +7,7 @@ alwaysApply: true
|
|||||||
|
|
||||||
## 改原型
|
## 改原型
|
||||||
|
|
||||||
修改 `src/prototypes/**` 且涉及**行为、文案、流程、判定或验收**时,同一轮必须跟进 **oneos-autoprd**:
|
修改 `src/prototypes/**` 且涉及**行为、文案、流程、判定或验收**时,同一轮必须跟进 **oneos-autoprd**(AutoPRD):
|
||||||
|
|
||||||
1. 更新 `.spec/requirements-prd.md`(用户故事:起点 → 怎么运作 → 闭环)。
|
1. 更新 `.spec/requirements-prd.md`(用户故事:起点 → 怎么运作 → 闭环)。
|
||||||
2. 更新 `annotation-source.json` **顶层** `directory.nodes` 中「产品需求说明(PRD)」。
|
2. 更新 `annotation-source.json` **顶层** `directory.nodes` 中「产品需求说明(PRD)」。
|
||||||
@@ -17,26 +17,16 @@ alwaysApply: true
|
|||||||
|
|
||||||
## 需求定稿
|
## 需求定稿
|
||||||
|
|
||||||
用户回复含 `需求定稿` / `定稿` / `确认定稿` / `本次定稿` 时:
|
用户回复含 `需求定稿` / `定稿` / `确认定稿` / `本次定稿` / `本轮定稿` 时:
|
||||||
|
|
||||||
1. 按 skill `references/release-changelog.md` 汇总**自上次定稿**的功能/逻辑变更。
|
1. 按 skill `references/release-changelog.md` 汇总**自上次定稿**的功能/逻辑变更,并递增 `prdVersion`(用户显式指定主/副/子时以用户为准)。
|
||||||
2. 追加到 PRD `## 10. 功能变更记录`(最新在上);更新 `.spec/autoprd-baseline.json`。
|
2. 追加到 PRD `## 10. 功能变更记录`(最新在上);更新 `.spec/autoprd-baseline.json`(含 `prdVersion`)。
|
||||||
3. **不要**写布局/UI/表结构类条目。
|
3. **不要**写布局/UI/表结构类条目。
|
||||||
|
|
||||||
## 云效建需求
|
## 云效(唯一组合 · YunxiaoPMapp)
|
||||||
|
|
||||||
使用 `yunxiao-requirement-lifecycle` **创建或完善**需求描述时,**先**跑 `oneos-autoprd`:
|
产品侧写云效**只**与 `$YunxiaoPMapp` 组合;**禁止加载** `yunxiao-requirement-lifecycle`。
|
||||||
|
|
||||||
- 需求说明 ← AutoPRD 正文
|
- 入库碎片:先 `$AutoRDO`,再 YunxiaoPMapp 记录需求(原始诉求段)。
|
||||||
- 更新内容 ← 第 10 章自上次定稿以来的条目(无则首版/无增量)
|
- 设计完成 / 完善产品说明:先 `oneos-autoprd` 落盘 MD,再写需求 `## 产品说明(AutoPRD)`;按交付**任务编号**回填【交付】描述(创建交付时保持占位,见 AutoPRD `yunxiao-delivery-sync.md`)。
|
||||||
- 旧更新内容 →「更新内容·历史」
|
- 【交付】/【分析】/【设计】树与交棒由 **YunxiaoPMapp** 负责;AutoPRD **不**建同名无前缀阶段任务。
|
||||||
|
|
||||||
## 云效状态 → 同名任务(AutoPRD 规则,不改云效 Skill)
|
|
||||||
|
|
||||||
需求推进至 **分析中 / 设计中 / 待开发** 时,按 `references/yunxiao-stage-tasks.md`:
|
|
||||||
|
|
||||||
- 建与需求**同名**任务并正式关联
|
|
||||||
- 标签:分析 / 设计 / 交付(或开发)
|
|
||||||
- 创建时间口径沿用需求
|
|
||||||
- 分析中、设计中负责人=创建人;待开发负责人=**何斐**
|
|
||||||
- 同阶段已有未取消关联任务则复用,不重复建
|
|
||||||
|
|||||||
85
.cursor/rules/oneos-v2-design-system.mdc
Normal file
85
.cursor/rules/oneos-v2-design-system.mdc
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
---
|
||||||
|
description: OneOS V2 全局定版设计规范(Stripe Violet 紫光高规 + 3视角架构 + PC/H5 移动端 100% 响应式 + 全量 UI 控件库 + 若依动态主题色 + 车牌号无点标准)
|
||||||
|
globs: src/prototypes/oneos-v2/**/*, src/prototypes/lease-contract-management/**/*, src/resources/design-system/**/*, src/prototypes/**/*
|
||||||
|
alwaysApply: true
|
||||||
|
---
|
||||||
|
|
||||||
|
# OneOS V2 全局定版设计规范(Cursor Agent 强制执行规则)
|
||||||
|
|
||||||
|
> **【硬性准则】**:在 `OneOS V2` 目录下**生成新页面、修改或迁移任何原型页面**时,AI Agent **必须首先 Read** 并严格遵守 `src/resources/design-system/DESIGN.md` 或 `src/prototypes/oneos-v2/DESIGN.md`!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. 新页面生成与修改工作流 (Mandatory Workflow)
|
||||||
|
|
||||||
|
1. **强前置步骤**:在创建或修改 `OneOS V2` 下的任何页面前,必须读取 `src/resources/design-system/DESIGN.md`,确认最新的 Token、UI 控件用法、3 视图模板和响应式规范。
|
||||||
|
2. **禁止使用原生 HTML 控件**:严禁直接使用原生 `<select>`、`<input type="date">` 或未经过 V2 封装的第三方组件。必须统一导入并使用 `UIComponents.tsx` 导出的封装控件:
|
||||||
|
- `V2Button`(主/次/描边/幽灵/危险/返回;详见 `DESIGN.md` §3.0)
|
||||||
|
- `V2Select`
|
||||||
|
- `V2DatePicker`
|
||||||
|
- `V2DateRangePicker`
|
||||||
|
- `V2SingleInputDateRangePicker`(单输入框双日历,默认推荐)
|
||||||
|
- `V2TimePicker`
|
||||||
|
- `V2SingleInputTimeRangePicker`(单输入框双时间)
|
||||||
|
- `V2RadioGroup`
|
||||||
|
- `V2CheckboxGroup`
|
||||||
|
- `V2Switch`
|
||||||
|
- `V2Steps`
|
||||||
|
- `V2Timeline`
|
||||||
|
- `V2ApprovalProgress`(默认 `direction="vertical"` 垂直贯穿时间轴)
|
||||||
|
- `V2Pagination`(统一分页控制器)
|
||||||
|
- `V2Empty`(空状态与异常页组件)
|
||||||
|
- `V2SegmentedControl`(顶栏视图/模式分段切换控件)
|
||||||
|
- `V2StatusTabs`(分类/状态过滤页签条)
|
||||||
|
- `V2ImageUpload`(图片拖拽/新增上传 · Web Dropzone + H5 拍照/相册;详见 `DESIGN.md` §3.17)
|
||||||
|
- `V2MobileHeader`
|
||||||
|
- `V2MobileBottomNav`
|
||||||
|
- `V2MobileActionBar`
|
||||||
|
3. **母版参考**:
|
||||||
|
- **台账三视角**:`src/prototypes/lease-contract-management/LeaseContractHub.tsx`(13 项高阶筛选、3 视图、嵌套车辆子表)。
|
||||||
|
- **结构化工单/处置表单页**:`src/prototypes/lease-contract-redesign/FaultDispositionForm.tsx`(左主表单三段卡 + 右 340px 指派/SLA;详见 `DESIGN.md` §4.8)。
|
||||||
|
4. **筛选查询收起(强制)**:台账筛选栏 /「更多筛选」展开后,点击 **查询** 必须应用条件并**自动收起**筛选栏(H5 为关闭 Bottom Sheet);**重置**清空后同样收起。详见 `DESIGN.md` §2.4.3。
|
||||||
|
5. **列表操作列(强制)**:常用「编辑 / 处理(处置)」**外侧**展示(最多 2 个);低频「查看记录 / 操作记录 / 历史」及危险操作收入 **⋮ 更多**。统一使用 `OperationActions`(`DESIGN.md` §3.16 / `vm-shared/DESIGN.md`)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 核心视觉与配色规范 (Stripe Fintech UI)
|
||||||
|
|
||||||
|
- **主色 (Primary Accent)**:Stripe Violet `#533AFD`(悬停 `#6346FF`,Focus 环 `#4226E8`,浅亮底 `#E0E7FF`,暗亮底 `rgba(83, 58, 253, 0.18)`)
|
||||||
|
- **画布背景**:浅色 `#F6F9FC` / 深色 `#0A0B0D`
|
||||||
|
- **卡片容器**:浅色 `#FFFFFF` / 深色 `#121418`
|
||||||
|
- **边框线**:浅色 `#E3E8EE` / 深色 `#23272F`
|
||||||
|
- **主正文**:浅色 `#0A2540` / 深色 `#F7FAFC`
|
||||||
|
- **次要正文**:浅色 `#425466` / 深色 `#A0AEC0`
|
||||||
|
- **语义色**:成功 `#10B981` · 预警 `#D97706` · 危险/错误 `#EF4444` · 提示 `#3B82F6`
|
||||||
|
- **若依 (RuoYi) 框架动态主题色**:所有组件背景、边框、选中态必须消费 CSS 变量 `var(--oneos-primary, var(--ln-primary, #533AFD))`,兼容若依的主题色动态切换。
|
||||||
|
- **双色模式**:通过 `[data-ds-mode="dark"]` 或 `[data-oneos-theme="dark"]` 响应,严禁出现外壳深内容浅的失配情况。
|
||||||
|
- **车牌号规范**:车牌号严禁出现间隔点 `·`(必须形如 `浙A88888F`、`京A66666`)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. PC / H5 移动端 App 嵌入 100% 响应式 (Mobile H5 Standard)
|
||||||
|
|
||||||
|
- **双形态适配**:所有 V2 原型必须支持 PC 屏宽 (≥1024px) 与 H5 移动端 (≤767px) 形态。
|
||||||
|
- **触控规格**:移动端 (≤767px) 场景下,所有可点击元素与输入框触控高度必须 **`≥ 44px`**(`min-height: 44px`),正文字号 **`≥ 14px`**。
|
||||||
|
- **Mobile Bottom Sheet**:移动端下 `V2Select`、`V2DatePicker` 等弹窗自动转为固定吸底 **Bottom Sheet 面板**,配有顶部抓手条与 44px 确定按钮。
|
||||||
|
- **移动端底部操作条**:提交与主操作按钮在移动端自动固定吸底(`V2MobileActionBar`)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 统一的三视角页面架构 (Three Core Views)
|
||||||
|
|
||||||
|
任何台账、列表、审批与履约管理页面必须提供或集成 3 视角模板:
|
||||||
|
1. **列表模式 (List View)**:包含 Bento Grid KPI 大盘 + Pill Tabs + 13 项高阶筛选(查询/重置后自动收起)+ 展开式嵌套子表格。
|
||||||
|
2. **看板模式 (Kanban View)**:包含 4 阶段 Pipeline 管道列(卡片快速操作与流程推进)。
|
||||||
|
3. **主从表单模式 (Split / Master-Detail View)**:左侧 340px 搜索任务/单据列表 + 右侧深度工作台(包含结构化表单、关联业务 Tabs 及履约图谱)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 规范参考文件路径
|
||||||
|
|
||||||
|
- 全局主规范文档:`src/resources/design-system/DESIGN.md`
|
||||||
|
- 规范展示页:`src/prototypes/oneos-v2/DesignSystemShowcase.tsx`
|
||||||
|
- 组件库文件:`src/resources/design-system/components/UIComponents.tsx`
|
||||||
|
- 全局 Token CSS:`src/resources/design-system/oneos-ds-tokens.css`
|
||||||
|
- 若依预设导出:`src/resources/design-system/ruoyi-theme-preset.json` & `ruoyi-oneos-v2-theme.css`
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
---
|
---
|
||||||
description: 云效「记录需求」须先点选优先级/推进至;统一运营管理平台走快路径,禁止默认参数与盲目探测
|
description: 产品侧云效写操作走 YunxiaoPMapp;强制 Plan 门禁;禁止加载已删除的 yunxiao-requirement-lifecycle
|
||||||
globs:
|
globs:
|
||||||
alwaysApply: true
|
alwaysApply: true
|
||||||
---
|
---
|
||||||
|
|
||||||
# 云效记录需求 · 参数门禁与快路径
|
# 云效记录需求 · 产品侧唯一入口
|
||||||
|
|
||||||
当用户使用 `$yunxiao-requirement-lifecycle` / 「记录需求」,且涉及优先级、推进至时:
|
产品侧凡「记录需求 / 推进至 / 交棒 / 创建迭代」等**会改云效**的操作:
|
||||||
|
|
||||||
1. **必须先拿到明确选择**:优先级(紧急/高/中/低)、推进至(分析中/设计中/设计完成/开发中)、**标签(从云效标签 catalog 点选,可多选)**。优先 `AskQuestion`;不可用则用 Plan 确认并由用户写明 A+B+C。
|
0. **只使用 `$YunxiaoPMapp`**(及入库前 `$AutoRDO`、设计完成 `$oneos-autoprd`)。
|
||||||
2. **禁止**在未选择时默认「中 + 分析中」并自动建单。「批准/Implement 计划」≠ 已完成点选。
|
**禁止加载**已删除的 `yunxiao-requirement-lifecycle`;勿按旧同名阶段任务规则建单。
|
||||||
3. 项目为**统一运营管理平台**(含 PC 端别名)时:先读
|
1. **强制先切 Cursor Plan 模式**(`SwitchMode` → `plan`):对齐需求/任务**编号**、推进目标、交付树策略等;用户确认后再一口气 apply。
|
||||||
`.cursor/skills/yunxiao-requirement-lifecycle/references/oneos-pc-fast-path.md` 与
|
2. 标题规范:`【新增】…` / `【优化】…`(详见 YunxiaoPMapp / 口令面)。
|
||||||
`.cursor/skills/yunxiao-requirement-lifecycle/assets/oneos-pc-runtime-ids.json`(标签清单见同目录 `oneos-pc-tag-catalog.md`),按已验证 API/ID 执行;禁止重复探测 create URL。
|
3. 查重与复用**只认任务编号**;创建【交付】描述占位,设计完成再灌 AutoPRD。
|
||||||
4. **标签禁止**按 `lines.ts` / 业务条线说明自动推断;只能用用户点选的 catalog 名。API 打标失败时 UI 兜底;仍失败则停下请用户回复标签名,不得声称已成功。
|
4. 项目常量见 `.cursor/skills/YunxiaoPMapp/assets/runtime-ids.json`(勿再引用旧 lifecycle 路径)。
|
||||||
5. 优先 API(创建时写入描述;标签用 `PATCH … propertyKey=tag`);浏览器仅作标签失败或状态连跳兜底;少截图、同失败不循环重试。
|
5. 细则以 `$YunxiaoPMapp` Skill 全文为准。
|
||||||
|
|||||||
83
.cursor/skills/AutoRDO/SKILL.md
Normal file
83
.cursor/skills/AutoRDO/SKILL.md
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
---
|
||||||
|
name: AutoRDO
|
||||||
|
description: >-
|
||||||
|
AutoRDO (Requirement Description Optimization): cleans fragmented chat logs,
|
||||||
|
voice transcripts, oral notes, and feedback ledgers into written title and description;
|
||||||
|
auto-detects 类型/优先级/标签/提交部门/提交人 from content; maps OneOS modules via oneos-domain.md;
|
||||||
|
splits multi-line into multiple results; if any 待确认 exists, MUST switch to Plan mode
|
||||||
|
for choice-based confirmation. Does not change Yunxiao status or create tasks.
|
||||||
|
Pair with YunxiaoPMapp for cloud write; never load yunxiao-requirement-lifecycle.
|
||||||
|
---
|
||||||
|
|
||||||
|
# AutoRDO
|
||||||
|
|
||||||
|
**Requirement Description Optimization**(需求描述优化)。
|
||||||
|
将碎片化、通俗化文字(聊天/录音/反馈台账)在**保留原意**前提下拆解为**标题、描述**,并**自动识别**类型、优先级、标签、提交部门、提交人,供入库写入云效需求。
|
||||||
|
多行/多条独立诉求 → **自动拆成多份**转译结果。
|
||||||
|
|
||||||
|
**强制**:清洗结果中**只要存在任意「待确认」**,Agent **必须立刻** `SwitchMode` → **plan**,逐条用选择题消解;**无需**用户再说「确认待确认」。无待确认则可直接交定稿。
|
||||||
|
|
||||||
|
## 边界(强制)
|
||||||
|
|
||||||
|
| 做 | 不做 |
|
||||||
|
|---|---|
|
||||||
|
| 提炼标题与书面描述;自动识别类型/优先级/标签/提交部门/提交人 | 改云效状态 / 建任务 / **直接**打云效标签 |
|
||||||
|
| 多行/多条 → 多份转译结果 | 写成完整 AutoPRD / 臆造业务结论 |
|
||||||
|
| 有待确认 → 强制 Plan 逐条确认 | 停在初稿等口令;把猜测写入定稿 |
|
||||||
|
| 去除描述**结尾句号** | 加载 `yunxiao-requirement-lifecycle` |
|
||||||
|
|
||||||
|
云效建单与打标由 **`$YunxiaoPMapp`** 负责;本 Skill 只出清洗稿与**推荐元数据**。
|
||||||
|
|
||||||
|
## 何时使用
|
||||||
|
|
||||||
|
- 口令含 `AutoRDO` / `清洗聊天` / `录音整理` / `原始诉求`
|
||||||
|
- 粘贴反馈台账(含部门/优先级/模块列)或口述碎片
|
||||||
|
- YunxiaoPMapp「记录需求」前必须先跑本 Skill(材料为碎片/台账时)
|
||||||
|
|
||||||
|
## 输入
|
||||||
|
|
||||||
|
- 聊天、会议速记、口述、录音转写
|
||||||
|
- **多行/台账**:含反馈人、所属部门、业务模块、优先级、PC或移动端等列时优先采信列值
|
||||||
|
- 确认阶段补充文字
|
||||||
|
|
||||||
|
## 处理规则
|
||||||
|
|
||||||
|
**强制前置**:ONE-OS 材料先 Read [references/oneos-domain.md](references/oneos-domain.md),元数据规则见 [references/meta-fields.md](references/meta-fields.md),再按 [references/rules.md](references/rules.md) 执行。
|
||||||
|
|
||||||
|
1. **多条拆解** → 每条独立成稿
|
||||||
|
2. **OneOS 对齐** → 模块/部门标准名
|
||||||
|
3. **元数据识别** → 类型、优先级、标签、提交部门、提交人(显式列 > 正文标记 > 语义推断;不确定 → 待确认)
|
||||||
|
4. **标题 + 描述转译** → 去口语、去结尾句号
|
||||||
|
5. **有待确认 → 强制 Plan** → 见 [references/confirm-pending.md](references/confirm-pending.md)
|
||||||
|
|
||||||
|
## 输出
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 原始诉求(AutoRDO)
|
||||||
|
|
||||||
|
**标题**:<清晰标题>
|
||||||
|
**类型**:【新增】|【优化】
|
||||||
|
**优先级**:P1-高|P2-中|P3-低
|
||||||
|
**标签**:<标准模块>[, PC端|小程序]
|
||||||
|
**提交部门**:<标准部门名或空>
|
||||||
|
**提交人**:<姓名或空>
|
||||||
|
|
||||||
|
**描述**:
|
||||||
|
<转译正文;无结尾句号>
|
||||||
|
反馈:<有则附日期/禅道/状态/端>
|
||||||
|
|
||||||
|
待确认:
|
||||||
|
- …
|
||||||
|
```
|
||||||
|
|
||||||
|
多条时先写「共 N 条」,再 `### 1` … `### N`。
|
||||||
|
交 YunxiaoPMapp 示例:`记录需求:标题=…;类型=…;优先级=…;标签=…;提交部门=…;提交人=…;描述=…`
|
||||||
|
|
||||||
|
## 口令
|
||||||
|
|
||||||
|
```text
|
||||||
|
AutoRDO:<粘贴聊天或台账行>
|
||||||
|
AutoRDO:录音转写如下 …
|
||||||
|
按下列补充消解待确认:
|
||||||
|
<补充说明>
|
||||||
|
```
|
||||||
4
.cursor/skills/AutoRDO/agents/openai.yaml
Normal file
4
.cursor/skills/AutoRDO/agents/openai.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
interface:
|
||||||
|
display_name: "AutoRDO"
|
||||||
|
short_description: "清洗诉求并识别类型优先级标签部门提交人"
|
||||||
|
default_prompt: "按 AutoRDO 清洗:先读 oneos-domain.md 与 meta-fields.md;多行拆多条;出标题+描述+类型/优先级/标签/提交部门/提交人。有待确认则同轮强制切 Plan 用选择题消解;不改云效、不直接打标、不贴词典全文。"
|
||||||
126
.cursor/skills/AutoRDO/references/confirm-pending.md
Normal file
126
.cursor/skills/AutoRDO/references/confirm-pending.md
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
# AutoRDO · 待确认逐条 Plan 确认
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
|
||||||
|
清洗稿中的「待确认」经产品经理**逐条人工确认**后,回填进标题/描述,得到可交 YunxiaoPMapp 的定稿。
|
||||||
|
确认过程**优先选择题**;选项用 [oneos-domain.md](oneos-domain.md) 辅助生成;也支持用补充说明/需求描述文字直接消解待确认点。
|
||||||
|
|
||||||
|
## 何时进入(强制)
|
||||||
|
|
||||||
|
```text
|
||||||
|
清洗初稿产出后:
|
||||||
|
若任一需求含「待确认」→ 同轮必须 SwitchMode → plan
|
||||||
|
若全部无待确认 → 不必进 Plan,初稿即定稿
|
||||||
|
```
|
||||||
|
|
||||||
|
- **触发条件只有一条**:存在待确认(单条或多条中任意一点)
|
||||||
|
- **禁止**要求用户再说「确认待确认」「开始确认」才进 Plan
|
||||||
|
- 用户在 Plan 中可用选择题作答,也可粘贴补充说明消解
|
||||||
|
|
||||||
|
**不进 Plan 的唯一情况**:清洗结果中没有任何「待确认」条目。
|
||||||
|
|
||||||
|
## Plan 门禁(强制)
|
||||||
|
|
||||||
|
1. 清洗初稿写出后(可先展示初稿摘要),**立刻** `SwitchMode` → **plan**,说明:存在待确认,须逐条确认后再回填定稿;本阶段仍**不写云效**
|
||||||
|
2. Plan 列出:待确认的**需求条号**、每条下的待确认点清单、推荐确认方式(选择题 / 文字补充)
|
||||||
|
3. **用户确认 / 批准 Plan / 「执行」之前**:禁止把未确认内容写进定稿描述
|
||||||
|
4. 批准后:按条推进确认 → 回填 → 输出定稿
|
||||||
|
|
||||||
|
## 逐条确认顺序
|
||||||
|
|
||||||
|
```text
|
||||||
|
需求 1 的待确认点 1 → 点 2 → … → 需求 1 定稿片段
|
||||||
|
需求 2 的待确认点 1 → …
|
||||||
|
…
|
||||||
|
全部完成后输出「已确认定稿」全集
|
||||||
|
```
|
||||||
|
|
||||||
|
- **一次只推进一个待确认点**(或同一点下的一组互斥选项),避免一屏堆十几个问题
|
||||||
|
- 多条需求时,Plan 清单可注明建议从第 1 条起;用户可指定跳过或改序
|
||||||
|
- 某条无「待确认」→ 跳过,保留初稿即可
|
||||||
|
|
||||||
|
## 确认方式(优先选择)
|
||||||
|
|
||||||
|
每个待确认点按下列优先级出题:
|
||||||
|
|
||||||
|
| 优先级 | 方式 | 适用 |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | **选择题**(2–5 个互斥选项 + 可选「其他/我补充」) | 模块归属、部门名称、类型/优先级、是否/范围、枚举字段、拆条边界等 |
|
||||||
|
| 2 | **多选** | 明确可多选的范围(如适用端:PC+H5) |
|
||||||
|
| 3 | **文字补充** | 无法枚举、需自由描述字段清单/规则细节时 |
|
||||||
|
|
||||||
|
### 选项如何用 OneOS 词典生成
|
||||||
|
|
||||||
|
先 Read `oneos-domain.md`,再出选项:
|
||||||
|
|
||||||
|
- **模块名不清**:候选 = 词典中相关条线的标准模块名(如还车应结款 / 违章管理 / 还车管理),勿自造模块
|
||||||
|
- **部门/角色口语**:候选 = 第 1 节标准名(业管→业务管理组,安全小组→安全部 等)+「保持单据原文分区名」
|
||||||
|
- **跨条线联动**:选项写清主责模块 vs 联动对象;标题只挂主责,联动写描述
|
||||||
|
- **故事点细节**:仅当材料或用户补充已暗示时,才把词典闭环中的合理分支列为选项;**禁止**把未提及的故事点细节默认选中
|
||||||
|
|
||||||
|
每题结构建议:
|
||||||
|
|
||||||
|
```text
|
||||||
|
【需求 n · 待确认 k】<待确认原文>
|
||||||
|
依据词典,请选择:
|
||||||
|
A. …
|
||||||
|
B. …
|
||||||
|
C. …
|
||||||
|
D. 其他(请补充一句)
|
||||||
|
也可用一段需求描述直接回答本点
|
||||||
|
```
|
||||||
|
|
||||||
|
## 用需求描述补充
|
||||||
|
|
||||||
|
用户可用以下任一方式消解待确认,**不必**每题都点选:
|
||||||
|
|
||||||
|
- 粘贴一段补充说明 / 功能规则 / 字段清单
|
||||||
|
- 回复「按下列描述确认:…」
|
||||||
|
- 对某一待确认点直接写答案句
|
||||||
|
|
||||||
|
Agent 须:
|
||||||
|
|
||||||
|
1. 将补充文字**映射**到对应待确认点(可一次消解多点)
|
||||||
|
2. 写入该条**描述**(书面化、去结尾句号),从「待确认」列表**移除已消解项**
|
||||||
|
3. 补充仍含糊的部分 → 保留或新开「待确认」,继续选择题
|
||||||
|
4. **不**把补充里未说的内容脑补进去
|
||||||
|
|
||||||
|
## 回填定稿规则
|
||||||
|
|
||||||
|
确认完成后,对该条输出「已确认」版本:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
### n(已确认)
|
||||||
|
|
||||||
|
## 原始诉求(AutoRDO)
|
||||||
|
|
||||||
|
**标题**:…
|
||||||
|
|
||||||
|
**描述**:
|
||||||
|
<初稿 + 已确认信息合并;无结尾句号>
|
||||||
|
|
||||||
|
待确认:
|
||||||
|
- (无则写「无」或省略本段)
|
||||||
|
```
|
||||||
|
|
||||||
|
- 标题若因模块/动作确认而需微调,可改,并在确认回合说明改了什么
|
||||||
|
- 未确认点**不得**假装已确认;可标「本条暂缓,待确认仍保留」
|
||||||
|
- 全部条完成后,给总览:已确认条数 / 仍含待确认条数
|
||||||
|
|
||||||
|
## 口令
|
||||||
|
|
||||||
|
```text
|
||||||
|
AutoRDO:<材料> → 有待确认则自动进 Plan
|
||||||
|
按下列补充消解待确认:
|
||||||
|
<粘贴补充说明>
|
||||||
|
第 6 条待确认选 A;第 7 条补充:字段非必填,计入应补汇总
|
||||||
|
```
|
||||||
|
|
||||||
|
(「确认待确认」等口令**不再作为**进 Plan 的前置条件;有待确认即强制进。)
|
||||||
|
|
||||||
|
## 不做
|
||||||
|
|
||||||
|
- 确认阶段仍不改云效、不建任务
|
||||||
|
- 不把 `oneos-domain.md` 全文贴进定稿
|
||||||
|
- 不跳过 Plan 直接把「猜的答案」写进描述
|
||||||
|
- 不等用户额外口令才进 Plan(有待确认必须进)
|
||||||
96
.cursor/skills/AutoRDO/references/meta-fields.md
Normal file
96
.cursor/skills/AutoRDO/references/meta-fields.md
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
# AutoRDO · 元数据自动识别
|
||||||
|
|
||||||
|
从粘贴内容(台账表格行、聊天、口述)自动识别下列字段,写入每条原始诉求输出;**不**直接改云效打标(打标由 YunxiaoPMapp 执行)。
|
||||||
|
|
||||||
|
## 输出字段
|
||||||
|
|
||||||
|
| 字段 | 说明 | 无依据时 |
|
||||||
|
|---|---|---|
|
||||||
|
| **类型** | `【新增】` / `【优化】`(与云效标题前缀一致) | 默认 `【优化】`,并列入待确认 |
|
||||||
|
| **优先级** | `P1-高` / `P2-中` / `P3-低` | 默认 `P2-中`,高不确定则待确认 |
|
||||||
|
| **标签** | 主模块标签(对齐 `oneos-domain.md` 标准模块名);可附端标签 `PC端` / `小程序` | 仅模块不确定则待确认 |
|
||||||
|
| **提交部门** | 映射到词典标准部门名 | 材料无部门且无法推断 → 待确认或空 |
|
||||||
|
| **提交人** | 反馈人/用户姓名 | 材料无人名 → 空(不臆造) |
|
||||||
|
|
||||||
|
## 识别优先级
|
||||||
|
|
||||||
|
```text
|
||||||
|
1. 显式列/字段(反馈台账:优先级、所属部门、反馈方、业务模块、PC或移动端…)
|
||||||
|
2. 正文中的明确标记(P1、【优化】、@某人、部门署名)
|
||||||
|
3. 语义推断(用词 + oneos-domain 模块/部门)
|
||||||
|
4. 仍不确定 → 待确认(选择题),禁止假装已确认
|
||||||
|
```
|
||||||
|
|
||||||
|
## 类型(【新增】/【优化】)
|
||||||
|
|
||||||
|
| 信号 | 类型 |
|
||||||
|
|---|---|
|
||||||
|
| 新增、增加、支持、允许、增加列/字段/入口、批量导入(首次能力) | 【新增】 |
|
||||||
|
| 优化、调整、修改、放开、更清晰、重构、移动至、改由、精确到、兼容 | 【优化】 |
|
||||||
|
| 台账/口令已写 `【新增】`/`【优化】` | 以显式为准 |
|
||||||
|
| 同时含新增与优化语义 | 以**主诉求**定类型;次要点写在描述 |
|
||||||
|
|
||||||
|
标题可带类型前缀供入库:`【优化】交车管理:…`;若用户只要裸标题,类型仍单独输出字段。
|
||||||
|
|
||||||
|
## 优先级
|
||||||
|
|
||||||
|
| 信号 | 优先级 |
|
||||||
|
|---|---|
|
||||||
|
| 列值 `P1-高` / `P1` / 紧急、阻塞、无法办理、P1 | `P1-高` |
|
||||||
|
| 列值 `P2-中` / `P2` | `P2-中` |
|
||||||
|
| 列值 `P3-低` / `P3` / 文案、置灰、体验微调 | `P3-低` |
|
||||||
|
| 无信号 | 默认 `P2-中` |
|
||||||
|
|
||||||
|
## 标签
|
||||||
|
|
||||||
|
1. **主标签** = 归属标准模块名(`oneos-domain.md`),如 `还车应结款`、`违章管理`、`交车管理`
|
||||||
|
2. 台账「业务模块」列优先;口语映射到标准名(验车管理→验车入库,调拨管理→车辆调拨)
|
||||||
|
3. **端标签**(可选,可多选):材料含 `PC端`/`小程序`/`PC及小程序` 时写入
|
||||||
|
4. 「其他」「全局优化」「小程序审批中心」等非模块名:主标签用最贴近模块或 `系统全局`;勿发明云效不存在的随意标签名
|
||||||
|
5. 输出格式:逗号分隔,如 `还车应结款, PC端`
|
||||||
|
|
||||||
|
## 提交部门
|
||||||
|
|
||||||
|
| 材料常见写法 | 标准输出 |
|
||||||
|
|---|---|
|
||||||
|
| 业务管理部、业管、业务管理 | 业务管理组 |
|
||||||
|
| 运维部、运维 | 运维部 |
|
||||||
|
| 数智中心、数智、信息化 | 数智部 |
|
||||||
|
| 安全部、安全 | 安全部 |
|
||||||
|
| 财务部、财务 | 财务部 |
|
||||||
|
| 法务部、法务 | 法务部 |
|
||||||
|
| 采购部/采购组 | 按词典区分输出 |
|
||||||
|
|
||||||
|
台账「所属部门」列优先;聊天中「我们运维…」可推断,低置信度则待确认。
|
||||||
|
|
||||||
|
## 提交人
|
||||||
|
|
||||||
|
- 台账「反馈方/用户」「反馈人」列 → 原样作为提交人
|
||||||
|
- 聊天 @姓名、署名「张三:」→ 取该名
|
||||||
|
- 多人联合反馈 → 取主反馈人(首列/首个署名);其余可写描述附注
|
||||||
|
- **禁止**用当前对话用户名冒充提交人(除非材料写明)
|
||||||
|
|
||||||
|
## 与描述附注的关系
|
||||||
|
|
||||||
|
- **结构化字段**(类型/优先级/标签/提交部门/提交人)单独成行,供 YunxiaoPMapp 建单口令复用
|
||||||
|
- 禅道编号、处理状态、反馈日期等 → 可放描述末行「反馈:…」附注,不升格为强制字段
|
||||||
|
|
||||||
|
## 输出模板(每条)
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 原始诉求(AutoRDO)
|
||||||
|
|
||||||
|
**标题**:<清晰标题;可选带【新增】/【优化】前缀>
|
||||||
|
**类型**:【新增】|【优化】
|
||||||
|
**优先级**:P1-高|P2-中|P3-低
|
||||||
|
**标签**:<模块>[, PC端|小程序]
|
||||||
|
**提交部门**:<标准部门名或空>
|
||||||
|
**提交人**:<姓名或空>
|
||||||
|
|
||||||
|
**描述**:
|
||||||
|
<转译正文;无结尾句号>
|
||||||
|
反馈:<日期 · 原文部门 · 状态 · 禅道号 · 端 …>(有则写)
|
||||||
|
|
||||||
|
待确认:
|
||||||
|
- …
|
||||||
|
```
|
||||||
399
.cursor/skills/AutoRDO/references/oneos-domain.md
Normal file
399
.cursor/skills/AutoRDO/references/oneos-domain.md
Normal file
@@ -0,0 +1,399 @@
|
|||||||
|
# ONE-OS 业务领域词典(供 AutoRDO 对齐)
|
||||||
|
|
||||||
|
> 来源:业务条线说明原型 `lease-business-line-overview`
|
||||||
|
> 用途:清洗标题/描述时,优先用下列**标准模块名、部门名、闭环表述**对齐,避免口语臆造模块或错挂条线。
|
||||||
|
> 系统定位:1 套系统 · 5 大业务条线闭环 · 3 大数据底座 · 演进方向为业财一体
|
||||||
|
> **强制**:本文件只用于理解与用词对齐;**禁止**把本词典全文贴进云效描述或 AutoRDO 输出稿。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. 系统总览
|
||||||
|
|
||||||
|
| 维度 | 口径 |
|
||||||
|
|---|---|
|
||||||
|
| 平台名 | ONE-OS(亦写作 OneOS) |
|
||||||
|
| 五大业务条线 | 租赁 · 能源 · 运维 · 安全 · 物流 |
|
||||||
|
| 三大数据底座 | 车辆资产运营情况 · 各业务条线盈亏情况 · 里程调度情况 |
|
||||||
|
| 现阶段 | 业务驱动 · 财务手工维护(收款/付款/核销多人工) |
|
||||||
|
| 演进方向 | 业财闭环一体化(打通财务 YS,「收款记录」「付款记录」与业务台账双向回写) |
|
||||||
|
|
||||||
|
**标题提炼提示**:口述涉及合同/台账/交还车/氢费/证照/调度时,先归入对应条线再落模块名;跨条线联动(如还车应结款联动违章事故)在描述中写明联动对象,标题以主责模块为准。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 业务部门 / 角色词典(标准用词)
|
||||||
|
|
||||||
|
清洗时统一下列名称;同义口语请映射到标准名。
|
||||||
|
|
||||||
|
| 标准名称 | 常见口语/别称 | 主要出现条线 |
|
||||||
|
|---|---|---|
|
||||||
|
| 业务管理组 | 业管、业务管理 | 租赁、运维、安全、物流 |
|
||||||
|
| 业务管理组-能源部 | 能源组、业管能源、业务管理部-能源组 | 能源、租赁还车 |
|
||||||
|
| 业务服务组 | 业务服务 | 物流 |
|
||||||
|
| 业务员 | 业务 | 租赁 |
|
||||||
|
| 调度岗 | 调度 | 物流 |
|
||||||
|
| 法务部 | 法务 | 租赁、运维采购合同 |
|
||||||
|
| 财务部 | 财务 | 租赁评级、能源账户、运维付款/维保、安全违章事故、物流台账 |
|
||||||
|
| 安全部 | 安全 | 租赁评级、证照、安全条线 |
|
||||||
|
| 运维部 | 运维、区域操作员 | 运维全链路、交还车、租赁提车后交车 |
|
||||||
|
| 采购部 | 采购 | 能源加氢站、运维采购合同/验车 |
|
||||||
|
| 采购组 | 采购组 | 供应商管理(能源/运维) |
|
||||||
|
| 数智部 | 数智、信息化 | 合同模板电子化、能源扩展 |
|
||||||
|
| 董事长 | 老板、总 | 非标合同、资产出售过户报废确认 |
|
||||||
|
| 司机 | 提车司机、内部司机 | 交车培训、故障、安全培训 |
|
||||||
|
| 加氢站 / 签约加氢站 | 站点、站方 | 能源 |
|
||||||
|
|
||||||
|
**组织边界提示**
|
||||||
|
|
||||||
|
- 「采购组」侧重供应商主数据;「采购部」侧重站点管理与采购/三方租赁合同。
|
||||||
|
- 「业务管理组」与「业务管理组-能源部」勿混用;氢费、加氢对账默认能源部。
|
||||||
|
- 物流调度明确:**非 TMS**,不做配载与承运商调度。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 功能模块总表(按条线)
|
||||||
|
|
||||||
|
### 2.1 租赁业务条线(6 模块 · 全链路闭环)
|
||||||
|
|
||||||
|
**条线闭环**:客户评级决定是否可签 → 标准模板支撑签约 → 租赁合同进入履约 → 提车应收对齐后交车 → 台账承接租期账单 → 还车应结款会签归档。
|
||||||
|
|
||||||
|
| 步 | 模块名 | 一句话定位 | 责任部门 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 1 | 客户管理 | 准入评级 · 决定能否签约、走哪条流程 | 业务管理组、法务部、财务部、安全部 |
|
||||||
|
| 2 | 标准合同管理 | 模板配置 · 支撑电子合同一键发起 | 法务部、数智部 |
|
||||||
|
| 3 | 租赁合同 | 签约发起 · 标准 / 非标 / 禁止三条路径 | 业务员、法务部 |
|
||||||
|
| 4 | 提车应收款 | 应收生成 · 实收对齐 · 触发交车 | 业务员、法务部、业务管理组、运维部 |
|
||||||
|
| 5 | 租赁业务台账 | 交车后账单 · 周期收费与实收延续 | 运维部、业务员、业务管理组 |
|
||||||
|
| 6 | 还车应结款 | 还车结算 · 多部门会签 · 归档闭环 | 业务管理组、安全部、运维部、业务管理组-能源部 |
|
||||||
|
|
||||||
|
**关键结果标签(客户管理)**:可标准签约 · 可签·走非标 · 禁止签约·高风险
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.2 能源业务条线(6 模块 · 业财闭环)
|
||||||
|
|
||||||
|
**条线闭环**:供应商主数据支撑站点绑定 → 签约站账号与订单主动上报 → 非签约站氢费补录对账 → 客户对账单关联收款 → 加氢记录标记已付款 → 成熟后向采购端与司机端延伸。
|
||||||
|
|
||||||
|
| 步 | 模块名 | 一句话定位 | 责任部门 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 1 | 供应商管理 | 加氢/充电站供应商 · 站点绑定与业财直连 | 采购组、财务部 |
|
||||||
|
| 2 | 加氢站管理 | 签约站 / 非签约站 · 账号、余额与价格 | 采购部、加氢站 |
|
||||||
|
| 3 | 加氢订单 | 主动上报 · PLC 自动采集 · 预约接单 | 签约加氢站、业务管理组-能源部 |
|
||||||
|
| 4 | 车辆氢费明细 | 非签约站补录 · 对账归档 · 余额关联 | 业务管理组-能源部 |
|
||||||
|
| 5 | 氢费账户 | 客户预付款 · 对账单 · 业财收款闭环 | 业务管理组-能源部、财务部 |
|
||||||
|
| 6 | 扩展规划 | 上游采购 · 下游司机服务 | 采购部、业务管理组-能源部、数智部 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.3 运维管理条线(15 模块)
|
||||||
|
|
||||||
|
**主线(main)**:验车入库 → 上牌 → 证照 → 备车 → 交车 → 还车 → 出售/过户/报废出库
|
||||||
|
**并行能力(support)**:供应商、采购合同、替换车、故障、年审、维保、异动、调拨(无严格先后)
|
||||||
|
|
||||||
|
**条线闭环**:供应商与采购合同入库 → 上牌证照与备车整备 → 交车/替换/还车闭环 → 故障与年审维保 → 异动调拨 → 出售/过户/报废审批出库。
|
||||||
|
|
||||||
|
| 步 | 模块名 | 轨道 | 一句话定位 | 责任部门 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| 1 | 供应商管理 | support | 整车厂 / 三方租赁 · 付款底座 | 采购组、财务部 |
|
||||||
|
| 2 | 车辆采购 / 三方租赁合同 | support | 车型数量 · 付款关联 · 验车任务 | 采购部、法务部、财务部 |
|
||||||
|
| 3 | 验车入库 | main | 采购 / 三方来源 · 验完自动入库 | 运维部、采购部 |
|
||||||
|
| 4 | 车辆上牌 | main | 车架号入库 · 完成牌证登记 | 运维部 |
|
||||||
|
| 5 | 证照管理 | main | 一车一档 · 到期待办推送 | 运维部、安全部 |
|
||||||
|
| 6 | 备车管理 | main | 交车前整备 · 随时可交付 | 运维部 |
|
||||||
|
| 7 | 交车管理 | main | 司机培训留痕 · 区域派单 · OCR 比对 · 电子签 | 运维部、业务管理组、司机 |
|
||||||
|
| 8 | 替换车管理 | support | 临时 / 永久替换 · 费用自动核算 | 运维部、业务管理组 |
|
||||||
|
| 9 | 还车管理 | main | 区域派单 · 费用自动计算 · 电子签 | 运维部、业务管理组 |
|
||||||
|
| 10 | 故障管理 | support | AI 助手 + 人工 · 证据链归档 | 运维部、司机 |
|
||||||
|
| 11 | 年审记录 | support | 提前 3 个月 · OCR 刷新证照 | 运维部 |
|
||||||
|
| 12 | 维修与保养记录 | support | 费用汇总 · 业财一体 · 盈亏核算 | 运维部、财务部 |
|
||||||
|
| 13 | 车辆异动 | support | 出库维修 / 年审 / 保养 · 成本归集 | 运维部 |
|
||||||
|
| 14 | 车辆调拨 | support | 跨区调拨 · 运维权转移 | 运维部、业务管理组 |
|
||||||
|
| 15 | 车辆出售、过户、报废 | main | 资产变更审批 · 过程留痕 · 自动出库 | 运维部、董事长、财务部 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.4 安全管理条线(6 模块 · 安全闭环)
|
||||||
|
|
||||||
|
**条线闭环**:司机信息与证照 → 定期培训与资料库学习 → 违规记录关联评级 → 违章/事故登记 → 联动还车应结款与代处理费用。
|
||||||
|
|
||||||
|
| 步 | 模块名 | 一句话定位 | 责任部门 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 1 | 司机管理 | 物流内部司机 · 信息证照一体 | 安全部、业务管理组 |
|
||||||
|
| 2 | 内部司机培训 | 定期安全培训 · 证据链留痕 | 安全部、司机 |
|
||||||
|
| 3 | 安全培训资料库 | 资料上传 · APP / 小程序学习 | 安全部、司机 |
|
||||||
|
| 4 | 违规记录 | 司机违规 · 关联评级 | 安全部、业务管理组 |
|
||||||
|
| 5 | 违章管理 | 分值罚款 · 还车联动 · 代处理 | 安全部、财务部、业务管理组 |
|
||||||
|
| 6 | 事故管理 | 权责划分 · 保险赔付 · 还车联动 | 安全部、财务部、业务管理组 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.5 物流业务条线(3 模块 · 经营闭环)
|
||||||
|
|
||||||
|
**条线闭环**:物流合同生效 → 轻量调度派车(交车后可办结)→ 办结自动生成物流业务明细 → 汇总盈亏 → 汇集项目盈亏表 → 演进关联收款记录完成业财闭环。
|
||||||
|
|
||||||
|
| 步 | 模块名 | 一句话定位 | 责任部门 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 1 | 物流合同 | 关键信息录入 · 业务确认生效 · 可派车 | 业务管理组、业务服务组 |
|
||||||
|
| 2 | 调度任务 | 轻量派车 · 交还车校验 · 办结出车 | 业务服务组、调度岗、运维部 |
|
||||||
|
| 3 | 物流台账 | 任务自动生成 · 补录导入 · 盈亏核算 | 业务服务组、财务部 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2.6 三大数据底座(管理决策层,非业务条线)
|
||||||
|
|
||||||
|
| 底座 | 看什么 | 主要数据来源条线 |
|
||||||
|
|---|---|---|
|
||||||
|
| 车辆资产运营情况 | 规模 · 结构 · 健康度 · 品牌型号出勤率下钻省市 | 运维、车辆管理、证照/保险、交车/备车 |
|
||||||
|
| 各业务条线盈亏情况 | 收入 · 成本 · 利润(条线/项目/单车) | 租赁台账、物流台账、氢费账户、收款、维保/事故/违章 |
|
||||||
|
| 里程调度情况 | 里程补贴 · 客户履约 · 智能替换与运维干预 | 车机/GPS/人工里程、客户里程约定、替换车、运维干预 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 流程闭环速查(端到端一句话)
|
||||||
|
|
||||||
|
| 条线 | 闭环一句话 |
|
||||||
|
|---|---|
|
||||||
|
| 租赁 | 客户 → 模板 → 签约 → 提车应收 → 交车 → 台账账单 → 还车应结款归档 |
|
||||||
|
| 能源 | 供应商 → 加氢站 → 订单采集 → 氢费明细 → 客户账户收款 → 记录已付款 |
|
||||||
|
| 运维 | 采购/验车入库 → 牌证备车 → 交还车 → 维保故障 → 异动调拨 → 处置出库 |
|
||||||
|
| 安全 | 司机档案 → 培训资料 → 违规评级 → 违章事故 → 还车应结款费用 |
|
||||||
|
| 物流 | 合同生效 → 调度派车办结 → 台账明细/盈亏 →(演进)收款业财闭环 |
|
||||||
|
| 系统级 | 五条线业务闭环 → 三大数据底座决策 → 打通财务 YS 业财一体 |
|
||||||
|
|
||||||
|
**高频跨模块联动(写描述时勿漏)**
|
||||||
|
|
||||||
|
- 租赁签约路径依赖**客户管理**评级(标准 / 非标 / 禁止)
|
||||||
|
- **提车应收**对齐后触发运维**交车**;交车成功生成**租赁业务台账**
|
||||||
|
- **还车管理**完成后生成**还车应结款**;安全**违章/事故**费用写入应结项
|
||||||
|
- 运维**采购/三方租赁合同**自动生成**验车入库**任务
|
||||||
|
- 物流**调度办结**须车辆已**交车**;办结自动写**物流台账**
|
||||||
|
- 能源签约站**加氢订单**与非签约站**氢费明细**统一进入**氢费账户**对账收款
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 故事点(按模块:起点 → 怎么运作 → 闭环)
|
||||||
|
|
||||||
|
> 结构对齐页面「起点 / 怎么运作 / 闭环」。标题用「模块名 + 核心动作」;描述保留谁发起、关键规则、闭环结果,不升格成完整 PRD。
|
||||||
|
> 下列为各模块业务事实摘要,用于**识别归属与用词**;材料未提及的细节**不得**脑补进描述。
|
||||||
|
|
||||||
|
### 4.1 租赁
|
||||||
|
|
||||||
|
#### 客户管理
|
||||||
|
- **起点**:业务管理组维护客户基础信息,作为后续合同与账单的统一客户主数据
|
||||||
|
- **怎么运作**:法务每 3 个月评估法律风险;财务实时维护财务风险等级;安全实时维护安全风险等级;系统综合形成签约策略
|
||||||
|
- **闭环**:未达禁止标准可签;偏离常规范式走「非标准流程」;达禁止标准禁止新签,现有合同标「高风险」并通知业务跟进或终止
|
||||||
|
|
||||||
|
#### 标准合同管理
|
||||||
|
- **起点**:法务部维护各车型试用/正式等标准模板,明确条款边界与风控要求
|
||||||
|
- **怎么运作**:数智部按模板配置电子合同;条款可设「触发车型」;「风控红线」被改进非标审批;「锁定区域」不可随意改
|
||||||
|
- **闭环**:业务员直选模板走标准流程;触碰红线或锁定区外修改转法务非标审批
|
||||||
|
|
||||||
|
#### 租赁合同
|
||||||
|
- **起点**:业务员选羚牛签约主体与乙方客户;系统按评级判标准/非标/禁止
|
||||||
|
- **怎么运作**:合同要素实时反写电子合同预览;生成电子合同/条款附件/授权委托书;越界转非标;支持续签、转正式、转三方、增值服务、授权委托书、主动终止等
|
||||||
|
- **闭环**:审批通过进入履约并串联提车应收、交车、台账;非标须法务与董事长确认后放行
|
||||||
|
|
||||||
|
#### 提车应收款
|
||||||
|
- **起点**:提交租赁合同审批时,按合同条款自动生成提车应收金额
|
||||||
|
- **怎么运作**:法务在「收款记录」导入到账(后期对接 YS/银企直联);业务/业管关联账单并分配金额;实收对齐后标记完成
|
||||||
|
- **闭环**:应收完成后按约定生成交车任务,属地运维执行交车
|
||||||
|
|
||||||
|
#### 租赁业务台账
|
||||||
|
- **起点**:运维交车成功后自动生成该车租赁账单,应付款日初始「待设置」
|
||||||
|
- **怎么运作**:设置应付款日后生成首期应收;提车实收写入首期;溢出并入第二期减免
|
||||||
|
- **闭环**:持续记录每期应收/实收/状态,支撑租期运营与还车结算
|
||||||
|
|
||||||
|
#### 还车应结款
|
||||||
|
- **起点**:运维完成还车后自动生成还车应结款任务
|
||||||
|
- **怎么运作**:业管、安全、运维、能源各自完成部门审批;汇总应退/应补;应补关联收款记录、应退关联付款记录
|
||||||
|
- **闭环**:业管发起总审批;完成后自动归档,租赁单条业务全链路闭环
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4.2 能源
|
||||||
|
|
||||||
|
#### 供应商管理
|
||||||
|
- **起点**:加氢站/充电站作为供应商纳入统一体系,采购组维护基础信息与结算要素
|
||||||
|
- **怎么运作**:创建站点时绑定供应商;氢费/电费对账支持直连付款;收付款明细关联财务记录;支撑付款/收款申请审批
|
||||||
|
- **闭环**:供应商主数据与站点、对账、财务贯通,打好能源业财基础
|
||||||
|
|
||||||
|
#### 加氢站管理
|
||||||
|
- **起点**:采购部统一管理签约站/非签约站;签约站须关联供应商与系统账号
|
||||||
|
- **怎么运作**:签约站账号登录加氢订单(PC/移动/H5);预付款余额;营业状态;成本价关联氢费记录;能源部形成对账单并发起付款(后期对接 YS)
|
||||||
|
- **闭环**:站点/账号/余额/价格/营业状态集中管理,签约站可自助上报
|
||||||
|
|
||||||
|
#### 加氢订单
|
||||||
|
- **起点**:签约站登录后多渠道上报订单;PLC 站点可自动获取
|
||||||
|
- **怎么运作**:多端快速识别记录;PLC 自动获取;联动「小羚羚」预约接单,司机确认;进入加氢记录供对账
|
||||||
|
- **闭环**:主动上报或自动采集,预约在线闭环,减少手工补录
|
||||||
|
|
||||||
|
#### 车辆氢费明细
|
||||||
|
- **起点**:非签约站氢费由业务管理组-能源部手动维护
|
||||||
|
- **怎么运作**:录入并关联站点/车辆/客户;对账后标「已对账」归档;联动预付款余额与客户能源账户;OCR 与电子围栏辅助核对
|
||||||
|
- **闭环**:签约/非签约氢费统一归集,余额变动可追溯
|
||||||
|
|
||||||
|
#### 氢费账户
|
||||||
|
- **起点**:管理客户氢费预付款余额与客户对账单
|
||||||
|
- **怎么运作**:维护余额变动;生成对账单;关联「收款记录」;收款后加氢记录标「已付款」;支持充值/开票直达财务(替代钉钉,对接 YS)
|
||||||
|
- **闭环**:明细→对账→收款全链路可核对,付款状态与财务实收一致
|
||||||
|
|
||||||
|
#### 扩展规划
|
||||||
|
- **起点**:条线成熟后向上游采购与下游司机服务延伸
|
||||||
|
- **怎么运作**:上游氢气采购;下游外部氢能车司机服务;与现有供应商/站点/订单/账户衔接
|
||||||
|
- **闭环**:覆盖「采购—站点—用氢—结算—司机服务」更大范围生态
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4.3 运维
|
||||||
|
|
||||||
|
#### 供应商管理
|
||||||
|
- **起点**:整车厂、三方租赁企业纳入供应商体系
|
||||||
|
- **怎么运作**:维护档案;为采购/三方租赁合同提供主数据;支撑付款底座
|
||||||
|
- **闭环**:与采购合同、付款记录贯通
|
||||||
|
|
||||||
|
#### 车辆采购 / 三方租赁合同
|
||||||
|
- **起点**:向整车厂/三方租赁厂商发起采购或三方租赁合同
|
||||||
|
- **怎么运作**:创建审批;关联付款记录;按条款自动生成验车任务
|
||||||
|
- **闭环**:合同、付款、验车联动,入库合规入口
|
||||||
|
|
||||||
|
#### 验车入库
|
||||||
|
- **起点**:对采购或三方来源氢能车执行验车
|
||||||
|
- **怎么运作**:接收验车任务;记录过程与问题;验完自动入库
|
||||||
|
- **闭环**:验车结果与合同、库存绑定,来源可审计
|
||||||
|
|
||||||
|
#### 车辆上牌
|
||||||
|
- **起点**:对仅有车架号的新车执行上牌
|
||||||
|
- **怎么运作**:筛选待上牌车;录入/同步牌照;更新库存状态
|
||||||
|
- **闭环**:牌证完整,为证照与交车提供前置条件
|
||||||
|
|
||||||
|
#### 证照管理
|
||||||
|
- **起点**:行驶证、道路运输证、登记证、特种设备证/标识、加氢卡、安全阀、压力表等一车一档
|
||||||
|
- **怎么运作**:维护档案与有效期;临近到期生成年审/等评/换证待办;推送运维/安全
|
||||||
|
- **闭环**:证照全生命周期管理,降低漏办与违规风险
|
||||||
|
|
||||||
|
#### 备车管理
|
||||||
|
- **起点**:日常提前整备,确保交车任务可随时交付
|
||||||
|
- **怎么运作**:按计划/库存策略发起检查;记录整备项与责任人
|
||||||
|
- **闭环**:交车前置完成,提升交付效率与质量一致性
|
||||||
|
|
||||||
|
#### 交车管理
|
||||||
|
- **起点**:承接租赁/物流交车任务,按区域派属地运维;司机先完成在线培训并留痕
|
||||||
|
- **怎么运作**:司机上传身份证/驾驶证/从业资格证、签名与现场拍照;交付证照及保险有效车辆;记录里程/氢量/电量/位置;OCR 胎纹;还车时比对算磨损等费用;E 签宝电子签归档
|
||||||
|
- **闭环**:培训与交车数据完整可查,为还车费用与争议提供依据
|
||||||
|
|
||||||
|
#### 替换车管理
|
||||||
|
- **起点**:因客户或车辆原因发起临时/永久替换
|
||||||
|
- **怎么运作**:选类型与新旧车;完成替换交还;客户原因自动算费用差
|
||||||
|
- **闭环**:过程可追踪、费用可核算,履约不中断
|
||||||
|
|
||||||
|
#### 还车管理
|
||||||
|
- **起点**:处理业务/业管还车任务,按区域派属地运维
|
||||||
|
- **怎么运作**:记录还车时间/里程/氢电量/位置;OCR 胎纹对比算磨损费;按里程与氢电差算费用;E 签宝确认归档
|
||||||
|
- **闭环**:费用依据交还对比自动出具
|
||||||
|
|
||||||
|
#### 故障管理
|
||||||
|
- **起点**:微信 AI 故障助手或人工记录故障关键信息
|
||||||
|
- **怎么运作**:记时间地点车型紧急程度;留存图文视频聊天证据;运维处理至关闭;形成待办统计;沉淀品牌故障类型统计支撑采购论证
|
||||||
|
- **闭环**:全过程留痕,证据链完整
|
||||||
|
|
||||||
|
#### 年审记录
|
||||||
|
- **起点**:按行驶证审验有效期提前 3 个月生成年审任务
|
||||||
|
- **怎么运作**:按车按月归集;完成后 OCR 新行驶证刷新证照;按月量化完成率
|
||||||
|
- **闭环**:任务不遗漏,证照与办理结果同步
|
||||||
|
|
||||||
|
#### 维修与保养记录
|
||||||
|
- **起点**:运维手动维护负责车辆维保记录(首期)
|
||||||
|
- **怎么运作**:配件费/人工费汇总;按承担方(客户/我司)生成客户账单或计入运维成本;计入车辆盈亏
|
||||||
|
- **闭环**:维保成本可追溯可分摊,支撑单车盈亏与对客户计费
|
||||||
|
|
||||||
|
#### 车辆异动
|
||||||
|
- **起点**:因当地维修/年审/保养出库异动,须提前审批
|
||||||
|
- **怎么运作**:记异动前后氢电量里程;异动期间加氢记录归集为异动成本
|
||||||
|
- **闭环**:可审批可计量,避免成本漏记
|
||||||
|
|
||||||
|
#### 车辆调拨
|
||||||
|
- **起点**:车辆从 A 地调至 B 地运营,须提前审批
|
||||||
|
- **怎么运作**:记发起方/费用/运输;接收方确认;运维操作权由 A 转 B
|
||||||
|
- **闭环**:跨区调拨透明,责任属地随车切换
|
||||||
|
|
||||||
|
#### 车辆出售、过户、报废
|
||||||
|
- **起点**:达出售/过户/报废条件发起资产变更,录入交易方价格过户残值等
|
||||||
|
- **怎么运作**:提交申请;董事长确认;运维记录全过程归档;完成后退出运营并出库
|
||||||
|
- **闭环**:处置审批留痕,生命周期闭环至出库归档
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4.4 安全
|
||||||
|
|
||||||
|
#### 司机管理
|
||||||
|
- **起点**:管理物流内部司机,支撑快速选取与档案维护
|
||||||
|
- **怎么运作**:维护基础信息与在职状态;管理驾驶证/从业资格证;与交车、台账联动
|
||||||
|
- **闭环**:主数据统一、证照可查,支撑调度与合规
|
||||||
|
|
||||||
|
#### 内部司机培训
|
||||||
|
- **起点**:定期开展安全培训并形成可追溯记录
|
||||||
|
- **怎么运作**:制定计划组织参训;记录时间内容参训人;形成证据链供交管查询
|
||||||
|
- **闭环**:培训电子归档,随时可调阅
|
||||||
|
|
||||||
|
#### 安全培训资料库
|
||||||
|
- **起点**:安全部上传培训与安全运营资料供司机学习
|
||||||
|
- **怎么运作**:维护课件制度指引;分类发布版本检索;司机经 APP/小程序学习
|
||||||
|
- **闭环**:资料集中更新,移动端可学可查
|
||||||
|
|
||||||
|
#### 违规记录
|
||||||
|
- **起点**:记录内部司机运营违规
|
||||||
|
- **怎么运作**:登记事件类型时间结果;关联司机档案;联动客户安全评级
|
||||||
|
- **闭环**:违规可追踪汇总,支撑选用与评级
|
||||||
|
|
||||||
|
#### 违章管理
|
||||||
|
- **起点**:记录交通违章并与还车应结款联动
|
||||||
|
- **怎么运作**:登记时间地点分值罚款及是否缴纳;未处理纳入还车结算;逾期未缴自动生成代处理费用
|
||||||
|
- **闭环**:违章可查,代处理费用与还车/财务口径一致
|
||||||
|
|
||||||
|
#### 事故管理
|
||||||
|
- **起点**:记录事故信息,支撑定责理赔与还车结算
|
||||||
|
- **怎么运作**:登记权责划分;记保险介入/赔付/上浮;联动还车应结款写入安全费用
|
||||||
|
- **闭环**:登记→赔付→上浮→应结款贯通,费用不遗漏
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4.5 物流
|
||||||
|
|
||||||
|
#### 物流合同
|
||||||
|
- **起点**:创建物流运力服务合同,录客户/车型/车辆数/交车时间地点,上传附件
|
||||||
|
- **怎么运作**:录入项目与合同要素;业务确认生效后可创建轻量调度并提示运维交车
|
||||||
|
- **闭环**:合同成为调度派车与交车的上游凭证
|
||||||
|
|
||||||
|
#### 调度任务
|
||||||
|
- **起点**:在生效合同下创建出车任务,派车派司机;非 TMS
|
||||||
|
- **怎么运作**:选合同、计划出车日、线路、是否多趟与计价口径;未交车须先交车;办结确认实际出车后自动生成物流业务明细一行
|
||||||
|
- **闭环**:出车事实追溯到合同与车牌,驱动台账落账
|
||||||
|
|
||||||
|
#### 物流台账
|
||||||
|
- **起点**:承接调度办结自动生成的出车明细,导入/行编辑补录异常与历史
|
||||||
|
- **怎么运作**:办结写入营收侧并算金额/总成本/盈亏;氢费/ETC 等成本可手工补录;汇集项目盈亏表;演进关联「收款记录」
|
||||||
|
- **闭环**:收入与司机/车辆成本同台账可核对,盈亏可对接财务实收
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. AutoRDO 应用约定
|
||||||
|
|
||||||
|
1. **标题**:优先 `模块标准名:核心动作/结果`(10–30 字),模块名以本词典为准(例:`验车入库:采购与三方租赁合同自动生成验车记录及入库`)
|
||||||
|
2. **条线归属**:一句需求只挂一个主模块;跨条线联动写在描述里,不硬塞进标题
|
||||||
|
3. **部门用词**:口语「业管/能源组/运维」等映射到第 1 节标准名
|
||||||
|
4. **闭环口径**:若材料只讲做到一半,闭环写实际说到的结果,缺的标「待确认」
|
||||||
|
5. **不做**:不把本词典全文贴进云效描述或输出稿;不脑补材料未出现的故事点细节
|
||||||
|
6. **业财关键词**:收款记录、付款记录、对账单、应收/实收、YS、银企直联、E 签宝、小羚羚、PLC——保留原文业务对象名,勿随意改写
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 条线演进(辅助理解,非强制写入描述)
|
||||||
|
|
||||||
|
| 条线 | 现阶段 | 演进方向 |
|
||||||
|
|---|---|---|
|
||||||
|
| 租赁 | 合同电子化 · 业务闭环化 | 移动端商城直连发起合同,后续自动打通 |
|
||||||
|
| 能源 | 手工维护氢费明细 | 签约站主动上报,能源部转为核对确认 |
|
||||||
|
| 运维 | 车辆使用环节闭环 | 入库→运作→出库全链路 |
|
||||||
|
| 安全 | 司机安全全链条 | 与客户安全评级挂钩、事前预判 |
|
||||||
|
| 物流 | 合同 + 调度办结落账 | 成本自动回填、司机在线、关联收款;不做完整 TMS |
|
||||||
|
| 系统 | 业务驱动 · 财务手工 | 打通 YS · 业财一体 |
|
||||||
67
.cursor/skills/AutoRDO/references/rules.md
Normal file
67
.cursor/skills/AutoRDO/references/rules.md
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# AutoRDO 清洗与拆解细则
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
|
||||||
|
碎片 → 可入库的书面「标题」与「描述」。保留原意;不写成产品 PRD。
|
||||||
|
多行/多条独立输入 → **多份**转译结果(一份需求一份稿)。
|
||||||
|
|
||||||
|
## 必做与精炼规则
|
||||||
|
|
||||||
|
| 规则 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| **多条拆解** | 输入为多条独立诉求时,**先拆后洗**:<br>• **拆分信号**(满足任一即可):换行且每行一句独立诉求;`1. 2. 3.` / `-` / `*` 列表;表格多行;空行分段;「另外」「还有」「第二条」等显式分条<br>• **每条**各自输出一份标题+描述+待确认,**禁止**合并成一条大需求<br>• **不拆**:同一条需求内部的续写、补充说明、功能规则子点(属于描述细节,挂在该条下)<br>• **边界不清**:无法判断是一条还是多条时,在文首标「待确认:拆条边界」,并按最可能的分条给出结果,请用户校对 |
|
||||||
|
| **OneOS 领域对齐** | 涉及 ONE-OS / 羚牛业务时,**先读** [oneos-domain.md](oneos-domain.md):<br>• 部门口语映射到标准名(业管→业务管理组,能源组→业务管理组-能源部 等)<br>• 标题模块名优先用词典标准名(如「验车入库」而非口语「验车管理」——若材料确指该模块)<br>• 跨条线联动写在描述,标题只挂主责模块<br>• **禁止**把词典全文或未在材料中出现的故事点细节写入输出 |
|
||||||
|
| **标题提炼** | 根据材料内容理解,自动概括简炼、清晰的标准需求标题:<br>• **内容理解**:准确识别归属的业务模块与核心动作/诉求(如:`验车入库:采购与三方租赁合同自动生成验车记录及入库`)。<br>• **自然流畅**:表达自然书面化,无需死板强求拼接固定句式;彻底剔除“我们要做一个”、“主要是用于”、“完成之后才能”等口语废话。<br>• **字数适中**:控制在 10-30 字内,能让读者一眼看懂需求核心。 |
|
||||||
|
| **元数据识别** | 详见 [meta-fields.md](meta-fields.md)。从台账列或正文自动识别并输出:<br>• **类型**:`【新增】`/`【优化】`<br>• **优先级**:`P1-高`/`P2-中`/`P3-低`<br>• **标签**:标准模块名(+ 可选 PC端/小程序)<br>• **提交部门**:映射词典标准名(业务管理部→业务管理组,数智中心→数智部 等)<br>• **提交人**:反馈方/用户列或署名<br>• 显式列优先;推断不确定则待确认;**不**直接写云效打标 |
|
||||||
|
| **描述转译** | 原文的转译结果,将口述/碎片材料转译为规范书面表达,保留原意(不改变谁要求什么、约束与例外;不替换成「更优方案」);业财对象名(收款记录、付款记录、YS、E 签宝、小羚羚、PLC 等)按词典保留 |
|
||||||
|
| 书面化 | 口语改成完整句子或清晰短条目;主谓齐全 |
|
||||||
|
| 去口头禅 | 删除:嗯、啊、那个、就是说、然后呢、对对对、你懂吧 等 |
|
||||||
|
| 自我修正 | 以最后一次明确口径为准;若前后矛盾且未决,列入「待确认」 |
|
||||||
|
| 去重复 | 同一意思多轮确认只保留一处;多条拆解时,各条之间不要互相抄写无关内容 |
|
||||||
|
| 轻度格式 | 可用短标题/条目;禁止展开成总览/角色/流程图/故事点等 PRD 结构 |
|
||||||
|
| 去结尾句号 | 描述中每个句子或条目末尾去掉 `。`;保留 `?` `!` 若确为疑问/感叹 |
|
||||||
|
| 待确认 | 材料含糊处写 `待确认:…`,不臆造;**只要存在待确认,同轮强制**进入 [confirm-pending.md](confirm-pending.md) 的 Plan 逐条确认(无需用户再说「确认待确认」) |
|
||||||
|
| **待确认 Plan 确认** | 详见 [confirm-pending.md](confirm-pending.md):<br>• 清洗结果含待确认 → **立刻** `SwitchMode` → plan<br>• 按需求条号**逐点**确认;**优先选择题**(2–5 项 +「其他/我补充」),选项用 `oneos-domain.md` 辅助<br>• 也支持用户粘贴**需求描述/补充说明**一次消解多点<br>• 确认后回填描述并移除已消解项;未确认不得写入定稿 |
|
||||||
|
|
||||||
|
## 多条拆解示例
|
||||||
|
|
||||||
|
**输入(多行):**
|
||||||
|
```text
|
||||||
|
还车应结款生成后自动展示违章事故信息,不必等安全员提交
|
||||||
|
验车完成后才能车辆入库
|
||||||
|
氢费账户对账单要能关联收款记录
|
||||||
|
```
|
||||||
|
|
||||||
|
**输出**:3 份独立的「原始诉求(AutoRDO)」,每份各自标题+描述;不要揉成一条。
|
||||||
|
|
||||||
|
## 标题提炼对比示例
|
||||||
|
|
||||||
|
- ❌ **坏标题(直抄口语/带废话)**:`我们现在要做一个验车管理功能主要是采购合同和三方租赁合同自动形成验车记录验车完成之后才能车辆入库`
|
||||||
|
- ✅ **好标题(自然清晰,覆盖标准模块)**:`验车入库:采购与三方租赁合同自动生成验车记录及入库`(模块名对齐 oneos-domain)
|
||||||
|
|
||||||
|
## 不做
|
||||||
|
|
||||||
|
- 不生成 AutoPRD 十章或「产品说明」
|
||||||
|
- 不写验收清单、故事点、mermaid
|
||||||
|
- 不改云效、不建【交付】/分析/设计
|
||||||
|
- 不加载 `yunxiao-requirement-lifecycle`
|
||||||
|
- 不把多条独立诉求合并成一条「大杂烩」需求
|
||||||
|
|
||||||
|
## 录音
|
||||||
|
|
||||||
|
1. 已有转写 → 按上文清洗转写稿并拆解标题与描述;转写中若含多条独立诉求,同样先拆后洗
|
||||||
|
2. 仅音频 → 回报「请提供转写文本后再 AutoRDO」,停止声称已清洗完成
|
||||||
|
|
||||||
|
## 质量自检
|
||||||
|
|
||||||
|
- [ ] 多行/多条输入时,已按条拆成多份结果(条数与输入独立诉求数一致或已说明待确认边界)
|
||||||
|
- [ ] 已对照 `oneos-domain.md`(ONE-OS 相关材料)
|
||||||
|
- [ ] **标题清晰通顺**(标准模块名 + 核心动作,无死板句式绑定,无口语废话)
|
||||||
|
- [ ] 部门/业财关键词已映射或保留为词典标准口径
|
||||||
|
- [ ] **描述为原文的转译结果**,干系人能认出这是自己说的意思;未脑补词典故事点
|
||||||
|
- [ ] 无口头禅堆砌、无未决矛盾被写成定论
|
||||||
|
- [ ] 描述末尾无 `。`
|
||||||
|
- [ ] 未冒充完整 PRD;未把词典全文写入输出
|
||||||
|
- [ ] 已输出类型/优先级/标签/提交部门/提交人(有依据或已标待确认;未臆造提交人)
|
||||||
|
- [ ] 若存在待确认:已同轮强制进 Plan(未等「确认待确认」口令);优先选择题、选项有词典依据;文字补充已映射到对应点;定稿无未确认臆造
|
||||||
|
- [ ] 若无待确认:未多余进 Plan
|
||||||
113
.cursor/skills/YunxiaoPM/SKILL.md
Normal file
113
.cursor/skills/YunxiaoPM/SKILL.md
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
---
|
||||||
|
name: YunxiaoPM
|
||||||
|
description: >-
|
||||||
|
产品经理云效(Projex)自动化:记录需求(压缩点选 1a2b3a4d:类型/项目/优先级/标签)、
|
||||||
|
实时点选云效项目、推进 待处理→已确认→分析中→设计中→设计完成→待开发,
|
||||||
|
交付树【交付】ASSOCIATED /【分析】【设计】TASK_SUB,无单快轨与编号直推交棒何斐,
|
||||||
|
创建迭代并挂【交付】(不挂需求)。用户说 YunxiaoPM、YunxiaoPMapp、需求任务、记录需求、受理确认、开始分析、
|
||||||
|
开始设计、设计完成、交棒开发、快轨待开发、编号直推、创建迭代 时使用。
|
||||||
|
不建【开发】/【测试】。凡写云效先 Plan 确认再一口气 apply;禁止对齐
|
||||||
|
yunxiao-requirement-lifecycle。
|
||||||
|
---
|
||||||
|
|
||||||
|
# 需求任务(YunxiaoPM)
|
||||||
|
|
||||||
|
产品部云效自动化。斜杠调起 **`/YunxiaoPM`**;对外中文名 **需求任务**(原名 YunxiaoPMapp)。本 Skill **自洽成篇**;**禁止** fork / include / 「对齐」`yunxiao-requirement-lifecycle`。
|
||||||
|
|
||||||
|
产品经理会话**不要**同时挂载旧 lifecycle Skill,避免双建任务。
|
||||||
|
|
||||||
|
## Plan 模式门禁(强制 · 凡写云效)
|
||||||
|
|
||||||
|
凡会改云效的操作(建单、改状态、建/改任务、打标、传附件、改负责人、建迭代等),Agent **第一步**必须:
|
||||||
|
|
||||||
|
1. `SwitchMode` → **plan**(说明:先对齐参数与执行清单,确认后再一口气 apply)。
|
||||||
|
2. **新建**依赖项目空间时:先按 [references/project-selection.md](references/project-selection.md) **实时拉项目列表并点选(门禁 PJ)**;禁止静默使用 `runtime-ids.json` 默认 `spaceIdentifier`。口令/选项**无法对应**时:**自动重拉项目列表一次**再匹配;仍失败则停请用户重选(禁止第 3 次空转拉取)。
|
||||||
|
3. Plan 写清:**已选项目名 + spaceId**、目标需求/任务**编号**、将改状态、将建/复用的交付·分析·设计编号策略、迭代版本类型(若适用)、§0.1① 占位风险勾选(若适用)、**不会做的事**(不建【开发】/【测试】、不按标题查重)。**记录需求**须按 [compact-select.md](references/compact-select.md) 给出 1–4 题字母表,接受压缩答复如 `1a2b3a4d`。
|
||||||
|
4. **用户确认 / 批准 Plan / 「执行」之前**:禁止 apply;项目未点选同禁。压缩串须先解析回显,再等「执行」。
|
||||||
|
5. 确认后切回 Agent,**同一轮按清单一口气执行到底**,再一次性校验回报;中途缺参才停下。
|
||||||
|
|
||||||
|
**例外(可读可不进 Plan):** 仅查状态 / 为什么没流转 / 给我方案。
|
||||||
|
|
||||||
|
**禁止:** 以「参数已齐」「速度路径」「用户很熟」跳过 Plan;「批准计划」若清单未点齐关键参数(含 **PJ 项目**),仍视为未完成门禁。
|
||||||
|
|
||||||
|
## 真相源模型
|
||||||
|
|
||||||
|
```text
|
||||||
|
需求状态 = 阶段看板唯一真相
|
||||||
|
【交付】 = 每需求最多 1 条容器(ASSOCIATED→需求)
|
||||||
|
【分析】/【设计】 = TASK_SUB→交付(交付「子项」必可见;与 ASSOCIATED 同 create 互斥)
|
||||||
|
【开发】/【测试】 = 不进本 Skill
|
||||||
|
查重/复用唯一渠道 = 任务编号(ONEOS-xx);禁止按标题
|
||||||
|
```
|
||||||
|
|
||||||
|
编号权威:需求描述 `## 工作项编号(系统)`(见 [references/workitem-ids.md](references/workitem-ids.md))。
|
||||||
|
操作顺序:口令显式编号 > 读该区块 > ASSOCIATED/SUB 校验;冲突则停。
|
||||||
|
|
||||||
|
## 外置调用(禁止本 Skill 内嵌对方全文)
|
||||||
|
|
||||||
|
| 时机 | 调用 |
|
||||||
|
|---|---|
|
||||||
|
| 入库清洗聊天/录音 | **`$AutoRDO`**(独立 Skill;路径 `AutoRDO/SKILL.md`;不内嵌清洗细则) |
|
||||||
|
| 设计完成 PRD + 对象存储链接 + 回填【交付】 | **`$oneos-autoprd`(AutoPRD)**;创建【交付】仍占位,设计完成才灌 MD |
|
||||||
|
| 人员 / 状态 / 字段 ID;项目 catalog 仅缓存 | [assets/runtime-ids.json](assets/runtime-ids.json) |
|
||||||
|
| **PJ 云效项目点选**(新建必选;实时列表) | [references/project-selection.md](references/project-selection.md) · [scripts/list_projects.py](scripts/list_projects.py) |
|
||||||
|
| **压缩点选 `1a2b3a4d`**(类型/项目/优先级/标签) | [references/compact-select.md](references/compact-select.md) · [scripts/list_tags.py](scripts/list_tags.py) |
|
||||||
|
| 阶段日历工时 | [references/work-hours.md](references/work-hours.md) + [assets/cn-workday-calendar.json](assets/cn-workday-calendar.json) + [scripts/workday_hours.py](scripts/workday_hours.py) |
|
||||||
|
|
||||||
|
## 路由(按需完整阅读)
|
||||||
|
|
||||||
|
| 场景 | 模块 |
|
||||||
|
|---|---|
|
||||||
|
| 交付树、关联约定、禁止项 | [references/model.md](references/model.md) |
|
||||||
|
| 描述双段 · AutoRDO / 占位 / AutoPRD | [references/description-split.md](references/description-split.md) |
|
||||||
|
| 步骤 0–5 标准路径 | [references/stage-flow.md](references/stage-flow.md) |
|
||||||
|
| 无单快轨到待开发 | [references/fast-track.md](references/fast-track.md) |
|
||||||
|
| 编号直推交棒 | [references/number-push.md](references/number-push.md) |
|
||||||
|
| 交棒门禁 · 回退最小集 | [references/handoff-and-rollback.md](references/handoff-and-rollback.md) |
|
||||||
|
| 计划开始/完成 · 阶段日历工时 | [references/work-hours.md](references/work-hours.md) |
|
||||||
|
| Make 导出 ZIP + 复制截图 | [references/make-export-attach.md](references/make-export-attach.md) |
|
||||||
|
| 创建迭代 · V主.副.子 · 只挂交付 | [references/sprint.md](references/sprint.md) |
|
||||||
|
| 口令面 | [references/commands.md](references/commands.md) |
|
||||||
|
| 记录需求元字段(优先级/标签/提交部门/提交人) | [references/record-meta-fields.md](references/record-meta-fields.md) |
|
||||||
|
| 云效项目点选 PJ | [references/project-selection.md](references/project-selection.md) |
|
||||||
|
| 验收清单 · 回报模板 | [references/acceptance.md](references/acceptance.md) |
|
||||||
|
| 交接契约(开发 Skill 入口) | [references/handoff-contract.md](references/handoff-contract.md) |
|
||||||
|
| 已验证实写 API · 极速建单 | [references/live-api.md](references/live-api.md) · [scripts/live_create_fast.py](scripts/live_create_fast.py) |
|
||||||
|
| 2026-07-23 复盘与耗时对比 | [references/live-perf-2026-07-23.md](references/live-perf-2026-07-23.md) |
|
||||||
|
|
||||||
|
## 口令速查
|
||||||
|
|
||||||
|
```text
|
||||||
|
记录需求:…;项目=(Plan 点选,勿默认);优先级=紧急|高|中|低;标签=…;提交部门=…;提交人=…;推进至=暂不推进|已确认|分析中|设计中|设计完成|待开发|待开发(快轨)
|
||||||
|
受理确认:ONEOS-xx
|
||||||
|
开始分析:ONEOS-xx
|
||||||
|
开始设计:ONEOS-xx;交付任务=…;分析任务=…
|
||||||
|
设计完成:ONEOS-xx;设计任务=…;原型=…
|
||||||
|
交棒开发:ONEOS-xx;交付任务=…
|
||||||
|
快轨待开发:ONEOS-xx
|
||||||
|
编号直推:分析任务=ONEOS-b / 设计任务=ONEOS-c / 交付任务=ONEOS-a
|
||||||
|
创建迭代:版本类型=主|副|子;交付任务=ONEOS-a,ONEOS-b,…;名称前缀=…
|
||||||
|
```
|
||||||
|
|
||||||
|
**PJ 项目**:新建前必须从云效实时列表点选(见 [project-selection.md](references/project-selection.md));口令带项目名仅作预填建议。
|
||||||
|
**压缩点选**:记录需求 Plan 展示 `1.类型 2.项目 3.优先级 4.标签` 字母表;你可回 `1a2b3a4d`(见 [compact-select.md](references/compact-select.md))。标签未命中会自动重拉一次标签候选并重生选项。
|
||||||
|
**记录需求**元字段(优先级/标签/提交部门/提交人):与压缩点选并用;缺项用字母表补齐。见 [references/record-meta-fields.md](references/record-meta-fields.md)。
|
||||||
|
|
||||||
|
后续口令**优先带任务编号**;未带则读「工作项编号(系统)」;仍无则询问;**禁止按标题补全**。
|
||||||
|
|
||||||
|
## 本 Skill 终点
|
||||||
|
|
||||||
|
交棒完成(需求=待开发;【交付】负责人=何斐)后结束。可一句:「请技术经理使用开发 Skill」。
|
||||||
|
例外:交棒后「创建迭代并关联交付」仍属 YunxiaoPM。
|
||||||
|
|
||||||
|
**明确不做:** 创建【开发】/【测试】、挂仓库、开分支、提测、写用例。
|
||||||
|
|
||||||
|
## §0.1 五条补齐(摘要)
|
||||||
|
|
||||||
|
1. **交棒占位**:标准路径下交付仍为 `等待设计任务完成后自动填入` 时**允许**交棒,但 Plan 必须勾选风险,回报首行标红。**快轨**有手工/原型时禁止占位(见 [fast-track.md](references/fast-track.md))。
|
||||||
|
2. **预计工时**:标准路径 = **阶段日历工时**(工作日×8);**快轨待开发**需求默认预计/实际各 **2**。
|
||||||
|
3. **编号真相源**在需求「工作项编号(系统)」;新建后立即 PATCH 该区块。
|
||||||
|
4. **无单快轨**:【设计】描述同步需求;计划起止=当日;TASK_SUB→交付后补 ASSOCIATED→需求;【交付】描述手工同步或 AutoPRD;交付/设计与需求同标签;设计当日完成态。
|
||||||
|
5. **描述双段**不互相覆盖;迭代**只挂【交付】**(需求不挂迭代);回退重做设计则**新开设计编号**,交付计划开始不改。
|
||||||
|
|
||||||
|
细则见各 references。
|
||||||
49
.cursor/skills/YunxiaoPM/acceptance.md
Normal file
49
.cursor/skills/YunxiaoPM/acceptance.md
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# 验收清单与回报
|
||||||
|
|
||||||
|
## apply 后必须自检
|
||||||
|
|
||||||
|
| # | 项 | 通过标准 |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | 需求编号 | 回报含 ONEOS-xx |
|
||||||
|
| 2 | 任务编号 | 交付/分析/设计凡新建或操作均回报编号;禁止只报标题 |
|
||||||
|
| 3 | 编号区块 | 需求「工作项编号(系统)」与实际一致 |
|
||||||
|
| 4 | ASSOCIATED | **仅交付**详情关联项可见需求(`createWorkitemRelationInfo=ASSOCIATED`;禁止 PARENT 冒充) |
|
||||||
|
| 5 | SUB | **必过**:分析/设计 create 用 `TASK_SUB→交付`(含 `parent`+`parentIdentifier`);交付「子项」tab 须可见。与 ASSOCIATED 同 create 互斥,阶段任务关联项可空(见 live-api.md) |
|
||||||
|
| 6 | 计划开始 | 未误覆盖已有值 |
|
||||||
|
| 7 | 阶段日历工时 | 有计划完成时已写入;脚注存在;回报用语正确 |
|
||||||
|
| 8 | 交棒 | 需求=待开发;交付负责人=何斐(交棒场景) |
|
||||||
|
| 9 | 占位风险 | 交付仍占位时首行标红 |
|
||||||
|
| 10 | 负向 | 本轮**无**【开发】/【测试】任务;未按标题查重 |
|
||||||
|
|
||||||
|
设计完成额外:AutoPRD 段已写;交付非占位(除非失败停下);ZIP+截图已挂或已列出缺项。
|
||||||
|
|
||||||
|
迭代额外:只挂【交付】(需求不挂);版本号符合递增规则。
|
||||||
|
|
||||||
|
## 回报模板(精简)
|
||||||
|
|
||||||
|
```text
|
||||||
|
【YunxiaoPMapp】
|
||||||
|
风险:(若有占位交棒则首行标红)
|
||||||
|
需求:ONEOS-xx | 状态=…
|
||||||
|
交付:ONEOS-a | 负责人=…
|
||||||
|
分析:ONEOS-b | …(无则写无)
|
||||||
|
设计:ONEOS-c | …(无则写无)
|
||||||
|
阶段日历工时:分析 Hh / 设计 Hh(若本轮写入)
|
||||||
|
附件:…(若本轮)
|
||||||
|
迭代:…(若本轮)
|
||||||
|
下一步:请技术经理使用开发 Skill(交棒后)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 适合全自动 vs 人工门禁
|
||||||
|
|
||||||
|
| 适合全自动 | 建议半自动/人工门禁 |
|
||||||
|
|---|---|
|
||||||
|
| 建单、打标签、挂迭代、写描述、建交付树、改状态、交棒负责人、幂等查重 | 受理(已确认)、是否快轨、设计完成是否真可开发、跨需求优先级与迭代容量、回退与取消 |
|
||||||
|
|
||||||
|
## 实写性能(2026-07-23 复盘)
|
||||||
|
|
||||||
|
| 项 | 要求 |
|
||||||
|
|---|---|
|
||||||
|
| 改状态 | 只用 `status/transit`(见 [live-api.md](live-api.md)) |
|
||||||
|
| 改【交付】负责人 | 只用 `PATCH …/{id}` + `propertyKey=assignedTo` |
|
||||||
|
| 极速复测 | `scripts/live_create_fast.py`;默认不开浏览器 |
|
||||||
4
.cursor/skills/YunxiaoPM/agents/openai.yaml
Normal file
4
.cursor/skills/YunxiaoPM/agents/openai.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
interface:
|
||||||
|
display_name: "需求任务"
|
||||||
|
short_description: "云效:压缩点选记录需求→分析/设计→交棒待开发→挂迭代"
|
||||||
|
default_prompt: "按需求任务(/YunxiaoPM)处理:先 Plan 出压缩点选字母表并确认项目,用户回 1a2b3a4d 与「执行」后再 apply。"
|
||||||
95
.cursor/skills/YunxiaoPM/assets/cn-workday-calendar.json
Normal file
95
.cursor/skills/YunxiaoPM/assets/cn-workday-calendar.json
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"timezone": "Asia/Shanghai",
|
||||||
|
"note": "法定放假日 holidays;国务院公布的周末调休补班日 workdays_on_weekend。缺年则禁止静默按仅去周末计算。",
|
||||||
|
"source": {
|
||||||
|
"2025": "国办发明电〔2024〕12号 https://www.gov.cn/zhengce/zhengceku/202411/content_6986383.htm",
|
||||||
|
"2026": "国办发明电〔2025〕7号 https://www.gov.cn/zhengce/content/202511/content_7047090.htm"
|
||||||
|
},
|
||||||
|
"years": {
|
||||||
|
"2025": {
|
||||||
|
"holidays": [
|
||||||
|
"2025-01-01",
|
||||||
|
"2025-01-28",
|
||||||
|
"2025-01-29",
|
||||||
|
"2025-01-30",
|
||||||
|
"2025-01-31",
|
||||||
|
"2025-02-01",
|
||||||
|
"2025-02-02",
|
||||||
|
"2025-02-03",
|
||||||
|
"2025-02-04",
|
||||||
|
"2025-04-04",
|
||||||
|
"2025-04-05",
|
||||||
|
"2025-04-06",
|
||||||
|
"2025-05-01",
|
||||||
|
"2025-05-02",
|
||||||
|
"2025-05-03",
|
||||||
|
"2025-05-04",
|
||||||
|
"2025-05-05",
|
||||||
|
"2025-05-31",
|
||||||
|
"2025-06-01",
|
||||||
|
"2025-06-02",
|
||||||
|
"2025-10-01",
|
||||||
|
"2025-10-02",
|
||||||
|
"2025-10-03",
|
||||||
|
"2025-10-04",
|
||||||
|
"2025-10-05",
|
||||||
|
"2025-10-06",
|
||||||
|
"2025-10-07",
|
||||||
|
"2025-10-08"
|
||||||
|
],
|
||||||
|
"workdays_on_weekend": [
|
||||||
|
"2025-01-26",
|
||||||
|
"2025-02-08",
|
||||||
|
"2025-04-27",
|
||||||
|
"2025-09-28",
|
||||||
|
"2025-10-11"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"2026": {
|
||||||
|
"holidays": [
|
||||||
|
"2026-01-01",
|
||||||
|
"2026-01-02",
|
||||||
|
"2026-01-03",
|
||||||
|
"2026-02-15",
|
||||||
|
"2026-02-16",
|
||||||
|
"2026-02-17",
|
||||||
|
"2026-02-18",
|
||||||
|
"2026-02-19",
|
||||||
|
"2026-02-20",
|
||||||
|
"2026-02-21",
|
||||||
|
"2026-02-22",
|
||||||
|
"2026-02-23",
|
||||||
|
"2026-04-04",
|
||||||
|
"2026-04-05",
|
||||||
|
"2026-04-06",
|
||||||
|
"2026-05-01",
|
||||||
|
"2026-05-02",
|
||||||
|
"2026-05-03",
|
||||||
|
"2026-05-04",
|
||||||
|
"2026-05-05",
|
||||||
|
"2026-06-19",
|
||||||
|
"2026-06-20",
|
||||||
|
"2026-06-21",
|
||||||
|
"2026-09-25",
|
||||||
|
"2026-09-26",
|
||||||
|
"2026-09-27",
|
||||||
|
"2026-10-01",
|
||||||
|
"2026-10-02",
|
||||||
|
"2026-10-03",
|
||||||
|
"2026-10-04",
|
||||||
|
"2026-10-05",
|
||||||
|
"2026-10-06",
|
||||||
|
"2026-10-07"
|
||||||
|
],
|
||||||
|
"workdays_on_weekend": [
|
||||||
|
"2026-01-04",
|
||||||
|
"2026-02-14",
|
||||||
|
"2026-02-28",
|
||||||
|
"2026-05-09",
|
||||||
|
"2026-09-20",
|
||||||
|
"2026-10-10"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
221
.cursor/skills/YunxiaoPM/assets/runtime-ids.json
Normal file
221
.cursor/skills/YunxiaoPM/assets/runtime-ids.json
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"skill": "YunxiaoPM",
|
||||||
|
"verified_at": "2026-07-25",
|
||||||
|
"note": "YunxiaoPM constants. Project space MUST be user-selected (PJ gate); project.spaceIdentifier is last-known cache only — never auto-apply. See references/project-selection.md.",
|
||||||
|
"project": {
|
||||||
|
"selection_mode": "user_pick_required",
|
||||||
|
"name": null,
|
||||||
|
"name_aliases": [
|
||||||
|
"01_ONEOS",
|
||||||
|
"ONEOS",
|
||||||
|
"统一运营管理平台",
|
||||||
|
"统一运营管理平台PC端",
|
||||||
|
"统一运营管理平台 PC 端"
|
||||||
|
],
|
||||||
|
"spaceIdentifier": null,
|
||||||
|
"customCode": null,
|
||||||
|
"spaceType": "Project",
|
||||||
|
"organizationIdentifier": "697c54a19df7fdfa65466405",
|
||||||
|
"default_sprint_name_prefix": "统一运营管理平台PC端",
|
||||||
|
"list_api": "GET /projex/api/workspace/project/search/list",
|
||||||
|
"last_selected": {
|
||||||
|
"name": "01_ONEOS",
|
||||||
|
"spaceIdentifier": "1280be963a5a2cc126a4118dca",
|
||||||
|
"customCode": "ONEOS",
|
||||||
|
"note": "历史常用项;仅作预填建议,禁止未点选即使用"
|
||||||
|
},
|
||||||
|
"refreshed_at": "2026-07-25"
|
||||||
|
},
|
||||||
|
"projects_catalog": [
|
||||||
|
{
|
||||||
|
"name": "05_羚牛碳资产平台",
|
||||||
|
"identifier": "ff104a3bce09463da136a97999",
|
||||||
|
"customCode": "CARBON"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "06_对外客户项目",
|
||||||
|
"identifier": "baca8b4d676c5af67e475caec0",
|
||||||
|
"customCode": "CUST"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "07_LNBOX",
|
||||||
|
"identifier": "35e1e915a052379bbdfb993aac",
|
||||||
|
"customCode": "LNBOX"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "04_AI应用",
|
||||||
|
"identifier": "d9002ea72c6c3a1a97b02be750",
|
||||||
|
"customCode": "AIAPP"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "03_数据中台",
|
||||||
|
"identifier": "a801cef5c9a68fa051c07432c7",
|
||||||
|
"customCode": "DATA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "02_小羚羚APP",
|
||||||
|
"identifier": "db771a2cca07bed43b369af077",
|
||||||
|
"customCode": "XLLAPP"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "01_ONEOS",
|
||||||
|
"identifier": "1280be963a5a2cc126a4118dca",
|
||||||
|
"customCode": "ONEOS"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "敏捷研发示例项目",
|
||||||
|
"identifier": "65eca0c2e16a23939081e19e14",
|
||||||
|
"customCode": "DEMO"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"people": {
|
||||||
|
"wangmian": {
|
||||||
|
"displayName": "王冕",
|
||||||
|
"identifier": "6811df000601d2fea60144a9",
|
||||||
|
"role": "产品创建人/默认负责人"
|
||||||
|
},
|
||||||
|
"hefei": {
|
||||||
|
"displayName": "何斐",
|
||||||
|
"identifier": "695f0400562f09713f9c3a93",
|
||||||
|
"role": "待开发交棒【交付】负责人"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"故障管理": "ceb526a7343995577645317e9a",
|
||||||
|
"还车应结款": "4204960ce658c94b17abb7c5f6",
|
||||||
|
"工作台": "b62d21beac55c0b43389915eab",
|
||||||
|
"交车管理": "b6947b5aca82a8c759612ba039",
|
||||||
|
"合同管理": "23873be81931cb0dc1bf87a456",
|
||||||
|
"安全培训": "76988b5f73ef515de5930d59b9",
|
||||||
|
"证照管理": "11f4c2ec65901a8f3199c81706",
|
||||||
|
"还车管理": "1e0fce2d6929ff4ac13b310e97"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"req": {
|
||||||
|
"待处理": "100005",
|
||||||
|
"已确认": "32",
|
||||||
|
"分析中": "154395",
|
||||||
|
"设计中": "156603",
|
||||||
|
"设计完成": "307012",
|
||||||
|
"待开发": "1582fc929d429111b925309493"
|
||||||
|
},
|
||||||
|
"task": {
|
||||||
|
"待处理": "100005",
|
||||||
|
"已完成": "100014"
|
||||||
|
},
|
||||||
|
"transit_api": "POST /projex/api/workitem/workitem/{id}/status/transit",
|
||||||
|
"fast_handoff_hops": [
|
||||||
|
"设计完成",
|
||||||
|
"待开发"
|
||||||
|
],
|
||||||
|
"note": "见 references/live-api.md;禁止再用 updateStatus"
|
||||||
|
},
|
||||||
|
"workitem_types": {
|
||||||
|
"product_req": {
|
||||||
|
"name": "产品类需求",
|
||||||
|
"category": "Req",
|
||||||
|
"identifier": "9uy29901re573f561d69jn40"
|
||||||
|
},
|
||||||
|
"task": {
|
||||||
|
"name": "任务",
|
||||||
|
"category": "Task",
|
||||||
|
"identifier": "ba102e46bc6a8483d9b7f25c"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"priority": {
|
||||||
|
"紧急": "646004e97f54bb77fec7b455df",
|
||||||
|
"高": "95b89e0a524d9693e1f335ffe5",
|
||||||
|
"中": "fa155d1214f9f8db222d39db3b",
|
||||||
|
"低": "92924feff9c1085891e7511872"
|
||||||
|
},
|
||||||
|
"fields": {
|
||||||
|
"plan_start": {
|
||||||
|
"fieldIdentifier": "79",
|
||||||
|
"name": "计划开始时间",
|
||||||
|
"value_shape": "YYYY-MM-DD HH:mm:ss China wall time preferred; epoch ms string also accepted",
|
||||||
|
"example": "2026-07-27 12:00:00",
|
||||||
|
"update_api": "POST /projex/api/workitem/workitem/field/value/{workitemId} form fieldValueList=JSON"
|
||||||
|
},
|
||||||
|
"plan_end": {
|
||||||
|
"fieldIdentifier": "80",
|
||||||
|
"name": "计划完成时间",
|
||||||
|
"value_shape": "YYYY-MM-DD HH:mm:ss or epoch ms string",
|
||||||
|
"update_api": "POST /projex/api/workitem/workitem/field/value/{workitemId} form fieldValueList=JSON"
|
||||||
|
},
|
||||||
|
"estimated_hours": {
|
||||||
|
"fieldIdentifier": "101586",
|
||||||
|
"name": "预计工时",
|
||||||
|
"note": "不可直接改字段;须工时预估登记",
|
||||||
|
"create_api": "POST /projex/api/workitem/workitem/time/estimate body spentTime,type,recordUserIdentifier,workitemIdentifier",
|
||||||
|
"delete_api": "DELETE /projex/api/workitem/workitem/time/estimate/{workitemId}/{estimateId}",
|
||||||
|
"list_api": "GET /projex/api/workitem/workitem/time/estimate/list?workitemIdentifier="
|
||||||
|
},
|
||||||
|
"actual_hours": {
|
||||||
|
"name": "实际工时",
|
||||||
|
"note": "快轨待开发默认 2",
|
||||||
|
"create_api": "POST /projex/api/workitem/workitem/time body actualTime,type,recordUserIdentifier,workitemIdentifier,gmtStart,gmtEnd (epoch ms string)",
|
||||||
|
"list_api": "GET /projex/api/workitem/workitem/time/list?workitemIdentifier=",
|
||||||
|
"fast_track_default": 2,
|
||||||
|
"verified_at": "2026-07-27",
|
||||||
|
"verified_on": "ONEOS-293"
|
||||||
|
},
|
||||||
|
"fast_track": {
|
||||||
|
"req_estimated_hours": 2,
|
||||||
|
"req_actual_hours": 2,
|
||||||
|
"design_plan_start_end_same_day": true,
|
||||||
|
"design_description": "copy_req_document",
|
||||||
|
"delivery_description": "manual_sync_or_autoprd",
|
||||||
|
"delivery_design_same_tags_as_req": true,
|
||||||
|
"design_associated_to_req_after_task_sub": true,
|
||||||
|
"document_update_api": "PATCH /projex/api/workitem/workitem/{id}/document {content,formatType:RICHTEXT}"
|
||||||
|
},
|
||||||
|
"submit_department": {
|
||||||
|
"fieldIdentifier": "3132597a9718d1c282b7ba5a0c",
|
||||||
|
"name": "提交部门",
|
||||||
|
"format": "string input",
|
||||||
|
"update_api": "POST /projex/api/workitem/workitem/field/value/{workitemId} form fieldValueList=JSON",
|
||||||
|
"verified_at": "2026-07-27",
|
||||||
|
"verified_on": "ONEOS-293"
|
||||||
|
},
|
||||||
|
"submitter": {
|
||||||
|
"fieldIdentifier": "9e01269e96f91fbb97d36bf5b3",
|
||||||
|
"name": "提交人",
|
||||||
|
"format": "string input",
|
||||||
|
"update_api": "POST /projex/api/workitem/workitem/field/value/{workitemId} form fieldValueList=JSON",
|
||||||
|
"verified_at": "2026-07-27",
|
||||||
|
"verified_on": "ONEOS-293"
|
||||||
|
},
|
||||||
|
"tag": {
|
||||||
|
"fieldIdentifier": "tag",
|
||||||
|
"name": "标签",
|
||||||
|
"propertyKey": "tag"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"assignee_rules": {
|
||||||
|
"待开发_交付任务": "hefei",
|
||||||
|
"分析中_交付与分析": "creator",
|
||||||
|
"设计中_设计": "creator"
|
||||||
|
},
|
||||||
|
"relation": {
|
||||||
|
"delivery_to_req": "ASSOCIATED",
|
||||||
|
"stage_to_delivery": "TASK_SUB",
|
||||||
|
"create_field": "createWorkitemRelationInfo",
|
||||||
|
"forbid": [
|
||||||
|
"PARENT_as_关联项",
|
||||||
|
"ASSOCIATED_only_for_stage_tasks_without_TASK_SUB"
|
||||||
|
],
|
||||||
|
"note": "交付必须 ASSOCIATED→需求。分析/设计默认 TASK_SUB→交付(子项 tab)。二者同 create 互斥。见 references/live-api.md"
|
||||||
|
},
|
||||||
|
"delivery_placeholder": "等待设计任务完成后自动填入",
|
||||||
|
"task_title_prefixes": {
|
||||||
|
"delivery": "【交付】",
|
||||||
|
"analysis": "【分析】",
|
||||||
|
"design": "【设计】"
|
||||||
|
},
|
||||||
|
"publish_url": {
|
||||||
|
"shape": "{baseUrl}/{prototype-id}/index.html",
|
||||||
|
"forbid_prototypes_prefix": true,
|
||||||
|
"require_index_html": true
|
||||||
|
}
|
||||||
|
}
|
||||||
317
.cursor/skills/YunxiaoPM/docs-YunxiaoPMapp-实现原理-开发Skill对接.md
Normal file
317
.cursor/skills/YunxiaoPM/docs-YunxiaoPMapp-实现原理-开发Skill对接.md
Normal file
@@ -0,0 +1,317 @@
|
|||||||
|
# YunxiaoPMapp 实现原理说明
|
||||||
|
|
||||||
|
> 供**开发部门**设计 / 制作「开发侧 Skill」(暂称 **YunxiaoDevapp**)时对齐契约。
|
||||||
|
> 本文描述产品侧 Skill **YunxiaoPMapp** 的模型、边界、数据契约与交棒接口;**不是**对 `yunxiao-requirement-lifecycle` 的兼容说明。
|
||||||
|
> 技能包:https://github.com/15810879921-coder/oneos-pm-skills · `skills/YunxiaoPMapp/`
|
||||||
|
> 文档版本:2026-07-24
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 为什么拆成两个 Skill
|
||||||
|
|
||||||
|
| | YunxiaoPMapp(产品) | 开发 Skill(待建) |
|
||||||
|
|---|---|---|
|
||||||
|
| 职责 | 需求从「待处理」到「待开发」交棒 | 从「待开发」到开发完成 / 提测前 |
|
||||||
|
| 任务类型 | 【交付】【分析】【设计】 | 【开发】(可多条)、可选挂仓库/分支 |
|
||||||
|
| 负责人交接 | 交棒时【交付】→ **何斐** | 拆【开发】子任务并指派研发 |
|
||||||
|
| 明确不做 | 建【开发】/【测试】、开分支、提测 | 不建【分析】/【设计】、不改 AutoRDO 段 |
|
||||||
|
|
||||||
|
**硬规则:** 两个 Skill **禁止互相 include / fork 全文**;只认本文第 6 章「交棒契约」。产品会话与开发会话不要同时挂载旧 `yunxiao-requirement-lifecycle`,避免双建任务树。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 核心真相源(必须先统一)
|
||||||
|
|
||||||
|
```text
|
||||||
|
需求状态 = 阶段看板唯一真相(分析中 / 设计中 / 待开发 …)
|
||||||
|
【交付】任务 = 每需求最多 1 条「交付容器」
|
||||||
|
【分析】【设计】 = 【交付】下的阶段子项(产品侧建)
|
||||||
|
【开发】【测试】 = 开发 / 测试 Skill 建(产品侧永不创建)
|
||||||
|
查重 / 复用 = 只认云效任务编号 ONEOS-xx,禁止按标题
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.1 关系模型(云效)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TB
|
||||||
|
Req["产品类需求 ONEOS-R"]
|
||||||
|
DEL["【交付】ONEOS-a"]
|
||||||
|
AN["【分析】ONEOS-b"]
|
||||||
|
DE["【设计】ONEOS-c"]
|
||||||
|
DEV["【开发】… 开发 Skill"]
|
||||||
|
TEST["【测试】… 测试 Skill"]
|
||||||
|
|
||||||
|
DEL -->|"ASSOCIATED 关联项"| REQ
|
||||||
|
AN -->|"TASK_SUB 子项"| DEL
|
||||||
|
DE -->|"TASK_SUB 子项"| DEL
|
||||||
|
DEV -.->|"建议:SUB→交付 或 ASSOCIATED→需求+交付"| DEL
|
||||||
|
TEST -.->|"测试 Skill"| REQ
|
||||||
|
```
|
||||||
|
|
||||||
|
| 关系 | 谁写 | 验收 |
|
||||||
|
|---|---|---|
|
||||||
|
| `ASSOCIATED` | **仅【交付】→ 需求** | 交付详情「关联项」可见需求 |
|
||||||
|
| `TASK_SUB` | 【分析】/【设计】→【交付】 | 交付详情「子项」可见阶段任务 |
|
||||||
|
| (开发侧建议) | 【开发】→【交付】或需求 | 由开发 Skill 自定,但须可编号查重 |
|
||||||
|
|
||||||
|
**踩坑(已复现):** 对分析/设计只写 `parentIdentifier` + `ASSOCIATED→需求`,交付「子项」会为空。正确:create 时 `createWorkitemRelationInfo=TASK_SUB` + `parent`/`parentIdentifier`=交付。同一 create **只能**带一条关系,ASSOCIATED 与 TASK_SUB 互斥。
|
||||||
|
|
||||||
|
### 2.2 标题只是展示
|
||||||
|
|
||||||
|
- 形式:`【交付】`/`【分析】`/`【设计】` + 需求标题
|
||||||
|
- **不参与查重**;改标题不影响幂等
|
||||||
|
- 开发侧【开发】标题建议 `【开发】` + 范围简述,同样**只认编号**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 编号权威源
|
||||||
|
|
||||||
|
需求描述固定区块(机器可解析):
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 工作项编号(系统)
|
||||||
|
- 交付:ONEOS-a
|
||||||
|
- 分析:ONEOS-b(无则写无)
|
||||||
|
- 设计:ONEOS-c(无则写无)
|
||||||
|
```
|
||||||
|
|
||||||
|
| 规则 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| 新建后立即 PATCH | 只改本区块,不动 AutoRDO / AutoPRD |
|
||||||
|
| 操作顺序 | 口令显式编号 > 读本区块 > ASSOCIATED/SUB 反查 |
|
||||||
|
| 冲突 | 停下人工;**禁止按标题猜** |
|
||||||
|
| 多交付编号 | 停止并列号请人合并 |
|
||||||
|
|
||||||
|
**开发 Skill 入口建议:** 口令必须带 `需求=ONEOS-R` + `交付任务=ONEOS-a`;缺则读本区块;仍无则询问。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 需求描述双段(产品写 · 开发只读)
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 原始诉求(AutoRDO)
|
||||||
|
(聊天/录音清洗稿;设计完成也不删)
|
||||||
|
|
||||||
|
## 产品说明(AutoPRD)
|
||||||
|
(设计完成才灌满;含对象存储预览链接)
|
||||||
|
|
||||||
|
## 工作项编号(系统)
|
||||||
|
- 交付 / 分析 / 设计
|
||||||
|
```
|
||||||
|
|
||||||
|
| 段 | 谁写 | 开发侧用法 |
|
||||||
|
|---|---|---|
|
||||||
|
| AutoRDO | `$AutoRDO` → 产品记需求时 | 占位交棒时**唯一可信**业务原文 |
|
||||||
|
| AutoPRD | `$oneos-autoprd` → 设计完成时 | 正式需求说明;缺则有权要求产品补设计完成 |
|
||||||
|
| 编号区块 | YunxiaoPMapp | 定位交付树 |
|
||||||
|
|
||||||
|
**【交付】描述:** 设计完成前固定占位文案 `等待设计任务完成后自动填入`;设计完成后替换为 AutoPRD 正文。
|
||||||
|
**允许占位交棒**,但产品回报必须标红风险;开发 Skill 应检测占位并提示「材料不齐,可凭 AutoRDO 开工或退回补设计」。
|
||||||
|
|
||||||
|
对象存储预览 URL 形态:`{baseUrl}/{prototype-id}/index.html`(禁止加 `prototypes/` 前缀、禁止去掉 `index.html`)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 产品侧阶段状态机(0→5)
|
||||||
|
|
||||||
|
```text
|
||||||
|
0 创建需求(待处理) ─AutoRDO→ 仅需求,不建任务
|
||||||
|
1 受理确认(已确认) 仍不建任务
|
||||||
|
2 分析中 建【交付】+【分析】
|
||||||
|
3 设计中 建【设计】;收口【分析】计划完成
|
||||||
|
4 设计完成 收口【设计】;AutoPRD+附件;灌【交付】描述
|
||||||
|
5 待开发交棒 ★ 需求→待开发;【交付】负责人→何斐
|
||||||
|
★ = YunxiaoPMapp 终点 / 开发 Skill 起点
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.1 各步要点(开发需知道的副作用)
|
||||||
|
|
||||||
|
| 步骤 | 需求状态 | 任务侧关键动作 |
|
||||||
|
|---|---|---|
|
||||||
|
| 2 分析中 | 分析中 | 新建【交付】ASSOCIATED→需求;描述=占位;计划开始仅空写当日且**此后不可改**;新建【分析】TASK_SUB→交付 |
|
||||||
|
| 3 设计中 | 设计中 | 新建【设计】;【分析】计划完成=当日 + 阶段日历工时 |
|
||||||
|
| 4 设计完成 | 设计完成 | 【设计】完成态;需求+交付挂 ZIP/截图;交付描述换正式说明 |
|
||||||
|
| 5 交棒 | **待开发** | **只改交付负责人→何斐**;不新建分析/设计;不写交付计划完成 |
|
||||||
|
|
||||||
|
### 5.2 两条旁路(仍交到同一终点)
|
||||||
|
|
||||||
|
| 路径 | 前提 | 行为 |
|
||||||
|
|---|---|---|
|
||||||
|
| **无单快轨** | 尚无分析路径 / 明确跳过分析 | 待开发 + 新建交付+设计(设计当日收口);**不建分析**;默认可不跑 AutoPRD |
|
||||||
|
| **编号直推** | 已有分析/设计**编号** | 收口空计划完成 → 待开发 + 交付交棒何斐;不新建冗余单 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 交棒契约(开发 Skill 必须实现)
|
||||||
|
|
||||||
|
### 6.1 入口条件(产品已完成)
|
||||||
|
|
||||||
|
```text
|
||||||
|
需求状态 = 待开发
|
||||||
|
【交付】任务编号 = ONEOS-a(唯一)
|
||||||
|
【交付】负责人 = 何斐
|
||||||
|
【交付】ASSOCIATED → 该需求
|
||||||
|
可选:分析/设计编号在「工作项编号(系统)」中
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2 开发 Skill 建议入口口令
|
||||||
|
|
||||||
|
```text
|
||||||
|
接手开发:需求=ONEOS-R;交付任务=ONEOS-a
|
||||||
|
拆分开发:交付任务=ONEOS-a;范围=前端|后端|…;负责人=…
|
||||||
|
开始开发:开发任务=ONEOS-d
|
||||||
|
开发完成:开发任务=ONEOS-d
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.3 开发 Skill 建议职责边界
|
||||||
|
|
||||||
|
| 应做 | 不应做 |
|
||||||
|
|---|---|
|
||||||
|
| 在【交付】下建一条或多条【开发】(编号幂等) | 再建【分析】/【设计】或第二套【交付】 |
|
||||||
|
| 正式关联:建议 SUB→交付,或同时 ASSOCIATED→需求 | 只按标题「【开发】xxx」查重 |
|
||||||
|
| 挂仓库 / 分支 / MR(按你们 Codeup 规范) | 覆盖需求 AutoRDO 段 |
|
||||||
|
| 改【开发】状态与负责人 | 擅自把需求从待开发退回(除非产品授权回退口令) |
|
||||||
|
| 检测交付描述是否仍为占位并提示 | 假装 AutoPRD 已齐全 |
|
||||||
|
| 全部【开发】完成后通知测试 Skill / 建【测试】 | 在产品 Skill 会话里混跑 |
|
||||||
|
|
||||||
|
### 6.4 共享常量(可引用,勿整包加载)
|
||||||
|
|
||||||
|
路径均在 `skills/YunxiaoPMapp/assets/`:
|
||||||
|
|
||||||
|
| 文件 | 内容 |
|
||||||
|
|---|---|
|
||||||
|
| `runtime-ids.json` | 项目 spaceId、何斐 ID、工作项类型、状态 transit、字段 79/80 |
|
||||||
|
| `cn-workday-calendar.json` | 法定节假日 / 调休(阶段日历工时) |
|
||||||
|
|
||||||
|
开发侧可复制一份到自己的 `assets/`,或只读引用短路径;**不要**把 YunxiaoPMapp 的 references 全文 include 进开发 Skill。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 计划时间与「阶段日历工时」
|
||||||
|
|
||||||
|
产品侧口径(开发侧若写计划时间建议对齐语义):
|
||||||
|
|
||||||
|
| 对象 | 计划开始 | 计划完成 | 预计工时 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 【交付】 | 首次分析中空则写当日,**永不覆盖** | 产品侧不写(留给上线) | 一般不推全周期 |
|
||||||
|
| 【分析】【设计】 | 创建时空则写当日,**永不覆盖** | 阶段收口日 | `工作日×8` |
|
||||||
|
|
||||||
|
```text
|
||||||
|
预计工时 = 阶段日历工时(Lead Time)≠ 人力投入人天
|
||||||
|
算法:起止日含首尾,扣周末与法定假,计入调休补班;×8 小时
|
||||||
|
禁止:(结束−开始+1)×8 的自然日算法
|
||||||
|
```
|
||||||
|
|
||||||
|
脚注固定:`【系统】预计工时=阶段日历工时(工作日×8),非人力投入预估`
|
||||||
|
脚本:`scripts/workday_hours.py`
|
||||||
|
|
||||||
|
**建议:** 开发 Skill 若给【开发】写预计工时,在文档中明确是「人力投入预估」还是「阶段日历工时」,避免与产品侧混称。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Agent 运行时原理(制作 Skill 时照抄模式)
|
||||||
|
|
||||||
|
### 8.1 Plan 门禁
|
||||||
|
|
||||||
|
凡写云效:`SwitchMode → plan` → 用户确认 → 一口气 apply → 一次校验回报。
|
||||||
|
禁止用「参数已齐 / 速度路径」跳过 Plan。
|
||||||
|
|
||||||
|
### 8.2 模块化路由
|
||||||
|
|
||||||
|
`SKILL.md` 只做路由与门禁;细则在 `references/*.md`;常量在 `assets/`;脚本在 `scripts/`。
|
||||||
|
外置能力(AutoRDO、AutoPRD)**调用对方 Skill**,不内嵌对方全文。
|
||||||
|
|
||||||
|
### 8.3 幂等
|
||||||
|
|
||||||
|
```text
|
||||||
|
幂等键 = 项目 + 需求编号 + 任务类型角色(交付/分析/设计/开发…)+ 已登记任务编号
|
||||||
|
命中编号 → 复用并补缺字段;禁止新建第二条同角色主容器(交付唯一)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8.4 验收与回报
|
||||||
|
|
||||||
|
每次 apply 后自检(产品侧清单见 `references/acceptance.md`)。开发侧建议至少回报:
|
||||||
|
|
||||||
|
```text
|
||||||
|
【YunxiaoDevapp】
|
||||||
|
需求:ONEOS-R | 状态=待开发|开发中|…
|
||||||
|
交付:ONEOS-a | 负责人=…
|
||||||
|
开发:ONEOS-d1, ONEOS-d2 | …
|
||||||
|
仓库/分支:…
|
||||||
|
下一步:…
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8.5 已验证写路径(可复用思路)
|
||||||
|
|
||||||
|
| 动作 | 约定(见 live-api.md) |
|
||||||
|
|---|---|
|
||||||
|
| 改状态 | `POST …/status/transit`(勿用错误 updateStatus) |
|
||||||
|
| 改负责人 | `PATCH …/{id}` + `propertyKey=assignedTo` |
|
||||||
|
| 建单关系 | create 带 `createWorkitemRelationInfo` |
|
||||||
|
| 极速复测 | `scripts/live_create_fast.py`(可参考,开发侧另写自己的脚本) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. 回退最小集(开发需配合)
|
||||||
|
|
||||||
|
| 场景 | 产品侧规则 | 开发侧注意 |
|
||||||
|
|---|---|---|
|
||||||
|
| 待开发 → 退回设计中 | 需求回退;交付负责人可改回产品;**交付计划开始不改**;重做设计则**新开设计编号** | 已建【开发】是否取消 / 暂停由开发 Skill 定义;勿静默删编号 |
|
||||||
|
| 设计完成后需求大变 | Plan 问是否回退;更新 AutoPRD;AutoRDO 保留+变更纪要 | 勿覆盖 AutoRDO |
|
||||||
|
| 取消需求 | 任务标取消;不删编号区块 | 同步取消未完成【开发】 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. 建议的「YunxiaoDevapp」目录骨架
|
||||||
|
|
||||||
|
```text
|
||||||
|
YunxiaoDevapp/
|
||||||
|
├── SKILL.md # 门禁 + 路由 + 边界(引用本文契约,不 include PMapp)
|
||||||
|
├── assets/
|
||||||
|
│ └── runtime-ids.json # 可从 PMapp 复制/裁剪
|
||||||
|
├── references/
|
||||||
|
│ ├── model.md # 【开发】与交付/需求的关系约定
|
||||||
|
│ ├── handoff-intake.md # 认交付编号 + 占位检测
|
||||||
|
│ ├── split-dev-tasks.md # 拆前端/后端多【开发】
|
||||||
|
│ ├── codeup.md # 分支 / MR / 关联
|
||||||
|
│ ├── commands.md # 口令面
|
||||||
|
│ └── acceptance.md
|
||||||
|
└── scripts/ # 可选极速 API
|
||||||
|
```
|
||||||
|
|
||||||
|
`SKILL.md` description 建议写明:触发词「接手开发 / 拆分开发 / 开始开发」;**Does NOT create 【分析】/【设计】**;入口条件需求=待开发。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. 对照检查表(开发 Skill 评审用)
|
||||||
|
|
||||||
|
- [ ] 是否只认「需求编号 + 交付任务编号」,禁止标题查重
|
||||||
|
- [ ] 是否拒绝创建第二套【交付】或【分析】【设计】
|
||||||
|
- [ ] 占位交棒时是否提示风险且不假装 PRD 齐全
|
||||||
|
- [ ] 【开发】是否可编号幂等、可挂到交付树
|
||||||
|
- [ ] 是否与 YunxiaoPMapp **会话隔离**(不同 Skill、不同口令)
|
||||||
|
- [ ] 计划开始字段是否遵守「已有值不覆盖」(若沿用同一字段)
|
||||||
|
- [ ] 提测 / 【测试】是否交给测试 Skill,本包边界清晰
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. 相关文档索引
|
||||||
|
|
||||||
|
| 主题 | 路径(仓库内) |
|
||||||
|
|---|---|
|
||||||
|
| Skill 入口 | `skills/YunxiaoPMapp/SKILL.md` |
|
||||||
|
| 交付树模型 | `skills/YunxiaoPMapp/references/model.md` |
|
||||||
|
| 交棒契约 | `skills/YunxiaoPMapp/references/handoff-contract.md` |
|
||||||
|
| 标准路径 0–5 | `skills/YunxiaoPMapp/references/stage-flow.md` |
|
||||||
|
| 交棒门禁 / 回退 | `skills/YunxiaoPMapp/references/handoff-and-rollback.md` |
|
||||||
|
| 描述双段 | `skills/YunxiaoPMapp/references/description-split.md` |
|
||||||
|
| 编号区块 | `skills/YunxiaoPMapp/references/workitem-ids.md` |
|
||||||
|
| 快轨 / 编号直推 | `references/fast-track.md` · `number-push.md` |
|
||||||
|
| 工时算法 | `references/work-hours.md` |
|
||||||
|
| 实写 API | `references/live-api.md` |
|
||||||
|
|
||||||
|
安装产品 Skill:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx skills add 15810879921-coder/oneos-pm-skills --skill YunxiaoPMapp -a cursor -g -y
|
||||||
|
```
|
||||||
179
.cursor/skills/YunxiaoPM/docs-产品部流转流程图.md
Normal file
179
.cursor/skills/YunxiaoPM/docs-产品部流转流程图.md
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
# 产品部流转:YunxiaoPMapp(到交棒为止)
|
||||||
|
|
||||||
|
> 用途:先把**产品部**在云效上的工作流转说清楚;开发 / 测试 / 发版不在本 Skill 内,仅在文末标出交接点。
|
||||||
|
> 依据:`references/stage-flow.md` · `model.md` · `fast-track.md` · `handoff-contract.md`
|
||||||
|
> 日期:2026-07-24
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 产品部管到哪里
|
||||||
|
|
||||||
|
```text
|
||||||
|
产品部(YunxiaoPMapp)终点 = 需求状态「待开发」+【交付】负责人「何斐」
|
||||||
|
之后 = 请技术经理使用开发 Skill(不建【开发】/【测试】)
|
||||||
|
```
|
||||||
|
|
||||||
|
| 谁 | 做什么 | 不做什么 |
|
||||||
|
|---|---|---|
|
||||||
|
| 产品 / YunxiaoPMapp | 建需求、打标签、建【交付】【分析】【设计】、推进状态、设计完成灌 AutoPRD、交棒 | 建【开发】【测试】、开分支、提测、发版 |
|
||||||
|
| 技术经理(接手) | 从「待开发」起拆开发 | 不改写 AutoRDO;不新建第二套【交付】 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 总览流程图(标准路径)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TB
|
||||||
|
subgraph inputs [材料入口]
|
||||||
|
Chat[聊天/录音/口述]
|
||||||
|
AutoRDO["$AutoRDO 清洗"]
|
||||||
|
Proto[原型页 Make]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph pm [产品部 · YunxiaoPMapp]
|
||||||
|
S0["0 创建需求\n状态=待处理\n只写 AutoRDO\n不建任务"]
|
||||||
|
S1["1 受理确认\n状态=已确认\n仍不建任务"]
|
||||||
|
S2["2 分析中\n建【交付】+【分析】"]
|
||||||
|
S3["3 设计中\n建【设计】\n收口【分析】"]
|
||||||
|
S4["4 设计完成\n收口【设计】\nAutoPRD+附件\n灌【交付】描述"]
|
||||||
|
S5["5 待开发交棒\n交付负责人→何斐\n★ 产品终点"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph after [产品之后 · 不在本 Skill]
|
||||||
|
Dev["开发 Skill\n拆【开发】…"]
|
||||||
|
Test["测试 Skill"]
|
||||||
|
Rel["发版"]
|
||||||
|
end
|
||||||
|
|
||||||
|
Chat --> AutoRDO --> S0
|
||||||
|
Proto -.-> S4
|
||||||
|
S0 --> S1 --> S2 --> S3 --> S4 --> S5
|
||||||
|
S5 -->|"交棒契约:需求编号+交付编号"| Dev
|
||||||
|
Dev --> Test --> Rel
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 各步说明(产品侧)
|
||||||
|
|
||||||
|
| 步骤 | 需求状态 | 云效任务动作 | 描述写什么 | 口令示例 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| 0 创建 | 待处理 | 无 | `## 原始诉求(AutoRDO)`;编号区块待建 | `记录需求:…;推进至=暂不推进` |
|
||||||
|
| 1 受理 | 已确认 | 仍无 | 不动 | `受理确认:ONEOS-xx` |
|
||||||
|
| 2 分析中 | 分析中 | 新建【交付】ASSOCIATED→需求;新建【分析】TASK_SUB→交付 | 交付=占位文案 | `开始分析:ONEOS-xx` |
|
||||||
|
| 3 设计中 | 设计中 | 新建【设计】TASK_SUB→交付;分析计划完成=当日+阶段日历工时 | — | `开始设计:ONEOS-xx;交付=…;分析=…` |
|
||||||
|
| 4 设计完成 | 设计完成 | 设计完成态;需求+交付挂 ZIP/截图;交付描述换 AutoPRD | `$oneos-autoprd` 灌 `## 产品说明` | `设计完成:ONEOS-xx;设计=…;原型=…` |
|
||||||
|
| 5 交棒 | **待开发** | **只**把【交付】负责人改为何斐 | 若仍占位须标红风险 | `交棒开发:ONEOS-xx;交付=…` |
|
||||||
|
|
||||||
|
**编号权威:** 需求描述 `## 工作项编号(系统)`(交付 / 分析 / 设计)。后续口令优先带 `ONEOS-xx`,禁止按标题查重。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 交付树(产品建出来的结构)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TB
|
||||||
|
REQ["产品类需求 ONEOS-R\n状态=阶段真相"]
|
||||||
|
DEL["【交付】ONEOS-a\nASSOCIATED→需求"]
|
||||||
|
AN["【分析】ONEOS-b"]
|
||||||
|
DE["【设计】ONEOS-c"]
|
||||||
|
|
||||||
|
DEL -->|"关联项 ASSOCIATED"| REQ
|
||||||
|
AN -->|"子项 TASK_SUB"| DEL
|
||||||
|
DE -->|"子项 TASK_SUB"| DEL
|
||||||
|
```
|
||||||
|
|
||||||
|
验收口诀:
|
||||||
|
- 打开【交付】→「关联项」能看到需求
|
||||||
|
- 打开【交付】→「子项」能看到分析/设计(必须 `TASK_SUB`,不能只写 parentIdentifier)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 两条旁路(仍交到同一终点)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
subgraph standard [标准]
|
||||||
|
A1[分析中] --> A2[设计中] --> A3[设计完成] --> A4[待开发]
|
||||||
|
end
|
||||||
|
subgraph fast [无单快轨]
|
||||||
|
B1[待处理/已确认等] --> B2["待开发\n建交付+设计当日收口\n不建分析"]
|
||||||
|
end
|
||||||
|
subgraph push [编号直推]
|
||||||
|
C1[已有分析/设计编号] --> C2[收口空计划完成] --> C3[待开发+交棒何斐]
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
| 路径 | 何时用 | 注意 |
|
||||||
|
|---|---|---|
|
||||||
|
| 标准 0→5 | 正常产品节奏 | 设计完成才灌 AutoPRD |
|
||||||
|
| 快轨 | 明确跳过分析、急交棒 | 默认可不跑 AutoPRD;交付常占位→回报标红 |
|
||||||
|
| 编号直推 | 树上已有阶段任务编号 | 不新建冗余单;只认编号 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 产品部人机边界(Plan 门禁)
|
||||||
|
|
||||||
|
```text
|
||||||
|
凡写云效:Plan 对齐 → 人确认 → 一口气 apply → 一次校验回报
|
||||||
|
```
|
||||||
|
|
||||||
|
| 适合全自动 | 建议人点一下 |
|
||||||
|
|---|---|
|
||||||
|
| 建单、打标、建树、改状态、交棒负责人、幂等复用 | 优先级、标签、是否快轨、设计是否真可开发、占位是否接受交棒 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 交棒给下游时交出什么
|
||||||
|
|
||||||
|
产品回报至少包含:
|
||||||
|
|
||||||
|
```text
|
||||||
|
【YunxiaoPMapp】
|
||||||
|
风险:(占位交棒则首行标红)
|
||||||
|
需求:ONEOS-R | 状态=待开发
|
||||||
|
交付:ONEOS-a | 负责人=何斐
|
||||||
|
分析:ONEOS-b 或 无
|
||||||
|
设计:ONEOS-c 或 快轨占位说明
|
||||||
|
下一步:请技术经理使用开发 Skill
|
||||||
|
```
|
||||||
|
|
||||||
|
下游入口条件见 `references/handoff-contract.md`:认 **需求编号 + 交付任务编号**。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 和全链路的关系(本文件边界)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
PM[产品部本文] --> Handoff[待开发交棒]
|
||||||
|
Handoff --> Dev[开发]
|
||||||
|
Dev --> QA[测试]
|
||||||
|
QA --> Rel[发版]
|
||||||
|
```
|
||||||
|
|
||||||
|
全链路(含谢佳伟 / 时生亮)见仓库原型:
|
||||||
|
`src/prototypes/yunxiao-pipeline-handbook/`
|
||||||
|
产品 Skill 对接开发说明:
|
||||||
|
`docs-YunxiaoPMapp-实现原理-开发Skill对接.md`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. 相关 references
|
||||||
|
|
||||||
|
| 主题 | 路径 |
|
||||||
|
|---|---|
|
||||||
|
| 标准 0–5 | `references/stage-flow.md` |
|
||||||
|
| 交付树 / 子项 | `references/model.md` |
|
||||||
|
| 快轨 | `references/fast-track.md` |
|
||||||
|
| 编号直推 | `references/number-push.md` |
|
||||||
|
| 交棒门禁 | `references/handoff-and-rollback.md` |
|
||||||
|
| 交棒契约 | `references/handoff-contract.md` |
|
||||||
|
| 口令 | `references/commands.md` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 延伸阅读
|
||||||
|
|
||||||
|
- 四角色泳道(产品/开发/测试/发版):`docs-四角色泳道流程图.md`
|
||||||
|
- 开发侧草案:`docs-开发侧流转草案.md`
|
||||||
318
.cursor/skills/YunxiaoPM/docs-全流程分步说明.md
Normal file
318
.cursor/skills/YunxiaoPM/docs-全流程分步说明.md
Normal file
@@ -0,0 +1,318 @@
|
|||||||
|
# 全流程分步说明:产品 → 开发 → 测试 → 发版
|
||||||
|
|
||||||
|
> 把整条链路拆成**按顺序执行的步骤**,每步说清:谁做、做什么、云效上变成什么、下一步谁接。
|
||||||
|
> 读完应能照着口令/动作走完一轮(标准路径)。
|
||||||
|
> 日期:2026-07-24
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 先记住三件事
|
||||||
|
|
||||||
|
1. **需求状态 = 阶段真相**
|
||||||
|
看需求状态就知道现在卡在哪一段(分析中 / 待开发 / 开发中 / 待测试…)。
|
||||||
|
2. **每条需求只有 1 个【交付】容器**
|
||||||
|
分析、设计、开发、测试都挂在这个交付下面(子项),不要再建第二个【交付】。
|
||||||
|
3. **编号说话,不靠标题查**
|
||||||
|
口令尽量带 `ONEOS-xx`;改标题不影响关联。
|
||||||
|
|
||||||
|
```text
|
||||||
|
需求(状态主轴)
|
||||||
|
└─【交付】(容器,关联到需求)
|
||||||
|
├─【分析】【设计】 ← 产品建
|
||||||
|
├─【开发】… ← 开发建
|
||||||
|
└─【测试】 ← 开发提测时建
|
||||||
|
【发版】另建,挂迭代 + 范围内需求
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 总步骤一览(共 18 步)
|
||||||
|
|
||||||
|
| 阶段 | 步骤 | 一句话 |
|
||||||
|
|---|---|---|
|
||||||
|
| **产品** | 1~6 | 从记诉求到交棒给何斐 |
|
||||||
|
| **开发** | 7~12 | 从拆任务到提测 |
|
||||||
|
| **测试** | 13~15 | 从接测到测试完成 |
|
||||||
|
| **发版** | 16~17 | 从建发版到发布结果 |
|
||||||
|
| **收口** | 18 | 产品验收关闭 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 阶段 A|产品(步骤 1~6)
|
||||||
|
|
||||||
|
### 步骤 1|记录需求
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 产品 / AI(YunxiaoPMapp) |
|
||||||
|
| **做什么** | 把聊天、录音、口述先洗成 AutoRDO,再建一条**产品类需求** |
|
||||||
|
| **需求状态** | **待处理** |
|
||||||
|
| **云效任务** | 不建任何任务 |
|
||||||
|
| **描述里写** | `## 原始诉求(AutoRDO)`;编号区先空着 |
|
||||||
|
| **口令例** | `记录需求:…;推进至=暂不推进` |
|
||||||
|
| **为什么** | 先落盘,避免口头需求丢;还没确认值不值得做 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 步骤 2|受理确认
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 产品 |
|
||||||
|
| **做什么** | 确认要做:定优先级、打标签(从云效标签里点选) |
|
||||||
|
| **需求状态** | **已确认** |
|
||||||
|
| **云效任务** | 仍不建任务 |
|
||||||
|
| **口令例** | `受理确认:ONEOS-xx` |
|
||||||
|
| **为什么** | 和「还没想清楚」的待处理分开;确认后才进分析/设计 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 步骤 3|开始分析
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 产品 / AI |
|
||||||
|
| **做什么** | ① 建 **【交付】**(整条需求的唯一容器,关联到需求)② 建 **【分析】**(挂在交付**子项**下) |
|
||||||
|
| **需求状态** | **分析中** |
|
||||||
|
| **云效任务** | 【交付】+【分析】 |
|
||||||
|
| **口令例** | `开始分析:ONEOS-xx` |
|
||||||
|
| **验收** | 打开【交付】→「关联项」有需求;「子项」有【分析】 |
|
||||||
|
| **为什么** | 分析要有落点;后续设计/开发/测试都挂同一棵树 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 步骤 4|开始设计
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 产品 / AI |
|
||||||
|
| **做什么** | 建 **【设计】**(子项挂交付);收口【分析】计划时间 |
|
||||||
|
| **需求状态** | **设计中** |
|
||||||
|
| **云效任务** | 新增【设计】 |
|
||||||
|
| **口令例** | `开始设计:ONEOS-xx;交付=…;分析=…` |
|
||||||
|
| **为什么** | 进入原型/方案设计;分析阶段收口 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 步骤 5|设计完成
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 产品 / AI |
|
||||||
|
| **做什么** | 收口【设计】;跑 AutoPRD,把**产品说明**灌进【交付】描述;挂原型 ZIP/截图等附件 |
|
||||||
|
| **需求状态** | **设计完成** |
|
||||||
|
| **口令例** | `设计完成:ONEOS-xx;设计=…;原型=…` |
|
||||||
|
| **为什么** | 开发接手时看的是【交付】里的产品说明,不是聊天记录 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 步骤 6|交棒开发(产品终点)
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 产品 / AI |
|
||||||
|
| **做什么** | 需求改为待开发;**【交付】负责人改为何斐**(不新建开发/测试任务) |
|
||||||
|
| **需求状态** | **待开发** ★ |
|
||||||
|
| **交出什么** | 需求编号 +【交付】编号 |
|
||||||
|
| **口令例** | `交棒开发:ONEOS-xx;交付=…` |
|
||||||
|
| **为什么** | 产品部到此结束;技术经理从这里拆开发 |
|
||||||
|
|
||||||
|
> 旁路:急单可用**快轨**(跳过分析、直接待开发),仍交到同一终点「待开发 + 交付→何斐」。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 阶段 B|开发(步骤 7~12)
|
||||||
|
|
||||||
|
### 步骤 7|分配开发任务
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 开发主管何斐 / 开发 Skill |
|
||||||
|
| **做什么** | 输入**交付任务编号** → 自动建 **【开发】**;标题=`【开发】`+需求标题;**描述人工补**;指定开发人;自动写计划时间 |
|
||||||
|
| **关联** | 子项挂【交付】;关联项挂需求 |
|
||||||
|
| **需求状态** | 仍为 **待开发**(确认即可,一般不用再改) |
|
||||||
|
| **口令例** | `分配任务:交付=ONEOS-a;开发人=张三` |
|
||||||
|
| **为什么** | 一条需求可拆多个开发任务;都挂在同一交付下 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 步骤 8|开始开发
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 开发人员 |
|
||||||
|
| **做什么** | 口令带上**开发任务编号** |
|
||||||
|
| **开发任务** | → **处理中** |
|
||||||
|
| **需求状态** | → **开发中** |
|
||||||
|
| **口令例** | `开始开发:ONEOS-d` |
|
||||||
|
| **为什么** | 看板一眼能看出「正在写代码」 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 步骤 9|写代码 / 提 MR
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 开发人员 |
|
||||||
|
| **做什么** | 按【交付】里的产品说明实现;分支/MR 建议挂上开发任务编号与需求编号 |
|
||||||
|
| **需求状态** | 仍为 **开发中** |
|
||||||
|
| **为什么** | 代码可追溯到哪条开发任务、哪条需求 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 步骤 10|AI 自测门禁(开发侧草案)
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | AI(开发完成后触发) |
|
||||||
|
| **做什么** | 找与**需求同标题**的测试计划 → 按用例自测 → 不过则自动提缺陷(标题含开发任务编号)并尝试修复,直到本计划用例全过 |
|
||||||
|
| **需求状态** | 仍为 **开发中**(未全过前) |
|
||||||
|
| **为什么** | 在正式提测前先挡住明显问题(属草案,规则可再收紧) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 步骤 11|开发任务完成
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 系统 / AI(用例全过之后) |
|
||||||
|
| **做什么** | 该条【开发】标为**已完成** |
|
||||||
|
| **需求状态** | → **开发完成**(若有多条开发,建议等**全部**完成再改,避免过早) |
|
||||||
|
| **为什么** | 标记「代码+门禁」这一段结束 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 步骤 12|完成开发 · 正式提测
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 开发人员(自测也完成) |
|
||||||
|
| **做什么** | 口令「完成开发」→ 自动建 **【测试】**(标题=`【测试】`+任务名);子项挂【交付】;建议再关联需求;指派测试(如谢佳伟) |
|
||||||
|
| **需求状态** | → **待测试** ★ |
|
||||||
|
| **口令例** | `完成开发:ONEOS-d` |
|
||||||
|
| **为什么** | 开发交棒给测试;测试侧开始接单 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 阶段 C|测试(步骤 13~15)
|
||||||
|
|
||||||
|
### 步骤 13|接测试任务
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 测试(谢佳伟等) |
|
||||||
|
| **做什么** | 打开【测试】任务;确认关联的需求与交付;准备/核对测试计划与用例包(建议按**需求编号**分包,比「同标题」更稳) |
|
||||||
|
| **需求状态** | **待测试** → 开始执行后改为 **测试中** |
|
||||||
|
| **为什么** | 正式测试以计划用例为准,不靠口头「测过了」 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 步骤 14|执行用例 · 缺陷回流
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 测试执行;失败时回流开发修 |
|
||||||
|
| **做什么** | 按用例执行;失败建缺陷 → 开发修复 → 再测 |
|
||||||
|
| **需求状态** | **测试中** |
|
||||||
|
| **为什么** | 质量关口;未绿不能进发版 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 步骤 15|测试完成
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 测试 / AI 辅助判定 |
|
||||||
|
| **做什么** | **本需求**相关用例全绿 →【测试】收口;通知发版对接人 |
|
||||||
|
| **需求状态** | → **测试完成** ★ |
|
||||||
|
| **注意** | 只卡本需求,不卡同迭代里别的需求 |
|
||||||
|
| **为什么** | 发版范围以「测试完成」的需求为准 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 阶段 D|发版(步骤 16~17)
|
||||||
|
|
||||||
|
### 步骤 16|建发版任务
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 发版对接人(时生亮)· 手工或 AI |
|
||||||
|
| **做什么** | 建 **【发版】**;关联**迭代** + 本期内要上的需求(建议再挂交付/测试);汇总更新说明 |
|
||||||
|
| **需求状态** | 进入发布流程时 → **发布中** |
|
||||||
|
| **为什么** | 一次发版可能含多条需求;要有明确范围清单 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 步骤 17|发布结果回写
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 发版对接人 / 流水线 |
|
||||||
|
| **做什么** | 执行发布 |
|
||||||
|
| **结果** | 成功 → **发布完成**;失败 → **发布失败**(可重试再进发布中) |
|
||||||
|
| **为什么** | 成败要回写云效,避免「以为发了其实没发」 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 阶段 E|收口(步骤 18)
|
||||||
|
|
||||||
|
### 步骤 18|业务验收 · 关闭
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **谁** | 产品 |
|
||||||
|
| **做什么** | 业务验收通过后,关闭需求,并收口【交付】 |
|
||||||
|
| **需求状态** | → **已关闭** |
|
||||||
|
| **为什么** | 全链路结束;树上任务与需求一致收口 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 状态主链(串起来看)
|
||||||
|
|
||||||
|
```text
|
||||||
|
待处理 → 已确认 → 分析中 → 设计中 → 设计完成
|
||||||
|
→ 待开发 ← 产品交棒给何斐
|
||||||
|
→ 开发中 → 开发完成
|
||||||
|
→ 待测试 → 测试中 → 测试完成
|
||||||
|
→ 发布中 → 发布完成(或发布失败可重试)
|
||||||
|
→ 已关闭 ← 产品验收关单
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四个交棒口(最重要)
|
||||||
|
|
||||||
|
| 交棒 | 交出人 | 接棒人 | 交出物 | 状态落点 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| ① 产品→开发 | 产品 | 何斐 | 需求号 + 交付号 | 待开发 |
|
||||||
|
| ② 开发→测试 | 开发人 | 测试 | 【测试】任务已建好 | 待测试 |
|
||||||
|
| ③ 测试→发版 | 测试 | 发版 | 本需求用例全绿 | 测试完成 |
|
||||||
|
| ④ 发版→产品 | 发版 | 产品 | 发布完成 / 更新说明 | 发布完成 → 已关闭 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 谁在什么时候动(对照表)
|
||||||
|
|
||||||
|
| 步骤 | 产品 | 开发主管 | 开发人 | 测试 | 发版 |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| 1~2 记需求/确认 | ● | | | | |
|
||||||
|
| 3~5 分析设计 | ● | | | | |
|
||||||
|
| 6 交棒 | ● | 接 | | | |
|
||||||
|
| 7 分配任务 | | ● | | | |
|
||||||
|
| 8~9 开始写码 | | | ● | | |
|
||||||
|
| 10~11 AI门禁/完成任务 | | | ●/AI | | |
|
||||||
|
| 12 提测 | | | ● | 接 | |
|
||||||
|
| 13~15 测试 | | | 修缺陷 | ● | |
|
||||||
|
| 16~17 发版 | | | | | ● |
|
||||||
|
| 18 关闭 | ● | | | | |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 相关文档
|
||||||
|
|
||||||
|
| 文档 | 用途 |
|
||||||
|
|---|---|
|
||||||
|
| `docs-四角色泳道流程图.md` | 泳道图总览 |
|
||||||
|
| `docs-产品部流转流程图.md` | 产品 1~6 细规 |
|
||||||
|
| `docs-开发侧流转草案.md` | 开发 7~12 细规与待拍板 |
|
||||||
|
| `yunxiao-pipeline-handbook` | 云效规则与配置 |
|
||||||
181
.cursor/skills/YunxiaoPM/docs-四角色泳道流程图.md
Normal file
181
.cursor/skills/YunxiaoPM/docs-四角色泳道流程图.md
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
# 四角色泳道图:产品 · 开发 · 测试 · 发版
|
||||||
|
|
||||||
|
> 用途:一张图看清从建需求到发版关闭,四条泳道各自做什么、在哪交棒。
|
||||||
|
> 依据:产品部流转 · 开发侧草案 · 生产线手册(测试/发版)
|
||||||
|
> 日期:2026-07-24
|
||||||
|
> 说明:开发泳道含「AI 用例门禁」草案;测试泳道为正式提测后的人/计划执行。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 泳道总览(推荐主图)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TB
|
||||||
|
subgraph PM["泳道① 产品"]
|
||||||
|
direction TB
|
||||||
|
P0["建需求 · 待处理<br/>只写 AutoRDO"]
|
||||||
|
P1["受理确认 · 已确认"]
|
||||||
|
P2["分析中<br/>建【交付】+【分析】"]
|
||||||
|
P3["设计中<br/>建【设计】"]
|
||||||
|
P4["设计完成<br/>AutoPRD 灌交付"]
|
||||||
|
P5["交棒 · 待开发<br/>交付负责人→何斐"]
|
||||||
|
P6["业务验收后<br/>关闭需求+交付"]
|
||||||
|
P0 --> P1 --> P2 --> P3 --> P4 --> P5
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph DEV["泳道② 开发"]
|
||||||
|
direction TB
|
||||||
|
D1["何斐:分配任务<br/>建【开发】SUB→交付"]
|
||||||
|
D2["开发人:开始开发<br/>任务处理中 · 需求开发中"]
|
||||||
|
D3["写代码 / 提 MR"]
|
||||||
|
D4["AI 按同标题测试计划自测<br/>不过→提缺陷并修"]
|
||||||
|
D5["开发任务已完成<br/>需求→开发完成"]
|
||||||
|
D6["完成开发(含自测)<br/>建【测试】· 需求待测试"]
|
||||||
|
D1 --> D2 --> D3 --> D4 --> D5 --> D6
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph QA["泳道③ 测试"]
|
||||||
|
direction TB
|
||||||
|
T1["接【测试】任务<br/>需求=待测试"]
|
||||||
|
T2["建/挂测试计划与用例<br/>(建议按需求编号分包)"]
|
||||||
|
T3["测试中 · 执行用例"]
|
||||||
|
T4["缺陷回流开发修复"]
|
||||||
|
T5["本需求用例全绿<br/>需求→测试完成"]
|
||||||
|
T1 --> T2 --> T3
|
||||||
|
T3 -.->|失败| T4
|
||||||
|
T4 -.->|再测| T3
|
||||||
|
T3 -->|通过| T5
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph REL["泳道④ 发版"]
|
||||||
|
direction TB
|
||||||
|
R1["建【发版】任务<br/>挂迭代+范围内需求"]
|
||||||
|
R2["汇总更新说明"]
|
||||||
|
R3["发布中"]
|
||||||
|
R4{"发布结果"}
|
||||||
|
R5["发布完成"]
|
||||||
|
R6["发布失败 · 可重试"]
|
||||||
|
R1 --> R2 --> R3 --> R4
|
||||||
|
R4 -->|成功| R5
|
||||||
|
R4 -->|失败| R6
|
||||||
|
R6 -.-> R3
|
||||||
|
end
|
||||||
|
|
||||||
|
P5 -->|"交棒契约<br/>需求编号+交付编号"| D1
|
||||||
|
D6 -->|"提测<br/>【测试】已挂交付"| T1
|
||||||
|
T5 -->|"交棒发版"| R1
|
||||||
|
R5 -->|"业务可验收"| P6
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 横向时间轴版(谁在哪一阶段动)
|
||||||
|
|
||||||
|
从左到右是需求状态主链;上下是四个角色。空格表示该角色此阶段无主动动作。
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
subgraph S_PM["产品阶段"]
|
||||||
|
direction TB
|
||||||
|
sp0["待处理→已确认"]
|
||||||
|
sp1["分析/设计/设计完成"]
|
||||||
|
sp2["待开发交棒"]
|
||||||
|
sp3["已关闭"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph S_DEV["开发阶段"]
|
||||||
|
direction TB
|
||||||
|
sd0["拆【开发】"]
|
||||||
|
sd1["开发中"]
|
||||||
|
sd2["AI门禁→开发完成"]
|
||||||
|
sd3["建【测试】→待测试"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph S_QA["测试阶段"]
|
||||||
|
direction TB
|
||||||
|
sq0["待测试"]
|
||||||
|
sq1["测试中"]
|
||||||
|
sq2["测试完成"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph S_REL["发版阶段"]
|
||||||
|
direction TB
|
||||||
|
sr0["建【发版】"]
|
||||||
|
sr1["发布中"]
|
||||||
|
sr2["完成/失败"]
|
||||||
|
end
|
||||||
|
|
||||||
|
sp0 --> sp1 --> sp2
|
||||||
|
sp2 --> sd0 --> sd1 --> sd2 --> sd3
|
||||||
|
sd3 --> sq0 --> sq1 --> sq2
|
||||||
|
sq2 --> sr0 --> sr1 --> sr2
|
||||||
|
sr2 --> sp3
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 交接点一览
|
||||||
|
|
||||||
|
| # | 从 → 到 | 交出什么 | 需求状态落点 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 1 | 产品 → 开发 | 需求编号 +【交付】编号;交付负责人=何斐 | **待开发** |
|
||||||
|
| 2 | 开发 → 测试 | 【测试】任务(子项挂交付);用例计划可先备好 | **待测试** |
|
||||||
|
| 3 | 测试 → 发版 | 本需求用例全绿;范围内需求清单 | **测试完成** |
|
||||||
|
| 4 | 发版 → 产品 | 发布完成证据 / 更新说明 | **发布完成** → 产品关单 **已关闭** |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 各泳道职责边界(一句话)
|
||||||
|
|
||||||
|
| 角色 | 管什么 | 不管什么 |
|
||||||
|
|---|---|---|
|
||||||
|
| **产品** | 建需求、【交付】【分析】【设计】、AutoPRD、交棒待开发、验收关闭 | 不建【开发】【测试】【发版】、不开分支 |
|
||||||
|
| **开发** | 拆【开发】、写码、AI 自测门禁、建【测试】提测 | 不改写产品 AutoRDO;不建第二套【交付】 |
|
||||||
|
| **测试** | 接【测试】、跑计划用例、缺陷回流、判测试完成 | 不擅自改需求状态到开发中;不建【发版】(可催) |
|
||||||
|
| **发版** | 建【发版】、挂迭代与范围、发布与回写成败 | 不替代测试判绿;不关闭需求(交给产品) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 云效工作项树(跨角色)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TB
|
||||||
|
REQ["需求 · 状态=阶段真相"]
|
||||||
|
DEL["【交付】ASSOCIATED→需求"]
|
||||||
|
AN["【分析】"]
|
||||||
|
DE["【设计】"]
|
||||||
|
DV["【开发】"]
|
||||||
|
TE["【测试】"]
|
||||||
|
RE["【发版】ASSOCIATED→迭代/需求"]
|
||||||
|
|
||||||
|
DEL --> REQ
|
||||||
|
AN -->|TASK_SUB| DEL
|
||||||
|
DE -->|TASK_SUB| DEL
|
||||||
|
DV -->|TASK_SUB| DEL
|
||||||
|
TE -->|TASK_SUB| DEL
|
||||||
|
DV -.->|ASSOCIATED| REQ
|
||||||
|
TE -.->|ASSOCIATED| REQ
|
||||||
|
RE -.->|关联范围| REQ
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 典型负责人(手册约定,可按项目改)
|
||||||
|
|
||||||
|
| 泳道 | 典型对接人 |
|
||||||
|
|---|---|
|
||||||
|
| 产品 | 王冕 · YunxiaoPMapp / AI |
|
||||||
|
| 开发 | 何斐(拆任务)→ 王雨昊 / 李振等(执行) |
|
||||||
|
| 测试 | 谢佳伟 |
|
||||||
|
| 发版 | 时生亮 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 相关文档
|
||||||
|
|
||||||
|
| 文档 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| `docs-全流程分步说明.md` | **整条链路逐步说明(推荐先读)** |
|
||||||
|
| `docs-产品部流转流程图.md` | 产品 0→5 细图 |
|
||||||
|
| `docs-开发侧流转草案.md` | 开发 D1–D5 细图 |
|
||||||
|
| `yunxiao-pipeline-handbook` | 全链路配置与规则 |
|
||||||
230
.cursor/skills/YunxiaoPM/docs-开发侧流转草案.md
Normal file
230
.cursor/skills/YunxiaoPM/docs-开发侧流转草案.md
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
# 开发侧流转草案(产品交棒之后)
|
||||||
|
|
||||||
|
> 来源:产品经理口述规则整理(2026-07-24)
|
||||||
|
> 上游终点:产品部 `docs-产品部流转流程图.md` → 需求=**待开发**,【交付】负责人=**何斐**
|
||||||
|
> 本文件目标:把「何斐拆任务 → 开发执行 → AI 用例门禁 → 提测」画清,供后续 **YunxiaoDevapp** Skill 定稿
|
||||||
|
> 状态:**草案**(文末有待拍板项)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 总览流程图
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TB
|
||||||
|
subgraph handoff [产品已交棒]
|
||||||
|
Ready["需求=待开发\n【交付】负责人=何斐"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph d1 [D1 分配开发]
|
||||||
|
Assign["何斐:分配任务 + 交付任务编号"]
|
||||||
|
CreateDev["自动建【开发】+需求标题\n描述人工补\n指定开发人\n写计划时间"]
|
||||||
|
Link["子项 TASK_SUB→交付\n关联项 ASSOCIATED→需求"]
|
||||||
|
StReady["需求保持/确认为 待开发"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph d2 [D2 开始开发]
|
||||||
|
Start["开发人:开始开发 + 开发任务编号"]
|
||||||
|
DevDoing["开发任务→处理中"]
|
||||||
|
ReqDoing["需求→开发中"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph d3 [D3 AI 用例门禁]
|
||||||
|
CodeDone["代码开发完成触发"]
|
||||||
|
FindPlan["按需求同标题找测试计划"]
|
||||||
|
AITest["AI 按用例自测"]
|
||||||
|
Fail["未通过→自动提缺陷\n标题含开发任务编号\nAI 写标题描述"]
|
||||||
|
Fix["自动修复→再测"]
|
||||||
|
PassGate["用例全部通过"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph d4 [D4 开发任务完成]
|
||||||
|
DevDone["该条【开发】→已完成"]
|
||||||
|
ReqDevDone["需求→开发完成"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph d5 [D5 完成开发·提测]
|
||||||
|
Finish["开发人:完成开发\n含自测完成"]
|
||||||
|
CreateTest["自动建【测试】+任务名\n子项→交付"]
|
||||||
|
PendingTest["需求→待测试"]
|
||||||
|
end
|
||||||
|
|
||||||
|
Ready --> Assign --> CreateDev --> Link --> StReady
|
||||||
|
StReady --> Start --> DevDoing --> ReqDoing
|
||||||
|
ReqDoing --> CodeDone --> FindPlan --> AITest
|
||||||
|
AITest -->|未通过| Fail --> Fix --> AITest
|
||||||
|
AITest -->|全通过| PassGate --> DevDone --> ReqDevDone
|
||||||
|
ReqDevDone --> Finish --> CreateTest --> PendingTest
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 分步说明(按你的 5 条)
|
||||||
|
|
||||||
|
### D1|何斐分配任务
|
||||||
|
|
||||||
|
| 项 | 规则 |
|
||||||
|
|---|---|
|
||||||
|
| 触发 | Skill 口令:`分配任务` + **交付任务编号** |
|
||||||
|
| 新建 | 【开发】任务;标题 = `【开发】` + **需求标题** |
|
||||||
|
| 描述 | **人工添加**(Skill 不代写正文,或只留空模板) |
|
||||||
|
| 负责人 | 口令指定开发人员 |
|
||||||
|
| 计划时间 | **自动创建**计划开始/计划完成(算法待定:阶段日历工时 or 人力预估,见待拍板) |
|
||||||
|
| 关联 | **子项** `TASK_SUB` →【交付】;**关联项** `ASSOCIATED` → 需求 |
|
||||||
|
| 需求状态 | 改为 / 确认为 **待开发**(见待拍板:与产品交棒是否重复) |
|
||||||
|
|
||||||
|
### D2|开始开发
|
||||||
|
|
||||||
|
| 项 | 规则 |
|
||||||
|
|---|---|
|
||||||
|
| 触发 | `开始开发` + **开发任务编号** |
|
||||||
|
| 开发任务 | → **处理中** |
|
||||||
|
| 需求 | → **开发中**(有 ≥1 条开发进入处理中即可,或本条触发即改,见待拍板) |
|
||||||
|
|
||||||
|
### D3|代码完成后 · AI 按测试计划自测
|
||||||
|
|
||||||
|
| 项 | 规则 |
|
||||||
|
|---|---|
|
||||||
|
| 触发 | 「代码开发完成」(MR 合并 / 口令 / Webhook,触发源待定) |
|
||||||
|
| 找计划 | **自动寻找与需求同标题的测试计划** |
|
||||||
|
| 执行 | AI 按该计划中用例自行测试 |
|
||||||
|
| 失败 | 自动提缺陷:标题含 **开发任务编号** + AI 生成标题/描述;再自动修复,循环直到用例全过 |
|
||||||
|
|
||||||
|
### D4|用例全通过
|
||||||
|
|
||||||
|
| 项 | 规则 |
|
||||||
|
|---|---|
|
||||||
|
| 该条【开发】 | → **已完成** |
|
||||||
|
| 需求 | → **开发完成** |
|
||||||
|
|
||||||
|
### D5|开发人「完成开发」(自测也完成)
|
||||||
|
|
||||||
|
| 项 | 规则 |
|
||||||
|
|---|---|
|
||||||
|
| 触发 | `完成开发` +(建议带)开发任务编号 |
|
||||||
|
| 新建 | 【测试】任务;标题 = `【测试】` + 任务名称(建议=需求标题) |
|
||||||
|
| 关联 | 子项 →【交付】(建议同时 ASSOCIATED→需求) |
|
||||||
|
| 需求 | → **待测试** |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 与产品部的衔接
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
PM["产品 YunxiaoPMapp\n待开发 + 交付→何斐"] --> DevSkill["开发 Skill 草案\n本文 D1–D5"]
|
||||||
|
DevSkill --> QA["测试执行人/Skill\n待测试之后"]
|
||||||
|
```
|
||||||
|
|
||||||
|
| 上游已具备 | 开发侧依赖 |
|
||||||
|
|---|---|
|
||||||
|
| 需求编号 +【交付】编号 | D1 入口只认编号,不按标题拆第二套交付 |
|
||||||
|
| 交付 ASSOCIATED→需求 | D1 开发任务再 ASSOCIATED→需求、SUB→交付 |
|
||||||
|
| 产品不建【开发】【测试】 | 仅开发 Skill 建这两类 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 待拍板(建议你先定这几条)
|
||||||
|
|
||||||
|
### 4.1 状态顺序是否自洽
|
||||||
|
|
||||||
|
你现在的顺序是:
|
||||||
|
|
||||||
|
```text
|
||||||
|
D3 AI 用例全过 → 开发任务已完成 + 需求「开发完成」
|
||||||
|
D5 完成开发 → 建【测试】+ 需求「待测试」
|
||||||
|
```
|
||||||
|
|
||||||
|
与现有手册常见顺序对比:
|
||||||
|
|
||||||
|
```text
|
||||||
|
手册常见:开发人完成自测 → 待测试 →(测试执行)→ 测试完成
|
||||||
|
你草案: AI 先跑测试计划用例过关 → 开发完成 → 人再点完成开发 → 待测试
|
||||||
|
```
|
||||||
|
|
||||||
|
需要确认:
|
||||||
|
1. D3 的「测试计划」是 **开发自测门禁**,正式【测试】任务仍留给谢佳伟?
|
||||||
|
2. 还是 D3 已等同正式测试,那 D5 再建【测试】是否重复?
|
||||||
|
|
||||||
|
### 4.2 「需求→待开发」写在 D1
|
||||||
|
|
||||||
|
产品交棒时需求**已经是待开发**。D1 再改一次通常多余。建议改为:
|
||||||
|
- D1 **校验**需求已是待开发;若不是则停下或只允许从设计完成快轨补交棒
|
||||||
|
- 有开发任务进入处理中时,需求才变为 **开发中**(即你的 D2)
|
||||||
|
|
||||||
|
### 4.3 「与需求同标题的测试计划」
|
||||||
|
|
||||||
|
标题易改、易撞名。更稳的是:
|
||||||
|
- 测试计划关联 **需求编号 / 迭代**,或
|
||||||
|
- 用例包命名 `CP-{需求编号}-…`
|
||||||
|
|
||||||
|
否则同名需求/改标题会导致找错计划。
|
||||||
|
|
||||||
|
### 4.4 AI 自动提缺陷并自动修复
|
||||||
|
|
||||||
|
风险高:无上限循环、误报、改回旧逻辑。建议门禁:
|
||||||
|
- 最多 N 轮;失败转人工
|
||||||
|
- 缺陷必须关联 **开发任务编号 + 需求编号 + 用例 ID**
|
||||||
|
- 与「防回归」清单联动,禁止静默改无关模块
|
||||||
|
|
||||||
|
### 4.5 多条【开发】时需求状态
|
||||||
|
|
||||||
|
| 场景 | 建议 |
|
||||||
|
|---|---|
|
||||||
|
| 任一条开始开发 | 需求 → 开发中 |
|
||||||
|
| 需求 → 开发完成 | **全部**未取消【开发】均为已完成(与手册 Y21 一致) |
|
||||||
|
| 需求 → 待测试 | 全部【开发】完成后,由末位「完成开发」或系统自动建【测试】 |
|
||||||
|
|
||||||
|
你原文 D4 写「该条」通过就把需求改成开发完成——多开发人并行时会过早。建议改成「全员开发任务完成」。
|
||||||
|
|
||||||
|
### 4.6 关联写法(与产品侧一致)
|
||||||
|
|
||||||
|
同一 create 只能带一条 `createWorkitemRelationInfo`:
|
||||||
|
- 优先保证【开发】/【测试】**子项挂在交付**(交付详情「子项」可见)
|
||||||
|
- ASSOCIATED→需求若同 create 互斥,需约定:先 SUB,再补 ASSOCIATED,或 OpenAPI 双挂
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 建议口令面(草案)
|
||||||
|
|
||||||
|
```text
|
||||||
|
分配任务:交付任务=ONEOS-a;开发人=张三,李四;计划开始=…;计划完成=…
|
||||||
|
开始开发:开发任务=ONEOS-d
|
||||||
|
代码完成:开发任务=ONEOS-d → 触发 AI 用例门禁(或 Webhook)
|
||||||
|
完成开发:开发任务=ONEOS-d → 建【测试】;需求→待测试
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 推荐定稿后的状态主链(供你勾选)
|
||||||
|
|
||||||
|
**方案 A(贴近你原文,AI 测作开发门禁)**
|
||||||
|
|
||||||
|
```text
|
||||||
|
待开发 → 开发中 →(AI 用例门禁)→ 开发完成 → 待测试 → 测试中 → 测试完成 → …
|
||||||
|
```
|
||||||
|
|
||||||
|
**方案 B(贴近现有生产线手册)**
|
||||||
|
|
||||||
|
```text
|
||||||
|
待开发 → 开发中 → 开发完成(人自测+MR)→ 待测试 → 测试中(人/AI 跑计划)→ 测试完成 → …
|
||||||
|
```
|
||||||
|
|
||||||
|
AI 跑测试计划放在 **待测试之后**,与【测试】任务负责人(如谢佳伟)对齐。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 下一步
|
||||||
|
|
||||||
|
1. 你拍板:**方案 A 或 B**,以及多【开发】时「开发完成 / 待测试」的聚合规则
|
||||||
|
2. 我按定稿输出 `YunxiaoDevapp` 的 `SKILL.md` 骨架 + 与产品交棒契约对齐段落
|
||||||
|
3. 再补一版「仅开发侧」验收清单(10 条以内)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 相关文档
|
||||||
|
|
||||||
|
| 文档 | 路径 |
|
||||||
|
|---|---|
|
||||||
|
| 产品部流转 | `docs-产品部流转流程图.md` |
|
||||||
|
| 产品↔开发契约 | `docs-YunxiaoPMapp-实现原理-开发Skill对接.md` |
|
||||||
|
| 全链路手册 | `src/prototypes/yunxiao-pipeline-handbook/` |
|
||||||
47
.cursor/skills/YunxiaoPM/fast-track.md
Normal file
47
.cursor/skills/YunxiaoPM/fast-track.md
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# 无单快轨到待开发
|
||||||
|
|
||||||
|
适用:口令明确「快轨」或「推进至待开发」且当前需求尚无标准分析路径任务(或用户确认跳过分析)。
|
||||||
|
|
||||||
|
## 动作表
|
||||||
|
|
||||||
|
| 对象 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| 需求 | 状态 → **待开发**;**预计工时=2**、**实际工时=2**(覆盖同日 8h 日历工时默认);标签按口令;更新编号区块 |
|
||||||
|
| 【交付】 | 无则新建;ASSOCIATED→需求(勿用 PARENT);负责人→何斐;**计划开始=创建当日**(`79`);**不写**计划完成;**描述双路径**(见下);**标签与需求相同**;更新编号区块 |
|
||||||
|
| 【设计】 | **必须新建**;**TASK_SUB→交付**(交付「子项」须可见);**描述=复制需求当前描述正文**;计划开始/完成均=当日(create 后 `field/value` 写 `79`+`80`);任务→完成态;**标签与需求相同**;建后再尝试 **ASSOCIATED→原始需求**(Cookie 常失败,见 live-api;失败须标红,**子项优先于关联项**);更新编号区块 |
|
||||||
|
| 【分析】 | **禁止创建** |
|
||||||
|
|
||||||
|
## 交付描述双路径(A1)
|
||||||
|
|
||||||
|
| 口令/材料 | 【交付】描述 |
|
||||||
|
|---|---|
|
||||||
|
| **手工描述**(无指定原型) | 同步需求当前手工/AutoRDO 正文(与设计一致可复制 document) |
|
||||||
|
| **指定原型页面** | 调用 `$oneos-autoprd`,从原型生成 AutoPRD「产品说明」写入【交付】 |
|
||||||
|
| 既无手工可同步正文、又无原型 | 才允许占位 `等待设计任务完成后自动填入`,Plan 勾选交棒占位风险,回报首行标红 |
|
||||||
|
|
||||||
|
有手工或原型时**禁止**交棒占位。
|
||||||
|
|
||||||
|
## AutoPRD
|
||||||
|
|
||||||
|
- 快轨默认可不跑 AutoPRD;**例外**:口令指定原型 → 交付走 AutoPRD 路径(上表)。
|
||||||
|
- 口令同时「设计完成 + 原型」时仍按步骤 4 灌需求产品说明段。
|
||||||
|
|
||||||
|
## 查重
|
||||||
|
|
||||||
|
只认任务编号。已有分析单不得因「快轨」被删除。
|
||||||
|
|
||||||
|
## 回报必含
|
||||||
|
|
||||||
|
- 需求 / 交付 / 设计编号
|
||||||
|
- 「快轨:未建分析;设计已同步需求描述并当日收口」
|
||||||
|
- 交付描述来源:手工同步 / AutoPRD / 占位(若占位则首行标红)
|
||||||
|
- 需求预计工时=2、实际工时=2
|
||||||
|
- 设计关联项含需求编号;交付子项含设计编号
|
||||||
|
|
||||||
|
## 与标准 / 编号直推对比
|
||||||
|
|
||||||
|
```text
|
||||||
|
标准:分析中→交付+分析 → 设计中→设计+收口分析 → 设计完成→收口设计 → 待开发交棒
|
||||||
|
快轨(无既有阶段单):→ 待开发:新建交付+设计+交棒何斐(无分析;设计当日收口;需求工时 2+2)
|
||||||
|
编号直推:已有分析/设计编号 → 收口空计划完成 → 待开发+交付交棒(不新建冗余单)
|
||||||
|
```
|
||||||
242
.cursor/skills/YunxiaoPM/live-api.md
Normal file
242
.cursor/skills/YunxiaoPM/live-api.md
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
# 云效实写 API(YunxiaoPMapp 已验证)
|
||||||
|
|
||||||
|
`verified_at`: 2026-07-25 · **项目须门禁 PJ 点选**(见 [project-selection.md](project-selection.md));历史验证样本项目为 `01_ONEOS` / 原「统一运营管理平台」(`last_selected.spaceIdentifier` 见 `assets/runtime-ids.json`,禁止未点选即使用)。
|
||||||
|
|
||||||
|
本文件只记**已跑通**的写法;禁止再盲试 `updateStatus` / 错误 `updateFieldValue` POST。
|
||||||
|
|
||||||
|
## 认证
|
||||||
|
|
||||||
|
- Cookie:Chrome 域 `.aliyun.com` / `devops.aliyun.com`(`browser_cookie3` 或 Playwright storage)
|
||||||
|
- Header:`x-xsrf-token` = cookie `XSRF-TOKEN`(URL 解码后)
|
||||||
|
- `Origin` / `Referer`:`https://devops.aliyun.com`
|
||||||
|
|
||||||
|
## 建单
|
||||||
|
|
||||||
|
`POST|PUT /projex/api/workitem/workitem?_input_charset=utf-8`
|
||||||
|
|
||||||
|
创建响应 `result.identifier` / `serialNumber` 即编号真相;**禁止按标题查重**。
|
||||||
|
|
||||||
|
## 改负责人(已通)
|
||||||
|
|
||||||
|
```http
|
||||||
|
PATCH /projex/api/workitem/workitem/{id}?_input_charset=utf-8
|
||||||
|
{"propertyKey":"assignedTo","propertyValue":"<userId>","operateType":"COVER"}
|
||||||
|
```
|
||||||
|
|
||||||
|
交棒:【交付】`propertyValue` = 何斐 ID。
|
||||||
|
|
||||||
|
## 打标签(已通)
|
||||||
|
|
||||||
|
```http
|
||||||
|
PATCH /projex/api/workitem/workitem/{id}?_input_charset=utf-8
|
||||||
|
{"workitemIdentifier":"{id}","propertyKey":"tag","propertyValue":"<tagId>[,<tagId>]","operateType":"COVER"}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 改状态(已通 · 唯一推荐)
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /projex/api/workitem/workitem/{id}/status/transit?_input_charset=utf-8
|
||||||
|
{"fromStatus":"<当前status.identifier>","toStatus":"<目标status.identifier>"}
|
||||||
|
```
|
||||||
|
|
||||||
|
成功:`code=200` 且 `result=true`。失败时 `errorMsg` 含「不能流转」。
|
||||||
|
|
||||||
|
### 需求状态 ID(本项目)
|
||||||
|
|
||||||
|
| 显示名 | identifier |
|
||||||
|
|---|---|
|
||||||
|
| 待处理 | `100005` |
|
||||||
|
| 已确认 | `32` |
|
||||||
|
| 分析中 | `154395` |
|
||||||
|
| 设计中 | `156603` |
|
||||||
|
| 设计完成 | `307012` |
|
||||||
|
| 待开发 | `1582fc929d429111b925309493` |
|
||||||
|
|
||||||
|
### 任务状态 ID
|
||||||
|
|
||||||
|
| 显示名 | identifier |
|
||||||
|
|---|---|
|
||||||
|
| 待处理 | `100005` |
|
||||||
|
| 已完成 | `100014` |
|
||||||
|
|
||||||
|
### 极速交棒跳转(工作流允许)
|
||||||
|
|
||||||
|
从「待处理」菜单可见直达「设计完成」;推荐最少跳:
|
||||||
|
|
||||||
|
```text
|
||||||
|
待处理 → 设计完成 → 待开发
|
||||||
|
```
|
||||||
|
|
||||||
|
标准路径若需看板留痕,可走完整链:已确认→分析中→设计中→设计完成→待开发(仍用本 API,勿开 UI)。
|
||||||
|
|
||||||
|
### 禁止(已证伪)
|
||||||
|
|
||||||
|
| 写法 | 结果 |
|
||||||
|
|---|---|
|
||||||
|
| `PATCH …/updateStatus` + `statusIdentifier` | `400 不能为空` |
|
||||||
|
| `PATCH …/{id}` + `propertyKey=status` | `property not found` |
|
||||||
|
| Playwright 点左侧/列表上的状态色块(`x<1100`) | 假成功、状态不落库 |
|
||||||
|
|
||||||
|
仅当 `status/transit` 不可用时,才用 UI:右侧详情状态钮(`getBoundingClientRect().x > 1100`)+ `.next-menu-item`。
|
||||||
|
|
||||||
|
## 计划开始/完成 · 提交部门/人 · 预计工时(2026-07-27 修订)
|
||||||
|
|
||||||
|
**通用字段写入(已通):**
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /projex/api/workitem/workitem/field/value/{workitemId}?_input_charset=utf-8
|
||||||
|
Content-Type: application/x-www-form-urlencoded
|
||||||
|
|
||||||
|
fieldValueList=[{"fieldIdentifier":"79","value":"2026-07-27 12:00:00"},{"fieldIdentifier":"3132597a9718d1c282b7ba5a0c","value":"业务管理部"},{"fieldIdentifier":"9e01269e96f91fbb97d36bf5b3","value":"何苗苗"}]
|
||||||
|
```
|
||||||
|
|
||||||
|
| 字段 | fieldIdentifier | value |
|
||||||
|
|---|---|---|
|
||||||
|
| 计划开始 | `79` | `YYYY-MM-DD HH:mm:ss`(推荐正午)或 epoch ms 字符串 |
|
||||||
|
| 计划完成 | `80` | 同上 |
|
||||||
|
| 提交部门 | `3132597a9718d1c282b7ba5a0c` | 纯文本 |
|
||||||
|
| 提交人 | `9e01269e96f91fbb97d36bf5b3` | 纯文本 |
|
||||||
|
|
||||||
|
**预计工时 `101586`:禁止直接改字段**(报「不可直接修改」)。须登记:
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /projex/api/workitem/workitem/time/estimate?_input_charset=utf-8
|
||||||
|
{"workitemIdentifier":"<id>","spentTime":8,"type":"develop","description":"阶段日历工时","recordUserIdentifier":"<userId>","forCreate":false,"containsRestDay":false}
|
||||||
|
```
|
||||||
|
|
||||||
|
删除多余预估:`DELETE /projex/api/workitem/workitem/time/estimate/{workitemId}/{estimateId}`
|
||||||
|
列表:`GET …/time/estimate/list?workitemIdentifier=`
|
||||||
|
|
||||||
|
旧写法 `PATCH …/updateWorkitemFieldValue` 对上述自定义字段常 `400 不能为空`,勿再优先使用。
|
||||||
|
|
||||||
|
## 父子 / 子项 / 关联项(已通 · 2026-07-23 修订 · 子项优先)
|
||||||
|
|
||||||
|
### 关联项(【交付】强制 · ASSOCIATED)
|
||||||
|
|
||||||
|
任务详情「关联项」只认 `ASSOCIATED`。**仅【交付】**建单时 `createWorkitemRelationInfo` 必须指向**需求**:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"createWorkitemRelationInfo": {
|
||||||
|
"relatedWorkitemIdentifier": "<需求id>",
|
||||||
|
"relatedToRelationIdentifier": "ASSOCIATED"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
校验:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /projex/api/workitem/v2/workitem/{交付id}/relation/workitem/list/by-relation-category?category=ASSOCIATED&isForward=true
|
||||||
|
```
|
||||||
|
|
||||||
|
`result` 含该需求即通过。
|
||||||
|
|
||||||
|
### 禁止(关联项)
|
||||||
|
|
||||||
|
| 写法 | 结果 |
|
||||||
|
|---|---|
|
||||||
|
| `relatedToRelationIdentifier=PARENT` 把交付挂需求 | 详情可能有 parent,**关联项仍为空** |
|
||||||
|
| 分析/设计只用 `ASSOCIATED→需求` + `parentIdentifier` | 关联项可能有,**交付子项仍为空**(ONEOS-246/247) |
|
||||||
|
| 建后再 `POST …/relation/record` 补关系 | Cookie 路径下常报「不能关联相同的工作项」 |
|
||||||
|
| `createWorkitemRelationList` | 不落 ASSOCIATED |
|
||||||
|
|
||||||
|
### 子项(【分析】/【设计】强制 · TASK_SUB)
|
||||||
|
|
||||||
|
「子项」页读 `PARENT_SUB` / `TASK_SUB`,分析/设计**必须**:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"parent": "<交付id>",
|
||||||
|
"parentIdentifier": "<交付id>",
|
||||||
|
"createWorkitemRelationInfo": {
|
||||||
|
"relatedWorkitemIdentifier": "<交付id>",
|
||||||
|
"relatedToRelationIdentifier": "TASK_SUB"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
同一 create 只能带一条 `createWorkitemRelationInfo`。
|
||||||
|
`ASSOCIATED→需求` 与 `TASK_SUB→交付` **不能同时写**。
|
||||||
|
|
||||||
|
**产品优先级:交付「子项」tab > 阶段任务「关联项」。**
|
||||||
|
交付本身仍必须 `ASSOCIATED→需求`。标准路径下分析/设计的「关联项」允许为空。
|
||||||
|
|
||||||
|
**无单快轨例外(设计双挂):** create 用 `TASK_SUB→交付` 后,须再补 **ASSOCIATED→原始需求**,使设计详情「关联项」可见需求。
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /projex/api/workitem/workitem/{设计id}/relation/record?_input_charset=utf-8
|
||||||
|
{"relationIdentifier":"ASSOCIATED","toWorkitemIdentifier":"<需求id>"}
|
||||||
|
```
|
||||||
|
|
||||||
|
**已证伪(Cookie · 2026-07-27):** 凡工作项**已创建**后再 `relation/record` 补挂(含 ASSOCIATED / TASK_SUB),常报「不能关联相同的工作项」;与是否已有父项无关。`createWorkitemRelationList` 亦不落 ASSOCIATED。
|
||||||
|
**可行路径:**
|
||||||
|
|
||||||
|
| 目标 | 做法 |
|
||||||
|
|---|---|
|
||||||
|
| 交付「子项」可见设计(优先) | create 带 `TASK_SUB→交付` |
|
||||||
|
| 设计「关联项」可见需求 | create 带 `ASSOCIATED→需求`(与上互斥,同 create 只能一条) |
|
||||||
|
| 双挂 | 需个人 `x-yunxiao-token` OpenAPI;Cookie 路径**不得**声称成功 |
|
||||||
|
|
||||||
|
产品默认:**子项优先**;关联项失败须在回报中标红并列出缺项。
|
||||||
|
|
||||||
|
校验子项:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /projex/api/workitem/v2/workitem/{交付id}/relation/workitem/list/by-relation-category?category=PARENT_SUB&isForward=true
|
||||||
|
```
|
||||||
|
|
||||||
|
结果须含对应分析/设计 identifier。
|
||||||
|
|
||||||
|
校验设计关联项:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /projex/api/workitem/v2/workitem/{设计id}/relation/workitem/list/by-relation-category?category=ASSOCIATED&isForward=true
|
||||||
|
```
|
||||||
|
|
||||||
|
`result` 须含原始需求 identifier。
|
||||||
|
|
||||||
|
### 无单快轨字段默认(2026-07-27)
|
||||||
|
|
||||||
|
| 对象 | 规则 |
|
||||||
|
|---|---|
|
||||||
|
| 【设计】描述 | 复制需求 document HTML |
|
||||||
|
| 【设计】`79`/`80` | 当日 `12:00:00` / `23:59:59`,create 后 `field/value`(勿 create 同时带 79+80) |
|
||||||
|
| 【交付】描述 | 手工同步需求正文,或原型→AutoPRD;禁止无故占位 |
|
||||||
|
| 【交付】`79` | 创建当日;不写 `80` |
|
||||||
|
| 【交付】/【设计】标签 | 与需求相同,`PATCH propertyKey=tag` |
|
||||||
|
| 需求预计工时 | `time/estimate` **spentTime=2**(先删多余预估) |
|
||||||
|
| 需求实际工时 | `POST …/workitem/time`,body 用 **`actualTime`**(非 spentTime)+ `gmtStart`/`gmtEnd` epoch ms 字符串;见 `runtime-ids.json` `fields.actual_hours` |
|
||||||
|
| 描述更新 | `PATCH …/workitem/{id}/document`,`{"content":"<html>","formatType":"RICHTEXT"}` |
|
||||||
|
|
||||||
|
## 迭代挂接(已通 · 2026-07-27 · 只挂交付)
|
||||||
|
|
||||||
|
创建迭代:`POST /projex/api/workspace/sprint`(必填 `staffIds`;可写 `capacityHours`)。
|
||||||
|
|
||||||
|
挂【交付】到迭代:
|
||||||
|
|
||||||
|
```http
|
||||||
|
PATCH /projex/api/workitem/workitem/{交付id}?_input_charset=utf-8
|
||||||
|
{"workitemIdentifier":"{交付id}","propertyKey":"sprint","propertyValue":"{sprintId}","operateType":"COVER"}
|
||||||
|
```
|
||||||
|
|
||||||
|
清空误挂(如需求):`propertyValue:""` + `operateType:"COVER"`。
|
||||||
|
|
||||||
|
**校验**必须读 `/extra`(详情主接口常不含 sprint 字段,禁止据此判失败):
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /projex/api/workitem/workitem/{id}/extra?_input_charset=utf-8
|
||||||
|
→ result.sprint[].identifier / name
|
||||||
|
```
|
||||||
|
|
||||||
|
产品规则:**只挂【交付】**;需求 / 分析 / 设计默认不挂(除非口令显式)。
|
||||||
|
|
||||||
|
### 极速建单注意
|
||||||
|
|
||||||
|
1. Cookie 只刷一次;全程纯 HTTP,默认**不开浏览器**。
|
||||||
|
2. 交付建完后,【分析】与【设计】**并行**创建(均 TASK_SUB→交付);标准/快轨两树可并行。
|
||||||
|
3. 状态用 `transit` + **本地追踪 fromStatus**(禁止每次 GET);负责人在交棒场景下**创建时即何斐**。
|
||||||
|
4. 建单 `fieldValueList` 可带计划开始 `79`;**不要**在 create 同时写 `79+80`(同日会 400)。
|
||||||
|
5. 标签必须 PATCH(create 带 tag 不落库);可与建子任务重叠;快轨交付/设计须与需求同标签。
|
||||||
|
6. `requests.Session` keep-alive;**禁止**对共享 opener 加全局锁。
|
||||||
|
7. 脚本入口:`scripts/live_create_fast.py`(v5:快轨描述/计划/标签/工时 2+2/设计 ASSOCIATED 补挂)。
|
||||||
660
.cursor/skills/YunxiaoPM/live_create_fast.py
Normal file
660
.cursor/skills/YunxiaoPM/live_create_fast.py
Normal file
@@ -0,0 +1,660 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""YunxiaoPM 极速真实建单 v5:快轨描述/计划/标签/工时 2+2/设计 ASSOCIATED 补挂。"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import urllib.parse
|
||||||
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||||
|
from datetime import datetime, timedelta, timezone
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
try:
|
||||||
|
import browser_cookie3
|
||||||
|
except ImportError: # pragma: no cover
|
||||||
|
browser_cookie3 = None
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
RUNTIME = json.loads((ROOT / "assets" / "runtime-ids.json").read_text())
|
||||||
|
STATUS = RUNTIME["status"]["req"]
|
||||||
|
TASK_STATUS = RUNTIME["status"]["task"]
|
||||||
|
FAST = RUNTIME.get("fields", {}).get("fast_track") or {}
|
||||||
|
|
||||||
|
SPACE = (
|
||||||
|
RUNTIME.get("project", {}).get("spaceIdentifier")
|
||||||
|
or (RUNTIME.get("project", {}).get("last_selected") or {}).get("spaceIdentifier")
|
||||||
|
)
|
||||||
|
if not SPACE:
|
||||||
|
raise RuntimeError(
|
||||||
|
"未选定项目 spaceIdentifier:须先走门禁 PJ 点选,或设置 runtime project.last_selected"
|
||||||
|
)
|
||||||
|
REQ_TYPE = RUNTIME["workitem_types"]["product_req"]["identifier"]
|
||||||
|
TASK_TYPE = RUNTIME["workitem_types"]["task"]["identifier"]
|
||||||
|
HEFEI = RUNTIME["people"]["hefei"]["identifier"]
|
||||||
|
WANG = RUNTIME["people"].get("wangmian", {}).get("identifier", "6811df000601d2fea60144a9")
|
||||||
|
PRI = RUNTIME["priority"]["中"]
|
||||||
|
TAG_FAULT = RUNTIME.get("tags", {}).get("故障管理", "ceb526a7343995577645317e9a")
|
||||||
|
PLACEHOLDER = RUNTIME["delivery_placeholder"]
|
||||||
|
PROTO = "https://prototype.lnoneos.com/vehicle-fault-handling/index.html"
|
||||||
|
TZ = timezone(timedelta(hours=8))
|
||||||
|
TODAY = datetime.now(TZ).strftime("%Y-%m-%d")
|
||||||
|
NOON = f"{TODAY} 12:00:00"
|
||||||
|
EOD = f"{TODAY} 23:59:59"
|
||||||
|
NOON_MS = str(
|
||||||
|
int(datetime.now(TZ).replace(hour=12, minute=0, second=0, microsecond=0).timestamp() * 1000)
|
||||||
|
)
|
||||||
|
START_MS = str(
|
||||||
|
int(datetime.now(TZ).replace(hour=9, minute=0, second=0, microsecond=0).timestamp() * 1000)
|
||||||
|
)
|
||||||
|
END_MS = str(
|
||||||
|
int(datetime.now(TZ).replace(hour=11, minute=0, second=0, microsecond=0).timestamp() * 1000)
|
||||||
|
)
|
||||||
|
FAST_EST = int(FAST.get("req_estimated_hours", 2))
|
||||||
|
FAST_ACT = int(FAST.get("req_actual_hours", 2))
|
||||||
|
|
||||||
|
PENDING = STATUS["待处理"]
|
||||||
|
DESIGN_DONE = STATUS["设计完成"]
|
||||||
|
PENDING_DEV = STATUS["待开发"]
|
||||||
|
TASK_DONE = TASK_STATUS["已完成"]
|
||||||
|
|
||||||
|
_COOKIE = ""
|
||||||
|
_XSRF = ""
|
||||||
|
|
||||||
|
|
||||||
|
def load_auth() -> None:
|
||||||
|
global _COOKIE, _XSRF
|
||||||
|
jar: dict[str, str] = {}
|
||||||
|
if browser_cookie3:
|
||||||
|
for domain in (".aliyun.com", "devops.aliyun.com", ".devops.aliyun.com"):
|
||||||
|
try:
|
||||||
|
for c in browser_cookie3.chrome(domain_name=domain):
|
||||||
|
jar[c.name] = c.value
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if not jar:
|
||||||
|
p = Path("/tmp/yunxiao_cookies.json")
|
||||||
|
if p.exists():
|
||||||
|
raw = json.loads(p.read_text())
|
||||||
|
jar = (
|
||||||
|
raw
|
||||||
|
if isinstance(raw, dict) and "XSRF-TOKEN" in raw
|
||||||
|
else {c["name"]: c["value"] for c in raw.get("cookies", [])}
|
||||||
|
)
|
||||||
|
_COOKIE = "; ".join(f"{k}={v}" for k, v in jar.items())
|
||||||
|
x = jar.get("XSRF-TOKEN", "")
|
||||||
|
_XSRF = urllib.parse.unquote(x) if "%" in x else x
|
||||||
|
if not _XSRF:
|
||||||
|
raise RuntimeError("缺少 XSRF-TOKEN:请先在 Chrome 登录 devops.aliyun.com")
|
||||||
|
|
||||||
|
|
||||||
|
def session() -> requests.Session:
|
||||||
|
s = requests.Session()
|
||||||
|
s.headers.update(
|
||||||
|
{
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Cookie": _COOKIE,
|
||||||
|
"x-xsrf-token": _XSRF,
|
||||||
|
"X-XSRF-TOKEN": _XSRF,
|
||||||
|
"Origin": "https://devops.aliyun.com",
|
||||||
|
"Referer": f"https://devops.aliyun.com/projex/project/{SPACE}/req",
|
||||||
|
"accept": "application/json",
|
||||||
|
"User-Agent": "YunxiaoPM-live_create_fast/5.0",
|
||||||
|
"Connection": "keep-alive",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def api(s: requests.Session, method: str, url: str, body: Any = None) -> dict:
|
||||||
|
r = s.request(method, url, json=body, timeout=60)
|
||||||
|
try:
|
||||||
|
return r.json()
|
||||||
|
except Exception:
|
||||||
|
r.raise_for_status()
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def create(s: requests.Session, payload: dict) -> dict:
|
||||||
|
url = "https://devops.aliyun.com/projex/api/workitem/workitem?_input_charset=utf-8"
|
||||||
|
j = api(s, "POST", url, payload)
|
||||||
|
r = j.get("result") or {}
|
||||||
|
if j.get("code") == 200 and isinstance(r, dict) and r.get("identifier"):
|
||||||
|
return r
|
||||||
|
j = api(s, "PUT", url, payload)
|
||||||
|
r = j.get("result") or {}
|
||||||
|
if j.get("code") == 200 and isinstance(r, dict) and r.get("identifier"):
|
||||||
|
return r
|
||||||
|
raise RuntimeError(f"create failed: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def get(s: requests.Session, wid: str) -> dict:
|
||||||
|
return api(
|
||||||
|
s,
|
||||||
|
"GET",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/{wid}?_input_charset=utf-8",
|
||||||
|
)["result"]
|
||||||
|
|
||||||
|
|
||||||
|
def apply_tag(s: requests.Session, wid: str, tag_id: str = TAG_FAULT) -> None:
|
||||||
|
j = api(
|
||||||
|
s,
|
||||||
|
"PATCH",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/{wid}?_input_charset=utf-8",
|
||||||
|
{
|
||||||
|
"workitemIdentifier": wid,
|
||||||
|
"propertyKey": "tag",
|
||||||
|
"propertyValue": tag_id,
|
||||||
|
"operateType": "COVER",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if j.get("code") != 200:
|
||||||
|
raise RuntimeError(f"tag failed {wid}: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def set_document(s: requests.Session, wid: str, html: str) -> None:
|
||||||
|
j = api(
|
||||||
|
s,
|
||||||
|
"PATCH",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/{wid}/document?_input_charset=utf-8",
|
||||||
|
{"content": html, "formatType": "RICHTEXT"},
|
||||||
|
)
|
||||||
|
if j.get("code") != 200 or j.get("errorMsg"):
|
||||||
|
raise RuntimeError(f"document failed {wid}: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def set_fields(s: requests.Session, wid: str, pairs: list[tuple[str, str]]) -> None:
|
||||||
|
data = urllib.parse.urlencode(
|
||||||
|
{
|
||||||
|
"fieldValueList": json.dumps(
|
||||||
|
[{"fieldIdentifier": k, "value": v} for k, v in pairs], ensure_ascii=False
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
r = s.post(
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/field/value/{wid}?_input_charset=utf-8",
|
||||||
|
data=data,
|
||||||
|
headers={"Content-Type": "application/x-www-form-urlencoded"},
|
||||||
|
timeout=60,
|
||||||
|
)
|
||||||
|
j = r.json()
|
||||||
|
if j.get("code") != 200:
|
||||||
|
raise RuntimeError(f"field/value failed {wid}: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def set_estimate_hours(s: requests.Session, wid: str, hours: int, user: str = WANG) -> None:
|
||||||
|
est = api(
|
||||||
|
s,
|
||||||
|
"GET",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/time/estimate/list?workitemIdentifier={wid}",
|
||||||
|
).get("result") or []
|
||||||
|
for row in est:
|
||||||
|
eid = row.get("identifier")
|
||||||
|
if eid:
|
||||||
|
api(
|
||||||
|
s,
|
||||||
|
"DELETE",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/time/estimate/{wid}/{eid}",
|
||||||
|
)
|
||||||
|
j = api(
|
||||||
|
s,
|
||||||
|
"POST",
|
||||||
|
"https://devops.aliyun.com/projex/api/workitem/workitem/time/estimate?_input_charset=utf-8",
|
||||||
|
{
|
||||||
|
"workitemIdentifier": wid,
|
||||||
|
"spentTime": hours,
|
||||||
|
"type": "develop",
|
||||||
|
"description": "快轨默认预计工时",
|
||||||
|
"recordUserIdentifier": user,
|
||||||
|
"forCreate": False,
|
||||||
|
"containsRestDay": False,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if j.get("code") != 200:
|
||||||
|
raise RuntimeError(f"estimate failed {wid}: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def set_actual_hours(s: requests.Session, wid: str, hours: int, user: str = WANG) -> None:
|
||||||
|
j = api(
|
||||||
|
s,
|
||||||
|
"POST",
|
||||||
|
"https://devops.aliyun.com/projex/api/workitem/workitem/time?_input_charset=utf-8",
|
||||||
|
{
|
||||||
|
"workitemIdentifier": wid,
|
||||||
|
"actualTime": hours,
|
||||||
|
"type": "develop",
|
||||||
|
"description": "快轨默认实际工时",
|
||||||
|
"recordUserIdentifier": user,
|
||||||
|
"gmtStart": START_MS,
|
||||||
|
"gmtEnd": END_MS,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if j.get("code") != 200 or not j.get("result"):
|
||||||
|
raise RuntimeError(f"actual time failed {wid}: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def try_associate_to_req(s: requests.Session, stage_id: str, req_id: str) -> bool:
|
||||||
|
"""建后补 ASSOCIATED→需求。Cookie 下常失败,成功返回 True。"""
|
||||||
|
bodies = [
|
||||||
|
{"relationIdentifier": "ASSOCIATED", "toWorkitemIdentifier": req_id},
|
||||||
|
{
|
||||||
|
"relationIdentifier": "ASSOCIATED",
|
||||||
|
"fromWorkitemIdentifier": stage_id,
|
||||||
|
"toWorkitemIdentifier": req_id,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
for body in bodies:
|
||||||
|
for url in (
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/{stage_id}/relation/record?_input_charset=utf-8",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/v2/workitem/{stage_id}/relation/record?_input_charset=utf-8",
|
||||||
|
):
|
||||||
|
j = api(s, "POST", url, body)
|
||||||
|
if j.get("code") == 200 and j.get("result") not in (None, False):
|
||||||
|
if not (isinstance(j.get("result"), dict) and j["result"].get("status") in (404, 405)):
|
||||||
|
rows = list_associated(s, stage_id)
|
||||||
|
if req_id in {r.get("identifier") for r in rows}:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def transit(s: requests.Session, wid: str, from_status: str, to_status: str) -> None:
|
||||||
|
if from_status == to_status:
|
||||||
|
return
|
||||||
|
j = api(
|
||||||
|
s,
|
||||||
|
"POST",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/{wid}/status/transit?_input_charset=utf-8",
|
||||||
|
{"fromStatus": from_status, "toStatus": to_status},
|
||||||
|
)
|
||||||
|
if not (j.get("code") == 200 and j.get("result") is True):
|
||||||
|
raise RuntimeError(f"transit {wid} {from_status}->{to_status}: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def md_to_html(md: str) -> str:
|
||||||
|
parts = []
|
||||||
|
for line in md.splitlines():
|
||||||
|
if line.startswith("## "):
|
||||||
|
parts.append(f"<h2>{line[3:]}</h2>")
|
||||||
|
elif line.startswith("### "):
|
||||||
|
parts.append(f"<h3>{line[4:]}</h3>")
|
||||||
|
elif line.startswith("- "):
|
||||||
|
parts.append(f"<p>• {line[2:]}</p>")
|
||||||
|
elif line.strip():
|
||||||
|
parts.append(f"<p>{line}</p>")
|
||||||
|
return "".join(parts)
|
||||||
|
|
||||||
|
|
||||||
|
def req_document_html(s: requests.Session, rid: str) -> str:
|
||||||
|
w = get(s, rid)
|
||||||
|
return ((w.get("document") or {}).get("content") or w.get("description") or "").strip()
|
||||||
|
|
||||||
|
|
||||||
|
def req_payload(subject: str, html: str) -> dict:
|
||||||
|
return {
|
||||||
|
"subject": subject,
|
||||||
|
"description": html,
|
||||||
|
"formatType": "RICHTEXT",
|
||||||
|
"document": {"content": html, "formatType": "RICHTEXT"},
|
||||||
|
"spaceIdentifier": SPACE,
|
||||||
|
"space": SPACE,
|
||||||
|
"spaceType": "Project",
|
||||||
|
"workitemTypeIdentifier": REQ_TYPE,
|
||||||
|
"workitemType": REQ_TYPE,
|
||||||
|
"categoryIdentifier": "Req",
|
||||||
|
"category": "Req",
|
||||||
|
"assignedTo": WANG,
|
||||||
|
"fieldValueList": [
|
||||||
|
{"fieldIdentifier": "priority", "value": PRI},
|
||||||
|
{"fieldIdentifier": "assignedTo", "value": WANG},
|
||||||
|
],
|
||||||
|
"attachmentIdList": [],
|
||||||
|
"cloneFrom": None,
|
||||||
|
"createWorkitemRelationList": [],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def task_payload(
|
||||||
|
subject: str,
|
||||||
|
html: str,
|
||||||
|
assignee: str,
|
||||||
|
*,
|
||||||
|
plan_start: bool = True,
|
||||||
|
associated_req: str | None = None,
|
||||||
|
parent_delivery: str | None = None,
|
||||||
|
) -> dict:
|
||||||
|
fvl = [
|
||||||
|
{"fieldIdentifier": "priority", "value": PRI},
|
||||||
|
{"fieldIdentifier": "assignedTo", "value": assignee},
|
||||||
|
]
|
||||||
|
if plan_start:
|
||||||
|
fvl.append({"fieldIdentifier": "79", "value": NOON_MS})
|
||||||
|
payload: dict[str, Any] = {
|
||||||
|
"subject": subject,
|
||||||
|
"description": html,
|
||||||
|
"formatType": "RICHTEXT",
|
||||||
|
"spaceIdentifier": SPACE,
|
||||||
|
"space": SPACE,
|
||||||
|
"spaceType": "Project",
|
||||||
|
"workitemTypeIdentifier": TASK_TYPE,
|
||||||
|
"workitemType": TASK_TYPE,
|
||||||
|
"categoryIdentifier": "Task",
|
||||||
|
"category": "Task",
|
||||||
|
"assignedTo": assignee,
|
||||||
|
"fieldValueList": fvl,
|
||||||
|
"attachmentIdList": [],
|
||||||
|
"cloneFrom": None,
|
||||||
|
}
|
||||||
|
if parent_delivery:
|
||||||
|
payload["parent"] = parent_delivery
|
||||||
|
payload["parentIdentifier"] = parent_delivery
|
||||||
|
payload["createWorkitemRelationInfo"] = {
|
||||||
|
"relatedWorkitemIdentifier": parent_delivery,
|
||||||
|
"relatedToRelationIdentifier": "TASK_SUB",
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
if not associated_req:
|
||||||
|
raise ValueError("associated_req required for delivery: ASSOCIATED→需求")
|
||||||
|
payload["createWorkitemRelationInfo"] = {
|
||||||
|
"relatedWorkitemIdentifier": associated_req,
|
||||||
|
"relatedToRelationIdentifier": "ASSOCIATED",
|
||||||
|
}
|
||||||
|
return payload
|
||||||
|
|
||||||
|
|
||||||
|
def list_associated(s: requests.Session, wid: str) -> list[dict]:
|
||||||
|
j = api(
|
||||||
|
s,
|
||||||
|
"GET",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/v2/workitem/{wid}/relation/workitem/list/by-relation-category?category=ASSOCIATED&isForward=true",
|
||||||
|
)
|
||||||
|
return j.get("result") or []
|
||||||
|
|
||||||
|
|
||||||
|
def assert_associated_to_req(s: requests.Session, wid: str, req_id: str, label: str) -> None:
|
||||||
|
rows = list_associated(s, wid)
|
||||||
|
ids = {r.get("identifier") for r in rows}
|
||||||
|
if req_id not in ids:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"{label} 关联项未挂需求:期望 {req_id},实际 {[r.get('serialNumber') for r in rows]}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
AUTO_RDO = """## 原始诉求(AutoRDO)
|
||||||
|
|
||||||
|
运维需在故障处置页承接机器人上报的故障,完成处置、挂起与归档,并保留证据链;工作台相关统计口径需与处置页一致
|
||||||
|
|
||||||
|
待确认:
|
||||||
|
- 本期是否含真实短信/邮件通道(现口径一般为演示模板)
|
||||||
|
|
||||||
|
## 工作项编号(系统)
|
||||||
|
- 交付:待建
|
||||||
|
- 分析:待建
|
||||||
|
- 设计:待建
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def summarize_from_create(w: dict, *, status: str, assignee_name: str) -> dict:
|
||||||
|
return {
|
||||||
|
"serial": w.get("serialNumber"),
|
||||||
|
"id": w.get("identifier"),
|
||||||
|
"subject": w.get("subject"),
|
||||||
|
"status": status,
|
||||||
|
"assignee": assignee_name,
|
||||||
|
"parent": w.get("parentIdentifier"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def build_normal() -> dict:
|
||||||
|
t0 = time.perf_counter()
|
||||||
|
s = session()
|
||||||
|
title = "【新增】故障处置(YunxiaoPMapp标准·极速v2)"
|
||||||
|
req = create(s, req_payload(title, md_to_html(AUTO_RDO + f"\n原型:{PROTO}\n")))
|
||||||
|
rid = req["identifier"]
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=2) as pool:
|
||||||
|
f_tag_r = pool.submit(apply_tag, session(), rid)
|
||||||
|
f_deliv = pool.submit(
|
||||||
|
create,
|
||||||
|
session(),
|
||||||
|
task_payload(
|
||||||
|
f"【交付】{title}",
|
||||||
|
f"<p>{PLACEHOLDER}</p>",
|
||||||
|
HEFEI,
|
||||||
|
associated_req=rid,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
deliv = f_deliv.result()
|
||||||
|
f_tag_r.result()
|
||||||
|
did = deliv["identifier"]
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=3) as pool:
|
||||||
|
f_tag_d = pool.submit(apply_tag, session(), did)
|
||||||
|
f_ana = pool.submit(
|
||||||
|
create,
|
||||||
|
session(),
|
||||||
|
task_payload(
|
||||||
|
f"【分析】{title}",
|
||||||
|
"<p>分析阶段:故障处置台账、挂起归档与证据链。</p>",
|
||||||
|
WANG,
|
||||||
|
associated_req=rid,
|
||||||
|
parent_delivery=did,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
f_des = pool.submit(
|
||||||
|
create,
|
||||||
|
session(),
|
||||||
|
task_payload(
|
||||||
|
f"【设计】{title}",
|
||||||
|
f"<p>设计阶段:对齐原型 {PROTO}</p>",
|
||||||
|
WANG,
|
||||||
|
associated_req=rid,
|
||||||
|
parent_delivery=did,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
ana = f_ana.result()
|
||||||
|
des = f_des.result()
|
||||||
|
f_tag_d.result()
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=3) as pool:
|
||||||
|
list(
|
||||||
|
as_completed(
|
||||||
|
[
|
||||||
|
pool.submit(transit, session(), rid, PENDING, DESIGN_DONE),
|
||||||
|
pool.submit(transit, session(), ana["identifier"], PENDING, TASK_DONE),
|
||||||
|
pool.submit(transit, session(), des["identifier"], PENDING, TASK_DONE),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
transit(s, rid, DESIGN_DONE, PENDING_DEV)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"path": "normal",
|
||||||
|
"elapsed_s": round(time.perf_counter() - t0, 3),
|
||||||
|
"req": summarize_from_create(req, status="待开发", assignee_name="王冕"),
|
||||||
|
"delivery": summarize_from_create(deliv, status="待处理", assignee_name="何斐"),
|
||||||
|
"analysis": summarize_from_create(ana, status="已完成", assignee_name="王冕"),
|
||||||
|
"design": summarize_from_create(des, status="已完成", assignee_name="王冕"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def build_fast(
|
||||||
|
*,
|
||||||
|
tag_id: str = TAG_FAULT,
|
||||||
|
has_prototype: bool = True,
|
||||||
|
delivery_html: str | None = None,
|
||||||
|
) -> dict:
|
||||||
|
"""无单快轨。
|
||||||
|
|
||||||
|
- 设计描述 = 需求 document
|
||||||
|
- 交付描述 = 手工同步需求正文(无原型)或传入 AutoPRD HTML;禁止无故占位
|
||||||
|
- 设计 79/80=当日;交付 79=当日
|
||||||
|
- 需求/交付/设计同标签
|
||||||
|
- 需求预计/实际工时各 2
|
||||||
|
- 设计 TASK_SUB→交付后尝试 ASSOCIATED→需求
|
||||||
|
"""
|
||||||
|
t0 = time.perf_counter()
|
||||||
|
s = session()
|
||||||
|
title = "【新增】故障处置(YunxiaoPM快轨·极速v5)"
|
||||||
|
req_html = md_to_html(AUTO_RDO + (f"\n原型:{PROTO}\n" if has_prototype else "\n"))
|
||||||
|
req = create(s, req_payload(title, req_html))
|
||||||
|
rid = req["identifier"]
|
||||||
|
# 以落库 document 为准(与手动建需后读需求一致)
|
||||||
|
req_html = req_document_html(s, rid) or req_html
|
||||||
|
|
||||||
|
if delivery_html:
|
||||||
|
deliv_html = delivery_html
|
||||||
|
desc_source = "autoprd"
|
||||||
|
elif req_html.strip():
|
||||||
|
deliv_html = req_html
|
||||||
|
desc_source = "manual_sync"
|
||||||
|
else:
|
||||||
|
deliv_html = f"<p>{PLACEHOLDER}</p>"
|
||||||
|
desc_source = "placeholder"
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=2) as pool:
|
||||||
|
f_tag_r = pool.submit(apply_tag, session(), rid, tag_id)
|
||||||
|
f_deliv = pool.submit(
|
||||||
|
create,
|
||||||
|
session(),
|
||||||
|
task_payload(
|
||||||
|
f"【交付】{title}",
|
||||||
|
deliv_html,
|
||||||
|
HEFEI,
|
||||||
|
associated_req=rid,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
deliv = f_deliv.result()
|
||||||
|
f_tag_r.result()
|
||||||
|
did = deliv["identifier"]
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=2) as pool:
|
||||||
|
f_tag_d = pool.submit(apply_tag, session(), did, tag_id)
|
||||||
|
f_des = pool.submit(
|
||||||
|
create,
|
||||||
|
session(),
|
||||||
|
task_payload(
|
||||||
|
f"【设计】{title}",
|
||||||
|
req_html,
|
||||||
|
WANG,
|
||||||
|
parent_delivery=did,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
des = f_des.result()
|
||||||
|
f_tag_d.result()
|
||||||
|
des_id = des["identifier"]
|
||||||
|
apply_tag(s, des_id, tag_id)
|
||||||
|
|
||||||
|
# 计划时间:设计起止当日;交付开始当日(create 已带 79,再 field/value 加固)
|
||||||
|
set_fields(s, des_id, [("79", NOON), ("80", EOD)])
|
||||||
|
set_fields(s, did, [("79", NOON)])
|
||||||
|
|
||||||
|
# 设计关联项补挂需求(可能失败,回报 risk)
|
||||||
|
design_assoc_ok = try_associate_to_req(s, des_id, rid)
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=2) as pool:
|
||||||
|
list(
|
||||||
|
as_completed(
|
||||||
|
[
|
||||||
|
pool.submit(transit, session(), rid, PENDING, DESIGN_DONE),
|
||||||
|
pool.submit(transit, session(), des_id, PENDING, TASK_DONE),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
transit(s, rid, DESIGN_DONE, PENDING_DEV)
|
||||||
|
|
||||||
|
set_estimate_hours(s, rid, FAST_EST)
|
||||||
|
set_actual_hours(s, rid, FAST_ACT)
|
||||||
|
|
||||||
|
risk = None
|
||||||
|
if desc_source == "placeholder":
|
||||||
|
risk = "交付描述仍为占位"
|
||||||
|
if not design_assoc_ok:
|
||||||
|
risk = (risk + ";" if risk else "") + "设计 ASSOCIATED→需求补挂失败(Cookie),须 UI/OpenAPI 兜底"
|
||||||
|
|
||||||
|
return {
|
||||||
|
"path": "fast",
|
||||||
|
"elapsed_s": round(time.perf_counter() - t0, 3),
|
||||||
|
"req": summarize_from_create(req, status="待开发", assignee_name="王冕"),
|
||||||
|
"delivery": summarize_from_create(deliv, status="待处理", assignee_name="何斐"),
|
||||||
|
"design": summarize_from_create(des, status="已完成", assignee_name="王冕"),
|
||||||
|
"analysis": None,
|
||||||
|
"delivery_desc_source": desc_source,
|
||||||
|
"design_associated_ok": design_assoc_ok,
|
||||||
|
"risk": risk,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
auth0 = time.perf_counter()
|
||||||
|
load_auth()
|
||||||
|
auth_s = round(time.perf_counter() - auth0, 3)
|
||||||
|
|
||||||
|
wall0 = time.perf_counter()
|
||||||
|
with ThreadPoolExecutor(max_workers=2) as pool:
|
||||||
|
f_fast = pool.submit(build_fast)
|
||||||
|
f_normal = pool.submit(build_normal)
|
||||||
|
fast = f_fast.result()
|
||||||
|
normal = f_normal.result()
|
||||||
|
build_s = round(time.perf_counter() - wall0, 3)
|
||||||
|
|
||||||
|
s = session()
|
||||||
|
assert_associated_to_req(s, normal["delivery"]["id"], normal["req"]["id"], "normal.delivery")
|
||||||
|
assert_associated_to_req(s, fast["delivery"]["id"], fast["req"]["id"], "fast.delivery")
|
||||||
|
|
||||||
|
def assert_sub(delivery_id: str, child_id: str, label: str) -> None:
|
||||||
|
rows = api(
|
||||||
|
s,
|
||||||
|
"GET",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/v2/workitem/{delivery_id}/relation/workitem/list/by-relation-category?category=PARENT_SUB&isForward=true",
|
||||||
|
).get("result") or []
|
||||||
|
ids = {r.get("identifier") for r in rows}
|
||||||
|
if child_id not in ids:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"{label} 未出现在交付子项:期望 {child_id},实际 {[r.get('serialNumber') for r in rows]}"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert_sub(normal["delivery"]["id"], normal["analysis"]["id"], "normal.analysis")
|
||||||
|
assert_sub(normal["delivery"]["id"], normal["design"]["id"], "normal.design")
|
||||||
|
assert_sub(fast["delivery"]["id"], fast["design"]["id"], "fast.design")
|
||||||
|
verify = {
|
||||||
|
"normal_req": get(s, normal["req"]["id"])["status"]["displayName"],
|
||||||
|
"fast_req": get(s, fast["req"]["id"])["status"]["displayName"],
|
||||||
|
"normal_delivery_assignee": (
|
||||||
|
get(s, normal["delivery"]["id"]).get("assignedTo") or {}
|
||||||
|
).get("displayName"),
|
||||||
|
"fast_delivery_assignee": (get(s, fast["delivery"]["id"]).get("assignedTo") or {}).get(
|
||||||
|
"displayName"
|
||||||
|
),
|
||||||
|
"delivery_associated_ok": True,
|
||||||
|
"stage_tasks_as_sub_ok": True,
|
||||||
|
"fast_design_associated_ok": fast.get("design_associated_ok"),
|
||||||
|
}
|
||||||
|
out = {
|
||||||
|
"normal": normal,
|
||||||
|
"fast": fast,
|
||||||
|
"verify": verify,
|
||||||
|
"auth_elapsed_s": auth_s,
|
||||||
|
"wall_elapsed_s": build_s,
|
||||||
|
"created_at": datetime.now(TZ).isoformat(),
|
||||||
|
"mode": "live_create_fast_v5_fast_track_rules",
|
||||||
|
"opts": {
|
||||||
|
"create_includes_plan_start": True,
|
||||||
|
"skip_plan_end_on_create": True,
|
||||||
|
"tracked_transit_no_get": True,
|
||||||
|
"delivery_assignee_hefei_at_create": True,
|
||||||
|
"overlap_tag_with_create": True,
|
||||||
|
"fast_req_hours": f"{FAST_EST}+{FAST_ACT}",
|
||||||
|
"relation": "delivery ASSOCIATED→req; analysis/design TASK_SUB→delivery; design post ASSOCIATED→req",
|
||||||
|
"http": "requests.Session keep-alive",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
Path("/tmp/yunxiao_pmapp_fast_v2_result.json").write_text(
|
||||||
|
json.dumps(out, ensure_ascii=False, indent=2)
|
||||||
|
)
|
||||||
|
print(json.dumps(out, ensure_ascii=False, indent=2))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
60
.cursor/skills/YunxiaoPM/model.md
Normal file
60
.cursor/skills/YunxiaoPM/model.md
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
# 交付树模型与关联约定
|
||||||
|
|
||||||
|
## 真相源
|
||||||
|
|
||||||
|
```text
|
||||||
|
需求状态 = 阶段看板唯一真相(分析中/设计中/待开发…)
|
||||||
|
【交付】任务 = 该需求的交付容器(每需求最多 1 条)
|
||||||
|
【分析】/【设计】 = YunxiaoPMapp 在交付下建的阶段子项
|
||||||
|
【开发】/【测试】 = 另属开发 Skill / 测试 Skill,不进本包
|
||||||
|
ASSOCIATED = 横向挂钩(【交付】 ↔ 需求)
|
||||||
|
SUB / TASK_SUB = 纵向拆解(交付 → 分析/设计)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 关系验收
|
||||||
|
|
||||||
|
| 关系 | 用在哪里 | 验收 | 优先级 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| ASSOCIATED | **仅【交付】** ↔ 需求 | 交付详情「关联项」能看到需求(**强制**) | 交付必过 |
|
||||||
|
| TASK_SUB | 【分析】/【设计】 → 【交付】 | 交付详情「子项」能看到阶段任务(**强制**) | 阶段任务必过 |
|
||||||
|
|
||||||
|
建单规则(Cookie 路径 · 同一 create 只能一条 `createWorkitemRelationInfo`):
|
||||||
|
|
||||||
|
| 对象 | `createWorkitemRelationInfo` | 另写字段 |
|
||||||
|
|---|---|---|
|
||||||
|
| 【交付】 | `ASSOCIATED` → 需求 | — |
|
||||||
|
| 【分析】/【设计】 | `TASK_SUB` → 交付 | `parent` + `parentIdentifier` = 交付 |
|
||||||
|
|
||||||
|
**禁止**对分析/设计只写 `parentIdentifier` + `ASSOCIATED→需求`:关联项可能有,但交付「子项」仍为空(ONEOS-246/247 已复现)。
|
||||||
|
勿用 `PARENT` 冒充关联项。细则见 [live-api.md](live-api.md)。
|
||||||
|
|
||||||
|
## 禁止
|
||||||
|
|
||||||
|
| 禁止 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| 创建或描述【开发】/【测试】 | 口令与回报均不出现 |
|
||||||
|
| 分析/设计未挂成交付子项(无 TASK_SUB) | 交付「子项」为 0,交棒验收失败 |
|
||||||
|
| 用任务名称/标题做唯一性或查重 | 不得 `subject` 匹配复用 |
|
||||||
|
| 同一需求认定多个交付任务编号 | 列出编号请人合并后再继续 |
|
||||||
|
| 功能模块标签用「分析/设计/交付」 | 模块标签打在需求(可选交付)上 |
|
||||||
|
|
||||||
|
## 任务标题(仅展示)
|
||||||
|
|
||||||
|
- 【交付】+ 需求标题
|
||||||
|
- 【分析】+ 需求标题
|
||||||
|
- 【设计】+ 需求标题
|
||||||
|
|
||||||
|
标题可改,**不参与查重**。
|
||||||
|
|
||||||
|
## 任务编号唯一性
|
||||||
|
|
||||||
|
**唯一允许的查重/复用渠道:云效任务编号**(如 `ONEOS-99` / `serialNumber`)。
|
||||||
|
|
||||||
|
| 场景 | 正确 | 错误 |
|
||||||
|
|---|---|---|
|
||||||
|
| 首次创建【交付】 | 建单成功后回报并写入「工作项编号(系统)」 | 下次用标题搜 |
|
||||||
|
| 复用【交付】 | 口令或编号区块带 `交付任务=ONEOS-xx` | list 后按 subject 相等 |
|
||||||
|
| 判断是否已有交付 | 编号区块或交付 ASSOCIATED 编号集合 | 数【交付】开头标题 |
|
||||||
|
| 分析/设计幂等 | 仅已登记编号 | 按【分析】+需求标题 |
|
||||||
|
|
||||||
|
按编号命中则复用;**计划开始已有值禁止改写**。
|
||||||
49
.cursor/skills/YunxiaoPM/references/acceptance.md
Normal file
49
.cursor/skills/YunxiaoPM/references/acceptance.md
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# 验收清单与回报
|
||||||
|
|
||||||
|
## apply 后必须自检
|
||||||
|
|
||||||
|
| # | 项 | 通过标准 |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | 需求编号 | 回报含 ONEOS-xx |
|
||||||
|
| 2 | 任务编号 | 交付/分析/设计凡新建或操作均回报编号;禁止只报标题 |
|
||||||
|
| 3 | 编号区块 | 需求「工作项编号(系统)」与实际一致 |
|
||||||
|
| 4 | ASSOCIATED | **仅交付**详情关联项可见需求(`createWorkitemRelationInfo=ASSOCIATED`;禁止 PARENT 冒充) |
|
||||||
|
| 5 | SUB | **必过**:分析/设计 create 用 `TASK_SUB→交付`(含 `parent`+`parentIdentifier`);交付「子项」tab 须可见。与 ASSOCIATED 同 create 互斥,阶段任务关联项可空(见 live-api.md) |
|
||||||
|
| 6 | 计划开始 | 未误覆盖已有值 |
|
||||||
|
| 7 | 阶段日历工时 | 有计划完成时已写入;脚注存在;回报用语正确 |
|
||||||
|
| 8 | 交棒 | 需求=待开发;交付负责人=何斐(交棒场景) |
|
||||||
|
| 9 | 占位风险 | 交付仍占位时首行标红 |
|
||||||
|
| 10 | 负向 | 本轮**无**【开发】/【测试】任务;未按标题查重 |
|
||||||
|
|
||||||
|
设计完成额外:AutoPRD 段已写;交付非占位(除非失败停下);ZIP+截图已挂或已列出缺项。
|
||||||
|
|
||||||
|
迭代额外:只挂【交付】(需求不挂);版本号符合递增规则。
|
||||||
|
|
||||||
|
## 回报模板(精简)
|
||||||
|
|
||||||
|
```text
|
||||||
|
【YunxiaoPM】
|
||||||
|
风险:(若有占位交棒则首行标红)
|
||||||
|
需求:ONEOS-xx | 状态=…
|
||||||
|
交付:ONEOS-a | 负责人=…
|
||||||
|
分析:ONEOS-b | …(无则写无)
|
||||||
|
设计:ONEOS-c | …(无则写无)
|
||||||
|
阶段日历工时:分析 Hh / 设计 Hh(若本轮写入)
|
||||||
|
附件:…(若本轮)
|
||||||
|
迭代:…(若本轮)
|
||||||
|
下一步:请技术经理使用开发 Skill(交棒后)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 适合全自动 vs 人工门禁
|
||||||
|
|
||||||
|
| 适合全自动 | 建议半自动/人工门禁 |
|
||||||
|
|---|---|
|
||||||
|
| 建单、打标签、挂迭代、写描述、建交付树、改状态、交棒负责人、幂等查重 | **PJ 云效项目点选**、受理(已确认)、是否快轨、设计完成是否真可开发、跨需求优先级与迭代容量、回退与取消 |
|
||||||
|
|
||||||
|
## 实写性能(2026-07-23 复盘)
|
||||||
|
|
||||||
|
| 项 | 要求 |
|
||||||
|
|---|---|
|
||||||
|
| 改状态 | 只用 `status/transit`(见 [live-api.md](live-api.md)) |
|
||||||
|
| 改【交付】负责人 | 只用 `PATCH …/{id}` + `propertyKey=assignedTo` |
|
||||||
|
| 极速复测 | `scripts/live_create_fast.py`;默认不开浏览器 |
|
||||||
22
.cursor/skills/YunxiaoPM/references/commands.md
Normal file
22
.cursor/skills/YunxiaoPM/references/commands.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# 口令面
|
||||||
|
|
||||||
|
```text
|
||||||
|
记录需求:…;项目=(必选·Plan 点选);优先级=紧急|高|中|低;标签=…;提交部门=…;提交人=…;推进至=暂不推进|已确认|分析中|设计中|设计完成|待开发|待开发(快轨)
|
||||||
|
受理确认:ONEOS-xx
|
||||||
|
开始分析:ONEOS-xx → 【交付】+【分析】并回报编号
|
||||||
|
开始设计:ONEOS-xx;交付任务=…;分析任务=… → 【设计】+收口分析
|
||||||
|
设计完成:ONEOS-xx;设计任务=…;原型=…
|
||||||
|
交棒开发:ONEOS-xx;交付任务=… → 待开发 + 该编号负责人=何斐
|
||||||
|
快轨待开发:ONEOS-xx → 待开发 +【交付】+【设计】(无【分析】)+ 交付负责人=何斐
|
||||||
|
编号直推:分析任务=ONEOS-b / 设计任务=ONEOS-c → 收口未完成计划完成 + 需求待开发 + 交付交棒何斐
|
||||||
|
创建迭代:版本类型=主|副|子;交付任务=ONEOS-a,ONEOS-b,…;名称前缀=…
|
||||||
|
AutoRDO:…(粘贴聊天/附录音)→ 再记录需求
|
||||||
|
```
|
||||||
|
|
||||||
|
版本自动规则:取同前缀下最大 `Vx.y.z`(旧 `Vx.y` 视为 `Vx.y.0`)再按主/副/子递增;迭代名=`{前缀}{新版本}`。
|
||||||
|
|
||||||
|
**PJ 项目**:新建需求/迭代前须点选云效项目(实时列表);禁止默认直指。见 [project-selection.md](project-selection.md)。
|
||||||
|
|
||||||
|
后续推进口令**优先显式带任务编号**;未带则读「工作项编号(系统)」;仍无则询问;**禁止按标题补全**。
|
||||||
|
|
||||||
|
YunxiaoPM 回报止于交棒;可一句「请技术经理使用开发 Skill」。
|
||||||
95
.cursor/skills/YunxiaoPM/references/compact-select.md
Normal file
95
.cursor/skills/YunxiaoPM/references/compact-select.md
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
# 压缩点选(`1a2b3a4d`)
|
||||||
|
|
||||||
|
记录需求 Plan **默认**用编号题 + 字母选项;用户可用一行压缩答复确认。
|
||||||
|
|
||||||
|
## Plan 展示模板
|
||||||
|
|
||||||
|
```text
|
||||||
|
请回复压缩点选,例:1a2b3a4d
|
||||||
|
(数字=题号,字母=选项;大小写不敏感;可写 1A2B3A4D)
|
||||||
|
|
||||||
|
1. 类型
|
||||||
|
A. 新增
|
||||||
|
B. 优化
|
||||||
|
|
||||||
|
2. 项目(云效实时列表;建议项可标★)
|
||||||
|
A. 01_ONEOS(ONEOS)★
|
||||||
|
B. 02_小羚羚APP(XLLAPP)
|
||||||
|
C. …
|
||||||
|
|
||||||
|
3. 优先级
|
||||||
|
A. 紧急
|
||||||
|
B. 高
|
||||||
|
C. 中
|
||||||
|
D. 低
|
||||||
|
|
||||||
|
4. 标签(云效候选;建议项可标★)
|
||||||
|
A. 故障管理★
|
||||||
|
B. 还车应结款
|
||||||
|
C. …
|
||||||
|
```
|
||||||
|
|
||||||
|
可选续题(口令已齐则可写入清单、压缩串可不含):
|
||||||
|
|
||||||
|
```text
|
||||||
|
5. 推进至 …
|
||||||
|
6. 迭代 …
|
||||||
|
```
|
||||||
|
|
||||||
|
## 解析规则
|
||||||
|
|
||||||
|
| 规则 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| 形态 | `(题号)(字母)` 连续拼接,如 `1a2b3a4d` |
|
||||||
|
| 题号 | `1`=类型 `2`=项目 `3`=优先级 `4`=标签;可扩展 `5` `6` |
|
||||||
|
| 字母 | `a`→第 1 项 … `z`→第 26 项;超出选项数 → 非法,停 |
|
||||||
|
| 缺题 | 该题若口令已唯一预填且列表唯一命中,可用预填;否则停并追问缺题 |
|
||||||
|
| 多答同题 | 后写覆盖先写 |
|
||||||
|
| 非法字符 | 停,重贴模板 |
|
||||||
|
|
||||||
|
解析成功后 Plan 回显人话确认一行,例如:
|
||||||
|
|
||||||
|
```text
|
||||||
|
已解析 1a2b3a4d → 类型=新增;项目=02_小羚羚APP;优先级=紧急;标签=(D 项名)
|
||||||
|
确认后回复「执行」
|
||||||
|
```
|
||||||
|
|
||||||
|
用户再回「执行」才 apply(仍守 Plan 门禁)。
|
||||||
|
|
||||||
|
## 与口令预填
|
||||||
|
|
||||||
|
口令已写 `类型:新增;项目:01_ONEOS;优先级:高;标签:故障管理` 时:
|
||||||
|
|
||||||
|
- 对应选项标 ★,并给出**建议压缩串**(如 `1a2a3b4a`),用户可直接改字母或整段重答。
|
||||||
|
- **不得**因有预填而跳过展示字母表;压缩确认(或逐题点选)仍是门禁。
|
||||||
|
|
||||||
|
## 标签未命中 → 自动重拉一次候选并重生选项
|
||||||
|
|
||||||
|
「标签无法对应」:口令标签名在**当前标签候选**中 0 命中(或多命中无法唯一)。
|
||||||
|
|
||||||
|
| 步骤 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| 1 | **自动重拉一次**标签候选(见下「标签候选来源」;强制刷新,不用旧缓存) |
|
||||||
|
| 2 | 用新列表**重新生成 4.A/B/C…** 选择项 |
|
||||||
|
| 3 | 回报:`已自动重拉标签列表(因无法对应)`;请用户重答 `4x` 或整串 |
|
||||||
|
| 4 | 仍无法对应 → 停;**禁止**第 3 次空转;**禁止**猜 tagId |
|
||||||
|
|
||||||
|
> 说明:此处重拉的是**标签候选列表**,不是项目列表。项目无法对应仍走 [project-selection.md](project-selection.md) 的「自动重拉一次」。
|
||||||
|
|
||||||
|
### 标签候选来源(当前已验证路径)
|
||||||
|
|
||||||
|
1. `runtime-ids.json` → `tags`
|
||||||
|
2. 目标项目(或预填项目)下近期工作项 `tag` 字段聚合去重
|
||||||
|
3. 重拉 = 再请求工作项列表聚合 + 合并 runtime;命中后可回写 `tags` 缓存
|
||||||
|
|
||||||
|
(专用 `tag/list` Cookie API 尚未稳定;有稳定端点后改写入 `live-api.md` 并切换。)
|
||||||
|
|
||||||
|
## 项目列表顺序
|
||||||
|
|
||||||
|
生成 2. 选项时:口令预填/建议项目置 **A** 并标 ★,其余按云效返回顺序接 B/C/…。
|
||||||
|
|
||||||
|
## Agent 义务
|
||||||
|
|
||||||
|
1. 记录需求进 Plan 时必须输出本模板(至少 1–4 题)。
|
||||||
|
2. 收到压缩串先解析回显,再等「执行」。
|
||||||
|
3. 标签/项目无法对应:各自动重拉**一次**并刷新对应题选项。
|
||||||
69
.cursor/skills/YunxiaoPM/references/description-split.md
Normal file
69
.cursor/skills/YunxiaoPM/references/description-split.md
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
# 需求描述 vs 交付描述
|
||||||
|
|
||||||
|
两类描述职责不同;禁止混写;禁止建【交付】时把 AutoPRD 六大块提前塞进交付描述。
|
||||||
|
|
||||||
|
## A. 需求描述 · AutoRDO 清洗
|
||||||
|
|
||||||
|
| 项 | 规则 |
|
||||||
|
|---|---|
|
||||||
|
| 触发 | 对话建需求 / 碎片材料入库 |
|
||||||
|
| 调用 | **必须**使用独立 Skill「**`$AutoRDO`**」(`AutoRDO/SKILL.md`;本 Skill 不内嵌清洗细则) |
|
||||||
|
| 输入 | 聊天记录、录音、口述材料 |
|
||||||
|
| 处理 | 保留原意;书面化;去口头禅;**去除结尾句号**(细则在 AutoRDO `references/rules.md`) |
|
||||||
|
| 输出 | 写入 `## 原始诉求(AutoRDO)` |
|
||||||
|
| 不做 | 本阶段不写 AutoPRD 六大块;不要求已有原型;不覆盖已有「产品说明」 |
|
||||||
|
|
||||||
|
口令:`AutoRDO:…` → 确认后 `记录需求:【新增】标题;描述=整理稿;推进至=…`
|
||||||
|
|
||||||
|
## B. 交付描述
|
||||||
|
|
||||||
|
### B1. 标准路径(分析中起建交付)
|
||||||
|
|
||||||
|
| 时机 | 【交付】描述 |
|
||||||
|
|---|---|
|
||||||
|
| 首次创建起至设计完成前 | 固定文案:`等待设计任务完成后自动填入` |
|
||||||
|
| 设计完成时 | 用 AutoPRD「产品说明」正文替换占位 |
|
||||||
|
|
||||||
|
### B2. 无单快轨建交付(覆盖 B1)
|
||||||
|
|
||||||
|
| 口令/材料 | 【交付】描述 |
|
||||||
|
|---|---|
|
||||||
|
| 手工描述(无指定原型) | **同步需求**当前手工/AutoRDO 正文;禁止占位 |
|
||||||
|
| 指定原型页面 | `$oneos-autoprd` 从原型生成写入;禁止占位 |
|
||||||
|
| 既无正文又无原型 | 才允许占位并标红风险 |
|
||||||
|
|
||||||
|
快轨【设计】描述始终复制需求当前描述正文(见 [fast-track.md](fast-track.md))。
|
||||||
|
|
||||||
|
## C. 需求描述双段模板(不可互相覆盖)
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 原始诉求(AutoRDO)
|
||||||
|
(清洗稿;设计完成也不删除)
|
||||||
|
|
||||||
|
## 产品说明(AutoPRD)
|
||||||
|
(六大块+对象存储链接;未设计完成前可无此节或写「待设计完成后填入」)
|
||||||
|
|
||||||
|
## 工作项编号(系统)
|
||||||
|
- 交付:…
|
||||||
|
- 分析:…
|
||||||
|
- 设计:…
|
||||||
|
```
|
||||||
|
|
||||||
|
## D. 设计完成 · AutoPRD + 附件
|
||||||
|
|
||||||
|
前提:设计任务完成且已关联对应原型页。
|
||||||
|
|
||||||
|
1. 调用 **`$oneos-autoprd`(AutoPRD)**,产出并落盘 `.spec/requirements-prd.md` + 标注同步:
|
||||||
|
- 对象存储预览链接:`{baseUrl}/{prototype-id}/index.html`(禁止加 `prototypes/` 前缀、禁止去掉 `index.html`)
|
||||||
|
- 产品说明 Markdown(总览/角色/流程/状态/风险/交付等,见 AutoPRD 模板)
|
||||||
|
2. 写入需求 `## 产品说明(AutoPRD)`;**禁止覆盖** `## 原始诉求(AutoRDO)` / `## 工作项编号(系统)`。
|
||||||
|
3. 【交付】描述:按**交付任务编号**用产品说明正文**替换**占位(细则见 AutoPRD `references/yunxiao-delivery-sync.md`);可附「原始诉求见需求描述」。**创建【交付】时不得提前灌 MD。**
|
||||||
|
4. 附件(需求 +【交付】均挂;失败则不得声称成功):
|
||||||
|
- Make「导出 HTML(含源码)」ZIP → [make-export-attach.md](make-export-attach.md)
|
||||||
|
- Make「复制截图」全交互页 → 同上
|
||||||
|
|
||||||
|
缺原型 / AutoPRD 失败 / 导出或截图失败 → **不得**报到设计完成并宣称附件齐全;停下并列出缺项。
|
||||||
|
|
||||||
|
执行顺序:先 AutoPRD 落盘与附件就绪 → 再改需求/交付描述与设计计划完成 → 最后改需求状态。
|
||||||
|
|
||||||
|
**禁止**加载 `yunxiao-requirement-lifecycle`;阶段任务树只由本 Skill(YunxiaoPMapp)创建。
|
||||||
47
.cursor/skills/YunxiaoPM/references/fast-track.md
Normal file
47
.cursor/skills/YunxiaoPM/references/fast-track.md
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# 无单快轨到待开发
|
||||||
|
|
||||||
|
适用:口令明确「快轨」或「推进至待开发」且当前需求尚无标准分析路径任务(或用户确认跳过分析)。
|
||||||
|
|
||||||
|
## 动作表
|
||||||
|
|
||||||
|
| 对象 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| 需求 | 状态 → **待开发**;**预计工时=2**、**实际工时=2**(覆盖同日 8h 日历工时默认);标签按口令;更新编号区块 |
|
||||||
|
| 【交付】 | 无则新建;ASSOCIATED→需求(勿用 PARENT);负责人→何斐;**计划开始=创建当日**(`79`);**不写**计划完成;**描述双路径**(见下);**标签与需求相同**;更新编号区块 |
|
||||||
|
| 【设计】 | **必须新建**;**TASK_SUB→交付**(交付「子项」须可见);**描述=复制需求当前描述正文**;计划开始/完成均=当日(create 后 `field/value` 写 `79`+`80`);任务→完成态;**标签与需求相同**;建后再尝试 **ASSOCIATED→原始需求**(Cookie 常失败,见 live-api;失败须标红,**子项优先于关联项**);更新编号区块 |
|
||||||
|
| 【分析】 | **禁止创建** |
|
||||||
|
|
||||||
|
## 交付描述双路径(A1)
|
||||||
|
|
||||||
|
| 口令/材料 | 【交付】描述 |
|
||||||
|
|---|---|
|
||||||
|
| **手工描述**(无指定原型) | 同步需求当前手工/AutoRDO 正文(与设计一致可复制 document) |
|
||||||
|
| **指定原型页面** | 调用 `$oneos-autoprd`,从原型生成 AutoPRD「产品说明」写入【交付】 |
|
||||||
|
| 既无手工可同步正文、又无原型 | 才允许占位 `等待设计任务完成后自动填入`,Plan 勾选交棒占位风险,回报首行标红 |
|
||||||
|
|
||||||
|
有手工或原型时**禁止**交棒占位。
|
||||||
|
|
||||||
|
## AutoPRD
|
||||||
|
|
||||||
|
- 快轨默认可不跑 AutoPRD;**例外**:口令指定原型 → 交付走 AutoPRD 路径(上表)。
|
||||||
|
- 口令同时「设计完成 + 原型」时仍按步骤 4 灌需求产品说明段。
|
||||||
|
|
||||||
|
## 查重
|
||||||
|
|
||||||
|
只认任务编号。已有分析单不得因「快轨」被删除。
|
||||||
|
|
||||||
|
## 回报必含
|
||||||
|
|
||||||
|
- 需求 / 交付 / 设计编号
|
||||||
|
- 「快轨:未建分析;设计已同步需求描述并当日收口」
|
||||||
|
- 交付描述来源:手工同步 / AutoPRD / 占位(若占位则首行标红)
|
||||||
|
- 需求预计工时=2、实际工时=2
|
||||||
|
- 设计关联项含需求编号;交付子项含设计编号
|
||||||
|
|
||||||
|
## 与标准 / 编号直推对比
|
||||||
|
|
||||||
|
```text
|
||||||
|
标准:分析中→交付+分析 → 设计中→设计+收口分析 → 设计完成→收口设计 → 待开发交棒
|
||||||
|
快轨(无既有阶段单):→ 待开发:新建交付+设计+交棒何斐(无分析;设计当日收口;需求工时 2+2)
|
||||||
|
编号直推:已有分析/设计编号 → 收口空计划完成 → 待开发+交付交棒(不新建冗余单)
|
||||||
|
```
|
||||||
20
.cursor/skills/YunxiaoPM/references/handoff-and-rollback.md
Normal file
20
.cursor/skills/YunxiaoPM/references/handoff-and-rollback.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# 交棒门禁与回退最小集
|
||||||
|
|
||||||
|
## 交棒门禁(待开发)
|
||||||
|
|
||||||
|
| 情形 | 规则 |
|
||||||
|
|---|---|
|
||||||
|
| 【交付】描述已是 AutoPRD 正式说明(非占位) | 允许交棒;Plan 正常列交付任务编号 + 负责人→何斐 |
|
||||||
|
| 【交付】描述仍为 `等待设计任务完成后自动填入` | **仍允许交棒**,但 Plan **必须**勾选风险项「交付描述仍为占位,技术侧仅可凭需求 AutoRDO 稿理解」;回报**首行标红**该风险;**禁止**静默交棒假装材料齐全 |
|
||||||
|
| 口令同时带原型且要求设计完成 | 先走步骤 4(AutoPRD+附件)成功,再交棒,不再勾占位风险 |
|
||||||
|
|
||||||
|
## 回退 / 变更(最小集 · 兼容计划开始不篡改)
|
||||||
|
|
||||||
|
| 场景 | 规则 |
|
||||||
|
|---|---|
|
||||||
|
| 待开发 → 退回设计中 | 需求状态回退;【交付】负责人可改回创建人/产品;**交付计划开始不改**;若需重做设计 → **新开**设计任务编号(旧设计保持已收口,不改其计划开始);更新「工作项编号(系统)」中的设计编号为新号 |
|
||||||
|
| 设计完成后需求大变 | 不自动改状态;Plan 询问是否回退设计中并新开设计编号;更新 AutoPRD 段;AutoRDO 段保留并追加「变更纪要」 |
|
||||||
|
| 取消需求 | 关联任务标取消/废止;不删编号区块;不改已写计划开始 |
|
||||||
|
| 度量含义 | 交付计划开始保留 = 全周期仍从首次开工起算;回退重做会拉长日历工时——回报注明「含回退重做」 |
|
||||||
|
|
||||||
|
凡写云效的回退仍须走 Plan 门禁。
|
||||||
14
.cursor/skills/YunxiaoPM/references/handoff-contract.md
Normal file
14
.cursor/skills/YunxiaoPM/references/handoff-contract.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# 交接契约(开发 Skill 入口)
|
||||||
|
|
||||||
|
YunxiaoPMapp 与开发 Skill **不要**互相 include 全文;仅认下列契约。
|
||||||
|
|
||||||
|
```text
|
||||||
|
PM 完成交棒 → 需求=待开发;【交付】任务编号=ONEOS-xx;负责人=何斐;ASSOCIATED 需求
|
||||||
|
若交付描述仍为占位 → 回报已标红风险
|
||||||
|
开发 Skill 入口 → 认「需求编号 + 交付任务编号」
|
||||||
|
占位时只可信需求「原始诉求(AutoRDO)」并有权要求产品补设计完成
|
||||||
|
```
|
||||||
|
|
||||||
|
共享常量(项目 ID、何斐 ID、节假日日历)可引用本 Skill 的 `assets/` 短路径,勿加载整份对方规则。
|
||||||
|
|
||||||
|
测试 Skill 另开;本契约不覆盖提测/缺陷。
|
||||||
242
.cursor/skills/YunxiaoPM/references/live-api.md
Normal file
242
.cursor/skills/YunxiaoPM/references/live-api.md
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
# 云效实写 API(YunxiaoPMapp 已验证)
|
||||||
|
|
||||||
|
`verified_at`: 2026-07-25 · **项目须门禁 PJ 点选**(见 [project-selection.md](project-selection.md));历史验证样本项目为 `01_ONEOS` / 原「统一运营管理平台」(`last_selected.spaceIdentifier` 见 `assets/runtime-ids.json`,禁止未点选即使用)。
|
||||||
|
|
||||||
|
本文件只记**已跑通**的写法;禁止再盲试 `updateStatus` / 错误 `updateFieldValue` POST。
|
||||||
|
|
||||||
|
## 认证
|
||||||
|
|
||||||
|
- Cookie:Chrome 域 `.aliyun.com` / `devops.aliyun.com`(`browser_cookie3` 或 Playwright storage)
|
||||||
|
- Header:`x-xsrf-token` = cookie `XSRF-TOKEN`(URL 解码后)
|
||||||
|
- `Origin` / `Referer`:`https://devops.aliyun.com`
|
||||||
|
|
||||||
|
## 建单
|
||||||
|
|
||||||
|
`POST|PUT /projex/api/workitem/workitem?_input_charset=utf-8`
|
||||||
|
|
||||||
|
创建响应 `result.identifier` / `serialNumber` 即编号真相;**禁止按标题查重**。
|
||||||
|
|
||||||
|
## 改负责人(已通)
|
||||||
|
|
||||||
|
```http
|
||||||
|
PATCH /projex/api/workitem/workitem/{id}?_input_charset=utf-8
|
||||||
|
{"propertyKey":"assignedTo","propertyValue":"<userId>","operateType":"COVER"}
|
||||||
|
```
|
||||||
|
|
||||||
|
交棒:【交付】`propertyValue` = 何斐 ID。
|
||||||
|
|
||||||
|
## 打标签(已通)
|
||||||
|
|
||||||
|
```http
|
||||||
|
PATCH /projex/api/workitem/workitem/{id}?_input_charset=utf-8
|
||||||
|
{"workitemIdentifier":"{id}","propertyKey":"tag","propertyValue":"<tagId>[,<tagId>]","operateType":"COVER"}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 改状态(已通 · 唯一推荐)
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /projex/api/workitem/workitem/{id}/status/transit?_input_charset=utf-8
|
||||||
|
{"fromStatus":"<当前status.identifier>","toStatus":"<目标status.identifier>"}
|
||||||
|
```
|
||||||
|
|
||||||
|
成功:`code=200` 且 `result=true`。失败时 `errorMsg` 含「不能流转」。
|
||||||
|
|
||||||
|
### 需求状态 ID(本项目)
|
||||||
|
|
||||||
|
| 显示名 | identifier |
|
||||||
|
|---|---|
|
||||||
|
| 待处理 | `100005` |
|
||||||
|
| 已确认 | `32` |
|
||||||
|
| 分析中 | `154395` |
|
||||||
|
| 设计中 | `156603` |
|
||||||
|
| 设计完成 | `307012` |
|
||||||
|
| 待开发 | `1582fc929d429111b925309493` |
|
||||||
|
|
||||||
|
### 任务状态 ID
|
||||||
|
|
||||||
|
| 显示名 | identifier |
|
||||||
|
|---|---|
|
||||||
|
| 待处理 | `100005` |
|
||||||
|
| 已完成 | `100014` |
|
||||||
|
|
||||||
|
### 极速交棒跳转(工作流允许)
|
||||||
|
|
||||||
|
从「待处理」菜单可见直达「设计完成」;推荐最少跳:
|
||||||
|
|
||||||
|
```text
|
||||||
|
待处理 → 设计完成 → 待开发
|
||||||
|
```
|
||||||
|
|
||||||
|
标准路径若需看板留痕,可走完整链:已确认→分析中→设计中→设计完成→待开发(仍用本 API,勿开 UI)。
|
||||||
|
|
||||||
|
### 禁止(已证伪)
|
||||||
|
|
||||||
|
| 写法 | 结果 |
|
||||||
|
|---|---|
|
||||||
|
| `PATCH …/updateStatus` + `statusIdentifier` | `400 不能为空` |
|
||||||
|
| `PATCH …/{id}` + `propertyKey=status` | `property not found` |
|
||||||
|
| Playwright 点左侧/列表上的状态色块(`x<1100`) | 假成功、状态不落库 |
|
||||||
|
|
||||||
|
仅当 `status/transit` 不可用时,才用 UI:右侧详情状态钮(`getBoundingClientRect().x > 1100`)+ `.next-menu-item`。
|
||||||
|
|
||||||
|
## 计划开始/完成 · 提交部门/人 · 预计工时(2026-07-27 修订)
|
||||||
|
|
||||||
|
**通用字段写入(已通):**
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /projex/api/workitem/workitem/field/value/{workitemId}?_input_charset=utf-8
|
||||||
|
Content-Type: application/x-www-form-urlencoded
|
||||||
|
|
||||||
|
fieldValueList=[{"fieldIdentifier":"79","value":"2026-07-27 12:00:00"},{"fieldIdentifier":"3132597a9718d1c282b7ba5a0c","value":"业务管理部"},{"fieldIdentifier":"9e01269e96f91fbb97d36bf5b3","value":"何苗苗"}]
|
||||||
|
```
|
||||||
|
|
||||||
|
| 字段 | fieldIdentifier | value |
|
||||||
|
|---|---|---|
|
||||||
|
| 计划开始 | `79` | `YYYY-MM-DD HH:mm:ss`(推荐正午)或 epoch ms 字符串 |
|
||||||
|
| 计划完成 | `80` | 同上 |
|
||||||
|
| 提交部门 | `3132597a9718d1c282b7ba5a0c` | 纯文本 |
|
||||||
|
| 提交人 | `9e01269e96f91fbb97d36bf5b3` | 纯文本 |
|
||||||
|
|
||||||
|
**预计工时 `101586`:禁止直接改字段**(报「不可直接修改」)。须登记:
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /projex/api/workitem/workitem/time/estimate?_input_charset=utf-8
|
||||||
|
{"workitemIdentifier":"<id>","spentTime":8,"type":"develop","description":"阶段日历工时","recordUserIdentifier":"<userId>","forCreate":false,"containsRestDay":false}
|
||||||
|
```
|
||||||
|
|
||||||
|
删除多余预估:`DELETE /projex/api/workitem/workitem/time/estimate/{workitemId}/{estimateId}`
|
||||||
|
列表:`GET …/time/estimate/list?workitemIdentifier=`
|
||||||
|
|
||||||
|
旧写法 `PATCH …/updateWorkitemFieldValue` 对上述自定义字段常 `400 不能为空`,勿再优先使用。
|
||||||
|
|
||||||
|
## 父子 / 子项 / 关联项(已通 · 2026-07-23 修订 · 子项优先)
|
||||||
|
|
||||||
|
### 关联项(【交付】强制 · ASSOCIATED)
|
||||||
|
|
||||||
|
任务详情「关联项」只认 `ASSOCIATED`。**仅【交付】**建单时 `createWorkitemRelationInfo` 必须指向**需求**:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"createWorkitemRelationInfo": {
|
||||||
|
"relatedWorkitemIdentifier": "<需求id>",
|
||||||
|
"relatedToRelationIdentifier": "ASSOCIATED"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
校验:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /projex/api/workitem/v2/workitem/{交付id}/relation/workitem/list/by-relation-category?category=ASSOCIATED&isForward=true
|
||||||
|
```
|
||||||
|
|
||||||
|
`result` 含该需求即通过。
|
||||||
|
|
||||||
|
### 禁止(关联项)
|
||||||
|
|
||||||
|
| 写法 | 结果 |
|
||||||
|
|---|---|
|
||||||
|
| `relatedToRelationIdentifier=PARENT` 把交付挂需求 | 详情可能有 parent,**关联项仍为空** |
|
||||||
|
| 分析/设计只用 `ASSOCIATED→需求` + `parentIdentifier` | 关联项可能有,**交付子项仍为空**(ONEOS-246/247) |
|
||||||
|
| 建后再 `POST …/relation/record` 补关系 | Cookie 路径下常报「不能关联相同的工作项」 |
|
||||||
|
| `createWorkitemRelationList` | 不落 ASSOCIATED |
|
||||||
|
|
||||||
|
### 子项(【分析】/【设计】强制 · TASK_SUB)
|
||||||
|
|
||||||
|
「子项」页读 `PARENT_SUB` / `TASK_SUB`,分析/设计**必须**:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"parent": "<交付id>",
|
||||||
|
"parentIdentifier": "<交付id>",
|
||||||
|
"createWorkitemRelationInfo": {
|
||||||
|
"relatedWorkitemIdentifier": "<交付id>",
|
||||||
|
"relatedToRelationIdentifier": "TASK_SUB"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
同一 create 只能带一条 `createWorkitemRelationInfo`。
|
||||||
|
`ASSOCIATED→需求` 与 `TASK_SUB→交付` **不能同时写**。
|
||||||
|
|
||||||
|
**产品优先级:交付「子项」tab > 阶段任务「关联项」。**
|
||||||
|
交付本身仍必须 `ASSOCIATED→需求`。标准路径下分析/设计的「关联项」允许为空。
|
||||||
|
|
||||||
|
**无单快轨例外(设计双挂):** create 用 `TASK_SUB→交付` 后,须再补 **ASSOCIATED→原始需求**,使设计详情「关联项」可见需求。
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /projex/api/workitem/workitem/{设计id}/relation/record?_input_charset=utf-8
|
||||||
|
{"relationIdentifier":"ASSOCIATED","toWorkitemIdentifier":"<需求id>"}
|
||||||
|
```
|
||||||
|
|
||||||
|
**已证伪(Cookie · 2026-07-27):** 凡工作项**已创建**后再 `relation/record` 补挂(含 ASSOCIATED / TASK_SUB),常报「不能关联相同的工作项」;与是否已有父项无关。`createWorkitemRelationList` 亦不落 ASSOCIATED。
|
||||||
|
**可行路径:**
|
||||||
|
|
||||||
|
| 目标 | 做法 |
|
||||||
|
|---|---|
|
||||||
|
| 交付「子项」可见设计(优先) | create 带 `TASK_SUB→交付` |
|
||||||
|
| 设计「关联项」可见需求 | create 带 `ASSOCIATED→需求`(与上互斥,同 create 只能一条) |
|
||||||
|
| 双挂 | 需个人 `x-yunxiao-token` OpenAPI;Cookie 路径**不得**声称成功 |
|
||||||
|
|
||||||
|
产品默认:**子项优先**;关联项失败须在回报中标红并列出缺项。
|
||||||
|
|
||||||
|
校验子项:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /projex/api/workitem/v2/workitem/{交付id}/relation/workitem/list/by-relation-category?category=PARENT_SUB&isForward=true
|
||||||
|
```
|
||||||
|
|
||||||
|
结果须含对应分析/设计 identifier。
|
||||||
|
|
||||||
|
校验设计关联项:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /projex/api/workitem/v2/workitem/{设计id}/relation/workitem/list/by-relation-category?category=ASSOCIATED&isForward=true
|
||||||
|
```
|
||||||
|
|
||||||
|
`result` 须含原始需求 identifier。
|
||||||
|
|
||||||
|
### 无单快轨字段默认(2026-07-27)
|
||||||
|
|
||||||
|
| 对象 | 规则 |
|
||||||
|
|---|---|
|
||||||
|
| 【设计】描述 | 复制需求 document HTML |
|
||||||
|
| 【设计】`79`/`80` | 当日 `12:00:00` / `23:59:59`,create 后 `field/value`(勿 create 同时带 79+80) |
|
||||||
|
| 【交付】描述 | 手工同步需求正文,或原型→AutoPRD;禁止无故占位 |
|
||||||
|
| 【交付】`79` | 创建当日;不写 `80` |
|
||||||
|
| 【交付】/【设计】标签 | 与需求相同,`PATCH propertyKey=tag` |
|
||||||
|
| 需求预计工时 | `time/estimate` **spentTime=2**(先删多余预估) |
|
||||||
|
| 需求实际工时 | `POST …/workitem/time`,body 用 **`actualTime`**(非 spentTime)+ `gmtStart`/`gmtEnd` epoch ms 字符串;见 `runtime-ids.json` `fields.actual_hours` |
|
||||||
|
| 描述更新 | `PATCH …/workitem/{id}/document`,`{"content":"<html>","formatType":"RICHTEXT"}` |
|
||||||
|
|
||||||
|
## 迭代挂接(已通 · 2026-07-27 · 只挂交付)
|
||||||
|
|
||||||
|
创建迭代:`POST /projex/api/workspace/sprint`(必填 `staffIds`;可写 `capacityHours`)。
|
||||||
|
|
||||||
|
挂【交付】到迭代:
|
||||||
|
|
||||||
|
```http
|
||||||
|
PATCH /projex/api/workitem/workitem/{交付id}?_input_charset=utf-8
|
||||||
|
{"workitemIdentifier":"{交付id}","propertyKey":"sprint","propertyValue":"{sprintId}","operateType":"COVER"}
|
||||||
|
```
|
||||||
|
|
||||||
|
清空误挂(如需求):`propertyValue:""` + `operateType:"COVER"`。
|
||||||
|
|
||||||
|
**校验**必须读 `/extra`(详情主接口常不含 sprint 字段,禁止据此判失败):
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /projex/api/workitem/workitem/{id}/extra?_input_charset=utf-8
|
||||||
|
→ result.sprint[].identifier / name
|
||||||
|
```
|
||||||
|
|
||||||
|
产品规则:**只挂【交付】**;需求 / 分析 / 设计默认不挂(除非口令显式)。
|
||||||
|
|
||||||
|
### 极速建单注意
|
||||||
|
|
||||||
|
1. Cookie 只刷一次;全程纯 HTTP,默认**不开浏览器**。
|
||||||
|
2. 交付建完后,【分析】与【设计】**并行**创建(均 TASK_SUB→交付);标准/快轨两树可并行。
|
||||||
|
3. 状态用 `transit` + **本地追踪 fromStatus**(禁止每次 GET);负责人在交棒场景下**创建时即何斐**。
|
||||||
|
4. 建单 `fieldValueList` 可带计划开始 `79`;**不要**在 create 同时写 `79+80`(同日会 400)。
|
||||||
|
5. 标签必须 PATCH(create 带 tag 不落库);可与建子任务重叠;快轨交付/设计须与需求同标签。
|
||||||
|
6. `requests.Session` keep-alive;**禁止**对共享 opener 加全局锁。
|
||||||
|
7. 脚本入口:`scripts/live_create_fast.py`(v5:快轨描述/计划/标签/工时 2+2/设计 ASSOCIATED 补挂)。
|
||||||
59
.cursor/skills/YunxiaoPM/references/live-perf-2026-07-23.md
Normal file
59
.cursor/skills/YunxiaoPM/references/live-perf-2026-07-23.md
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
# 2026-07-23 真实建单复盘与极速优化
|
||||||
|
|
||||||
|
## 测试结论
|
||||||
|
|
||||||
|
标准 + 快轨均可建到「待开发」交棒;交付树、标签「故障管理」、快轨无【分析】均正确。
|
||||||
|
|
||||||
|
| 轮次 | 编号 |
|
||||||
|
|---|---|
|
||||||
|
| 第一轮(探测+UI) | ONEOS-141~147 |
|
||||||
|
| 极速 v1 | ONEOS-148~154 |
|
||||||
|
| 极速 v2 | ONEOS-164~177(含中间探针) |
|
||||||
|
|
||||||
|
## 过程问题(已修)
|
||||||
|
|
||||||
|
| # | 问题 | 根因 | 修复 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 1 | 状态改不动 / 假成功 | 误用 `updateStatus`;UI 点列表区 | `POST …/status/transit` |
|
||||||
|
| 2 | 负责人改不成 | `updateFieldValue` 错 | `PATCH …/{id}` + `assignedTo` |
|
||||||
|
| 3 | 状态 ID 不全 | 未抓网络 | 写入 `runtime-ids.json` |
|
||||||
|
| 4 | 极慢 | Playwright + 串行探测 | 纯 HTTP + 并行 |
|
||||||
|
| 5 | v1 仍偏慢 | 多余 GET、串行 PATCH 计划、交棒再改负责人 | 见下节 v2 |
|
||||||
|
|
||||||
|
## 性能对比
|
||||||
|
|
||||||
|
| 口径 | 优化前(第一轮) | 极速 v1 | 极速 v2(本轮) |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 会话墙钟 | ≈ **17.9 分钟** | — | — |
|
||||||
|
| 两路径并行建单墙钟 | ≈4.1 分钟自动化 | **4.4 s** | **2.2 s** |
|
||||||
|
| 标准单路径 | 失败反复 | 3.7 s | **2.2 s** |
|
||||||
|
| 快轨单路径 | 失败反复 | 3.7 s | **2.1 s** |
|
||||||
|
| 浏览器 | 多次 | 无 | 无 |
|
||||||
|
|
||||||
|
相对第一轮会话 ≈ **490×**;相对 v1 再快约 **2×**。
|
||||||
|
|
||||||
|
## v2 压榨点(已落地)
|
||||||
|
|
||||||
|
1. `status/transit` **本地追踪** `fromStatus`,跳过每次 GET。
|
||||||
|
2. 建单 `fieldValueList` 带**计划开始(79)**;计划完成不在 create 写(同日会 400)。
|
||||||
|
3. 【交付】创建时负责人直接 **何斐**(省 PATCH)。
|
||||||
|
4. `requests.Session` keep-alive;**去掉全局锁**(否则并行失效)。
|
||||||
|
5. 打标签与建子任务 **重叠**;两路径并行。
|
||||||
|
6. 交棒后汇总用创建响应,校验 GET 移出主路径计时。
|
||||||
|
|
||||||
|
## 探针结论(未采用)
|
||||||
|
|
||||||
|
| 尝试 | 结果 |
|
||||||
|
|---|---|
|
||||||
|
| create `fieldValueList` 带 tag | 建单成功但标签不落库 → 仍须 PATCH |
|
||||||
|
| create 同时写 79+80 | `400 计划…转化异常` |
|
||||||
|
| urllib 全局 lock + 单 opener | 并行被串行化,单路径 ≈4 s |
|
||||||
|
|
||||||
|
## 仍可再压(收益变小)
|
||||||
|
|
||||||
|
1. 标签 API 若将来支持 create 落库,可再少 2~4 次 PATCH。
|
||||||
|
2. HTTP/2 或连接预热(DNS/TLS 复用到进程级)。
|
||||||
|
3. 业务允许「建单即待开发」且平台支持初始状态 → 少 2 次 transit。
|
||||||
|
4. 计划完成改为交棒后异步补写(当前故意跳过)。
|
||||||
|
|
||||||
|
脚本:`scripts/live_create_fast.py`(mode=`live_create_fast_v2`)。
|
||||||
53
.cursor/skills/YunxiaoPM/references/make-export-attach.md
Normal file
53
.cursor/skills/YunxiaoPM/references/make-export-attach.md
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# Make 导出与截图附件
|
||||||
|
|
||||||
|
设计完成(步骤 4)且已关联原型页时:需求与【交付】均挂附件。任一侧失败 → 不得声称设计完成附件齐全。
|
||||||
|
|
||||||
|
## 1. 导出 HTML(含源码)ZIP
|
||||||
|
|
||||||
|
与 Make「发布 → 导出 HTML(含源码)」对齐。
|
||||||
|
|
||||||
|
优先本地 Make Admin:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET {adminOrigin}/api/export-html?path={prototypePath}&projectId={projectId}&includeSource=true
|
||||||
|
```
|
||||||
|
|
||||||
|
| 参数 | 要求 |
|
||||||
|
|---|---|
|
||||||
|
| `path` | 原型路径(如 `prototypes/oneos-h5-vehicle-assets`) |
|
||||||
|
| `includeSource` | **必须** `true` |
|
||||||
|
| 响应 | ZIP(`PK` 头);文件名建议 `{prototype-id}-html-source.zip` |
|
||||||
|
|
||||||
|
失败时:提示用户在 Make 客户端对该原型执行「发布 → 导出 HTML(含源码)」,把 ZIP 路径发回。
|
||||||
|
**禁止**用「仅对象存储链接」冒充已附带源码包。
|
||||||
|
|
||||||
|
## 2. 复制截图(全交互页)
|
||||||
|
|
||||||
|
1. Make「发布 → **复制截图**」(或等价:导出该原型主界面及所有交互页截图)。
|
||||||
|
2. 上传到需求附件与【交付】附件。
|
||||||
|
3. 缺页/失败 → 列出缺项,不得报成功。
|
||||||
|
|
||||||
|
## 3. 挂载范围
|
||||||
|
|
||||||
|
同一 ZIP / 同一批截图:
|
||||||
|
|
||||||
|
1. 上传到需求 identifier
|
||||||
|
2. 上传到【交付】任务 identifier
|
||||||
|
|
||||||
|
优先 API;未知 upload 端点时用已登录浏览器在详情页「附件」上传。
|
||||||
|
|
||||||
|
## 4. 与对象存储的关系
|
||||||
|
|
||||||
|
| 产物 | 用途 |
|
||||||
|
|---|---|
|
||||||
|
| `{baseUrl}/{id}/index.html` | AutoPRD 描述内可点预览链接 |
|
||||||
|
| 导出 ZIP(含源码) | 附件,供开发离线打开 |
|
||||||
|
| 交互页截图 | 附件,供评审/开发对照 |
|
||||||
|
|
||||||
|
三者职责不同,不可互相替代。
|
||||||
|
|
||||||
|
## 负向
|
||||||
|
|
||||||
|
- 不得导出错误原型页(须 Plan 确认原型路径/名称)。
|
||||||
|
- 不得把别的需求的旧 ZIP 复用到新需求。
|
||||||
|
- 快轨交棒默认不跑本附件流程(除非口令同时设计完成+原型)。
|
||||||
60
.cursor/skills/YunxiaoPM/references/model.md
Normal file
60
.cursor/skills/YunxiaoPM/references/model.md
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
# 交付树模型与关联约定
|
||||||
|
|
||||||
|
## 真相源
|
||||||
|
|
||||||
|
```text
|
||||||
|
需求状态 = 阶段看板唯一真相(分析中/设计中/待开发…)
|
||||||
|
【交付】任务 = 该需求的交付容器(每需求最多 1 条)
|
||||||
|
【分析】/【设计】 = YunxiaoPMapp 在交付下建的阶段子项
|
||||||
|
【开发】/【测试】 = 另属开发 Skill / 测试 Skill,不进本包
|
||||||
|
ASSOCIATED = 横向挂钩(【交付】 ↔ 需求)
|
||||||
|
SUB / TASK_SUB = 纵向拆解(交付 → 分析/设计)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 关系验收
|
||||||
|
|
||||||
|
| 关系 | 用在哪里 | 验收 | 优先级 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| ASSOCIATED | **仅【交付】** ↔ 需求 | 交付详情「关联项」能看到需求(**强制**) | 交付必过 |
|
||||||
|
| TASK_SUB | 【分析】/【设计】 → 【交付】 | 交付详情「子项」能看到阶段任务(**强制**) | 阶段任务必过 |
|
||||||
|
|
||||||
|
建单规则(Cookie 路径 · 同一 create 只能一条 `createWorkitemRelationInfo`):
|
||||||
|
|
||||||
|
| 对象 | `createWorkitemRelationInfo` | 另写字段 |
|
||||||
|
|---|---|---|
|
||||||
|
| 【交付】 | `ASSOCIATED` → 需求 | — |
|
||||||
|
| 【分析】/【设计】 | `TASK_SUB` → 交付 | `parent` + `parentIdentifier` = 交付 |
|
||||||
|
|
||||||
|
**禁止**对分析/设计只写 `parentIdentifier` + `ASSOCIATED→需求`:关联项可能有,但交付「子项」仍为空(ONEOS-246/247 已复现)。
|
||||||
|
勿用 `PARENT` 冒充关联项。细则见 [live-api.md](live-api.md)。
|
||||||
|
|
||||||
|
## 禁止
|
||||||
|
|
||||||
|
| 禁止 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| 创建或描述【开发】/【测试】 | 口令与回报均不出现 |
|
||||||
|
| 分析/设计未挂成交付子项(无 TASK_SUB) | 交付「子项」为 0,交棒验收失败 |
|
||||||
|
| 用任务名称/标题做唯一性或查重 | 不得 `subject` 匹配复用 |
|
||||||
|
| 同一需求认定多个交付任务编号 | 列出编号请人合并后再继续 |
|
||||||
|
| 功能模块标签用「分析/设计/交付」 | 模块标签打在需求(可选交付)上 |
|
||||||
|
|
||||||
|
## 任务标题(仅展示)
|
||||||
|
|
||||||
|
- 【交付】+ 需求标题
|
||||||
|
- 【分析】+ 需求标题
|
||||||
|
- 【设计】+ 需求标题
|
||||||
|
|
||||||
|
标题可改,**不参与查重**。
|
||||||
|
|
||||||
|
## 任务编号唯一性
|
||||||
|
|
||||||
|
**唯一允许的查重/复用渠道:云效任务编号**(如 `ONEOS-99` / `serialNumber`)。
|
||||||
|
|
||||||
|
| 场景 | 正确 | 错误 |
|
||||||
|
|---|---|---|
|
||||||
|
| 首次创建【交付】 | 建单成功后回报并写入「工作项编号(系统)」 | 下次用标题搜 |
|
||||||
|
| 复用【交付】 | 口令或编号区块带 `交付任务=ONEOS-xx` | list 后按 subject 相等 |
|
||||||
|
| 判断是否已有交付 | 编号区块或交付 ASSOCIATED 编号集合 | 数【交付】开头标题 |
|
||||||
|
| 分析/设计幂等 | 仅已登记编号 | 按【分析】+需求标题 |
|
||||||
|
|
||||||
|
按编号命中则复用;**计划开始已有值禁止改写**。
|
||||||
35
.cursor/skills/YunxiaoPM/references/number-push.md
Normal file
35
.cursor/skills/YunxiaoPM/references/number-push.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# 编号直推到待开发
|
||||||
|
|
||||||
|
适用:标准路径已建过【分析】和/或【设计】,用**任务编号**一口气推到待开发交棒。
|
||||||
|
|
||||||
|
## 入口(只认编号)
|
||||||
|
|
||||||
|
```text
|
||||||
|
交棒开发:需求=ONEOS-xx;交付任务=ONEOS-a;分析任务=ONEOS-b;设计任务=ONEOS-c
|
||||||
|
交棒开发:分析任务=ONEOS-b → 由分析 ASSOCIATED/SUB 反查需求与交付
|
||||||
|
交棒开发:设计任务=ONEOS-c → 同上反查
|
||||||
|
```
|
||||||
|
|
||||||
|
禁止用标题猜。编号对不上关联树 → 停下列出关联,不瞎改。
|
||||||
|
|
||||||
|
## 动作表
|
||||||
|
|
||||||
|
| 对象 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| 需求 | 状态 → **待开发**(按云效连跳) |
|
||||||
|
| 【交付】 | **必须**用交付任务编号定位;负责人→何斐;不改计划开始;不写计划完成;描述仍占位则保持(除非同时设计完成+原型+AutoPRD) |
|
||||||
|
| 【分析】 | 若有编号:计划完成若为空 → 写当日并推工时;**不新建**第二条 |
|
||||||
|
| 【设计】 | 若有编号:计划完成若为空 → 写当日并推工时;**不新建**第二条 |
|
||||||
|
| 仅有分析、尚无设计 | **不强制补建【设计】**(与无单快轨区分);回报注明「无设计任务编号」 |
|
||||||
|
| 仅有设计、无分析 | 收口设计 + 交棒;**不补建分析** |
|
||||||
|
|
||||||
|
## 与无单快轨区别
|
||||||
|
|
||||||
|
| | 无单快轨 | 编号直推 |
|
||||||
|
|---|---|---|
|
||||||
|
| 前提 | 尚无分析/设计阶段单(或明确跳过分析) | 已有分析和/或设计**任务编号** |
|
||||||
|
| 【分析】 | 禁止创建 | 有编号则收口,无则不建 |
|
||||||
|
| 【设计】 | 必须新建且当日收口 | 有编号则收口;仅分析无设计时不强制新建 |
|
||||||
|
| 定位 | 新建后登记编号 | **仅任务编号**定位/反查 |
|
||||||
|
|
||||||
|
仍不创建【开发】/【测试】。交棒占位风险见 [handoff-and-rollback.md](handoff-and-rollback.md)。
|
||||||
73
.cursor/skills/YunxiaoPM/references/project-selection.md
Normal file
73
.cursor/skills/YunxiaoPM/references/project-selection.md
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
# 门禁 PJ · 云效项目选择(强制点选)
|
||||||
|
|
||||||
|
凡 **新建需求 / 新建任务树 / 创建迭代 / 其它写入依赖 `spaceIdentifier`** 的操作,项目必须由用户从云效实时列表**点选**。禁止静默使用 `runtime-ids.json` 里的默认 `project.spaceIdentifier`。
|
||||||
|
|
||||||
|
## 何时触发
|
||||||
|
|
||||||
|
| 场景 | 是否必须选项目 |
|
||||||
|
|---|---|
|
||||||
|
| 记录需求 / 无单快轨新建 | **必须** |
|
||||||
|
| 创建迭代(新挂项目空间) | **必须**(与需求同项目时沿用已锁定项,仍须在 Plan 写出项目名+ID) |
|
||||||
|
| 仅推进已有编号(受理确认、开始分析…) | **不必重选**;以该编号所在项目为准,Plan 写出项目名 |
|
||||||
|
| 只读查询 | 不强制 |
|
||||||
|
|
||||||
|
## 执行顺序(建单前)
|
||||||
|
|
||||||
|
1. **实时拉取**云效项目列表(Cookie + XSRF):
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /projex/api/workspace/project/search/list
|
||||||
|
?category=Project&scope=all&toPage=1&pageSize=100
|
||||||
|
&conditions={"conditionGroups":[[]]}
|
||||||
|
&extraConditions=…(可与页面一致:当前用户参与 + public)
|
||||||
|
&orderBy={"fieldIdentifier":"gmtCreate","format":"input","order":"desc","className":"date"}
|
||||||
|
&_input_charset=utf-8
|
||||||
|
```
|
||||||
|
|
||||||
|
2. 将结果整理为单选列表:`{name}({customCode})`;选项 id 用 `identifier`(spaceId)。
|
||||||
|
3. **AskQuestion / Plan 单选**「PJ. 云效项目」;未点选 → **禁止 create**。
|
||||||
|
4. 「批准 Plan」≠ 已选项目;Plan 里仍是空选项或写「默认 01_ONEOS」而未点选 → 停。
|
||||||
|
5. 用户点选后:本轮 apply 全程使用该 `spaceIdentifier`;回报写清项目名 + customCode + spaceId。
|
||||||
|
6. 拉取成功后可回写 `assets/runtime-ids.json` → `projects_catalog`(缓存);**缓存不得当作已选项**。
|
||||||
|
|
||||||
|
## 无法对应 → 自动重拉一次
|
||||||
|
|
||||||
|
「无法对应」任一成立即触发:
|
||||||
|
|
||||||
|
| # | 情形 |
|
||||||
|
|---|---|
|
||||||
|
| 1 | 口令/预填的项目名、customCode、别名在**当前列表**中 0 命中 |
|
||||||
|
| 2 | 口令给出的 spaceId / identifier 不在当前列表 |
|
||||||
|
| 3 | 用户点选的选项 id 在 apply 前校验时已不在列表(列表过期) |
|
||||||
|
| 4 | 仅命中 `projects_catalog` 缓存、与本次实时列表不一致 |
|
||||||
|
| 5 | 首次拉取失败后改用了缓存,用户按缓存点选后 create 报项目/空间无效 |
|
||||||
|
|
||||||
|
**动作(固定一次):**
|
||||||
|
|
||||||
|
1. **立即再调一次**同一 `project/search/list`(强制网络,不用缓存)。
|
||||||
|
2. 用新列表重新做匹配 / 刷新 Plan 单选选项;可回写 `projects_catalog`。
|
||||||
|
3. 回报注明:`已自动重拉项目列表(因无法对应)`。
|
||||||
|
4. **仍无法对应** → 停,展示最新列表请用户重选;**禁止**再自动拉第 3 次;**禁止**猜一个 spaceId 继续建单。
|
||||||
|
|
||||||
|
匹配规则(名/码):忽略大小写;`name` 全等或包含;`customCode` 全等;`name_aliases` 全等。多命中视为无法唯一对应 → 重拉后仍多命中则请用户点选,不自动选定。
|
||||||
|
|
||||||
|
## 禁止
|
||||||
|
|
||||||
|
- 未询问就写入 `project.spaceIdentifier`(即便 catalog 标了 `suggested`)
|
||||||
|
- 按口令里的「统一运营管理平台」字符串静默映射而不展示列表点选(口令仅作**预填建议**,仍须用户确认点选)
|
||||||
|
- API 失败时擅自沿用上次默认;应展示 `projects_catalog` 缓存并标明「离线缓存,请确认」,仍须点选;用户确认后若仍无法对应 → 走上一节「自动重拉一次」
|
||||||
|
- 多项目并行建单却共用一个未确认的 spaceId
|
||||||
|
- 「无法对应」时循环重拉超过 1 次,或跳过点选直接建单
|
||||||
|
|
||||||
|
## 口令预填
|
||||||
|
|
||||||
|
```text
|
||||||
|
记录需求:…;项目=01_ONEOS;…
|
||||||
|
```
|
||||||
|
|
||||||
|
若口令已含项目名/编号前缀且在实时列表中**唯一命中**:Plan 可预勾该选项,但仍须用户确认;0 命中或多命中 → **先自动重拉一次**再匹配;仍 0/多 → 不预勾,只展示最新列表。
|
||||||
|
|
||||||
|
## 脚本
|
||||||
|
|
||||||
|
`scripts/list_projects.py`:stdout JSON `projects[]`。
|
||||||
|
带查询时:`python3 scripts/list_projects.py --match '01_ONEOS'` —— 0 命中/多命中则自动重拉一次再匹配(`refetched: true`)。
|
||||||
58
.cursor/skills/YunxiaoPM/references/record-meta-fields.md
Normal file
58
.cursor/skills/YunxiaoPM/references/record-meta-fields.md
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# 记录需求 · 元字段(优先级 / 标签 / 提交部门 / 提交人)
|
||||||
|
|
||||||
|
建单前消费网页 / AutoRDO / 口令中的四类元信息。细则与 `assets/runtime-ids.json` 对齐;**禁止臆造未验证的 fieldIdentifier**。
|
||||||
|
|
||||||
|
## 口令形态
|
||||||
|
|
||||||
|
```text
|
||||||
|
记录需求:…;优先级=紧急|高|中|低;标签=…;提交部门=…;提交人=…;推进至=…
|
||||||
|
```
|
||||||
|
|
||||||
|
四字段均可选出现;网页或 AutoRDO 提示里已带的值与口令等价。
|
||||||
|
|
||||||
|
## Plan 是否追问
|
||||||
|
|
||||||
|
记录需求 **一律**走 [compact-select.md](compact-select.md) 字母表(类型/项目/优先级/标签),即使用户口令已写齐;给出建议压缩串,等用户回 `1a2b3a4d`(或改字母)并「执行」。
|
||||||
|
|
||||||
|
| 条件 | 行为 |
|
||||||
|
|---|---|
|
||||||
|
| 口令已含类型/项目/优先级/标签 | 对应选项标 ★ + 建议压缩串;**仍须**压缩确认或显式点选 |
|
||||||
|
| 标签名 0 命中 / 多命中 | **自动重拉一次**标签候选并重生 4.A/B/C…;仍失败则停 |
|
||||||
|
| 仅缺提交部门/提交人 | 压缩 1–4 确认后,缺则追问或写入描述页脚 |
|
||||||
|
| 仅缺「推进至」等 | 按既有口令规则;可作 5. 题字母表 |
|
||||||
|
|
||||||
|
## 写入策略
|
||||||
|
|
||||||
|
### 优先级(已验证)
|
||||||
|
|
||||||
|
- 映射:`runtime-ids.json` → `priority`(紧急 / 高 / 中 / 低)。
|
||||||
|
- create 时写入 `fieldIdentifier: "priority"`(与 [live-api.md](live-api.md) / `live_create_fast.py` 一致)。
|
||||||
|
- 未给优先级时:Plan 追问;脚本默认「中」仅作既有兜底,口令/网页有值时以用户值为准。
|
||||||
|
|
||||||
|
### 标签(已验证)
|
||||||
|
|
||||||
|
- 映射:`runtime-ids.json` → `tags`(按显示名取 tagId)。
|
||||||
|
- 标签须 **PATCH** `propertyKey: "tag"`(create 带 tag 不落库)。
|
||||||
|
- 口令/网页给出的标签名若不在候选:按 [compact-select.md](compact-select.md) **自动重拉一次**标签列表并重生选项;仍无则停在 Plan,勿猜 ID。
|
||||||
|
|
||||||
|
### 提交部门 / 提交人(已验证 · 2026-07-27 · ONEOS-293)
|
||||||
|
|
||||||
|
| 字段 | fieldIdentifier |
|
||||||
|
|---|---|
|
||||||
|
| 提交部门 | `3132597a9718d1c282b7ba5a0c` |
|
||||||
|
| 提交人 | `9e01269e96f91fbb97d36bf5b3` |
|
||||||
|
|
||||||
|
| 规则 | 说明 |
|
||||||
|
|---|---|
|
||||||
|
| **写入** | `POST /projex/api/workitem/workitem/field/value/{workitemId}`,`Content-Type: application/x-www-form-urlencoded`,参数 `fieldValueList` = JSON 数组字符串 `[{"fieldIdentifier","value"}]` |
|
||||||
|
| **形态** | 均为普通文本 input(非人员选择器);口令值原样写入 |
|
||||||
|
| **页脚** | 仍可在描述页脚重复一份,便于检索;**不能替代**字段写入 |
|
||||||
|
| **计划开始** | 字段 `79`,同一 `field/value` API;推荐 `YYYY-MM-DD 12:00:00`。快轨:【交付】/【设计】创建当日写入;【设计】另写计划完成 `80`=`当日 23:59:59` |
|
||||||
|
| **预计工时** | 字段 `101586` **禁止**直接 PATCH;用 `POST …/time/estimate`(`spentTime`)登记;删多余用 `DELETE …/time/estimate/{workitemId}/{estimateId}` |
|
||||||
|
| **实际工时** | `POST …/workitem/time`,body **`actualTime`**(非 spentTime)+ `gmtStart`/`gmtEnd`(epoch ms 字符串);快轨待开发需求默认 **2** |
|
||||||
|
| **描述更新** | `PATCH …/workitem/{id}/document`,`{"content","formatType":"RICHTEXT"}` |
|
||||||
|
| **快轨标签** | 【交付】【设计】建单后 `PATCH propertyKey=tag`,`propertyValue` 与需求 tagId 一致(多标签逗号拼接) |
|
||||||
|
|
||||||
|
## 与描述双段的关系
|
||||||
|
|
||||||
|
页脚元信息写在「原始诉求」段末或整篇描述末尾均可,**不得覆盖** `## 产品说明(AutoPRD)` / `## 工作项编号(系统)` 区块(见 [description-split.md](description-split.md))。
|
||||||
63
.cursor/skills/YunxiaoPM/references/sprint.md
Normal file
63
.cursor/skills/YunxiaoPM/references/sprint.md
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# 创建迭代并关联交付
|
||||||
|
|
||||||
|
产品经理可将已交棒(或已有编号)的多条【交付】任务打进同一云效迭代。
|
||||||
|
|
||||||
|
## 口令
|
||||||
|
|
||||||
|
```text
|
||||||
|
创建迭代:版本类型=副;交付任务=ONEOS-a,ONEOS-b,ONEOS-c;名称前缀=统一运营管理平台PC端
|
||||||
|
创建迭代:版本类型=子;交付任务=ONEOS-99;名称前缀=统一运营管理平台PC端
|
||||||
|
```
|
||||||
|
|
||||||
|
| 参数 | 规则 |
|
||||||
|
|---|---|
|
||||||
|
| 交付任务 | **1..N 个任务编号**(逗号分隔);禁止用标题凑数 |
|
||||||
|
| 版本类型 | 主 / 副 / 子;未点选则停下询问,禁止默认猜 |
|
||||||
|
| 名称前缀 | 可选;缺省 `统一运营管理平台PC端`。最终名=`{前缀}{版本号}` |
|
||||||
|
|
||||||
|
## 版本号 `V{主}.{副}.{子}`
|
||||||
|
|
||||||
|
| 版本类型 | 含义 | 递增 |
|
||||||
|
|---|---|---|
|
||||||
|
| **主** | 功能重制 | 主+1,副→0,子→0(V1.3.2→V2.0.0) |
|
||||||
|
| **副** | 新功能上线 | 副+1,子→0(V1.3.2→V1.4.0) |
|
||||||
|
| **子** | bug/优化 | 子+1(V1.3.2→V1.3.3) |
|
||||||
|
|
||||||
|
### 取基线再递增
|
||||||
|
|
||||||
|
1. 拉取当前项目云效迭代列表。
|
||||||
|
2. 从迭代**名称**解析 `V数字.数字.数字`;旧名 `V数字.数字` 视为 `.0`。
|
||||||
|
3. 同名称前缀内取**最大**版本为基线(主→副→子比较);避免 PC 与小程序串号。
|
||||||
|
4. 按用户点选类型递增,写入新迭代名称。
|
||||||
|
5. 无一可解析版本:基线 `V0.0.0` 再递增(主→V1.0.0,副→V0.1.0,子→V0.0.1);或口令显式给起始版本。
|
||||||
|
|
||||||
|
禁止:手填与规则冲突的版本号却声称自动生成;禁止用交付标题推断版本类型。
|
||||||
|
|
||||||
|
## 创建与关联
|
||||||
|
|
||||||
|
| 步骤 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| 1 | 算出新版本 → 拼迭代全名 |
|
||||||
|
| 2 | 创建迭代(起止日期口令未给则询问或用项目默认,禁止瞎填) |
|
||||||
|
| 3 | **只挂【交付】**:N 个交付任务挂迭代;交付失败不得报完成 |
|
||||||
|
| 4 | 幂等:同名迭代已存在 → 不新建,补挂尚未关联的交付,回报「复用迭代」 |
|
||||||
|
| 5 | 回报:迭代名、版本号、identifier、已关联交付编号、失败编号 |
|
||||||
|
|
||||||
|
**禁止**把需求挂进迭代(需求侧「迭代」字段保持空)。不挂【分析】/【设计】除非口令显式点名。
|
||||||
|
**不**在本步创建【开发】/【测试】。仍须 Plan 门禁。
|
||||||
|
|
||||||
|
### 挂接 API(已通 · 校验走 `/extra`)
|
||||||
|
|
||||||
|
```http
|
||||||
|
PATCH /projex/api/workitem/workitem/{交付id}?_input_charset=utf-8
|
||||||
|
{"workitemIdentifier":"{交付id}","propertyKey":"sprint","propertyValue":"{sprintId}","operateType":"COVER"}
|
||||||
|
```
|
||||||
|
|
||||||
|
校验(详情主接口**不**含 sprint,勿用其判空):
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /projex/api/workitem/workitem/{id}/extra?_input_charset=utf-8
|
||||||
|
→ result.sprint[].identifier
|
||||||
|
```
|
||||||
|
|
||||||
|
清空误挂的需求迭代:同上 PATCH,`propertyValue:""` + `operateType:"COVER"`(或 `CLEAR`)。
|
||||||
63
.cursor/skills/YunxiaoPM/references/stage-flow.md
Normal file
63
.cursor/skills/YunxiaoPM/references/stage-flow.md
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# 标准路径:待处理 → 待开发交棒
|
||||||
|
|
||||||
|
人员/状态等常量见 [../assets/runtime-ids.json](../assets/runtime-ids.json)。**项目空间**须按 [project-selection.md](project-selection.md) 点选,禁止默认直指。查重只用任务编号。
|
||||||
|
|
||||||
|
## 步骤 0|创建需求
|
||||||
|
|
||||||
|
| 云效动作 | 落地 |
|
||||||
|
|---|---|
|
||||||
|
| 新建产品类需求 | POST 建单;标题 `【新增】`/`【优化】` |
|
||||||
|
| 需求描述 | **先** AutoRDO 清洗再写入 `## 原始诉求(AutoRDO)`;本步不写 AutoPRD |
|
||||||
|
| 默认状态 | **待处理**;不建任务、不改负责人 |
|
||||||
|
| 可选推进 | 口令点选目标状态;未选则停在待处理 |
|
||||||
|
|
||||||
|
## 步骤 1|受理 → 已确认
|
||||||
|
|
||||||
|
| 云效动作 | 落地 |
|
||||||
|
|---|---|
|
||||||
|
| 状态 | 待处理 → **已确认** |
|
||||||
|
| 任务 | **仍不建**交付/分析/设计 |
|
||||||
|
|
||||||
|
若用户只「创建」未受理:只提示「受理后请推进至已确认」,不自动跳。
|
||||||
|
|
||||||
|
## 步骤 2|分析中
|
||||||
|
|
||||||
|
| 对象 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| 【交付】 | 无则新建;标题 `【交付】`+需求标题;**ASSOCIATED→需求**(勿用 PARENT);负责人=创建人/产品;**计划开始仅空时写当日**;不写计划完成;描述=`等待设计任务完成后自动填入`;更新编号区块 |
|
||||||
|
| 【分析】 | 新建;**TASK_SUB→交付**(`parent`+`parentIdentifier`+`createWorkitemRelationInfo=TASK_SUB`);交付「子项」须可见;计划开始=当日(仅空时);负责人默认可=创建人;更新编号区块 |
|
||||||
|
|
||||||
|
| 需求 | 状态=`分析中` |
|
||||||
|
|
||||||
|
## 步骤 3|设计中
|
||||||
|
|
||||||
|
| 对象 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| 【交付】 | 已存在则按编号复用;没有则补建;**不改交付计划开始**;不写交付计划完成 |
|
||||||
|
| 【设计】 | 新建;**TASK_SUB→交付**(同分析);计划开始=当日(仅空时);更新编号区块 |
|
||||||
|
| 【分析】 | **计划完成**=状态更新日;推算阶段日历工时(见 work-hours) |
|
||||||
|
| 需求 | 状态=`设计中` |
|
||||||
|
|
||||||
|
## 步骤 4|设计完成
|
||||||
|
|
||||||
|
| 对象 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| 【设计】 | 计划完成=当日;推算工时;任务→完成态 |
|
||||||
|
| 需求 | AutoPRD 写入 `## 产品说明`;挂 ZIP+截图;状态=`设计完成` |
|
||||||
|
| 【交付】 | 不换负责人;不改计划开始;不写计划完成;描述改为 AutoPRD 正文;同样挂附件 |
|
||||||
|
|
||||||
|
顺序与失败门禁见 [description-split.md](description-split.md)。
|
||||||
|
|
||||||
|
## 步骤 5|待开发交棒(本 Skill 终点 · 标准路径)
|
||||||
|
|
||||||
|
| 对象 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| 需求 | 状态=`待开发` |
|
||||||
|
| 【交付】 | 按**任务编号**定位;**负责人→何斐**;不改计划开始;不写计划完成 |
|
||||||
|
| 【分析】/【设计】 | 不新建;不改已有计划开始;前序未收口按步骤 3/4 处理 |
|
||||||
|
|
||||||
|
执行 [handoff-and-rollback.md](handoff-and-rollback.md) §交棒门禁。
|
||||||
|
|
||||||
|
**不做:** 【开发】/【测试】、仓库、分支、提测。
|
||||||
|
|
||||||
|
快轨 / 编号直推见专文。创建迭代见 [sprint.md](sprint.md)。
|
||||||
73
.cursor/skills/YunxiaoPM/references/work-hours.md
Normal file
73
.cursor/skills/YunxiaoPM/references/work-hours.md
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
# 计划时间与阶段日历工时
|
||||||
|
|
||||||
|
适用于【交付】/【分析】/【设计】统一口径。
|
||||||
|
|
||||||
|
## 用途
|
||||||
|
|
||||||
|
| 对象 | 计划开始→计划完成 |
|
||||||
|
|---|---|
|
||||||
|
| 【交付】 | 需求开工→上线全周期(本 Skill **不**写交付计划完成;上线由后续段) |
|
||||||
|
| 【分析】 | 分析阶段时长 |
|
||||||
|
| 【设计】 | 设计阶段时长 |
|
||||||
|
|
||||||
|
## 计划开始(不可篡改)
|
||||||
|
|
||||||
|
| 对象 | 首次写入 | 之后 |
|
||||||
|
|---|---|---|
|
||||||
|
| 【交付】 | 首次进入分析中且字段为空 → 当日 | **禁止覆盖** |
|
||||||
|
| 【分析】 | 首次创建且为空 → 当日 | **禁止覆盖** |
|
||||||
|
| 【设计】 | 首次创建且为空 → 当日 | **禁止覆盖** |
|
||||||
|
|
||||||
|
日期写入形态:中国时区正午 epoch ms 字符串,见 [../assets/runtime-ids.json](../assets/runtime-ids.json) `fields.plan_start`。
|
||||||
|
|
||||||
|
## 计划完成
|
||||||
|
|
||||||
|
| 环节 | 写计划完成的对象 |
|
||||||
|
|---|---|
|
||||||
|
| 推进到设计中 | 【分析】= 状态更新日 |
|
||||||
|
| 推进到设计完成 | 【设计】= 状态更新日 |
|
||||||
|
| 无单快轨建设计 | 【设计】= 当日(同轮收口) |
|
||||||
|
| 编号直推收口 | 口令涉及的分析/设计若计划完成为空 → 当日 |
|
||||||
|
| 上线/关闭 | 【交付】计划完成(**本 Skill 暂不写**) |
|
||||||
|
|
||||||
|
## 预计工时 = 阶段日历工时(Lead Time)
|
||||||
|
|
||||||
|
有计划完成且已有计划开始时,写入该对象云效「预计工时」:
|
||||||
|
|
||||||
|
```text
|
||||||
|
workdays = 0
|
||||||
|
从计划开始日到计划完成日(含首尾)逐日:
|
||||||
|
周六或周日 → 跳过(除非该日是调休补班)
|
||||||
|
法定放假日 → 跳过
|
||||||
|
调休补班日(含周末上班)→ 计入
|
||||||
|
其余周一~周五 → 计入
|
||||||
|
预计工时(小时) = workdays × 8
|
||||||
|
```
|
||||||
|
|
||||||
|
**禁止**用「(结束日 − 开始日 + 1)× 8」日历天数算法。
|
||||||
|
|
||||||
|
### 语义与脚注(强制)
|
||||||
|
|
||||||
|
- 正式名称:**阶段日历工时**,**不是**投入人天/排期负荷。
|
||||||
|
- 任务描述末尾固定脚注:
|
||||||
|
`【系统】预计工时=阶段日历工时(工作日×8),非人力投入预估`
|
||||||
|
- 回报写「阶段日历工时 Hh」,**禁止**写「需投入 Hh」。
|
||||||
|
- 本 Skill **不自动写**「人力投入预估」。
|
||||||
|
|
||||||
|
### 日历数据源
|
||||||
|
|
||||||
|
- 使用 [../assets/cn-workday-calendar.json](../assets/cn-workday-calendar.json)(按自然年;跨年须覆盖起止两侧年份)。
|
||||||
|
- 缺当年日历 → **停下**提示补日历;**禁止**静默按「仅去周末」算完并报成功。
|
||||||
|
- 计算脚本:[../scripts/workday_hours.py](../scripts/workday_hours.py)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 scripts/workday_hours.py 2026-03-06 2026-03-09
|
||||||
|
```
|
||||||
|
|
||||||
|
缺计划开始则只写结束、不推工时,回报提示。
|
||||||
|
|
||||||
|
## 示例
|
||||||
|
|
||||||
|
- 开始=周五、结束=下周一(无节假日)→ 五+一 → 16h
|
||||||
|
- 区间全在法定放假内 → 0h
|
||||||
|
- 某周日为调休补班且落在区间内 → 该日计入 8h
|
||||||
22
.cursor/skills/YunxiaoPM/references/workitem-ids.md
Normal file
22
.cursor/skills/YunxiaoPM/references/workitem-ids.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# 工作项编号(系统)
|
||||||
|
|
||||||
|
## 权威源
|
||||||
|
|
||||||
|
需求描述固定区块(机器可解析;人工只读即可):
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 工作项编号(系统)
|
||||||
|
- 交付:ONEOS-xx
|
||||||
|
- 分析:ONEOS-yy(无则写无)
|
||||||
|
- 设计:ONEOS-zz(无则写无)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 规则
|
||||||
|
|
||||||
|
1. **禁止**仅靠本地会话映射当唯一真相。
|
||||||
|
2. 每次新建/登记交付·分析·设计编号后,**立即 PATCH 更新该区块**(只改本区块,不动 AutoRDO / AutoPRD 正文)。
|
||||||
|
3. 操作顺序:口令显式编号 > 读本区块 > ASSOCIATED/SUB 反查校验。
|
||||||
|
4. 三者冲突 → 停下人工;**仍禁止按标题猜**。
|
||||||
|
5. 本地缓存仅加速,启动以云效该区块为准。
|
||||||
|
6. 区块出现两个交付编号 → 停止并列号请人合并。
|
||||||
|
7. 取消需求:关联任务标取消/废止;**不删**本区块(留痕)。
|
||||||
221
.cursor/skills/YunxiaoPM/runtime-ids.json
Normal file
221
.cursor/skills/YunxiaoPM/runtime-ids.json
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"skill": "YunxiaoPM",
|
||||||
|
"verified_at": "2026-07-25",
|
||||||
|
"note": "YunxiaoPM constants. Project space MUST be user-selected (PJ gate); project.spaceIdentifier is last-known cache only — never auto-apply. See references/project-selection.md.",
|
||||||
|
"project": {
|
||||||
|
"selection_mode": "user_pick_required",
|
||||||
|
"name": null,
|
||||||
|
"name_aliases": [
|
||||||
|
"01_ONEOS",
|
||||||
|
"ONEOS",
|
||||||
|
"统一运营管理平台",
|
||||||
|
"统一运营管理平台PC端",
|
||||||
|
"统一运营管理平台 PC 端"
|
||||||
|
],
|
||||||
|
"spaceIdentifier": null,
|
||||||
|
"customCode": null,
|
||||||
|
"spaceType": "Project",
|
||||||
|
"organizationIdentifier": "697c54a19df7fdfa65466405",
|
||||||
|
"default_sprint_name_prefix": "统一运营管理平台PC端",
|
||||||
|
"list_api": "GET /projex/api/workspace/project/search/list",
|
||||||
|
"last_selected": {
|
||||||
|
"name": "01_ONEOS",
|
||||||
|
"spaceIdentifier": "1280be963a5a2cc126a4118dca",
|
||||||
|
"customCode": "ONEOS",
|
||||||
|
"note": "历史常用项;仅作预填建议,禁止未点选即使用"
|
||||||
|
},
|
||||||
|
"refreshed_at": "2026-07-25"
|
||||||
|
},
|
||||||
|
"projects_catalog": [
|
||||||
|
{
|
||||||
|
"name": "05_羚牛碳资产平台",
|
||||||
|
"identifier": "ff104a3bce09463da136a97999",
|
||||||
|
"customCode": "CARBON"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "06_对外客户项目",
|
||||||
|
"identifier": "baca8b4d676c5af67e475caec0",
|
||||||
|
"customCode": "CUST"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "07_LNBOX",
|
||||||
|
"identifier": "35e1e915a052379bbdfb993aac",
|
||||||
|
"customCode": "LNBOX"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "04_AI应用",
|
||||||
|
"identifier": "d9002ea72c6c3a1a97b02be750",
|
||||||
|
"customCode": "AIAPP"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "03_数据中台",
|
||||||
|
"identifier": "a801cef5c9a68fa051c07432c7",
|
||||||
|
"customCode": "DATA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "02_小羚羚APP",
|
||||||
|
"identifier": "db771a2cca07bed43b369af077",
|
||||||
|
"customCode": "XLLAPP"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "01_ONEOS",
|
||||||
|
"identifier": "1280be963a5a2cc126a4118dca",
|
||||||
|
"customCode": "ONEOS"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "敏捷研发示例项目",
|
||||||
|
"identifier": "65eca0c2e16a23939081e19e14",
|
||||||
|
"customCode": "DEMO"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"people": {
|
||||||
|
"wangmian": {
|
||||||
|
"displayName": "王冕",
|
||||||
|
"identifier": "6811df000601d2fea60144a9",
|
||||||
|
"role": "产品创建人/默认负责人"
|
||||||
|
},
|
||||||
|
"hefei": {
|
||||||
|
"displayName": "何斐",
|
||||||
|
"identifier": "695f0400562f09713f9c3a93",
|
||||||
|
"role": "待开发交棒【交付】负责人"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"故障管理": "ceb526a7343995577645317e9a",
|
||||||
|
"还车应结款": "4204960ce658c94b17abb7c5f6",
|
||||||
|
"工作台": "b62d21beac55c0b43389915eab",
|
||||||
|
"交车管理": "b6947b5aca82a8c759612ba039",
|
||||||
|
"合同管理": "23873be81931cb0dc1bf87a456",
|
||||||
|
"安全培训": "76988b5f73ef515de5930d59b9",
|
||||||
|
"证照管理": "11f4c2ec65901a8f3199c81706",
|
||||||
|
"还车管理": "1e0fce2d6929ff4ac13b310e97"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"req": {
|
||||||
|
"待处理": "100005",
|
||||||
|
"已确认": "32",
|
||||||
|
"分析中": "154395",
|
||||||
|
"设计中": "156603",
|
||||||
|
"设计完成": "307012",
|
||||||
|
"待开发": "1582fc929d429111b925309493"
|
||||||
|
},
|
||||||
|
"task": {
|
||||||
|
"待处理": "100005",
|
||||||
|
"已完成": "100014"
|
||||||
|
},
|
||||||
|
"transit_api": "POST /projex/api/workitem/workitem/{id}/status/transit",
|
||||||
|
"fast_handoff_hops": [
|
||||||
|
"设计完成",
|
||||||
|
"待开发"
|
||||||
|
],
|
||||||
|
"note": "见 references/live-api.md;禁止再用 updateStatus"
|
||||||
|
},
|
||||||
|
"workitem_types": {
|
||||||
|
"product_req": {
|
||||||
|
"name": "产品类需求",
|
||||||
|
"category": "Req",
|
||||||
|
"identifier": "9uy29901re573f561d69jn40"
|
||||||
|
},
|
||||||
|
"task": {
|
||||||
|
"name": "任务",
|
||||||
|
"category": "Task",
|
||||||
|
"identifier": "ba102e46bc6a8483d9b7f25c"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"priority": {
|
||||||
|
"紧急": "646004e97f54bb77fec7b455df",
|
||||||
|
"高": "95b89e0a524d9693e1f335ffe5",
|
||||||
|
"中": "fa155d1214f9f8db222d39db3b",
|
||||||
|
"低": "92924feff9c1085891e7511872"
|
||||||
|
},
|
||||||
|
"fields": {
|
||||||
|
"plan_start": {
|
||||||
|
"fieldIdentifier": "79",
|
||||||
|
"name": "计划开始时间",
|
||||||
|
"value_shape": "YYYY-MM-DD HH:mm:ss China wall time preferred; epoch ms string also accepted",
|
||||||
|
"example": "2026-07-27 12:00:00",
|
||||||
|
"update_api": "POST /projex/api/workitem/workitem/field/value/{workitemId} form fieldValueList=JSON"
|
||||||
|
},
|
||||||
|
"plan_end": {
|
||||||
|
"fieldIdentifier": "80",
|
||||||
|
"name": "计划完成时间",
|
||||||
|
"value_shape": "YYYY-MM-DD HH:mm:ss or epoch ms string",
|
||||||
|
"update_api": "POST /projex/api/workitem/workitem/field/value/{workitemId} form fieldValueList=JSON"
|
||||||
|
},
|
||||||
|
"estimated_hours": {
|
||||||
|
"fieldIdentifier": "101586",
|
||||||
|
"name": "预计工时",
|
||||||
|
"note": "不可直接改字段;须工时预估登记",
|
||||||
|
"create_api": "POST /projex/api/workitem/workitem/time/estimate body spentTime,type,recordUserIdentifier,workitemIdentifier",
|
||||||
|
"delete_api": "DELETE /projex/api/workitem/workitem/time/estimate/{workitemId}/{estimateId}",
|
||||||
|
"list_api": "GET /projex/api/workitem/workitem/time/estimate/list?workitemIdentifier="
|
||||||
|
},
|
||||||
|
"actual_hours": {
|
||||||
|
"name": "实际工时",
|
||||||
|
"note": "快轨待开发默认 2",
|
||||||
|
"create_api": "POST /projex/api/workitem/workitem/time body actualTime,type,recordUserIdentifier,workitemIdentifier,gmtStart,gmtEnd (epoch ms string)",
|
||||||
|
"list_api": "GET /projex/api/workitem/workitem/time/list?workitemIdentifier=",
|
||||||
|
"fast_track_default": 2,
|
||||||
|
"verified_at": "2026-07-27",
|
||||||
|
"verified_on": "ONEOS-293"
|
||||||
|
},
|
||||||
|
"fast_track": {
|
||||||
|
"req_estimated_hours": 2,
|
||||||
|
"req_actual_hours": 2,
|
||||||
|
"design_plan_start_end_same_day": true,
|
||||||
|
"design_description": "copy_req_document",
|
||||||
|
"delivery_description": "manual_sync_or_autoprd",
|
||||||
|
"delivery_design_same_tags_as_req": true,
|
||||||
|
"design_associated_to_req_after_task_sub": true,
|
||||||
|
"document_update_api": "PATCH /projex/api/workitem/workitem/{id}/document {content,formatType:RICHTEXT}"
|
||||||
|
},
|
||||||
|
"submit_department": {
|
||||||
|
"fieldIdentifier": "3132597a9718d1c282b7ba5a0c",
|
||||||
|
"name": "提交部门",
|
||||||
|
"format": "string input",
|
||||||
|
"update_api": "POST /projex/api/workitem/workitem/field/value/{workitemId} form fieldValueList=JSON",
|
||||||
|
"verified_at": "2026-07-27",
|
||||||
|
"verified_on": "ONEOS-293"
|
||||||
|
},
|
||||||
|
"submitter": {
|
||||||
|
"fieldIdentifier": "9e01269e96f91fbb97d36bf5b3",
|
||||||
|
"name": "提交人",
|
||||||
|
"format": "string input",
|
||||||
|
"update_api": "POST /projex/api/workitem/workitem/field/value/{workitemId} form fieldValueList=JSON",
|
||||||
|
"verified_at": "2026-07-27",
|
||||||
|
"verified_on": "ONEOS-293"
|
||||||
|
},
|
||||||
|
"tag": {
|
||||||
|
"fieldIdentifier": "tag",
|
||||||
|
"name": "标签",
|
||||||
|
"propertyKey": "tag"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"assignee_rules": {
|
||||||
|
"待开发_交付任务": "hefei",
|
||||||
|
"分析中_交付与分析": "creator",
|
||||||
|
"设计中_设计": "creator"
|
||||||
|
},
|
||||||
|
"relation": {
|
||||||
|
"delivery_to_req": "ASSOCIATED",
|
||||||
|
"stage_to_delivery": "TASK_SUB",
|
||||||
|
"create_field": "createWorkitemRelationInfo",
|
||||||
|
"forbid": [
|
||||||
|
"PARENT_as_关联项",
|
||||||
|
"ASSOCIATED_only_for_stage_tasks_without_TASK_SUB"
|
||||||
|
],
|
||||||
|
"note": "交付必须 ASSOCIATED→需求。分析/设计默认 TASK_SUB→交付(子项 tab)。二者同 create 互斥。见 references/live-api.md"
|
||||||
|
},
|
||||||
|
"delivery_placeholder": "等待设计任务完成后自动填入",
|
||||||
|
"task_title_prefixes": {
|
||||||
|
"delivery": "【交付】",
|
||||||
|
"analysis": "【分析】",
|
||||||
|
"design": "【设计】"
|
||||||
|
},
|
||||||
|
"publish_url": {
|
||||||
|
"shape": "{baseUrl}/{prototype-id}/index.html",
|
||||||
|
"forbid_prototypes_prefix": true,
|
||||||
|
"require_index_html": true
|
||||||
|
}
|
||||||
|
}
|
||||||
227
.cursor/skills/YunxiaoPM/scripts/list_projects.py
Normal file
227
.cursor/skills/YunxiaoPM/scripts/list_projects.py
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""拉取云效项目列表(供 YunxiaoPMapp 门禁 PJ 点选)。stdout = JSON。
|
||||||
|
|
||||||
|
无法对应时自动重拉一次:
|
||||||
|
python3 scripts/list_projects.py --match '01_ONEOS'
|
||||||
|
python3 scripts/list_projects.py --match-id 1280be963a5a2cc126a4118dca
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import urllib.parse
|
||||||
|
from datetime import datetime, timedelta, timezone
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
RUNTIME = json.loads((ROOT / "assets" / "runtime-ids.json").read_text())
|
||||||
|
ORG = RUNTIME.get("project", {}).get("organizationIdentifier", "697c54a19df7fdfa65466405")
|
||||||
|
WANG = RUNTIME.get("people", {}).get("wangmian", {}).get("identifier", "6811df000601d2fea60144a9")
|
||||||
|
ALIASES = [a.lower() for a in (RUNTIME.get("project", {}).get("name_aliases") or [])]
|
||||||
|
TZ = timezone(timedelta(hours=8))
|
||||||
|
|
||||||
|
|
||||||
|
def load_jar() -> dict[str, str]:
|
||||||
|
jar: dict[str, str] = {}
|
||||||
|
try:
|
||||||
|
import browser_cookie3
|
||||||
|
|
||||||
|
for domain in (".aliyun.com", "devops.aliyun.com", ".devops.aliyun.com"):
|
||||||
|
try:
|
||||||
|
for c in browser_cookie3.chrome(domain_name=domain):
|
||||||
|
jar[c.name] = c.value
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if not jar.get("XSRF-TOKEN"):
|
||||||
|
p = Path("/tmp/yunxiao_cookies.json")
|
||||||
|
if p.exists():
|
||||||
|
raw = json.loads(p.read_text())
|
||||||
|
jar = (
|
||||||
|
raw
|
||||||
|
if isinstance(raw, dict) and "XSRF-TOKEN" in raw
|
||||||
|
else {c["name"]: c["value"] for c in raw.get("cookies", [])}
|
||||||
|
)
|
||||||
|
if not jar.get("XSRF-TOKEN"):
|
||||||
|
raise RuntimeError("缺少 XSRF-TOKEN:请先在 Chrome 登录 devops.aliyun.com")
|
||||||
|
return jar
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_projects() -> list[dict[str, Any]]:
|
||||||
|
jar = load_jar()
|
||||||
|
x = jar.get("XSRF-TOKEN", "")
|
||||||
|
xsrf = urllib.parse.unquote(x) if "%" in x else x
|
||||||
|
cookie = "; ".join(f"{k}={v}" for k, v in jar.items())
|
||||||
|
headers = {
|
||||||
|
"Cookie": cookie,
|
||||||
|
"x-xsrf-token": xsrf,
|
||||||
|
"X-XSRF-TOKEN": xsrf,
|
||||||
|
"Origin": "https://devops.aliyun.com",
|
||||||
|
"Referer": "https://devops.aliyun.com/projex",
|
||||||
|
"accept": "application/json",
|
||||||
|
}
|
||||||
|
extra = json.dumps(
|
||||||
|
{
|
||||||
|
"conditionGroups": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"className": "user",
|
||||||
|
"fieldIdentifier": "users",
|
||||||
|
"format": "multiList",
|
||||||
|
"operator": "CONTAINS",
|
||||||
|
"value": [WANG],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"className": "string",
|
||||||
|
"fieldIdentifier": "scope",
|
||||||
|
"format": "list",
|
||||||
|
"operator": "CONTAINS",
|
||||||
|
"value": ["public"],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
]
|
||||||
|
},
|
||||||
|
separators=(",", ":"),
|
||||||
|
)
|
||||||
|
params = {
|
||||||
|
"extraConditions": extra,
|
||||||
|
"conditions": json.dumps({"conditionGroups": [[]]}, separators=(",", ":")),
|
||||||
|
"orderBy": json.dumps(
|
||||||
|
{
|
||||||
|
"fieldIdentifier": "gmtCreate",
|
||||||
|
"format": "input",
|
||||||
|
"order": "desc",
|
||||||
|
"className": "date",
|
||||||
|
},
|
||||||
|
separators=(",", ":"),
|
||||||
|
),
|
||||||
|
"scope": "all",
|
||||||
|
"category": "Project",
|
||||||
|
"toPage": 1,
|
||||||
|
"pageSize": 100,
|
||||||
|
"_input_charset": "utf-8",
|
||||||
|
}
|
||||||
|
r = requests.get(
|
||||||
|
"https://devops.aliyun.com/projex/api/workspace/project/search/list",
|
||||||
|
headers=headers,
|
||||||
|
params=params,
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
|
r.raise_for_status()
|
||||||
|
rows = r.json().get("result") or []
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"name": p.get("name"),
|
||||||
|
"identifier": p.get("identifier"),
|
||||||
|
"customCode": p.get("customCode"),
|
||||||
|
"logicalStatus": p.get("logicalStatus"),
|
||||||
|
"status": (p.get("status") or {}).get("displayName"),
|
||||||
|
"scope": p.get("scope"),
|
||||||
|
}
|
||||||
|
for p in rows
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def match_projects(
|
||||||
|
projects: list[dict[str, Any]],
|
||||||
|
*,
|
||||||
|
query: str | None = None,
|
||||||
|
space_id: str | None = None,
|
||||||
|
) -> list[dict[str, Any]]:
|
||||||
|
if space_id:
|
||||||
|
sid = space_id.strip()
|
||||||
|
return [p for p in projects if p.get("identifier") == sid]
|
||||||
|
if not query:
|
||||||
|
return []
|
||||||
|
q = query.strip().lower()
|
||||||
|
hits: list[dict[str, Any]] = []
|
||||||
|
for p in projects:
|
||||||
|
name = (p.get("name") or "").lower()
|
||||||
|
code = (p.get("customCode") or "").lower()
|
||||||
|
if q == name or q == code or q in name or name in q:
|
||||||
|
hits.append(p)
|
||||||
|
continue
|
||||||
|
if q in ALIASES and (code == "oneos" or "oneos" in name or "运营" in name):
|
||||||
|
hits.append(p)
|
||||||
|
# de-dupe by identifier
|
||||||
|
seen: set[str] = set()
|
||||||
|
out: list[dict[str, Any]] = []
|
||||||
|
for p in hits:
|
||||||
|
i = p.get("identifier") or ""
|
||||||
|
if i in seen:
|
||||||
|
continue
|
||||||
|
seen.add(i)
|
||||||
|
out.append(p)
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def list_projects(
|
||||||
|
*,
|
||||||
|
match: str | None = None,
|
||||||
|
match_id: str | None = None,
|
||||||
|
) -> dict:
|
||||||
|
projects = fetch_projects()
|
||||||
|
payload: dict[str, Any] = {
|
||||||
|
"fetched_at": datetime.now(TZ).isoformat(),
|
||||||
|
"organizationIdentifier": ORG,
|
||||||
|
"count": len(projects),
|
||||||
|
"projects": projects,
|
||||||
|
"selection_required": True,
|
||||||
|
"refetched": False,
|
||||||
|
"note": "禁止默认直指;须 AskQuestion/Plan 点选后再写入 spaceIdentifier",
|
||||||
|
}
|
||||||
|
if not match and not match_id:
|
||||||
|
return payload
|
||||||
|
|
||||||
|
hits = match_projects(projects, query=match, space_id=match_id)
|
||||||
|
if len(hits) == 1:
|
||||||
|
payload["matches"] = hits
|
||||||
|
payload["match_status"] = "unique"
|
||||||
|
return payload
|
||||||
|
|
||||||
|
# 无法对应(0 或多)→ 自动重拉一次
|
||||||
|
projects2 = fetch_projects()
|
||||||
|
hits2 = match_projects(projects2, query=match, space_id=match_id)
|
||||||
|
payload["projects"] = projects2
|
||||||
|
payload["count"] = len(projects2)
|
||||||
|
payload["refetched"] = True
|
||||||
|
payload["refetch_reason"] = "无法对应" if len(hits) != 1 else "unexpected"
|
||||||
|
if len(hits) == 0:
|
||||||
|
payload["refetch_reason"] = "首次0命中"
|
||||||
|
elif len(hits) > 1:
|
||||||
|
payload["refetch_reason"] = "首次多命中"
|
||||||
|
payload["matches"] = hits2
|
||||||
|
if len(hits2) == 1:
|
||||||
|
payload["match_status"] = "unique_after_refetch"
|
||||||
|
elif len(hits2) == 0:
|
||||||
|
payload["match_status"] = "none_after_refetch"
|
||||||
|
payload["note"] = "已自动重拉一次仍无法对应;请用户从最新列表点选;禁止再拉第3次"
|
||||||
|
else:
|
||||||
|
payload["match_status"] = "ambiguous_after_refetch"
|
||||||
|
payload["note"] = "已自动重拉一次仍多命中;请用户点选;禁止自动选定"
|
||||||
|
payload["fetched_at"] = datetime.now(TZ).isoformat()
|
||||||
|
return payload
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
ap = argparse.ArgumentParser(description="YunxiaoPMapp 项目列表 / 匹配(无法对应则重拉一次)")
|
||||||
|
ap.add_argument("--match", help="按项目名或 customCode 匹配")
|
||||||
|
ap.add_argument("--match-id", help="按 spaceIdentifier 匹配")
|
||||||
|
args = ap.parse_args()
|
||||||
|
print(
|
||||||
|
json.dumps(
|
||||||
|
list_projects(match=args.match, match_id=args.match_id),
|
||||||
|
ensure_ascii=False,
|
||||||
|
indent=2,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
190
.cursor/skills/YunxiaoPM/scripts/list_tags.py
Normal file
190
.cursor/skills/YunxiaoPM/scripts/list_tags.py
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""标签候选列表(聚合工作项 tag + runtime);未命中可 --match 后自动重拉一次。"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import urllib.parse
|
||||||
|
from datetime import datetime, timedelta, timezone
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
RUNTIME = json.loads((ROOT / "assets" / "runtime-ids.json").read_text())
|
||||||
|
TZ = timezone(timedelta(hours=8))
|
||||||
|
|
||||||
|
|
||||||
|
def load_jar() -> dict[str, str]:
|
||||||
|
jar: dict[str, str] = {}
|
||||||
|
try:
|
||||||
|
import browser_cookie3
|
||||||
|
|
||||||
|
for domain in (".aliyun.com", "devops.aliyun.com", ".devops.aliyun.com"):
|
||||||
|
try:
|
||||||
|
for c in browser_cookie3.chrome(domain_name=domain):
|
||||||
|
jar[c.name] = c.value
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if not jar.get("XSRF-TOKEN"):
|
||||||
|
p = Path("/tmp/yunxiao_cookies.json")
|
||||||
|
if p.exists():
|
||||||
|
raw = json.loads(p.read_text())
|
||||||
|
jar = (
|
||||||
|
raw
|
||||||
|
if isinstance(raw, dict) and "XSRF-TOKEN" in raw
|
||||||
|
else {c["name"]: c["value"] for c in raw.get("cookies", [])}
|
||||||
|
)
|
||||||
|
if not jar.get("XSRF-TOKEN"):
|
||||||
|
raise RuntimeError("缺少 XSRF-TOKEN")
|
||||||
|
return jar
|
||||||
|
|
||||||
|
|
||||||
|
def session() -> requests.Session:
|
||||||
|
jar = load_jar()
|
||||||
|
x = jar.get("XSRF-TOKEN", "")
|
||||||
|
xsrf = urllib.parse.unquote(x) if "%" in x else x
|
||||||
|
s = requests.Session()
|
||||||
|
s.headers.update(
|
||||||
|
{
|
||||||
|
"Cookie": "; ".join(f"{k}={v}" for k, v in jar.items()),
|
||||||
|
"x-xsrf-token": xsrf,
|
||||||
|
"X-XSRF-TOKEN": xsrf,
|
||||||
|
"Origin": "https://devops.aliyun.com",
|
||||||
|
"Referer": "https://devops.aliyun.com/projex",
|
||||||
|
"accept": "application/json",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_tags(space_id: str) -> list[dict[str, str]]:
|
||||||
|
s = session()
|
||||||
|
by_id: dict[str, str] = {}
|
||||||
|
for name, tid in (RUNTIME.get("tags") or {}).items():
|
||||||
|
by_id[tid] = name
|
||||||
|
body = {
|
||||||
|
"spaceIdentifier": space_id,
|
||||||
|
"spaceType": "Project",
|
||||||
|
"category": "Req",
|
||||||
|
"toPage": 1,
|
||||||
|
"pageSize": 100,
|
||||||
|
"conditions": json.dumps({"conditionGroups": [[]]}),
|
||||||
|
}
|
||||||
|
rows = (
|
||||||
|
s.post(
|
||||||
|
"https://devops.aliyun.com/projex/api/workitem/workitem/list?_input_charset=utf-8",
|
||||||
|
json=body,
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
|
.json()
|
||||||
|
.get("result")
|
||||||
|
or []
|
||||||
|
)
|
||||||
|
for row in rows:
|
||||||
|
for t in row.get("tag") or []:
|
||||||
|
tid = t.get("identifier")
|
||||||
|
name = t.get("name") or t.get("displayName")
|
||||||
|
if tid and name:
|
||||||
|
by_id[tid] = name
|
||||||
|
# Task 再扫一页,补标签
|
||||||
|
body["category"] = "Task"
|
||||||
|
rows = (
|
||||||
|
s.post(
|
||||||
|
"https://devops.aliyun.com/projex/api/workitem/workitem/list?_input_charset=utf-8",
|
||||||
|
json=body,
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
|
.json()
|
||||||
|
.get("result")
|
||||||
|
or []
|
||||||
|
)
|
||||||
|
for row in rows:
|
||||||
|
for t in row.get("tag") or []:
|
||||||
|
tid = t.get("identifier")
|
||||||
|
name = t.get("name") or t.get("displayName")
|
||||||
|
if tid and name:
|
||||||
|
by_id[tid] = name
|
||||||
|
return [{"name": n, "identifier": i} for i, n in sorted(by_id.items(), key=lambda x: x[1])]
|
||||||
|
|
||||||
|
|
||||||
|
def match_tags(tags: list[dict[str, str]], query: str) -> list[dict[str, str]]:
|
||||||
|
q = query.strip().lower()
|
||||||
|
hits = []
|
||||||
|
for t in tags:
|
||||||
|
name = (t.get("name") or "").lower()
|
||||||
|
if q == name or q in name or name in q:
|
||||||
|
hits.append(t)
|
||||||
|
return hits
|
||||||
|
|
||||||
|
|
||||||
|
def list_tags(*, space_id: str, match: str | None = None, prefer: str | None = None) -> dict[str, Any]:
|
||||||
|
tags = fetch_tags(space_id)
|
||||||
|
# prefer 置顶
|
||||||
|
if prefer:
|
||||||
|
prefer_l = prefer.strip().lower()
|
||||||
|
tags = sorted(
|
||||||
|
tags,
|
||||||
|
key=lambda t: (0 if (t.get("name") or "").lower() == prefer_l else 1, t.get("name") or ""),
|
||||||
|
)
|
||||||
|
out: dict[str, Any] = {
|
||||||
|
"fetched_at": datetime.now(TZ).isoformat(),
|
||||||
|
"spaceIdentifier": space_id,
|
||||||
|
"count": len(tags),
|
||||||
|
"tags": tags,
|
||||||
|
"refetched": False,
|
||||||
|
"note": "标签未命中须自动重拉一次并重生 4.A/B/C 选项;见 compact-select.md",
|
||||||
|
}
|
||||||
|
if not match:
|
||||||
|
return out
|
||||||
|
hits = match_tags(tags, match)
|
||||||
|
if len(hits) == 1:
|
||||||
|
out["matches"] = hits
|
||||||
|
out["match_status"] = "unique"
|
||||||
|
return out
|
||||||
|
# 无法对应 → 重拉一次
|
||||||
|
tags2 = fetch_tags(space_id)
|
||||||
|
if prefer:
|
||||||
|
prefer_l = prefer.strip().lower()
|
||||||
|
tags2 = sorted(
|
||||||
|
tags2,
|
||||||
|
key=lambda t: (0 if (t.get("name") or "").lower() == prefer_l else 1, t.get("name") or ""),
|
||||||
|
)
|
||||||
|
hits2 = match_tags(tags2, match)
|
||||||
|
out["tags"] = tags2
|
||||||
|
out["count"] = len(tags2)
|
||||||
|
out["refetched"] = True
|
||||||
|
out["refetch_reason"] = "首次0命中" if len(hits) == 0 else "首次多命中"
|
||||||
|
out["matches"] = hits2
|
||||||
|
if len(hits2) == 1:
|
||||||
|
out["match_status"] = "unique_after_refetch"
|
||||||
|
elif len(hits2) == 0:
|
||||||
|
out["match_status"] = "none_after_refetch"
|
||||||
|
out["note"] = "已自动重拉标签列表仍无法对应;请用户点选 4.x;禁止再拉第3次"
|
||||||
|
else:
|
||||||
|
out["match_status"] = "ambiguous_after_refetch"
|
||||||
|
out["fetched_at"] = datetime.now(TZ).isoformat()
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
ap = argparse.ArgumentParser()
|
||||||
|
ap.add_argument("--space", required=True, help="spaceIdentifier")
|
||||||
|
ap.add_argument("--match", help="标签名")
|
||||||
|
ap.add_argument("--prefer", help="置顶标签名")
|
||||||
|
args = ap.parse_args()
|
||||||
|
print(
|
||||||
|
json.dumps(
|
||||||
|
list_tags(space_id=args.space, match=args.match, prefer=args.prefer),
|
||||||
|
ensure_ascii=False,
|
||||||
|
indent=2,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
660
.cursor/skills/YunxiaoPM/scripts/live_create_fast.py
Normal file
660
.cursor/skills/YunxiaoPM/scripts/live_create_fast.py
Normal file
@@ -0,0 +1,660 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""YunxiaoPM 极速真实建单 v5:快轨描述/计划/标签/工时 2+2/设计 ASSOCIATED 补挂。"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import urllib.parse
|
||||||
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||||
|
from datetime import datetime, timedelta, timezone
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
try:
|
||||||
|
import browser_cookie3
|
||||||
|
except ImportError: # pragma: no cover
|
||||||
|
browser_cookie3 = None
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
RUNTIME = json.loads((ROOT / "assets" / "runtime-ids.json").read_text())
|
||||||
|
STATUS = RUNTIME["status"]["req"]
|
||||||
|
TASK_STATUS = RUNTIME["status"]["task"]
|
||||||
|
FAST = RUNTIME.get("fields", {}).get("fast_track") or {}
|
||||||
|
|
||||||
|
SPACE = (
|
||||||
|
RUNTIME.get("project", {}).get("spaceIdentifier")
|
||||||
|
or (RUNTIME.get("project", {}).get("last_selected") or {}).get("spaceIdentifier")
|
||||||
|
)
|
||||||
|
if not SPACE:
|
||||||
|
raise RuntimeError(
|
||||||
|
"未选定项目 spaceIdentifier:须先走门禁 PJ 点选,或设置 runtime project.last_selected"
|
||||||
|
)
|
||||||
|
REQ_TYPE = RUNTIME["workitem_types"]["product_req"]["identifier"]
|
||||||
|
TASK_TYPE = RUNTIME["workitem_types"]["task"]["identifier"]
|
||||||
|
HEFEI = RUNTIME["people"]["hefei"]["identifier"]
|
||||||
|
WANG = RUNTIME["people"].get("wangmian", {}).get("identifier", "6811df000601d2fea60144a9")
|
||||||
|
PRI = RUNTIME["priority"]["中"]
|
||||||
|
TAG_FAULT = RUNTIME.get("tags", {}).get("故障管理", "ceb526a7343995577645317e9a")
|
||||||
|
PLACEHOLDER = RUNTIME["delivery_placeholder"]
|
||||||
|
PROTO = "https://prototype.lnoneos.com/vehicle-fault-handling/index.html"
|
||||||
|
TZ = timezone(timedelta(hours=8))
|
||||||
|
TODAY = datetime.now(TZ).strftime("%Y-%m-%d")
|
||||||
|
NOON = f"{TODAY} 12:00:00"
|
||||||
|
EOD = f"{TODAY} 23:59:59"
|
||||||
|
NOON_MS = str(
|
||||||
|
int(datetime.now(TZ).replace(hour=12, minute=0, second=0, microsecond=0).timestamp() * 1000)
|
||||||
|
)
|
||||||
|
START_MS = str(
|
||||||
|
int(datetime.now(TZ).replace(hour=9, minute=0, second=0, microsecond=0).timestamp() * 1000)
|
||||||
|
)
|
||||||
|
END_MS = str(
|
||||||
|
int(datetime.now(TZ).replace(hour=11, minute=0, second=0, microsecond=0).timestamp() * 1000)
|
||||||
|
)
|
||||||
|
FAST_EST = int(FAST.get("req_estimated_hours", 2))
|
||||||
|
FAST_ACT = int(FAST.get("req_actual_hours", 2))
|
||||||
|
|
||||||
|
PENDING = STATUS["待处理"]
|
||||||
|
DESIGN_DONE = STATUS["设计完成"]
|
||||||
|
PENDING_DEV = STATUS["待开发"]
|
||||||
|
TASK_DONE = TASK_STATUS["已完成"]
|
||||||
|
|
||||||
|
_COOKIE = ""
|
||||||
|
_XSRF = ""
|
||||||
|
|
||||||
|
|
||||||
|
def load_auth() -> None:
|
||||||
|
global _COOKIE, _XSRF
|
||||||
|
jar: dict[str, str] = {}
|
||||||
|
if browser_cookie3:
|
||||||
|
for domain in (".aliyun.com", "devops.aliyun.com", ".devops.aliyun.com"):
|
||||||
|
try:
|
||||||
|
for c in browser_cookie3.chrome(domain_name=domain):
|
||||||
|
jar[c.name] = c.value
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if not jar:
|
||||||
|
p = Path("/tmp/yunxiao_cookies.json")
|
||||||
|
if p.exists():
|
||||||
|
raw = json.loads(p.read_text())
|
||||||
|
jar = (
|
||||||
|
raw
|
||||||
|
if isinstance(raw, dict) and "XSRF-TOKEN" in raw
|
||||||
|
else {c["name"]: c["value"] for c in raw.get("cookies", [])}
|
||||||
|
)
|
||||||
|
_COOKIE = "; ".join(f"{k}={v}" for k, v in jar.items())
|
||||||
|
x = jar.get("XSRF-TOKEN", "")
|
||||||
|
_XSRF = urllib.parse.unquote(x) if "%" in x else x
|
||||||
|
if not _XSRF:
|
||||||
|
raise RuntimeError("缺少 XSRF-TOKEN:请先在 Chrome 登录 devops.aliyun.com")
|
||||||
|
|
||||||
|
|
||||||
|
def session() -> requests.Session:
|
||||||
|
s = requests.Session()
|
||||||
|
s.headers.update(
|
||||||
|
{
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Cookie": _COOKIE,
|
||||||
|
"x-xsrf-token": _XSRF,
|
||||||
|
"X-XSRF-TOKEN": _XSRF,
|
||||||
|
"Origin": "https://devops.aliyun.com",
|
||||||
|
"Referer": f"https://devops.aliyun.com/projex/project/{SPACE}/req",
|
||||||
|
"accept": "application/json",
|
||||||
|
"User-Agent": "YunxiaoPM-live_create_fast/5.0",
|
||||||
|
"Connection": "keep-alive",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def api(s: requests.Session, method: str, url: str, body: Any = None) -> dict:
|
||||||
|
r = s.request(method, url, json=body, timeout=60)
|
||||||
|
try:
|
||||||
|
return r.json()
|
||||||
|
except Exception:
|
||||||
|
r.raise_for_status()
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def create(s: requests.Session, payload: dict) -> dict:
|
||||||
|
url = "https://devops.aliyun.com/projex/api/workitem/workitem?_input_charset=utf-8"
|
||||||
|
j = api(s, "POST", url, payload)
|
||||||
|
r = j.get("result") or {}
|
||||||
|
if j.get("code") == 200 and isinstance(r, dict) and r.get("identifier"):
|
||||||
|
return r
|
||||||
|
j = api(s, "PUT", url, payload)
|
||||||
|
r = j.get("result") or {}
|
||||||
|
if j.get("code") == 200 and isinstance(r, dict) and r.get("identifier"):
|
||||||
|
return r
|
||||||
|
raise RuntimeError(f"create failed: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def get(s: requests.Session, wid: str) -> dict:
|
||||||
|
return api(
|
||||||
|
s,
|
||||||
|
"GET",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/{wid}?_input_charset=utf-8",
|
||||||
|
)["result"]
|
||||||
|
|
||||||
|
|
||||||
|
def apply_tag(s: requests.Session, wid: str, tag_id: str = TAG_FAULT) -> None:
|
||||||
|
j = api(
|
||||||
|
s,
|
||||||
|
"PATCH",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/{wid}?_input_charset=utf-8",
|
||||||
|
{
|
||||||
|
"workitemIdentifier": wid,
|
||||||
|
"propertyKey": "tag",
|
||||||
|
"propertyValue": tag_id,
|
||||||
|
"operateType": "COVER",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if j.get("code") != 200:
|
||||||
|
raise RuntimeError(f"tag failed {wid}: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def set_document(s: requests.Session, wid: str, html: str) -> None:
|
||||||
|
j = api(
|
||||||
|
s,
|
||||||
|
"PATCH",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/{wid}/document?_input_charset=utf-8",
|
||||||
|
{"content": html, "formatType": "RICHTEXT"},
|
||||||
|
)
|
||||||
|
if j.get("code") != 200 or j.get("errorMsg"):
|
||||||
|
raise RuntimeError(f"document failed {wid}: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def set_fields(s: requests.Session, wid: str, pairs: list[tuple[str, str]]) -> None:
|
||||||
|
data = urllib.parse.urlencode(
|
||||||
|
{
|
||||||
|
"fieldValueList": json.dumps(
|
||||||
|
[{"fieldIdentifier": k, "value": v} for k, v in pairs], ensure_ascii=False
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
r = s.post(
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/field/value/{wid}?_input_charset=utf-8",
|
||||||
|
data=data,
|
||||||
|
headers={"Content-Type": "application/x-www-form-urlencoded"},
|
||||||
|
timeout=60,
|
||||||
|
)
|
||||||
|
j = r.json()
|
||||||
|
if j.get("code") != 200:
|
||||||
|
raise RuntimeError(f"field/value failed {wid}: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def set_estimate_hours(s: requests.Session, wid: str, hours: int, user: str = WANG) -> None:
|
||||||
|
est = api(
|
||||||
|
s,
|
||||||
|
"GET",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/time/estimate/list?workitemIdentifier={wid}",
|
||||||
|
).get("result") or []
|
||||||
|
for row in est:
|
||||||
|
eid = row.get("identifier")
|
||||||
|
if eid:
|
||||||
|
api(
|
||||||
|
s,
|
||||||
|
"DELETE",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/time/estimate/{wid}/{eid}",
|
||||||
|
)
|
||||||
|
j = api(
|
||||||
|
s,
|
||||||
|
"POST",
|
||||||
|
"https://devops.aliyun.com/projex/api/workitem/workitem/time/estimate?_input_charset=utf-8",
|
||||||
|
{
|
||||||
|
"workitemIdentifier": wid,
|
||||||
|
"spentTime": hours,
|
||||||
|
"type": "develop",
|
||||||
|
"description": "快轨默认预计工时",
|
||||||
|
"recordUserIdentifier": user,
|
||||||
|
"forCreate": False,
|
||||||
|
"containsRestDay": False,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if j.get("code") != 200:
|
||||||
|
raise RuntimeError(f"estimate failed {wid}: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def set_actual_hours(s: requests.Session, wid: str, hours: int, user: str = WANG) -> None:
|
||||||
|
j = api(
|
||||||
|
s,
|
||||||
|
"POST",
|
||||||
|
"https://devops.aliyun.com/projex/api/workitem/workitem/time?_input_charset=utf-8",
|
||||||
|
{
|
||||||
|
"workitemIdentifier": wid,
|
||||||
|
"actualTime": hours,
|
||||||
|
"type": "develop",
|
||||||
|
"description": "快轨默认实际工时",
|
||||||
|
"recordUserIdentifier": user,
|
||||||
|
"gmtStart": START_MS,
|
||||||
|
"gmtEnd": END_MS,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if j.get("code") != 200 or not j.get("result"):
|
||||||
|
raise RuntimeError(f"actual time failed {wid}: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def try_associate_to_req(s: requests.Session, stage_id: str, req_id: str) -> bool:
|
||||||
|
"""建后补 ASSOCIATED→需求。Cookie 下常失败,成功返回 True。"""
|
||||||
|
bodies = [
|
||||||
|
{"relationIdentifier": "ASSOCIATED", "toWorkitemIdentifier": req_id},
|
||||||
|
{
|
||||||
|
"relationIdentifier": "ASSOCIATED",
|
||||||
|
"fromWorkitemIdentifier": stage_id,
|
||||||
|
"toWorkitemIdentifier": req_id,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
for body in bodies:
|
||||||
|
for url in (
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/{stage_id}/relation/record?_input_charset=utf-8",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/v2/workitem/{stage_id}/relation/record?_input_charset=utf-8",
|
||||||
|
):
|
||||||
|
j = api(s, "POST", url, body)
|
||||||
|
if j.get("code") == 200 and j.get("result") not in (None, False):
|
||||||
|
if not (isinstance(j.get("result"), dict) and j["result"].get("status") in (404, 405)):
|
||||||
|
rows = list_associated(s, stage_id)
|
||||||
|
if req_id in {r.get("identifier") for r in rows}:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def transit(s: requests.Session, wid: str, from_status: str, to_status: str) -> None:
|
||||||
|
if from_status == to_status:
|
||||||
|
return
|
||||||
|
j = api(
|
||||||
|
s,
|
||||||
|
"POST",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/workitem/{wid}/status/transit?_input_charset=utf-8",
|
||||||
|
{"fromStatus": from_status, "toStatus": to_status},
|
||||||
|
)
|
||||||
|
if not (j.get("code") == 200 and j.get("result") is True):
|
||||||
|
raise RuntimeError(f"transit {wid} {from_status}->{to_status}: {j}")
|
||||||
|
|
||||||
|
|
||||||
|
def md_to_html(md: str) -> str:
|
||||||
|
parts = []
|
||||||
|
for line in md.splitlines():
|
||||||
|
if line.startswith("## "):
|
||||||
|
parts.append(f"<h2>{line[3:]}</h2>")
|
||||||
|
elif line.startswith("### "):
|
||||||
|
parts.append(f"<h3>{line[4:]}</h3>")
|
||||||
|
elif line.startswith("- "):
|
||||||
|
parts.append(f"<p>• {line[2:]}</p>")
|
||||||
|
elif line.strip():
|
||||||
|
parts.append(f"<p>{line}</p>")
|
||||||
|
return "".join(parts)
|
||||||
|
|
||||||
|
|
||||||
|
def req_document_html(s: requests.Session, rid: str) -> str:
|
||||||
|
w = get(s, rid)
|
||||||
|
return ((w.get("document") or {}).get("content") or w.get("description") or "").strip()
|
||||||
|
|
||||||
|
|
||||||
|
def req_payload(subject: str, html: str) -> dict:
|
||||||
|
return {
|
||||||
|
"subject": subject,
|
||||||
|
"description": html,
|
||||||
|
"formatType": "RICHTEXT",
|
||||||
|
"document": {"content": html, "formatType": "RICHTEXT"},
|
||||||
|
"spaceIdentifier": SPACE,
|
||||||
|
"space": SPACE,
|
||||||
|
"spaceType": "Project",
|
||||||
|
"workitemTypeIdentifier": REQ_TYPE,
|
||||||
|
"workitemType": REQ_TYPE,
|
||||||
|
"categoryIdentifier": "Req",
|
||||||
|
"category": "Req",
|
||||||
|
"assignedTo": WANG,
|
||||||
|
"fieldValueList": [
|
||||||
|
{"fieldIdentifier": "priority", "value": PRI},
|
||||||
|
{"fieldIdentifier": "assignedTo", "value": WANG},
|
||||||
|
],
|
||||||
|
"attachmentIdList": [],
|
||||||
|
"cloneFrom": None,
|
||||||
|
"createWorkitemRelationList": [],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def task_payload(
|
||||||
|
subject: str,
|
||||||
|
html: str,
|
||||||
|
assignee: str,
|
||||||
|
*,
|
||||||
|
plan_start: bool = True,
|
||||||
|
associated_req: str | None = None,
|
||||||
|
parent_delivery: str | None = None,
|
||||||
|
) -> dict:
|
||||||
|
fvl = [
|
||||||
|
{"fieldIdentifier": "priority", "value": PRI},
|
||||||
|
{"fieldIdentifier": "assignedTo", "value": assignee},
|
||||||
|
]
|
||||||
|
if plan_start:
|
||||||
|
fvl.append({"fieldIdentifier": "79", "value": NOON_MS})
|
||||||
|
payload: dict[str, Any] = {
|
||||||
|
"subject": subject,
|
||||||
|
"description": html,
|
||||||
|
"formatType": "RICHTEXT",
|
||||||
|
"spaceIdentifier": SPACE,
|
||||||
|
"space": SPACE,
|
||||||
|
"spaceType": "Project",
|
||||||
|
"workitemTypeIdentifier": TASK_TYPE,
|
||||||
|
"workitemType": TASK_TYPE,
|
||||||
|
"categoryIdentifier": "Task",
|
||||||
|
"category": "Task",
|
||||||
|
"assignedTo": assignee,
|
||||||
|
"fieldValueList": fvl,
|
||||||
|
"attachmentIdList": [],
|
||||||
|
"cloneFrom": None,
|
||||||
|
}
|
||||||
|
if parent_delivery:
|
||||||
|
payload["parent"] = parent_delivery
|
||||||
|
payload["parentIdentifier"] = parent_delivery
|
||||||
|
payload["createWorkitemRelationInfo"] = {
|
||||||
|
"relatedWorkitemIdentifier": parent_delivery,
|
||||||
|
"relatedToRelationIdentifier": "TASK_SUB",
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
if not associated_req:
|
||||||
|
raise ValueError("associated_req required for delivery: ASSOCIATED→需求")
|
||||||
|
payload["createWorkitemRelationInfo"] = {
|
||||||
|
"relatedWorkitemIdentifier": associated_req,
|
||||||
|
"relatedToRelationIdentifier": "ASSOCIATED",
|
||||||
|
}
|
||||||
|
return payload
|
||||||
|
|
||||||
|
|
||||||
|
def list_associated(s: requests.Session, wid: str) -> list[dict]:
|
||||||
|
j = api(
|
||||||
|
s,
|
||||||
|
"GET",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/v2/workitem/{wid}/relation/workitem/list/by-relation-category?category=ASSOCIATED&isForward=true",
|
||||||
|
)
|
||||||
|
return j.get("result") or []
|
||||||
|
|
||||||
|
|
||||||
|
def assert_associated_to_req(s: requests.Session, wid: str, req_id: str, label: str) -> None:
|
||||||
|
rows = list_associated(s, wid)
|
||||||
|
ids = {r.get("identifier") for r in rows}
|
||||||
|
if req_id not in ids:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"{label} 关联项未挂需求:期望 {req_id},实际 {[r.get('serialNumber') for r in rows]}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
AUTO_RDO = """## 原始诉求(AutoRDO)
|
||||||
|
|
||||||
|
运维需在故障处置页承接机器人上报的故障,完成处置、挂起与归档,并保留证据链;工作台相关统计口径需与处置页一致
|
||||||
|
|
||||||
|
待确认:
|
||||||
|
- 本期是否含真实短信/邮件通道(现口径一般为演示模板)
|
||||||
|
|
||||||
|
## 工作项编号(系统)
|
||||||
|
- 交付:待建
|
||||||
|
- 分析:待建
|
||||||
|
- 设计:待建
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def summarize_from_create(w: dict, *, status: str, assignee_name: str) -> dict:
|
||||||
|
return {
|
||||||
|
"serial": w.get("serialNumber"),
|
||||||
|
"id": w.get("identifier"),
|
||||||
|
"subject": w.get("subject"),
|
||||||
|
"status": status,
|
||||||
|
"assignee": assignee_name,
|
||||||
|
"parent": w.get("parentIdentifier"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def build_normal() -> dict:
|
||||||
|
t0 = time.perf_counter()
|
||||||
|
s = session()
|
||||||
|
title = "【新增】故障处置(YunxiaoPMapp标准·极速v2)"
|
||||||
|
req = create(s, req_payload(title, md_to_html(AUTO_RDO + f"\n原型:{PROTO}\n")))
|
||||||
|
rid = req["identifier"]
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=2) as pool:
|
||||||
|
f_tag_r = pool.submit(apply_tag, session(), rid)
|
||||||
|
f_deliv = pool.submit(
|
||||||
|
create,
|
||||||
|
session(),
|
||||||
|
task_payload(
|
||||||
|
f"【交付】{title}",
|
||||||
|
f"<p>{PLACEHOLDER}</p>",
|
||||||
|
HEFEI,
|
||||||
|
associated_req=rid,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
deliv = f_deliv.result()
|
||||||
|
f_tag_r.result()
|
||||||
|
did = deliv["identifier"]
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=3) as pool:
|
||||||
|
f_tag_d = pool.submit(apply_tag, session(), did)
|
||||||
|
f_ana = pool.submit(
|
||||||
|
create,
|
||||||
|
session(),
|
||||||
|
task_payload(
|
||||||
|
f"【分析】{title}",
|
||||||
|
"<p>分析阶段:故障处置台账、挂起归档与证据链。</p>",
|
||||||
|
WANG,
|
||||||
|
associated_req=rid,
|
||||||
|
parent_delivery=did,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
f_des = pool.submit(
|
||||||
|
create,
|
||||||
|
session(),
|
||||||
|
task_payload(
|
||||||
|
f"【设计】{title}",
|
||||||
|
f"<p>设计阶段:对齐原型 {PROTO}</p>",
|
||||||
|
WANG,
|
||||||
|
associated_req=rid,
|
||||||
|
parent_delivery=did,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
ana = f_ana.result()
|
||||||
|
des = f_des.result()
|
||||||
|
f_tag_d.result()
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=3) as pool:
|
||||||
|
list(
|
||||||
|
as_completed(
|
||||||
|
[
|
||||||
|
pool.submit(transit, session(), rid, PENDING, DESIGN_DONE),
|
||||||
|
pool.submit(transit, session(), ana["identifier"], PENDING, TASK_DONE),
|
||||||
|
pool.submit(transit, session(), des["identifier"], PENDING, TASK_DONE),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
transit(s, rid, DESIGN_DONE, PENDING_DEV)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"path": "normal",
|
||||||
|
"elapsed_s": round(time.perf_counter() - t0, 3),
|
||||||
|
"req": summarize_from_create(req, status="待开发", assignee_name="王冕"),
|
||||||
|
"delivery": summarize_from_create(deliv, status="待处理", assignee_name="何斐"),
|
||||||
|
"analysis": summarize_from_create(ana, status="已完成", assignee_name="王冕"),
|
||||||
|
"design": summarize_from_create(des, status="已完成", assignee_name="王冕"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def build_fast(
|
||||||
|
*,
|
||||||
|
tag_id: str = TAG_FAULT,
|
||||||
|
has_prototype: bool = True,
|
||||||
|
delivery_html: str | None = None,
|
||||||
|
) -> dict:
|
||||||
|
"""无单快轨。
|
||||||
|
|
||||||
|
- 设计描述 = 需求 document
|
||||||
|
- 交付描述 = 手工同步需求正文(无原型)或传入 AutoPRD HTML;禁止无故占位
|
||||||
|
- 设计 79/80=当日;交付 79=当日
|
||||||
|
- 需求/交付/设计同标签
|
||||||
|
- 需求预计/实际工时各 2
|
||||||
|
- 设计 TASK_SUB→交付后尝试 ASSOCIATED→需求
|
||||||
|
"""
|
||||||
|
t0 = time.perf_counter()
|
||||||
|
s = session()
|
||||||
|
title = "【新增】故障处置(YunxiaoPM快轨·极速v5)"
|
||||||
|
req_html = md_to_html(AUTO_RDO + (f"\n原型:{PROTO}\n" if has_prototype else "\n"))
|
||||||
|
req = create(s, req_payload(title, req_html))
|
||||||
|
rid = req["identifier"]
|
||||||
|
# 以落库 document 为准(与手动建需后读需求一致)
|
||||||
|
req_html = req_document_html(s, rid) or req_html
|
||||||
|
|
||||||
|
if delivery_html:
|
||||||
|
deliv_html = delivery_html
|
||||||
|
desc_source = "autoprd"
|
||||||
|
elif req_html.strip():
|
||||||
|
deliv_html = req_html
|
||||||
|
desc_source = "manual_sync"
|
||||||
|
else:
|
||||||
|
deliv_html = f"<p>{PLACEHOLDER}</p>"
|
||||||
|
desc_source = "placeholder"
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=2) as pool:
|
||||||
|
f_tag_r = pool.submit(apply_tag, session(), rid, tag_id)
|
||||||
|
f_deliv = pool.submit(
|
||||||
|
create,
|
||||||
|
session(),
|
||||||
|
task_payload(
|
||||||
|
f"【交付】{title}",
|
||||||
|
deliv_html,
|
||||||
|
HEFEI,
|
||||||
|
associated_req=rid,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
deliv = f_deliv.result()
|
||||||
|
f_tag_r.result()
|
||||||
|
did = deliv["identifier"]
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=2) as pool:
|
||||||
|
f_tag_d = pool.submit(apply_tag, session(), did, tag_id)
|
||||||
|
f_des = pool.submit(
|
||||||
|
create,
|
||||||
|
session(),
|
||||||
|
task_payload(
|
||||||
|
f"【设计】{title}",
|
||||||
|
req_html,
|
||||||
|
WANG,
|
||||||
|
parent_delivery=did,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
des = f_des.result()
|
||||||
|
f_tag_d.result()
|
||||||
|
des_id = des["identifier"]
|
||||||
|
apply_tag(s, des_id, tag_id)
|
||||||
|
|
||||||
|
# 计划时间:设计起止当日;交付开始当日(create 已带 79,再 field/value 加固)
|
||||||
|
set_fields(s, des_id, [("79", NOON), ("80", EOD)])
|
||||||
|
set_fields(s, did, [("79", NOON)])
|
||||||
|
|
||||||
|
# 设计关联项补挂需求(可能失败,回报 risk)
|
||||||
|
design_assoc_ok = try_associate_to_req(s, des_id, rid)
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=2) as pool:
|
||||||
|
list(
|
||||||
|
as_completed(
|
||||||
|
[
|
||||||
|
pool.submit(transit, session(), rid, PENDING, DESIGN_DONE),
|
||||||
|
pool.submit(transit, session(), des_id, PENDING, TASK_DONE),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
transit(s, rid, DESIGN_DONE, PENDING_DEV)
|
||||||
|
|
||||||
|
set_estimate_hours(s, rid, FAST_EST)
|
||||||
|
set_actual_hours(s, rid, FAST_ACT)
|
||||||
|
|
||||||
|
risk = None
|
||||||
|
if desc_source == "placeholder":
|
||||||
|
risk = "交付描述仍为占位"
|
||||||
|
if not design_assoc_ok:
|
||||||
|
risk = (risk + ";" if risk else "") + "设计 ASSOCIATED→需求补挂失败(Cookie),须 UI/OpenAPI 兜底"
|
||||||
|
|
||||||
|
return {
|
||||||
|
"path": "fast",
|
||||||
|
"elapsed_s": round(time.perf_counter() - t0, 3),
|
||||||
|
"req": summarize_from_create(req, status="待开发", assignee_name="王冕"),
|
||||||
|
"delivery": summarize_from_create(deliv, status="待处理", assignee_name="何斐"),
|
||||||
|
"design": summarize_from_create(des, status="已完成", assignee_name="王冕"),
|
||||||
|
"analysis": None,
|
||||||
|
"delivery_desc_source": desc_source,
|
||||||
|
"design_associated_ok": design_assoc_ok,
|
||||||
|
"risk": risk,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
auth0 = time.perf_counter()
|
||||||
|
load_auth()
|
||||||
|
auth_s = round(time.perf_counter() - auth0, 3)
|
||||||
|
|
||||||
|
wall0 = time.perf_counter()
|
||||||
|
with ThreadPoolExecutor(max_workers=2) as pool:
|
||||||
|
f_fast = pool.submit(build_fast)
|
||||||
|
f_normal = pool.submit(build_normal)
|
||||||
|
fast = f_fast.result()
|
||||||
|
normal = f_normal.result()
|
||||||
|
build_s = round(time.perf_counter() - wall0, 3)
|
||||||
|
|
||||||
|
s = session()
|
||||||
|
assert_associated_to_req(s, normal["delivery"]["id"], normal["req"]["id"], "normal.delivery")
|
||||||
|
assert_associated_to_req(s, fast["delivery"]["id"], fast["req"]["id"], "fast.delivery")
|
||||||
|
|
||||||
|
def assert_sub(delivery_id: str, child_id: str, label: str) -> None:
|
||||||
|
rows = api(
|
||||||
|
s,
|
||||||
|
"GET",
|
||||||
|
f"https://devops.aliyun.com/projex/api/workitem/v2/workitem/{delivery_id}/relation/workitem/list/by-relation-category?category=PARENT_SUB&isForward=true",
|
||||||
|
).get("result") or []
|
||||||
|
ids = {r.get("identifier") for r in rows}
|
||||||
|
if child_id not in ids:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"{label} 未出现在交付子项:期望 {child_id},实际 {[r.get('serialNumber') for r in rows]}"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert_sub(normal["delivery"]["id"], normal["analysis"]["id"], "normal.analysis")
|
||||||
|
assert_sub(normal["delivery"]["id"], normal["design"]["id"], "normal.design")
|
||||||
|
assert_sub(fast["delivery"]["id"], fast["design"]["id"], "fast.design")
|
||||||
|
verify = {
|
||||||
|
"normal_req": get(s, normal["req"]["id"])["status"]["displayName"],
|
||||||
|
"fast_req": get(s, fast["req"]["id"])["status"]["displayName"],
|
||||||
|
"normal_delivery_assignee": (
|
||||||
|
get(s, normal["delivery"]["id"]).get("assignedTo") or {}
|
||||||
|
).get("displayName"),
|
||||||
|
"fast_delivery_assignee": (get(s, fast["delivery"]["id"]).get("assignedTo") or {}).get(
|
||||||
|
"displayName"
|
||||||
|
),
|
||||||
|
"delivery_associated_ok": True,
|
||||||
|
"stage_tasks_as_sub_ok": True,
|
||||||
|
"fast_design_associated_ok": fast.get("design_associated_ok"),
|
||||||
|
}
|
||||||
|
out = {
|
||||||
|
"normal": normal,
|
||||||
|
"fast": fast,
|
||||||
|
"verify": verify,
|
||||||
|
"auth_elapsed_s": auth_s,
|
||||||
|
"wall_elapsed_s": build_s,
|
||||||
|
"created_at": datetime.now(TZ).isoformat(),
|
||||||
|
"mode": "live_create_fast_v5_fast_track_rules",
|
||||||
|
"opts": {
|
||||||
|
"create_includes_plan_start": True,
|
||||||
|
"skip_plan_end_on_create": True,
|
||||||
|
"tracked_transit_no_get": True,
|
||||||
|
"delivery_assignee_hefei_at_create": True,
|
||||||
|
"overlap_tag_with_create": True,
|
||||||
|
"fast_req_hours": f"{FAST_EST}+{FAST_ACT}",
|
||||||
|
"relation": "delivery ASSOCIATED→req; analysis/design TASK_SUB→delivery; design post ASSOCIATED→req",
|
||||||
|
"http": "requests.Session keep-alive",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
Path("/tmp/yunxiao_pmapp_fast_v2_result.json").write_text(
|
||||||
|
json.dumps(out, ensure_ascii=False, indent=2)
|
||||||
|
)
|
||||||
|
print(json.dumps(out, ensure_ascii=False, indent=2))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
92
.cursor/skills/YunxiaoPM/scripts/workday_hours.py
Executable file
92
.cursor/skills/YunxiaoPM/scripts/workday_hours.py
Executable file
@@ -0,0 +1,92 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Compute YunxiaoPMapp stage calendar hours = workdays × 8.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python3 workday_hours.py YYYY-MM-DD YYYY-MM-DD
|
||||||
|
python3 workday_hours.py YYYY-MM-DD YYYY-MM-DD --calendar /path/to/cn-workday-calendar.json
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from datetime import date, datetime, timedelta
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def parse_day(s: str) -> date:
|
||||||
|
return datetime.strptime(s, "%Y-%m-%d").date()
|
||||||
|
|
||||||
|
|
||||||
|
def load_calendar(path: Path) -> dict:
|
||||||
|
data = json.loads(path.read_text(encoding="utf-8"))
|
||||||
|
years = data.get("years") or {}
|
||||||
|
holidays: set[str] = set()
|
||||||
|
makeup: set[str] = set()
|
||||||
|
for _y, block in years.items():
|
||||||
|
holidays.update(block.get("holidays") or [])
|
||||||
|
makeup.update(block.get("workdays_on_weekend") or [])
|
||||||
|
return {"holidays": holidays, "makeup": makeup, "years": set(years.keys())}
|
||||||
|
|
||||||
|
|
||||||
|
def ensure_years_covered(start: date, end: date, years: set[str]) -> None:
|
||||||
|
y = start.year
|
||||||
|
while y <= end.year:
|
||||||
|
if str(y) not in years:
|
||||||
|
raise SystemExit(
|
||||||
|
f"缺少 {y} 年日历:请在 assets/cn-workday-calendar.json 补全后再计算。"
|
||||||
|
"禁止仅去周末静默估算。"
|
||||||
|
)
|
||||||
|
y += 1
|
||||||
|
|
||||||
|
|
||||||
|
def is_workday(d: date, holidays: set[str], makeup: set[str]) -> bool:
|
||||||
|
key = d.isoformat()
|
||||||
|
if key in holidays:
|
||||||
|
return False
|
||||||
|
if key in makeup:
|
||||||
|
return True
|
||||||
|
return d.weekday() < 5 # Mon=0 .. Fri=4
|
||||||
|
|
||||||
|
|
||||||
|
def count_workdays(start: date, end: date, holidays: set[str], makeup: set[str]) -> int:
|
||||||
|
if end < start:
|
||||||
|
raise SystemExit("结束日早于开始日")
|
||||||
|
n = 0
|
||||||
|
cur = start
|
||||||
|
while cur <= end:
|
||||||
|
if is_workday(cur, holidays, makeup):
|
||||||
|
n += 1
|
||||||
|
cur += timedelta(days=1)
|
||||||
|
return n
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
parser = argparse.ArgumentParser(description="阶段日历工时 = 工作日×8")
|
||||||
|
parser.add_argument("start", help="计划开始 YYYY-MM-DD")
|
||||||
|
parser.add_argument("end", help="计划完成 YYYY-MM-DD")
|
||||||
|
parser.add_argument(
|
||||||
|
"--calendar",
|
||||||
|
default=str(Path(__file__).resolve().parent.parent / "assets" / "cn-workday-calendar.json"),
|
||||||
|
help="日历 JSON 路径",
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
start = parse_day(args.start)
|
||||||
|
end = parse_day(args.end)
|
||||||
|
cal = load_calendar(Path(args.calendar))
|
||||||
|
ensure_years_covered(start, end, cal["years"])
|
||||||
|
days = count_workdays(start, end, cal["holidays"], cal["makeup"])
|
||||||
|
hours = days * 8
|
||||||
|
out = {
|
||||||
|
"start": start.isoformat(),
|
||||||
|
"end": end.isoformat(),
|
||||||
|
"workdays": days,
|
||||||
|
"stage_calendar_hours": hours,
|
||||||
|
"label": "阶段日历工时(工作日×8),非人力投入预估",
|
||||||
|
}
|
||||||
|
print(json.dumps(out, ensure_ascii=False, indent=2))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
63
.cursor/skills/YunxiaoPM/stage-flow.md
Normal file
63
.cursor/skills/YunxiaoPM/stage-flow.md
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# 标准路径:待处理 → 待开发交棒
|
||||||
|
|
||||||
|
项目常量见 [../assets/runtime-ids.json](../assets/runtime-ids.json)。查重只用任务编号。
|
||||||
|
|
||||||
|
## 步骤 0|创建需求
|
||||||
|
|
||||||
|
| 云效动作 | 落地 |
|
||||||
|
|---|---|
|
||||||
|
| 新建产品类需求 | POST 建单;标题 `【新增】`/`【优化】` |
|
||||||
|
| 需求描述 | **先** AutoRDO 清洗再写入 `## 原始诉求(AutoRDO)`;本步不写 AutoPRD |
|
||||||
|
| 默认状态 | **待处理**;不建任务、不改负责人 |
|
||||||
|
| 可选推进 | 口令点选目标状态;未选则停在待处理 |
|
||||||
|
|
||||||
|
## 步骤 1|受理 → 已确认
|
||||||
|
|
||||||
|
| 云效动作 | 落地 |
|
||||||
|
|---|---|
|
||||||
|
| 状态 | 待处理 → **已确认** |
|
||||||
|
| 任务 | **仍不建**交付/分析/设计 |
|
||||||
|
|
||||||
|
若用户只「创建」未受理:只提示「受理后请推进至已确认」,不自动跳。
|
||||||
|
|
||||||
|
## 步骤 2|分析中
|
||||||
|
|
||||||
|
| 对象 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| 【交付】 | 无则新建;标题 `【交付】`+需求标题;**ASSOCIATED→需求**(勿用 PARENT);负责人=创建人/产品;**计划开始仅空时写当日**;不写计划完成;描述=`等待设计任务完成后自动填入`;更新编号区块 |
|
||||||
|
| 【分析】 | 新建;**TASK_SUB→交付**(`parent`+`parentIdentifier`+`createWorkitemRelationInfo=TASK_SUB`);交付「子项」须可见;计划开始=当日(仅空时);负责人默认可=创建人;更新编号区块 |
|
||||||
|
|
||||||
|
| 需求 | 状态=`分析中` |
|
||||||
|
|
||||||
|
## 步骤 3|设计中
|
||||||
|
|
||||||
|
| 对象 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| 【交付】 | 已存在则按编号复用;没有则补建;**不改交付计划开始**;不写交付计划完成 |
|
||||||
|
| 【设计】 | 新建;**TASK_SUB→交付**(同分析);计划开始=当日(仅空时);更新编号区块 |
|
||||||
|
| 【分析】 | **计划完成**=状态更新日;推算阶段日历工时(见 work-hours) |
|
||||||
|
| 需求 | 状态=`设计中` |
|
||||||
|
|
||||||
|
## 步骤 4|设计完成
|
||||||
|
|
||||||
|
| 对象 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| 【设计】 | 计划完成=当日;推算工时;任务→完成态 |
|
||||||
|
| 需求 | AutoPRD 写入 `## 产品说明`;挂 ZIP+截图;状态=`设计完成` |
|
||||||
|
| 【交付】 | 不换负责人;不改计划开始;不写计划完成;描述改为 AutoPRD 正文;同样挂附件 |
|
||||||
|
|
||||||
|
顺序与失败门禁见 [description-split.md](description-split.md)。
|
||||||
|
|
||||||
|
## 步骤 5|待开发交棒(本 Skill 终点 · 标准路径)
|
||||||
|
|
||||||
|
| 对象 | 动作 |
|
||||||
|
|---|---|
|
||||||
|
| 需求 | 状态=`待开发` |
|
||||||
|
| 【交付】 | 按**任务编号**定位;**负责人→何斐**;不改计划开始;不写计划完成 |
|
||||||
|
| 【分析】/【设计】 | 不新建;不改已有计划开始;前序未收口按步骤 3/4 处理 |
|
||||||
|
|
||||||
|
执行 [handoff-and-rollback.md](handoff-and-rollback.md) §交棒门禁。
|
||||||
|
|
||||||
|
**不做:** 【开发】/【测试】、仓库、分支、提测。
|
||||||
|
|
||||||
|
快轨 / 编号直推见专文。创建迭代见 [sprint.md](sprint.md)。
|
||||||
@@ -1,146 +1,108 @@
|
|||||||
---
|
---
|
||||||
name: oneos-autoprd
|
name: oneos-autoprd
|
||||||
description: >-
|
description: >-
|
||||||
Generates and keeps in sync OneOS AutoPRD (PM-facing requirements) plus Axhub
|
OneOS AutoPRD: generates PM-facing requirements (总览/目标/边界/角色/用户故事
|
||||||
Make annotation directory Markdown/PRD; on 需求定稿/定稿/确认定稿/本次定稿 appends
|
起点→运作→闭环/故事点/正逆向/流程图/关键逻辑/状态/风险/交付) and syncs Axhub Make
|
||||||
functional release changelog below the PRD since last baseline. When a Yunxiao
|
annotation PRD. On 需求定稿/本轮定稿 appends functional changelog with auto
|
||||||
requirement advances to 分析中/设计中/待开发, creates a same-titled linked task
|
V主.副.子 (user 主/副/子 override wins). With YunxiaoPMapp design-complete,
|
||||||
(tag+create-time follow the requirement; 分析中/设计中 assignee=creator, 待开发
|
writes Markdown into 【交付】 by task number (not at create; placeholder until then).
|
||||||
assignee=何斐). Use eagerly for prototypes, AutoPRD, or Yunxiao requirement
|
Use for AutoPRD, prototypes, 产品说明, 本轮定稿. Never create same-titled stage
|
||||||
description/更新内容/stage advance—do not skip annotation sync, 定稿 changelog,
|
tasks; never load yunxiao-requirement-lifecycle—cloud combo is YunxiaoPMapp only.
|
||||||
or stage-task creation.
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# OneOS AutoPRD
|
# AutoPRD(oneos-autoprd)
|
||||||
|
|
||||||
为 OneOS 业务模块生成**产品经理可读、可评审、可排期**的需求说明,并**自动挂到 Axhub Make 标注工具 → 原型目录**。
|
为 OneOS 业务模块生成**产品经理可读、可评审、可排期**的需求说明,并**自动挂到 Axhub Make 标注工具 → 原型目录**。
|
||||||
|
|
||||||
另支持:**需求定稿**时汇总功能/逻辑变更记录;与云效组合时提供「需求说明 + 更新内容」;需求进入**分析中 / 设计中 / 待开发**时**自动创建与需求同名的关联任务**(规则见下,写在本 Skill,不改云效 Skill)。
|
另支持:**本轮定稿 / 需求定稿**时汇总功能变更并**自动递增 PRD 版本号**;与 **`$YunxiaoPMapp`** 组合时,在**设计完成**(或显式同步交付)把 Markdown 写入【交付】任务描述。
|
||||||
|
|
||||||
颗粒度对齐「保险采购」全模块 PRD:讲清做什么、谁用、故事点、正逆向、流程图与关键业务逻辑;**不写**表结构、接口、字段代码名、文件路径、实现清单。
|
**禁止加载** `yunxiao-requirement-lifecycle`。云效状态机与【交付】/【分析】/【设计】树**只**由 YunxiaoPMapp 负责;本 Skill **不**建同名无前缀阶段任务。
|
||||||
|
|
||||||
|
颗粒度:讲清做什么、谁用、故事点、正逆向、流程图与关键业务逻辑;**不写**表结构、接口、字段代码名、文件路径、实现清单。
|
||||||
|
|
||||||
## 何时使用(含自动触发)
|
## 何时使用(含自动触发)
|
||||||
|
|
||||||
**主动调用时**
|
**主动调用**
|
||||||
|
|
||||||
- AutoPRD、OneOS 需求说明、整模块 PRD、故事点 + 流程图
|
- AutoPRD、OneOS 需求说明、整模块 PRD、故事点 + 流程图、产品说明
|
||||||
|
|
||||||
**改原型时必须自动跟进(全局规则)**
|
**改原型时必须自动跟进**
|
||||||
|
|
||||||
- 正在修改 `src/prototypes/<id>/` 下页面、交互、文案、判定、验收相关内容
|
- 修改 `src/prototypes/<id>/` 下页面、交互、文案、判定、验收相关内容
|
||||||
- 同一轮交付内同步更新 PRD Markdown + 标注目录,不得只改代码
|
- 同一轮同步更新 PRD Markdown + 标注目录;**纯样式且无产品语义变化可跳过全量重写**
|
||||||
|
|
||||||
**需求定稿时(强制)**
|
**需求定稿时(强制)**
|
||||||
|
|
||||||
- 用户回复含:`需求定稿` / `定稿` / `确认定稿` / `本次定稿`
|
- 关键字:`需求定稿` / `定稿` / `确认定稿` / `本次定稿` / **`本轮定稿`**
|
||||||
- 执行 [references/release-changelog.md](references/release-changelog.md):写第 10 章 + 更新基线
|
- 执行 [references/release-changelog.md](references/release-changelog.md):第 10 章 + `prdVersion` 基线
|
||||||
|
|
||||||
**云效建需求 / 完善需求时(强制组合)**
|
**与 YunxiaoPMapp 组合(强制 · 唯一云效组合)**
|
||||||
|
|
||||||
- 与 `$yunxiao-requirement-lifecycle` 一起使用时:先跑本 Skill,再写云效描述
|
- 设计完成或完善「产品说明」:先本 Skill 落盘 MD,再由 YunxiaoPMapp / 本 Skill 按 [yunxiao-description.md](references/yunxiao-description.md) 写入需求 `## 产品说明(AutoPRD)`(**不覆盖** `## 原始诉求(AutoRDO)` / `## 工作项编号(系统)`)
|
||||||
- **需求说明** ← PRD 正文(或浓缩交付口径 + 关键章节)
|
- **创建【交付】时不写 PRD 正文**(占位由 YunxiaoPMapp 写入);设计完成或口令「同步交付说明」时按 [yunxiao-delivery-sync.md](references/yunxiao-delivery-sync.md) 用任务**编号**回填【交付】
|
||||||
- **更新内容** ← 第 10 章中**自上次定稿以来**的条目(无增量则「首版定稿 / 本轮无功能增量」)
|
- 入库前聊天/录音清洗:先 `$AutoRDO`,再 YunxiaoPMapp 记录需求
|
||||||
|
|
||||||
**云效需求推进至分析中 / 设计中 / 待开发时(强制)**
|
|
||||||
|
|
||||||
- 无论口令来自本 Skill 还是云效 Skill,只要本轮把需求推到上述状态,就执行 [references/yunxiao-stage-tasks.md](references/yunxiao-stage-tasks.md)
|
|
||||||
- 自动建**与需求同名**的任务并正式关联;标签与创建时间口径沿用需求;分析中/设计中负责人=创建人,待开发负责人=**何斐**
|
|
||||||
|
|
||||||
不要用本 Skill 替代:需求探索访谈、设计比稿、纯样式微调(无产品语义变化时可跳过全量重写)。
|
|
||||||
|
|
||||||
## 工作流
|
## 工作流
|
||||||
|
|
||||||
### 主流程(写/同步 PRD)
|
### 主流程(写/同步 PRD)
|
||||||
|
|
||||||
1. **定模块**:确认 OneOS 模块名与 `src/prototypes/<prototype-id>/`。
|
1. **定模块**:OneOS 模块名与 `src/prototypes/<prototype-id>/`。
|
||||||
2. **读上下文(只取产品语义)**
|
2. **读上下文(只取产品语义)**
|
||||||
- 用户说明、已确认口径、原型标注、`.spec/`、业务条线说明(`lines.ts`)
|
- 用户说明、已确认口径、原型标注、`.spec/`、业务条线说明(`lines.ts`)
|
||||||
- 忽略实现细节;字段名/接口改写成业务语言。
|
- 忽略实现细节;字段名/接口改写成业务语言。
|
||||||
3. **收敛边界**:做什么 / 不做什么、外部依赖、与其它模块关系。
|
3. **收敛边界**:做什么 / 不做什么、外部依赖、与其它模块关系。
|
||||||
4. **按模板成文**:下方「输出结构」;缺关键信息最多问 1~2 个问题,其余写「假设」。
|
4. **按模板成文**:见「输出结构」与 [references/template.md](references/template.md)。
|
||||||
5. **落盘 + 标注同步(强制)** — 见 [references/annotation-sync.md](references/annotation-sync.md)。
|
5. **落盘 + 标注同步(强制)** — [references/annotation-sync.md](references/annotation-sync.md)。
|
||||||
|
|
||||||
| 顺序 | 动作 |
|
| 顺序 | 动作 |
|
||||||
|------|------|
|
|------|------|
|
||||||
| A | 写/更新 `src/prototypes/<id>/.spec/requirements-prd.md` |
|
| A | 写/更新 `src/prototypes/<id>/.spec/requirements-prd.md` |
|
||||||
| B | 写/更新 `src/resources/prd/<id>-autoprd.md` |
|
| B | 写/更新 `src/resources/prd/<id>-autoprd.md` |
|
||||||
| C | 更新 `annotation-source.json` **顶层** `directory.nodes`(PRD 全文 + 推荐分章);禁止只写 `data.directory` |
|
| C | 更新 `annotation-source.json` **顶层** `directory.nodes`(PRD 全文 + 推荐分章) |
|
||||||
| D | 若存在 `scripts/sync-annotation-directory.mjs`,执行之 |
|
| D | 若存在 `scripts/sync-annotation-directory.mjs`,执行之 |
|
||||||
|
|
||||||
6. **交付说明**:路径、标注目录入口、故事点合计、开放问题/假设。
|
6. **交付说明**:路径、标注入口、故事点合计、开放问题/假设。
|
||||||
|
|
||||||
### 定稿流程(关键字触发)
|
### 定稿流程
|
||||||
|
|
||||||
见 [references/release-changelog.md](references/release-changelog.md)。摘要:
|
见 [references/release-changelog.md](references/release-changelog.md)。含自动 `V主.副.子`;**用户显式指定主/副/子时以用户为准**。
|
||||||
|
|
||||||
1. 读 PRD + `.spec/autoprd-baseline.json`
|
### 云效需求「产品说明」(与 YunxiaoPMapp 双段模板)
|
||||||
2. 汇总自上次定稿以来的**功能/逻辑**变更(排除样式/UI/表结构)
|
|
||||||
3. 追加到 `## 10. 功能变更记录`(最新在上)
|
|
||||||
4. 更新基线 JSON + 标注目录
|
|
||||||
5. 若同时发云效:本次定稿块 →「更新内容」;旧段 →「更新内容·历史」
|
|
||||||
|
|
||||||
### 云效交接格式(给 yunxiao skill 直接粘贴)
|
见 [references/yunxiao-description.md](references/yunxiao-description.md)。
|
||||||
|
|
||||||
```markdown
|
### 云效【交付】回填(设计完成 · 非创建时)
|
||||||
## 原型链接
|
|
||||||
<对象存储或预览 URL>
|
|
||||||
|
|
||||||
## 需求说明
|
见 [references/yunxiao-delivery-sync.md](references/yunxiao-delivery-sync.md)。
|
||||||
<AutoPRD 正文或交付口径 + 必要章节>
|
|
||||||
|
|
||||||
## 更新内容
|
|
||||||
<第 10 章本次定稿块;无则「首版定稿」或「本轮无功能/逻辑增量」>
|
|
||||||
|
|
||||||
## 更新内容·历史
|
|
||||||
<以往更新内容倒序,勿删除>
|
|
||||||
```
|
|
||||||
|
|
||||||
### 云效阶段任务(状态推进时强制)
|
|
||||||
|
|
||||||
见 [references/yunxiao-stage-tasks.md](references/yunxiao-stage-tasks.md)。摘要:
|
|
||||||
|
|
||||||
| 需求状态 | 任务标签 | 负责人 | 标题 |
|
|
||||||
|----------|----------|--------|------|
|
|
||||||
| 分析中 | 分析 | 需求创建人 | 与需求同名 |
|
|
||||||
| 设计中 | 设计 | 需求创建人 | 与需求同名 |
|
|
||||||
| 待开发 | 交付(或开发) | 何斐 | 与需求同名 |
|
|
||||||
|
|
||||||
正式关联需求;创建时间口径沿用需求;同阶段未取消任务不重复建。
|
|
||||||
|
|
||||||
## 写作硬约束
|
## 写作硬约束
|
||||||
|
|
||||||
**必须写**
|
**必须写(映射用户概要)**
|
||||||
|
|
||||||
- 一句话定位 + 目标 / 非目标
|
| 概要能力 | 落在章节 |
|
||||||
- 模块边界(含 mermaid 总览更好)
|
|---|---|
|
||||||
- 角色与目标(角色名优先对齐业务条线说明)
|
| 总览 | §1 一句话与目标 |
|
||||||
- **用户故事**(业务条线说明口径)+ Epic 级**故事点(SP)**粗估
|
| 目标 / 边界 | §1–2 |
|
||||||
- 分功能**正向**与**逆向/边界**
|
| 角色 | §3 |
|
||||||
- 至少 1~2 个 **mermaid** 流程图
|
| 用户故事(起点→运作→闭环)+ 故事点 | §4 |
|
||||||
- **关键业务逻辑**(业务话)
|
| 正逆向流程 | §5 |
|
||||||
- 验收清单 + 「交付口径」一段话
|
| 关键逻辑 / 状态 / 风险 | §6(及验收相关) |
|
||||||
- 定稿后:**功能变更记录**(第 10 章)
|
| 流程图 | §7 |
|
||||||
|
| 交付 | §9 交付口径 |
|
||||||
|
| 定稿变更 | §10 |
|
||||||
|
|
||||||
|
另:验收清单 §8;对象存储预览链接形态 `{baseUrl}/{prototype-id}/index.html`(禁止加 `prototypes/` 前缀、禁止去掉 `index.html`)。
|
||||||
|
|
||||||
**禁止写**
|
**禁止写**
|
||||||
|
|
||||||
- 数据库表、字段名、接口路径、代码路径、组件名、存储 key
|
- 数据库表、字段名、接口路径、代码路径、组件名、存储 key
|
||||||
- 研发实现指令(可写「正式环境由审批中心回写」这类业务依赖)
|
- 变更记录里的样式/UI/表结构优化
|
||||||
- 在变更记录里写样式/UI/表结构优化
|
- 引导加载 `yunxiao-requirement-lifecycle` 或「同名阶段任务」建单
|
||||||
|
|
||||||
## 用户故事口径(强制 · 对齐业务条线说明)
|
## 用户故事口径(强制 · 对齐业务条线说明)
|
||||||
|
|
||||||
真相源:原型 **业务条线说明**(`lease-business-line-overview` / `lines.ts`)。
|
真相源:业务条线说明(`lease-business-line-overview` / `lines.ts`)。
|
||||||
每条能力用「责任部门 → **起点** → **怎么运作** → **闭环**」叙述;**不要**用「作为…我希望…」宽表作主叙述。
|
主叙述:**起点 → 怎么运作 → 闭环**(不要用「作为…我希望…」宽表作主叙述)。
|
||||||
|
|
||||||
| 块 | 写什么 |
|
|
||||||
|----|--------|
|
|
||||||
| 角色 | 谁负责、谁协同 |
|
|
||||||
| 起点 | 谁在什么前提下启动 |
|
|
||||||
| 怎么运作 | 有序步骤,含跨角色协作 |
|
|
||||||
| 关键结果 | 可选标签 |
|
|
||||||
| 闭环 | 业务终点与可追溯性 |
|
|
||||||
|
|
||||||
可选:`US-xx`、压缩句「作为…我想…以便…」、规模 S/M/L 或 SP(仅排期,不替代主叙述)。
|
|
||||||
|
|
||||||
## 输出结构
|
## 输出结构
|
||||||
|
|
||||||
@@ -158,26 +120,27 @@ description: >-
|
|||||||
## 7. 总览流程图
|
## 7. 总览流程图
|
||||||
## 8. 验收清单
|
## 8. 验收清单
|
||||||
## 9. 交付口径
|
## 9. 交付口径
|
||||||
## 10. 功能变更记录 ← 定稿后维护;日常改原型不强制每改必写
|
## 10. 功能变更记录 ← 定稿维护;含 V主.副.子
|
||||||
```
|
```
|
||||||
|
|
||||||
## 质量自检
|
## 质量自检
|
||||||
|
|
||||||
- [ ] 产品经理不看代码也能评审
|
- [ ] 产品经理不看代码也能评审
|
||||||
- [ ] 用户故事为起点 / 怎么运作 / 闭环
|
- [ ] 用户故事为起点 / 怎么运作 / 闭环
|
||||||
- [ ] `.spec/requirements-prd.md` 已更新
|
- [ ] `.spec/requirements-prd.md` + 标注目录已同步
|
||||||
- [ ] 标注目录「产品需求说明(PRD)」已同步且正文一致
|
- [ ] 定稿时:第 10 章含版本号 + `autoprd-baseline.json` 含 `prdVersion`
|
||||||
- [ ] 定稿时:第 10 章 + `autoprd-baseline.json` 已更新
|
- [ ] 与 YunxiaoPMapp 设计完成:【交付】按**编号**回填,创建时未提前灌 MD
|
||||||
- [ ] 推进至分析中/设计中/待开发时:同名任务已创建或复用,正式关联,负责人正确
|
- [ ] 全文无 `yunxiao-requirement-lifecycle` 引导;无同名阶段任务建单
|
||||||
- [ ] 无表结构 / 接口 / 代码路径;变更记录无样式/UI 废话
|
- [ ] 变更记录无样式/UI/表结构废话
|
||||||
|
|
||||||
## 参考
|
## 参考
|
||||||
|
|
||||||
- 定稿变更日志:[references/release-changelog.md](references/release-changelog.md)
|
- 定稿与版本:[references/release-changelog.md](references/release-changelog.md)
|
||||||
- 云效阶段任务:[references/yunxiao-stage-tasks.md](references/yunxiao-stage-tasks.md)
|
- 云效产品说明:[references/yunxiao-description.md](references/yunxiao-description.md)
|
||||||
- 标注同步细则:[references/annotation-sync.md](references/annotation-sync.md)
|
- 【交付】回填:[references/yunxiao-delivery-sync.md](references/yunxiao-delivery-sync.md)
|
||||||
- 章节模板:[references/template.md](references/template.md)
|
- 标注同步:[references/annotation-sync.md](references/annotation-sync.md)
|
||||||
|
- 模板:[references/template.md](references/template.md)
|
||||||
- 故事示例:[references/granularity-example.md](references/granularity-example.md)
|
- 故事示例:[references/granularity-example.md](references/granularity-example.md)
|
||||||
- 业务条线:`src/prototypes/lease-business-line-overview/lines.ts`
|
- 业务条线:`src/prototypes/lease-business-line-overview/lines.ts`
|
||||||
- 复杂判定规格:配合项目规则 `business-logic-documentation`
|
- 云效组合(唯一):`$YunxiaoPMapp`
|
||||||
- 云效组合:`$yunxiao-requirement-lifecycle`(建需求时先本 Skill)
|
- 入库清洗:`$AutoRDO`
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user