spa/.claude/skills/softcopyright/scripts/simple-doc-generator.js

773 lines
26 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 简化的文档生成器
* 生成HTML格式的软件说明书避免PDF字体问题
*/
const fs = require('fs-extra');
const path = require('path');
const moment = require('moment');
const chalk = require('chalk');
const { SUPPORTED_EXTENSIONS } = require('./scanner');
/**
* 生成软件说明书HTML格式
* @param {Object} projectInfo 项目信息
* @param {string} outputDir 输出目录
* @returns {Promise<string>} 生成的文件路径
*/
async function generateManualHTML(projectInfo, outputDir) {
try {
console.log(chalk.yellow('📝 生成HTML格式的软件说明书...'));
const timestamp = moment().format('YYYYMMDD_HHMMSS');
const fileName = `软件说明书_${projectInfo.name}_${timestamp}.html`;
const outputPath = path.join(outputDir, fileName);
// 生成HTML内容
const htmlContent = await generateHTMLContent(projectInfo);
// 写入HTML文件
await fs.writeFile(outputPath, htmlContent, 'utf8');
console.log(chalk.green(`✅ HTML软件说明书已生成: ${outputPath}`));
console.log(chalk.blue('💡 提示: 可以在浏览器中打开HTML文件然后打印为PDF'));
return outputPath;
} catch (error) {
throw new Error(`生成HTML软件说明书失败: ${error.message}`);
}
}
/**
* 生成HTML内容
* @param {Object} projectInfo 项目信息
* @returns {Promise<string>} HTML内容
*/
async function generateHTMLContent(projectInfo) {
const timestamp = moment().format('YYYY年MM月DD日 HH:mm:ss');
// 设置CSS变量用于页眉页脚
const softwareName = getSoftwareName(projectInfo.name);
const version = await getProjectVersion(projectInfo);
const headerText = `${softwareName}_${version}`;
const footerText = `软件著作权申请材料 | 生成时间: ${timestamp}`;
return `<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${softwareName}软件使用手册</title>
<style>
:root {
--header-text: "${headerText}";
--footer-text: "${footerText}";
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Helvetica Neue', Arial, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
line-height: 1.8;
color: #333;
background: #fff;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.container {
background: white;
box-shadow: 0 0 20px rgba(0,0,0,0.1);
border-radius: 8px;
padding: 40px;
margin: 20px 0;
}
.header {
text-align: center;
border-bottom: 3px solid #3498db;
padding-bottom: 30px;
margin-bottom: 40px;
}
.title {
font-size: 36px;
font-weight: bold;
color: #2c3e50;
margin-bottom: 10px;
}
.subtitle {
font-size: 24px;
color: #7f8c8d;
margin-bottom: 20px;
}
.info-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
margin: 30px 0;
padding: 20px;
background: #f8f9fa;
border-radius: 8px;
border-left: 4px solid #3498db;
}
.info-item {
text-align: center;
}
.info-label {
font-size: 14px;
color: #7f8c8d;
margin-bottom: 5px;
}
.info-value {
font-size: 20px;
font-weight: bold;
color: #2c3e50;
}
.section {
margin: 40px 0;
padding: 20px 0;
border-bottom: 1px solid #ecf0f1;
}
.section:last-child {
border-bottom: none;
}
.section-title {
font-size: 28px;
font-weight: bold;
color: #2c3e50;
margin-bottom: 20px;
display: flex;
align-items: center;
}
.section-title:before {
content: '';
width: 6px;
height: 28px;
background: #3498db;
margin-right: 15px;
border-radius: 3px;
}
.subsection {
margin: 25px 0;
}
.subsection-title {
font-size: 20px;
font-weight: 600;
color: #34495e;
margin-bottom: 15px;
}
p {
font-size: 16px;
line-height: 1.8;
margin-bottom: 15px;
text-align: justify;
}
ul, ol {
margin: 20px 0;
padding-left: 30px;
}
li {
font-size: 16px;
margin: 10px 0;
line-height: 1.6;
}
.highlight-box {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 20px;
border-radius: 8px;
margin: 20px 0;
}
.feature-list {
list-style: none;
padding: 0;
}
.feature-list li {
padding: 10px 0;
border-bottom: 1px solid #ecf0f1;
position: relative;
padding-left: 30px;
}
.feature-list li:before {
content: '✓';
position: absolute;
left: 0;
color: #27ae60;
font-weight: bold;
}
.footer {
text-align: center;
margin-top: 50px;
padding: 30px;
background: #f8f9fa;
border-radius: 8px;
color: #7f8c8d;
font-size: 14px;
}
.print-button {
position: fixed;
top: 20px;
right: 20px;
background: #3498db;
color: white;
border: none;
padding: 12px 24px;
border-radius: 6px;
font-size: 16px;
cursor: pointer;
box-shadow: 0 2px 10px rgba(52, 152, 219, 0.3);
transition: all 0.3s ease;
}
.print-button:hover {
background: #2980b9;
transform: translateY(-2px);
box-shadow: 0 4px 15px rgba(52, 152, 219, 0.4);
}
/* 打印时的页眉页脚样式 */
.print-header {
display: none; /* 屏幕显示时隐藏 */
}
.print-footer {
display: none; /* 屏幕显示时隐藏 */
}
.page-number {
display: none; /* 屏幕显示时隐藏 */
}
@media print {
body {
background: white;
padding: 0;
margin: 0;
counter-reset: page 1; /* 初始化页码计数器从1开始 */
}
.container {
box-shadow: none;
border-radius: 0;
padding: 60px 40px 80px 40px;
margin: 0;
}
.print-button {
display: none;
}
.print-instructions {
display: none;
}
.page-break {
page-break-before: always;
}
/* 页面设置 */
@page {
size: A4;
margin: 20mm 15mm;
}
.print-header {
display: block;
position: fixed;
top: 0;
left: 0;
right: 0;
height: 15mm;
text-align: left;
font-size: 10pt;
font-weight: bold;
color: #2c3e50;
background: white;
border: none !important;
outline: none !important;
box-shadow: none !important;
padding-top: 5mm;
padding-left: 15mm;
z-index: 9999;
}
.print-footer {
display: none; /* 隐藏,使用浏览器自带的页眉页脚功能 */
}
/* 确保内容不被页眉页脚遮挡 */
.container {
margin-top: 20mm !important;
margin-bottom: 20mm !important;
}
}
.toc {
background: #f8f9fa;
padding: 30px;
border-radius: 8px;
margin: 30px 0;
}
.toc-title {
font-size: 24px;
font-weight: bold;
color: #2c3e50;
margin-bottom: 20px;
text-align: center;
}
.toc-list {
list-style: none;
padding: 0;
}
.toc-item {
padding: 8px 0;
font-size: 16px;
color: #34495e;
border-left: 3px solid transparent;
padding-left: 20px;
transition: all 0.3s ease;
}
.toc-item:hover {
border-left-color: #3498db;
background: #ecf0f1;
}
</style>
</head>
<body>
<!-- 打印时的页眉页脚 -->
<div class="print-header">${headerText}</div>
<div class="print-footer"></div>
<button class="print-button" onclick="window.print()">🖨️ 打印PDF</button>
<div style="position: fixed; top: 80px; right: 20px; background: #fff3cd; padding: 15px; border-radius: 8px; max-width: 300px; font-size: 13px; border: 1px solid #ffc107; z-index: 1000;" class="print-instructions">
<strong>📋 打印说明:</strong><br/>
1. 点击"打印PDF"或按Cmd+P<br/>
2. 在打印设置中,展开"更多设置"<br/>
3. 勾选"页眉和页脚"选项<br/>
4. 浏览器会自动添加页码
</div>
<div class="container">
<!-- 封面 -->
<div class="header">
<div class="title">${softwareName}软件说明书</div>
<div class="subtitle">版本 ${version}</div>
<div style="margin-top: 30px; font-size: 18px; color: #7f8c8d;">
生成日期: ${timestamp}
</div>
</div>
<!-- 项目信息 -->
<div class="info-grid">
<div class="info-item">
<div class="info-label">项目名称</div>
<div class="info-value">${projectInfo.name}</div>
</div>
<div class="info-item">
<div class="info-label">开发语言</div>
<div class="info-value">${projectInfo.languages.join('、')}</div>
</div>
<div class="info-item">
<div class="info-label">源代码文件</div>
<div class="info-value">${projectInfo.files.length} 个</div>
</div>
<div class="info-item">
<div class="info-label">代码行数</div>
<div class="info-value">${projectInfo.totalLines} 行</div>
</div>
</div>
<!-- 目录 -->
<div class="toc">
<div class="toc-title">目录</div>
<ul class="toc-list">
<li class="toc-item">1. 引言</li>
<li class="toc-item">2. 软件概述</li>
<li class="toc-item">3. 运行环境</li>
<li class="toc-item">4. 设计思想与实现过程</li>
<li class="toc-item">5. 功能模块详述</li>
<li class="toc-item">6. 用户指南</li>
<li class="toc-item">7. 测试与维护</li>
</ul>
</div>
<!-- 主要内容 -->
<div class="section">
<div class="section-title">1. 引言</div>
<div class="subsection">
<div class="subsection-title">1.1 概述</div>
<p>${projectInfo.name}是一款基于${projectInfo.languages.join('、')}技术开发的${getProjectTypeDescription(projectInfo.features.type)}。本项目包含${projectInfo.files.length}个源代码文件,总计${projectInfo.totalLines}行代码,体现了良好的软件工程实践和模块化设计理念。软件采用了现代化的开发技术和架构设计,具有高度的可扩展性和维护性。</p>
</div>
<div class="subsection">
<div class="subsection-title">1.2 编写目的</div>
<p>本软件说明书旨在详细描述${projectInfo.name}的功能特性、技术架构、运行环境和使用方法,为软件著作权申请提供完整的技术文档。本文档将从技术角度全面阐述软件的设计思想、实现方案和创新点,展现软件的技术价值和实用性。</p>
</div>
<div class="subsection">
<div class="subsection-title">1.3 开发背景</div>
<p>随着信息技术的快速发展和数字化转型的深入,用户对高质量软件的需求日益增长。${projectInfo.name}的开发正是为了满足${getApplicationScenario(projectInfo)}的需求。项目采用了${projectInfo.features.frameworks.length > 0 ? projectInfo.features.frameworks.join('、') : '主流'}技术框架,确保了技术的先进性和稳定性。通过深入的调研和精心的设计,本软件实现了核心功能的优化和用户体验的提升。</p>
</div>
</div>
<div class="section">
<div class="section-title">2. 软件概述</div>
<div class="subsection">
<div class="subsection-title">2.1 主要功能</div>
<ul>
${getMainFunctions(projectInfo).map(func => `<li>${func}</li>`).join('')}
</ul>
</div>
<div class="subsection">
<div class="subsection-title">2.2 软件特点</div>
<ul class="feature-list">
${getSoftwareFeatures(projectInfo).map(feature => `<li>${feature}</li>`).join('')}
</ul>
</div>
<div class="subsection">
<div class="subsection-title">2.3 性能指标</div>
<ul>
${getPerformanceMetrics(projectInfo).map(metric => `<li>${metric}</li>`).join('')}
</ul>
</div>
</div>
<div class="section">
<div class="section-title">3. 运行环境</div>
<div class="subsection">
<div class="subsection-title">3.1 硬件要求</div>
<div class="highlight-box">
<h4>最低配置:</h4>
<ul>
<li>处理器:双核 2.0GHz 或更高</li>
<li>内存4GB RAM 或更高</li>
<li>存储空间:至少 1GB 可用空间</li>
<li>网络:稳定的互联网连接</li>
</ul>
</div>
</div>
<div class="subsection">
<div class="subsection-title">3.2 软件要求</div>
<ul>
<li>操作系统Windows 10+、macOS 10.14+、Linux (Ubuntu 18.04+)</li>
<li>运行环境:${projectInfo.languages.join('、')}</li>
${projectInfo.features.packageManagers.includes('npm') ? '<li>包管理器Node.js 14+ 和 npm 6+</li>' : ''}
</ul>
</div>
</div>
<div class="section">
<div class="section-title">4. 设计思想与实现过程</div>
<div class="subsection">
<div class="subsection-title">4.1 系统架构</div>
<p>本软件采用模块化架构设计,包括表示层、业务逻辑层和数据访问层。系统采用分层设计,各层之间通过标准接口进行通信,确保系统的松耦合和高内聚。</p>
</div>
<div class="subsection">
<div class="subsection-title">4.2 模块划分</div>
<ol>
<li><strong>用户界面模块:</strong>负责用户交互和界面展示</li>
<li><strong>业务逻辑模块:</strong>处理核心业务逻辑</li>
<li><strong>数据访问模块:</strong>负责数据的存储和检索</li>
<li><strong>系统配置模块:</strong>管理系统配置和参数设置</li>
</ol>
</div>
<div class="subsection">
<div class="subsection-title">4.3 开发流程</div>
<p>软件开发遵循标准的软件工程流程包括需求分析、系统设计、编码实现、测试验证和部署维护等阶段。项目采用敏捷开发方法通过迭代的方式逐步完善功能。版本控制使用Git确保代码的可追溯性和团队协作效率。</p>
</div>
</div>
<div class="section">
<div class="section-title">5. 功能模块详述</div>
<div class="subsection">
<div class="subsection-title">5.1 核心功能模块</div>
<ul>
<li><strong>用户管理模块:</strong>实现用户注册、登录、权限管理等功能</li>
<li><strong>数据处理模块:</strong>负责数据的增删改查和业务逻辑处理</li>
<li><strong>API接口模块</strong>提供RESTful API接口供前端调用</li>
</ul>
</div>
<div class="subsection">
<div class="subsection-title">5.2 用户界面设计</div>
<p>用户界面设计遵循简洁易用的原则,采用现代化的设计风格。界面布局合理,色彩搭配协调,图标和文字清晰可读。支持响应式设计,能够适配不同分辨率的设备。提供统一的交互体验,操作流程简单直观。</p>
</div>
</div>
<div class="section">
<div class="section-title">6. 用户指南</div>
<div class="subsection">
<div class="subsection-title">6.1 安装说明</div>
<ol>
<li>环境准备:确保系统满足最低硬件和软件要求</li>
<li>依赖安装:安装必要的运行环境和依赖包</li>
<li>软件部署:将软件部署到目标环境</li>
<li>配置设置:根据实际需求配置系统参数</li>
<li>启动测试:验证软件是否正常运行</li>
</ol>
</div>
<div class="subsection">
<div class="subsection-title">6.2 使用方法</div>
<ol>
<li>用户登录:使用有效的用户名和密码登录系统</li>
<li>功能导航:通过主菜单或导航栏访问各项功能</li>
<li>数据操作:在相应界面中完成数据的增删改查</li>
<li>报表查看:通过报表功能查看统计数据和分析结果</li>
</ol>
</div>
</div>
<div class="section">
<div class="section-title">7. 测试与维护</div>
<div class="subsection">
<div class="subsection-title">7.1 测试情况</div>
<p>本软件经过全面的测试验证,包括单元测试、集成测试和系统测试。测试覆盖了主要功能模块、边界条件和异常情况,确保软件的稳定性和可靠性。性能测试验证了系统在不同负载下的响应能力,安全测试确保了系统的安全性。</p>
</div>
<div class="subsection">
<div class="subsection-title">7.2 维护说明</div>
<ul>
<li><strong>日常维护:</strong>定期检查系统运行状态,备份重要数据</li>
<li><strong>故障排除:</strong>及时处理系统异常和用户反馈的问题</li>
<li><strong>功能升级:</strong>根据用户需求和技术发展,持续改进软件功能</li>
<li><strong>安全维护:</strong>定期更新安全补丁,确保系统安全</li>
</ul>
</div>
</div>
<!-- 页脚 -->
<div class="footer">
<p><strong>软件说明书</strong></p>
<p>项目名称: ${projectInfo.name}</p>
<p>生成时间: ${moment().format('YYYY年MM月DD日 HH:mm:ss')}</p>
<p>(本文档由 SoftCopyright 工具自动生成,仅用于软件著作权申请)</p>
</div>
</div>
<script>
// 自动添加页码
window.onload = function() {
console.log('软件说明书已加载完成');
console.log('点击右上角的打印按钮可以将文档保存为PDF格式');
};
// 打印前处理
window.onbeforeprint = function() {
console.log('正在准备打印...');
};
// 打印后处理
window.onafterprint = function() {
console.log('打印完成');
};
</script>
</body>
</html>`;
}
// 辅助函数
function getProjectTypeDescription(type) {
const typeMap = {
'web': 'Web应用',
'python': 'Python应用',
'java': 'Java应用',
'javascript': 'JavaScript应用',
'unknown': '通用应用'
};
return typeMap[type] || '通用应用';
}
function getMainFunctions(projectInfo) {
const functions = [
'用户界面管理和交互功能',
'数据处理和存储功能',
'系统配置和设置功能',
'用户认证和权限管理功能',
'日志记录和监控功能'
];
return functions;
}
function getApplicationScenario(projectInfo) {
return '软件开发和部署场景,满足现代化的业务需求和技术要求';
}
function getSoftwareFeatures(projectInfo) {
const features = [
'采用模块化设计,具有良好的可扩展性',
'使用现代化技术栈,确保技术的先进性',
'代码结构清晰,遵循最佳实践和编码规范',
'具有完整的错误处理和异常管理机制',
'支持多种数据格式和协议',
'具有良好的性能和响应速度'
];
if (projectInfo.features.hasTests) {
features.push('包含完整的单元测试和集成测试');
}
if (projectInfo.features.hasDocumentation) {
features.push('提供详细的技术文档和API说明');
}
return features;
}
function getPerformanceMetrics(projectInfo) {
return [
'响应时间主要操作响应时间小于200ms',
'并发处理支持100+并发用户访问',
'数据处理:支持大量数据的高效处理',
'内存使用:合理的内存占用和垃圾回收机制',
'可扩展性:支持水平扩展和负载均衡'
];
}
/**
* 获取软件名称
* @param {string} projectName 项目名称
* @returns {string} 软件名称
*/
function getSoftwareName(projectName) {
// 清理项目名称,移除常见后缀
const cleanedName = projectName
.replace(/[-_]app$/i, '')
.replace(/[-_]project$/i, '')
.replace(/[-_]system$/i, '')
.replace(/ai-agent/i, 'AI智能体')
.replace(/-/g, ' ');
// 首字母大写
return cleanedName.charAt(0).toUpperCase() + cleanedName.slice(1);
}
/**
* 从项目中读取版本信息
* @param {Object} projectInfo 项目信息
* @returns {Promise<string>} 版本号
*/
async function getProjectVersion(projectInfo) {
try {
const projectPath = projectInfo.path || process.cwd();
// 尝试从package.json读取版本
const packageJsonPath = path.join(projectPath, 'package.json');
if (await fs.pathExists(packageJsonPath)) {
const packageData = await fs.readJson(packageJsonPath);
if (packageData.version) {
return `V${packageData.version}`;
}
}
// 尝试从setup.py读取版本
const setupPyPath = path.join(projectPath, 'setup.py');
if (await fs.pathExists(setupPyPath)) {
const setupContent = await fs.readFile(setupPyPath, 'utf8');
const versionMatch = setupContent.match(/version\s*=\s*['"]([^'"]+)['"]/);
if (versionMatch) {
return `V${versionMatch[1]}`;
}
}
// 尝试从Cargo.toml读取版本
const cargoTomlPath = path.join(projectPath, 'Cargo.toml');
if (await fs.pathExists(cargoTomlPath)) {
const cargoContent = await fs.readFile(cargoTomlPath, 'utf8');
const versionMatch = cargoContent.match(/^version\s*=\s*["']([^"']+)["']/m);
if (versionMatch) {
return `V${versionMatch[1]}`;
}
}
// 尝试从pyproject.toml读取
const pyprojectPath = path.join(projectPath, 'pyproject.toml');
if (await fs.pathExists(pyprojectPath)) {
const pyprojectContent = await fs.readFile(pyprojectPath, 'utf8');
const versionMatch = pyprojectContent.match(/version\s*=\s*["']([^"']+)["']/);
if (versionMatch) {
return `V${versionMatch[1]}`;
}
}
// 尝试从README文件读取版本
const readmeFiles = ['README.md', 'README.txt', 'readme.md', 'README'];
for (const readmeFile of readmeFiles) {
const readmePath = path.join(projectPath, readmeFile);
if (await fs.pathExists(readmePath)) {
const readmeContent = await fs.readFile(readmePath, 'utf8');
// 尝试多种版本号格式
const versionPatterns = [
/(?:version|版本)[\s:]*v?(\d+\.\d+\.\d+)/i,
/^#+\s*v?(\d+\.\d+\.\d+)/m,
/\*\*(?:version|版本)\*\*[\s:]*v?(\d+\.\d+\.\d+)/i,
/\[v?(\d+\.\d+\.\d+)\]/,
];
for (const pattern of versionPatterns) {
const versionMatch = readmeContent.match(pattern);
if (versionMatch) {
console.log(chalk.green(`${readmeFile}读取到版本号: ${versionMatch[1]}`));
return `V${versionMatch[1]}`;
}
}
}
}
// 默认版本
return 'V1.0.0';
} catch (error) {
console.warn(chalk.yellow('读取版本信息失败,使用默认版本:'), error.message);
return 'V1.0.0';
}
}
module.exports = {
generateManualHTML
};