Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pnpm dev # http://localhost:3000 ;Console 在 /_console/ ;管理员 adm
| D3 重启与清理 | 改对象/视图/hook 需重启 dev;清理 `dist/` 与 `.objectstack/` 下本实例数据库(种子数据可重建) |
| D4 测试账号 | 管理员 admin@objectos.ai / admin123;各岗位账号在 Setup 建用户后分配岗位:人力审核、人力负责人、部门填报、分公司核对、分管领导(种子只建组织树,用户不可种子) |
| E1 报告形态 | Markdown 测试报告挂工作项评论(模板见 os-project-dev-test) |
| E2 截图归档 | 孤儿分支 `acceptance-evidence`,图链用 commit SHA 形式;**截图与证据文件禁止提交到 main 或功能分支的代码树**(`docs/evidence/` 已在 .gitignore),维护者 2026-09-02 要求 |
| E2 截图归档 | 孤儿分支 `acceptance-evidence`,图链用 commit SHA 形式;**截图与证据文件禁止提交到 main 或功能分支的代码树**(`docs/evidence/` 已在 .gitignore);**例外:操作手册的配图**是手册正文的一部分,随源稿归档在 `docs/手册/图片/`(维护者 2026-09-03 决定),维护者 2026-09-02 要求 |
| F2 合并权限 | 无——仅库级授权生效(AI 不自行合并) |
| G1 失败升级 | 工作项评论 @ 技术负责人 |
| G2 平台问题上报 | objectstack-ai/objectstack 仓库 issue(现象、最小复现、期望能力、平台版本);**只上报,不修复**——不认领平台 issue、不在平台仓开 PR(维护者 2026-09-03 要求) |
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
| [docs/00-设计方案.md](docs/00-设计方案.md) | 设计方案 V1.0(客户 2026-09-02 确认,唯一需求基准);Word 成品在 [docs/交付/](docs/交付/)(V0.9 送审稿、V1.0 客户确认版),由 `pnpm docs:docx` 从本源稿生成 |
| [docs/01-需求解读报告.md](docs/01-需求解读报告.md) | 场景地图、平台能力覆盖度、风险、疑点(疑点已由设计方案 V1.0 关闭) |
| [docs/02-总体方案蓝图.md](docs/02-总体方案蓝图.md) | os 能力映射、对象模型总图、模块依赖与开发顺序 |
| [docs/手册/KPI考核管理系统-操作手册.md](docs/手册/KPI考核管理系统-操作手册.md) | 分角色操作手册 V0.1(送审稿):通用操作 + 五个业务角色分章,含真实系统截图;Word 成品在 [docs/交付/](docs/交付/),由 `pnpm docs:manual` 从本源稿生成 |
| [CLAUDE.md](CLAUDE.md) | 开发约定与 dev-issue 启用清单 |

## 快速开始
Expand Down
Binary file not shown.
1,190 changes: 1,190 additions & 0 deletions docs/手册/KPI考核管理系统-操作手册.md

Large diffs are not rendered by default.

