fujian_water_biz_doc/scripts/unified_export.sh

738 lines
18 KiB
Bash
Executable File
Raw 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.

#!/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 1200 -H 800 --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 1200 -H 800 --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 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;
}
th {
background-color: #4472c4;
color: white;
font-weight: bold;
padding: 8pt;
border: 1pt solid #2f5597;
text-align: center;
}
td {
padding: 6pt 8pt;
border: 1pt solid #a6a6a6;
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/reference.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 '<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">')
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
"water_biz_system_architecture")
doc_title="福建水务营收系统-系统架构设计"
;;
"water_biz_module_design")
doc_title="福建水务营收系统-模块功能设计"
;;
"water_biz_database_design")
doc_title="福建水务营收系统-数据库设计"
;;
"water_biz_interface_design")
doc_title="福建水务营收系统-接口设计"
;;
"water_biz_deployment_design")
doc_title="福建水务营收系统-部署设计"
;;
"water_biz_security_design")
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=(
# "water_biz_system_architecture.md"
# "water_biz_module_design.md"
# "water_biz_database_design.md"
# "water_biz_interface_design.md"
# "water_biz_deployment_design.md"
# "water_biz_security_design.md"
# "water_biz_overview_design.md"
"新-详细设计说明书.md"
"新-概要设计说明书.md"
"新-数据库设计说明书.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