#!/bin/zsh # 福建水务营收系统 - 分离文档导出工具 # 将每个设计文档分别导出为不同格式,支持独立的Mermaid图表处理 set -e # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # 日志函数 log_info() { echo -e "${BLUE}[INFO]${NC} $1" } log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } log_error() { echo -e "${RED}[ERROR]${NC} $1" } # 检查依赖 check_dependencies() { log_info "检查依赖工具..." # 检查 pandoc if ! command -v pandoc &> /dev/null; then log_error "pandoc 未安装,请运行 'brew install pandoc' 安装" exit 1 fi # 检查 node.js 和 mermaid-cli if ! command -v node &> /dev/null; then log_error "Node.js 未安装,请从 https://nodejs.org/ 下载安装" exit 1 fi # 安装或检查 mermaid-cli if ! npx mmdc --version &> /dev/null && ! command -v mmdc &> /dev/null; then log_info "安装 mermaid-cli..." npm install @mermaid-js/mermaid-cli --save-dev if [ $? -ne 0 ]; then log_error "mermaid-cli 安装失败" exit 1 fi fi log_success "所有依赖检查完成" } # 处理单个文档中的Mermaid图表 process_single_document_mermaid() { local input_file="$1" local output_file="$2" local doc_name="$3" local temp_dir="temp_mermaid_${doc_name}_$$" log_info "处理文档 $doc_name 中的Mermaid图表..." # 创建临时目录 mkdir -p "$temp_dir" local diagram_count=0 local in_mermaid=false local mermaid_content="" local line_number=0 # 创建文档头部 cat > "$output_file" << EOF --- title: "$doc_name" author: "系统设计团队" date: "2024年12月19日" documentclass: article geometry: margin=1in fontsize: 11pt mainfont: "PingFang SC" CJKmainfont: "PingFang SC" --- EOF while IFS= read -r line; do line_number=$((line_number + 1)) if [[ "$line" =~ ^\`\`\`mermaid ]]; then in_mermaid=true mermaid_content="" continue elif [[ "$line" =~ ^\`\`\`$ ]] && [ "$in_mermaid" = true ]; then # 处理Mermaid图表 diagram_count=$((diagram_count + 1)) local mermaid_file="$temp_dir/diagram_$diagram_count.mmd" local png_file="$temp_dir/diagram_$diagram_count.png" # 保存Mermaid代码 echo "$mermaid_content" > "$mermaid_file" # 转换为PNG log_info "转换 $doc_name 图表 $diagram_count..." # 使用多种方式尝试转换 local convert_success=false # 方式1:使用npx if npx mmdc -i "$mermaid_file" -o "$png_file" -w 2400 -H 1600 --backgroundColor white --theme default 2>/dev/null; then convert_success=true # 方式2:使用全局mmdc elif command -v mmdc &> /dev/null && mmdc -i "$mermaid_file" -o "$png_file" -w 2400 -H 1600 --backgroundColor white --theme default 2>/dev/null; then convert_success=true fi if [ "$convert_success" = true ] && [ -f "$png_file" ]; then # 调用Python脚本调整图片尺寸(限制高度23公分) if command -v python3 &> /dev/null; then python3 "scripts/resize_image.py" "$png_file" --max-height-cm 23 2>/dev/null || { log_warning "$doc_name 图表 $diagram_count 尺寸调整失败,继续使用原图" } else log_warning "Python3 未安装,跳过图片尺寸调整" fi # 成功转换,仅添加图片引用 echo "" >> "$output_file" echo "**图表 $diagram_count**" >> "$output_file" echo "" >> "$output_file" echo "![图表 $diagram_count]($png_file)" >> "$output_file" echo "" >> "$output_file" log_success "$doc_name 图表 $diagram_count 转换成功" else # 转换失败,保留原始代码 echo "" >> "$output_file" echo '```mermaid' >> "$output_file" echo "$mermaid_content" >> "$output_file" echo '```' >> "$output_file" echo "" >> "$output_file" log_warning "$doc_name 图表 $diagram_count 转换失败,保留原始代码" fi in_mermaid=false elif [ "$in_mermaid" = true ]; then mermaid_content+="$line"$'\n' else echo "$line" >> "$output_file" fi done < "$input_file" log_success "$doc_name 图表处理完成,共处理了 $diagram_count 个图表" # 返回临时目录路径供后续使用 echo "$temp_dir" } # 创建增强的CSS样式 create_enhanced_css() { local css_file="$1" cat > "$css_file" << 'CSS_EOF' /* 福建水务营收系统文档样式 */ @page { margin: 2cm; size: A4; } body { font-family: "PingFang SC", "Microsoft YaHei", "SimSun", sans-serif; font-size: 11pt; line-height: 1.6; color: #333; max-width: none; margin: 0; padding: 0; } /* 标题样式 */ h1 { font-size: 18pt; font-weight: bold; color: #1f4e79; margin-top: 24pt; margin-bottom: 12pt; border-bottom: 2pt solid #1f4e79; padding-bottom: 6pt; page-break-after: avoid; } h2 { font-size: 16pt; font-weight: bold; color: #2f5597; margin-top: 18pt; margin-bottom: 10pt; border-bottom: 1pt solid #2f5597; padding-bottom: 4pt; page-break-after: avoid; } h3 { font-size: 14pt; font-weight: bold; color: #365f91; margin-top: 14pt; margin-bottom: 8pt; page-break-after: avoid; } h4 { font-size: 12pt; font-weight: bold; color: #4472c4; margin-top: 12pt; margin-bottom: 6pt; page-break-after: avoid; } h5 { font-size: 11pt; font-weight: bold; color: #5b9bd5; margin-top: 10pt; margin-bottom: 5pt; page-break-after: avoid; } h6 { font-size: 10pt; font-weight: bold; color: #70ad47; margin-top: 8pt; margin-bottom: 4pt; page-break-after: avoid; } /* 段落样式 */ p { margin-top: 0; margin-bottom: 8pt; text-align: justify; text-justify: inter-ideograph; } /* 表格样式(黑色边框) */ table { border-collapse: collapse; width: 100%; margin: 12pt 0; font-size: 10pt; page-break-inside: avoid; border: 1pt solid #000; /* 外边框黑色 */ } th { background-color: #4472c4; color: white; font-weight: bold; padding: 8pt; border: 1pt solid #000; /* 表头黑线 */ text-align: center; } td { padding: 6pt 8pt; border: 1pt solid #000; /* 单元格黑线 */ vertical-align: top; } tr:nth-child(even) { background-color: #f2f2f2; } /* 代码样式 */ code { font-family: "Courier New", "Monaco", monospace; font-size: 9pt; background-color: #f5f5f5; padding: 2pt 4pt; border-radius: 2pt; border: 1pt solid #e1e1e1; } pre { font-family: "Courier New", "Monaco", monospace; font-size: 9pt; background-color: #f8f8f8; padding: 12pt; border: 1pt solid #e1e1e1; border-radius: 4pt; overflow-x: auto; margin: 12pt 0; page-break-inside: avoid; } pre code { background: none; padding: 0; border: none; } /* 列表样式 */ ul, ol { margin: 8pt 0; padding-left: 24pt; } li { margin: 4pt 0; } /* 图片样式 */ img { max-width: 100%; height: auto; display: block; margin: 12pt auto; border: 1pt solid #e1e1e1; border-radius: 4pt; page-break-inside: avoid; } /* 图表标题 */ img + p, p + img { text-align: center; font-weight: bold; color: #4472c4; font-size: 10pt; margin: 6pt 0; } /* 分页符 */ .page-break { page-break-before: always; } /* 避免孤行和寡行 */ p, li, dt, dd { orphans: 2; widows: 2; } /* 链接样式 */ a { color: #0563c1; text-decoration: underline; } a:visited { color: #954f72; } /* 引用样式 */ blockquote { margin: 12pt 0; padding: 12pt; background-color: #f9f9f9; border-left: 4pt solid #4472c4; font-style: italic; } /* 水平分隔线 */ hr { border: none; border-top: 1pt solid #d1d1d1; margin: 18pt 0; } /* Details/Summary 样式 */ details { margin: 8pt 0; border: 1pt solid #e1e1e1; border-radius: 4pt; padding: 8pt; } summary { font-weight: bold; cursor: pointer; color: #4472c4; margin-bottom: 8pt; } /* 强调样式 */ strong, b { font-weight: bold; color: #1f4e79; } em, i { font-style: italic; color: #365f91; } /* 印刷样式优化 */ @media print { body { font-size: 10pt; line-height: 1.4; } h1 { font-size: 16pt; } h2 { font-size: 14pt; } h3 { font-size: 12pt; } h4 { font-size: 11pt; } h5 { font-size: 10pt; } h6 { font-size: 9pt; } table { font-size: 9pt; } code, pre { font-size: 8pt; } /* 避免在不适当的地方分页 */ h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } table, pre, img { page-break-inside: avoid; } } CSS_EOF log_success "CSS样式文件创建完成" } # 导出单个文档为Word格式 export_single_to_docx() { local input_file="$1" local output_file="$2" local doc_title="$3" local temp_dir="$4" log_info "导出 $doc_title 为Word格式..." # 创建输出目录 mkdir -p "$(dirname "$output_file")" # 使用pandoc转换 pandoc "$input_file" \ -o "$output_file" \ --from markdown+smart \ --to docx \ --standalone \ --toc \ --toc-depth=4 \ --highlight-style=tango \ --reference-doc=templates/reference2.docx \ --resource-path=".:$temp_dir" \ --metadata title="$doc_title" \ --metadata author="系统设计团队" \ --metadata date="2024年12月19日" \ 2>/dev/null || \ pandoc "$input_file" \ -o "$output_file" \ --from markdown+smart \ --to docx \ --standalone \ --toc \ --toc-depth=4 \ --resource-path=".:$temp_dir" \ --metadata title="$doc_title" \ --metadata author="系统设计团队" \ --metadata date="2024年12月19日" if [ $? -eq 0 ]; then log_success "$doc_title Word文档导出成功: $output_file" else log_error "$doc_title Word文档导出失败" return 1 fi } # 导出单个文档为PDF格式 export_single_to_pdf() { local input_file="$1" local output_file="$2" local doc_title="$3" local css_file="$4" local temp_dir="$5" log_info "导出 $doc_title 为PDF格式..." # 创建输出目录 mkdir -p "$(dirname "$output_file")" # 使用pandoc转换为PDF pandoc "$input_file" \ -o "$output_file" \ --from markdown+smart \ --to pdf \ --pdf-engine=wkhtmltopdf \ --css="$css_file" \ --standalone \ --toc \ --toc-depth=4 \ --number-sections \ --resource-path=".:$temp_dir" \ --metadata title="$doc_title" \ --metadata author="系统设计团队" \ --metadata date="2024年12月19日" \ --variable geometry:margin=2cm \ --variable fontsize:11pt \ --variable CJKmainfont:"PingFang SC" \ 2>/dev/null || \ pandoc "$input_file" \ -o "$output_file" \ --from markdown+smart \ --to html5 \ --css="$css_file" \ --standalone \ --toc \ --toc-depth=4 \ --number-sections \ --resource-path=".:$temp_dir" \ --metadata title="$doc_title" \ --metadata author="系统设计团队" \ --metadata date="2024年12月19日" | \ wkhtmltopdf --page-size A4 --margin-top 2cm --margin-bottom 2cm --margin-left 2cm --margin-right 2cm - "$output_file" 2>/dev/null if [ $? -eq 0 ]; then log_success "$doc_title PDF文档导出成功: $output_file" else log_warning "$doc_title PDF文档导出失败,尝试HTML方式..." # 如果PDF导出失败,导出HTML作为替代 export_single_to_html "$input_file" "${output_file%.pdf}.html" "$doc_title" "$css_file" "$temp_dir" fi } # 导出单个文档为HTML格式 export_single_to_html() { local input_file="$1" local output_file="$2" local doc_title="$3" local css_file="$4" local temp_dir="$5" log_info "导出 $doc_title 为HTML格式..." # 创建输出目录 mkdir -p "$(dirname "$output_file")" # 使用pandoc转换为HTML pandoc "$input_file" \ -o "$output_file" \ --from markdown+smart \ --to html5 \ --css="$css_file" \ --standalone \ --toc \ --toc-depth=4 \ --number-sections \ --highlight-style=tango \ --resource-path=".:$temp_dir" \ --metadata title="$doc_title" \ --metadata author="系统设计团队" \ --metadata date="2024年12月19日" \ --include-in-header=<(echo '') if [ $? -eq 0 ]; then log_success "$doc_title HTML文档导出成功: $output_file" else log_error "$doc_title HTML文档导出失败" return 1 fi } # 处理单个文档 process_single_document() { local doc_file="$1" local export_format="$2" local css_file="$3" # 从文件名提取文档名称和中文标题 local doc_name=$(basename "$doc_file" .md) local doc_title="" case "$doc_name" in "02_System_Architecture") doc_title="福建水务营收系统-系统架构设计" ;; "02_Module_Traceability_Index") doc_title="福建水务营收系统-模块追溯索引" ;; "01_Database_Design") doc_title="福建水务营收系统-数据库设计" ;; "03_Interface_Design") doc_title="福建水务营收系统-接口设计" ;; "05_Deployment_Design") doc_title="福建水务营收系统-部署设计" ;; "04_Security_Design") doc_title="福建水务营收系统-安全设计" ;; "01_System_Overview") doc_title="福建水务营收系统-系统概述" ;; "03_Summary_Design") doc_title="福建水务营收系统-概要设计说明书" ;; "01_Detailed_Design") doc_title="福建水务营收系统-详细设计说明书" ;; "02_Table_Specs") doc_title="福建水务营收系统-单表规格补充(历史映射)" ;; "06_Sensitive_Data_Encryption") doc_title="福建水务营收系统-敏感数据加密方案" ;; "03_CA_Esignature_Supplement") doc_title="福建水务营收系统-报装CA电子签章补充" ;; "11_UP_Detailed") doc_title="福建水务营收系统-统一平台模块正文" ;; "12_REV_Detailed") doc_title="福建水务营收系统-营收业务模块正文" ;; "13_CS_Detailed") doc_title="福建水务营收系统-客户服务模块正文" ;; "14_METER_Detailed") doc_title="福建水务营收系统-表务模块正文" ;; "15_INST_Detailed") doc_title="福建水务营收系统-报装与签章模块正文" ;; *) doc_title="福建水务营收系统-$doc_name" ;; esac log_info "处理文档: $doc_title" # 处理Mermaid图表 local processed_md="output/${doc_name}_processed.md" local temp_dir=$(process_single_document_mermaid "$doc_file" "$processed_md" "$doc_name") # 导出不同格式 if [[ "$export_format" == "all" || "$export_format" == "docx" ]]; then export_single_to_docx "$processed_md" "output/${doc_name}.docx" "$doc_title" "$temp_dir" fi if [[ "$export_format" == "all" || "$export_format" == "pdf" ]]; then export_single_to_pdf "$processed_md" "output/${doc_name}.pdf" "$doc_title" "$css_file" "$temp_dir" fi if [[ "$export_format" == "all" || "$export_format" == "html" ]]; then export_single_to_html "$processed_md" "output/${doc_name}.html" "$doc_title" "$css_file" "$temp_dir" fi log_success "文档 $doc_title 处理完成" echo "" } # 主函数 main() { local export_format="${1:-all}" echo "🚀 福建水务营收系统 - 分离文档导出工具" echo "=========================================" echo "" # 检查依赖 check_dependencies # 创建输出目录 mkdir -p output # 创建CSS样式 local css_file="output/document_style.css" create_enhanced_css "$css_file" # 定义要处理的文档列表 local documents=( "docs/design/01_Overview/01_System_Overview.md" "docs/design/01_Overview/02_System_Architecture.md" "docs/design/01_Overview/03_Summary_Design.md" "docs/design/02_Detailed_Design/01_Detailed_Design.md" "docs/design/02_Detailed_Design/02_Module_Traceability_Index.md" "docs/design/02_Detailed_Design/03_CA_Esignature_Supplement.md" "docs/design/02_Detailed_Design/11_UP_Detailed.md" "docs/design/02_Detailed_Design/12_REV_Detailed.md" "docs/design/02_Detailed_Design/13_CS_Detailed.md" "docs/design/02_Detailed_Design/14_METER_Detailed.md" "docs/design/02_Detailed_Design/15_INST_Detailed.md" "docs/design/03_Technical_Design/01_Database_Design.md" "docs/design/03_Technical_Design/02_Table_Specs.md" "docs/design/03_Technical_Design/03_Interface_Design.md" "docs/design/03_Technical_Design/04_Security_Design.md" "docs/design/03_Technical_Design/05_Deployment_Design.md" "docs/design/03_Technical_Design/06_Sensitive_Data_Encryption.md" ) local processed_count=0 # 处理每个文档 for doc in "${documents[@]}"; do if [[ -f "$doc" ]]; then processed_count=$((processed_count + 1)) log_info "正在处理文档 [$processed_count/${#documents[@]}]: $doc" process_single_document "$doc" "$export_format" "$css_file" else log_warning "文档不存在: $doc" fi done echo "" echo "🎉 分离文档导出完成!" echo "" echo "📁 输出文件 ($processed_count 个文档):" for doc in "${documents[@]}"; do if [[ -f "$doc" ]]; then local doc_name=$(basename "$doc" .md) if [[ "$export_format" == "all" || "$export_format" == "docx" ]]; then echo " 📄 $doc_name.docx" fi if [[ "$export_format" == "all" || "$export_format" == "pdf" ]]; then echo " 📄 $doc_name.pdf" fi if [[ "$export_format" == "all" || "$export_format" == "html" ]]; then echo " 📄 $doc_name.html" fi fi done echo "" echo "💡 提示:" echo " - 每个文档都独立处理Mermaid图表" echo " - 文档标题和内容保持独立" echo " - 每个文档都有独立的目录结构" echo " - 图表文件保存在对应的临时目录中" echo "" } # 显示使用说明 show_usage() { echo "用法: $0 [格式]" echo "" echo "格式选项:" echo " all 导出所有格式 (默认)" echo " docx 仅导出Word格式" echo " pdf 仅导出PDF格式" echo " html 仅导出HTML格式" echo "" echo "示例:" echo " $0 # 导出所有格式" echo " $0 docx # 仅导出Word" echo " $0 pdf # 仅导出PDF" echo " $0 html # 仅导出HTML" } # 处理命令行参数 case "${1:-}" in -h|--help|help) show_usage exit 0 ;; all|docx|pdf|html|"") main "${1:-all}" ;; *) echo "错误: 不支持的格式 '$1'" echo "" show_usage exit 1 ;; esac