Binary file added docs/手册/图片/01-01-denglu.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/手册/图片/01-02-gongzuotai.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/手册/图片/01-03-qiehuan-yingyong.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/手册/图片/01-04-daiban-duilie.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/手册/图片/01-05-xiugai-mima.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/手册/图片/01-06-daochu-excel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/手册/图片/02-01-zhibiaoku-liebiao.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/手册/图片/02-04-zhibiao-xiangqing.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/手册/图片/02-05-jieti-qujian.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/手册/图片/02-06-fangan-liebiao.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/手册/图片/02-07-xinjian-fangan.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/手册/图片/02-10-fangan-xiangqing.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/手册/图片/02-11-liucheng-jiedian.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/手册/图片/02-12-canyu-zhuti.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/手册/图片/02-16-daochu-excel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/手册/图片/02-17-daoru-duihuakuang.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/手册/图片/02-20-zhengyi-daichuli.png
Binary file added docs/手册/图片/02-21-caina-zhengyi.png
Binary file added docs/手册/图片/02-22-fabu-queren.png
Binary file added docs/手册/图片/02-24-fabu-chenggong.png
Binary file added docs/手册/图片/02-25-renli-shenhe-duilie.png
Binary file added docs/手册/图片/02-26-bohui-duihuakuang.png
Binary file added docs/手册/图片/02-27-shenhe-tongguo.png
Binary file added docs/手册/图片/02-28-dengji-jiajianfen.png
Binary file added docs/手册/图片/02-30-pizhun-luodi.png
Binary file added docs/手册/图片/02-31-guidang.png
Binary file added docs/手册/图片/02-32-guidang-kuaizhao.png
Binary file added docs/手册/图片/02-33-shenji-chaxun.png
Binary file added docs/手册/图片/03-01-tianbaodan-liebiao.png
Binary file added docs/手册/图片/03-03-luru-shijizhi.png
Binary file added docs/手册/图片/03-04-jisuan-shuoming.png
Binary file added docs/手册/图片/03-05-daoru-mingxi.png
Binary file added docs/手册/图片/03-06-tijiao-beilan.png
Binary file added docs/手册/图片/03-07-tijiao-chenggong.png
Binary file added docs/手册/图片/03-08-bohui-yuanyin.png
Binary file added docs/手册/图片/03-10-tijiao-shenpi.png
Binary file added docs/手册/图片/04-01-daiwo-hedui.png
Binary file added docs/手册/图片/04-03-tichu-zhengyi.png
Binary file added docs/手册/图片/04-04-queren-wuwu.png
Binary file added docs/手册/图片/05-02-pizhun-jiajianfen.png
Binary file added docs/手册/图片/06-05-jieguo-kanban.png
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
"test": "vitest run",
"verify": "pnpm validate && pnpm typecheck && pnpm test",
"e2e": "node scripts/e2e-flow.mjs",
"docs:docx": "node scripts/md2docx.cjs docs/00-设计方案.md docs/交付/KPI考核管理系统-设计方案-V1.0.docx"
"docs:docx": "node scripts/md2docx.cjs docs/00-设计方案.md docs/交付/KPI考核管理系统-设计方案-V1.0.docx",
"docs:manual": "node scripts/md2docx.cjs docs/手册/KPI考核管理系统-操作手册.md docs/交付/KPI考核管理系统-操作手册-V0.1.docx"
},
"dependencies": {
"@objectstack/connector-mcp": "^17.2.0",
Expand Down
37 changes: 31 additions & 6 deletions scripts/md2docx.cjs
Original file line number Diff line number Diff line change
@@ -1,13 +1,36 @@
// Minimal Markdown → docx converter for the design proposal (headings, cover div,
// version table, tables with captions, bullets, paragraphs, code block, page breaks).
// Minimal Markdown → docx converter for the delivery documents (headings, cover div,
// version table, tables with captions, bullets, paragraphs, code block, page breaks,
// and images: a `![alt](相对路径.png)` line is embedded, scaled to the text width and centred).
const fs = require('fs');
const path = require('path');
const D = require('docx');
const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell, WidthType, HeadingLevel, AlignmentType, PageBreak, ShadingType, BorderStyle, LevelFormat, TableOfContents, Footer, Header, PageNumber } = D;
const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell, WidthType, HeadingLevel, AlignmentType, PageBreak, ShadingType, BorderStyle, LevelFormat, TableOfContents, Footer, Header, PageNumber, ImageRun } = D;

const src = fs.readFileSync(process.argv[2], 'utf8').split('\n');
const out = process.argv[3];
let coverChildren = []; let versionText = "";
const SRC_DIR = path.dirname(path.resolve(process.argv[2]));
/** 版心宽度(px @96dpi):A4 宽 11906 twip − 左右页边距 1500 twip ×2 = 8906 twip。 */
const CONTENT_PX = Math.floor((8906 / 1440) * 96);
/** 从 PNG 的 IHDR 块直接读宽高(避免引入图像库)。 */
function pngSize(buf) {
if (buf.length < 24 || buf.readUInt32BE(0) !== 0x89504e47) return null;
return { width: buf.readUInt32BE(16), height: buf.readUInt32BE(20) };
}
function imageParagraph(relPath) {
const file = path.resolve(SRC_DIR, decodeURIComponent(relPath));
const buf = fs.readFileSync(file);
const size = pngSize(buf);
if (!size) throw new Error('unsupported image (PNG only): ' + file);
const width = Math.min(size.width, CONTENT_PX);
const height = Math.round((size.height * width) / size.width);
return new Paragraph({
children: [new ImageRun({ data: buf, type: 'png', transformation: { width, height } })],
alignment: AlignmentType.CENTER,
spacing: { before: 160, after: 60 },
keepNext: true,
});
}
let coverChildren = []; let versionText = ""; let docName = "设计方案"; let coverTitleCount = 0;
const FONT_CN = 'SimSun', FONT_HEAD = 'SimHei', FONT_EN = 'Times New Roman', FONT_MONO = 'Consolas';
const runs = (text, extra = {}) => {
// inline **bold** and `code`
Expand Down Expand Up @@ -56,6 +79,7 @@ while (i < src.length) {
if (inCover) {
const t = line.replace(/^#+\s*/, '').replace(/\*\*/g, '');
const isTitle = line.startsWith('#');
if (isTitle) { coverTitleCount += 1; if (coverTitleCount === 2) docName = t.trim(); }
if (/^版本号/.test(t)) versionText = t.replace(/^版本号[::]\s*/, "").replace(/[((].*$/, "").trim();
coverChildren.push(new Paragraph({ children: [new TextRun({ text: t, bold: true, size: isTitle ? 48 : 28, font: { eastAsia: isTitle ? FONT_HEAD : FONT_CN, ascii: FONT_EN, hAnsi: FONT_EN } })], alignment: AlignmentType.CENTER, spacing: { before: isTitle ? 360 : 120, after: 120 } }));
continue;
Expand All @@ -67,13 +91,14 @@ while (i < src.length) {
if ((m = line.match(/^### (.+)/))) { children.push(new Paragraph({ heading: HeadingLevel.HEADING_3, children: [new TextRun({ text: m[1], bold: true, size: 24, font: { eastAsia: FONT_HEAD, ascii: FONT_EN, hAnsi: FONT_EN }, color: '1B2540' })], spacing: { before: 200, after: 100 } })); continue; }
if ((m = line.match(/^\*\*(表 \d+ [^*]+)\*\*$/))) { pendingCaption = m[1]; continue; }
if (line.startsWith(">")) { const qt = line.replace(/^>\s?/, ""); if (qt.trim() === "") continue; children.push(new Paragraph({ children: runs(qt, { size: 21 }), indent: { left: 480, right: 480 }, shading: { fill: "F2F4F7", type: ShadingType.CLEAR, color: "auto" }, spacing: { after: 40, line: 300 } })); continue; }
if ((m = line.match(/^!\[[^\]]*\]\(([^)]+)\)\s*$/))) { children.push(imageParagraph(m[1])); continue; }
if ((m = line.match(/^(图 \d+ .+)$/))) { children.push(new Paragraph({ children: runs(m[1], { bold: true, size: 22 }), alignment: AlignmentType.CENTER, spacing: { after: 160 } })); continue; }
if ((m = line.match(/^- (.+)/))) { children.push(new Paragraph({ children: runs(m[1]), numbering: { reference: 'bul', level: 0 }, spacing: { after: 80, line: 340 } })); continue; }
children.push(para(line));
}
flushTable();
const doc = new Document({
creator: 'KPI 项目组', title: 'KPI 考核管理系统 设计方案 ' + versionText,
creator: 'KPI 项目组', title: 'KPI 考核管理系统 ' + docName + ' ' + versionText,
styles: { default: { document: { run: { font: { eastAsia: FONT_CN, ascii: FONT_EN, hAnsi: FONT_EN }, size: 24 } } } },
numbering: { config: [{ reference: 'bul', levels: [{ level: 0, format: LevelFormat.BULLET, text: '•', alignment: AlignmentType.LEFT, style: { paragraph: { indent: { left: 480, hanging: 240 } } } }] }] },
features: { updateFields: true },
Expand All @@ -82,7 +107,7 @@ const doc = new Document({
children: coverChildren,
}, {
properties: { page: { margin: { top: 1440, bottom: 1440, left: 1500, right: 1500 }, pageNumbers: { start: 1 } } },
headers: { default: new Header({ children: [new Paragraph({ children: [new TextRun({ text: 'KPI 考核管理系统 · 设计方案 ' + versionText, size: 18, color: '6C7686', font: { eastAsia: FONT_CN } })], alignment: AlignmentType.RIGHT })] }) },
headers: { default: new Header({ children: [new Paragraph({ children: [new TextRun({ text: 'KPI 考核管理系统 · ' + docName + ' ' + versionText, size: 18, color: '6C7686', font: { eastAsia: FONT_CN } })], alignment: AlignmentType.RIGHT })] }) },
footers: { default: new Footer({ children: [new Paragraph({ children: [new TextRun({ text: '第 ', size: 18, font: { eastAsia: FONT_CN } }), new TextRun({ children: [PageNumber.CURRENT], size: 18 }), new TextRun({ text: ' 页 共 ', size: 18, font: { eastAsia: FONT_CN } }), new TextRun({ children: [PageNumber.TOTAL_PAGES], size: 18 }), new TextRun({ text: ' 页', size: 18, font: { eastAsia: FONT_CN } })], alignment: AlignmentType.CENTER })] }) },
children,
}],
Expand Down
Loading