You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

376 lines
15 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# -*- coding: utf-8 -*-
import json
import os
import time
from urllib.parse import quote
import requests
from docx import Document
from docx.oxml.ns import qn
from docx.shared import Inches, Pt, RGBColor
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from flask import Flask, send_file, render_template
from flask_cors import CORS
app = Flask(__name__)
MUBU_HOST = "https://mubu.com/"
ROOT = os.path.abspath('.') # 表示当前所处的文件夹的绝对路径
# 获取当前日期
def get_current_day():
return time.strftime('%Y-%m-%d', time.localtime(time.time()))
# 获取当前日期时间
def get_current_time():
return time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
# 获取两个字符之间的
def get_str_btw(s, f, b):
par = s.partition(f)
return (par[2].partition(b))[0][:]
# 网络请求
def getResponse(url):
print("url = " + url)
response = requests.get(url, timeout=30) # 请求超时时间为10秒
response.raise_for_status()
# http请求的返回状态若为200则表示请求成功,返回的状态码是 int类型
code = response.status_code
if code == 200:
return response
else:
return None
# 判断是否为json
def isJson(jsonStr):
"""判断是否为json对象"""
try:
json.loads(jsonStr)
except Exception as e:
return False
return True
# 获取颜色RGB
def color(value):
digit = list(map(str, range(10))) + list("abcdef")
if isinstance(value, tuple):
string = '#'
for i in value:
a1 = i // 16
a2 = i % 16
string += digit[a1] + digit[a2]
return string
elif isinstance(value, str):
a1 = digit.index(value[1]) * 16 + digit.index(value[2])
a2 = digit.index(value[3]) * 16 + digit.index(value[4])
a3 = digit.index(value[5]) * 16 + digit.index(value[6])
return (a1, a2, a3)
# 保存图片到本地
def get_image(url, pic_name):
"""
:param pic_name:
:param url: 图片链接参数
:return: 无返回值,直接保存一张图片
"""
try:
response = requests.get(url)
with open(pic_name, "wb") as fp:
for data in response.iter_content(128):
fp.write(data)
return True
except Exception as e:
return False
# 生成文档
def generateDocx(doc, dic, level):
# print("--------------------------------------------------")
# print(dic)
if dic is not None and isinstance(dic, list) and len(dic) > 0:
for dicIndex in range(len(dic)):
# print("level=" + str(level) + "; len=" + str(len(dic)) + "; i = " + str(dicIndex))
thisNode = dic[dicIndex]
if isinstance(thisNode, dict):
thisNodeHeading = thisNode.get("heading")
thisNodeText = thisNode.get("text")
if thisNodeText == "评语保存":
thisNodeText
thisNodeColor = thisNode.get("color")
thisNodeNote = thisNode.get("note")
thisNodeCollapsed = thisNode.get("collapsed")
thisNodeFinish = thisNode.get("finish")
thisNodeImages = thisNode.get("images")
# print(thisNodeHeading, thisNodeText)
# 处理缺失的值
thisNodeText = thisNodeText is None and "" or thisNodeText
# 处理颜色
thisNodeColor_ = (0, 0, 0)
if thisNodeColor is not None and thisNodeColor is not "":
thisNodeColor_ = color(thisNodeColor)
# V3版本 颜色使用了 class
# <span class=" text-color-yellow"> rgb(223, 132, 0) !important
# <span class=" text-color-red"> rgb(239, 4, 42) !important
# <span class=" text-color-green"> rgb(78, 180, 52) !important
# <span class=" text-color-blue"> rgb(0, 145, 255) !important
# <span class=" text-color-purple"> rgb(122, 95, 255) !important
if thisNodeText.find("<span class=\" text-color-yellow\">") > -1:
thisNodeColor_ = (223, 132, 0)
thisNodeText = thisNodeText.replace("<span class=\" text-color-yellow\">", "")
if thisNodeText.find("<span class=\" text-color-red\">") > -1:
thisNodeColor_ = (239, 4, 42)
thisNodeText = thisNodeText.replace("<span class=\" text-color-red\">", "")
if thisNodeText.find("<span class=\" text-color-green\">") > -1:
thisNodeColor_ = (78, 180, 52)
thisNodeText = thisNodeText.replace("<span class=\" text-color-green\">", "")
if thisNodeText.find("<span class=\" text-color-blue\">") > -1:
thisNodeColor_ = (0, 145, 255)
thisNodeText = thisNodeText.replace("<span class=\" text-color-blue\">", "")
if thisNodeText.find("<span class=\" text-color-purple\">") > -1:
thisNodeColor_ = (122, 95, 255)
thisNodeText = thisNodeText.replace("<span class=\" text-color-purple\">", "")
# 判断是否加粗
thisNodeBold = False
if thisNodeText.find("<span class=\"bold\">") > -1:
thisNodeBold = True
thisNodeText = thisNodeText.replace("<span class=\"bold\">", "")
thisNodeText = thisNodeText.replace("<span>", "")
thisNodeText = thisNodeText.replace("</span>", "")
# 添加标题和段落,采用不同的形式
if thisNodeHeading is not None and int(thisNodeHeading) and int(thisNodeHeading) != 0:
paragraph = doc.add_heading('', level=int(level))
else:
paragraph = doc.add_paragraph('', style='List Bullet')
paragraph_run = paragraph.add_run(thisNodeText)
paragraph_run.font.name = u'Times New Roman'
paragraph_run.element.rPr.rFonts.set(qn('w:eastAsia'), '微软雅黑')
# print(thisNodeColor_)
paragraph_run.font.color.rgb = RGBColor(thisNodeColor_[0], thisNodeColor_[1], thisNodeColor_[2])
if thisNodeBold:
paragraph_run.font.bold = True # 加粗
paragraph_format = paragraph.paragraph_format
paragraph_format.left_indent = Inches(0.15 * (level - 1)) # 调整左缩进0.3英寸
paragraph_format.space_before = Pt(0) # 上行间距
paragraph_format.space_after = Pt(0) # 下行间距
paragraph_format.line_spacing = Pt(14*1.3) # 行距
# document.add_paragraph('Intese quote', style="Intense Quote")
# document.add_paragraph('first item in ordered list', style='List Number')
# 处理备注
if thisNodeNote is not None and thisNodeNote != "":
# if isJson(thisNodeNote):
# thisNodeNote = str(json.dumps(thisNodeNote, indent=2))
thisNodeNote = thisNodeNote.replace("<span>", "")
thisNodeNote = thisNodeNote.replace("</span>", "")
thisNodeNote = thisNodeNote.replace("&nbsp;", " ")
thisNodeNote = thisNodeNote.replace("", "") # \u200b0长度字符 (幕布中的那个红点)
thisNodeNote = thisNodeNote.replace("<br>", "\n")
thisNodeNote = thisNodeNote.replace("\" ", "\"")
thisNodeNote = thisNodeNote.replace(" \"", "\"")
thisNodeNote = thisNodeNote.replace("\",", "\",\n")
thisNodeNote = thisNodeNote.replace("\n\n", "\n")
thisNodeNote = thisNodeNote.replace("\n\n", "\n")
thisNodeNote = thisNodeNote.replace("\n\n", "\n")
thisNodeNote = thisNodeNote.replace("\n\n", "\n")
#thisNodeNote = thisNodeNote.replace(" ", "")
thisNodeNoteParagraph = doc.add_paragraph()
thisNodeNoteParagraph.paragraph_format.left_indent = Inches(0.1 * (level - 1)) # 调整左缩进0.3英寸
note_run = thisNodeNoteParagraph.add_run(thisNodeNote)
note_run.font.color.rgb = RGBColor(105, 105, 105)
note_run.font.italic = True # 斜体
note_run.font.size = Pt(10)
else:
pass
# 处理图片
if thisNodeImages is not None:
# print(thisNodeImages)
# print(len(thisNodeImages))
if isinstance(thisNodeImages, list) and len(thisNodeImages) > 0:
for img in range(len(thisNodeImages)):
thisNodeImage = thisNodeImages[img]
uri = thisNodeImage.get("uri")
if uri is not None:
img_src = "https://api2.mubu.com/v3/" + uri
file_name = uri.replace("document_image/", "")
# 将远程数据下载到本地,第二个参数就是要保存到本地的文件名
if get_image(img_src, file_name):
doc.add_picture(file_name, width=Inches(4)) # 添加图, 设置宽度
os.remove(file_name) # 删除临时文件
else:
pass
else:
pass
else:
pass
# 处理子节点
thisNodeChildren = thisNode.get("children")
if thisNodeChildren is not None:
generateDocx(doc, thisNodeChildren, level + 1)
else:
pass
else:
pass
else:
pass
# 生成文档封皮
def generatePage(doc, docName):
# 设置页眉 页脚
# sections = document.sections
section = doc.sections[0]
# 页眉
header = section.header
header_paragraph = header.paragraphs[0]
header_paragraph.text = "\n\t东师理想慧办公系统接口文档"
# 页脚
# footer = section.footer
# footer_paragraph = footer.paragraphs[0]
# footer_paragraph.text = ""
# 设置封皮 居中
fpParagraph = doc.add_paragraph()
fpParagraph.add_run("\n").font.size = Pt(44)
fpParagraph.add_run("\n").font.size = Pt(44)
fpParagraph.add_run("\n").font.size = Pt(44)
fpParagraph = doc.add_paragraph()
fpParagraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
fpParagraph_run = fpParagraph.add_run(docName)
fpParagraph_run.font.size = Pt(28)
fpParagraph_run.font.bold = True # 加粗
fpParagraph_run.font.name = 'Times New Roman'
fpParagraph_run.element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')
fpParagraph = doc.add_paragraph()
fpParagraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
fpParagraph_run = fpParagraph.add_run("系统接口文档\n")
fpParagraph_run.font.size = Pt(22)
fpParagraph_run.font.bold = True # 加粗
fpParagraph_run.font.name = 'Times New Roman'
fpParagraph_run.element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')
# 设置分页
doc.add_page_break()
# 设置标题 居中
title = doc.add_heading(level=0)
title.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
title_run = title.add_run(docName)
title_run.font.size = Pt(14)
title_run.font.name = 'Times New Roman'
title_run.element.rPr.rFonts.set(qn('w:eastAsia'), '微软雅黑')
# 设置目录位置 居中
muluParagraph = doc.add_paragraph()
# muluParagraph.paragraph_format.left_indent = Inches(0.1 * (level - 1)) # 调整左缩进0.3英寸
mulu_run = muluParagraph.add_run("[请在此处手动添加目录]")
mulu_run.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
mulu_run.font.color.rgb = RGBColor(105, 105, 105)
mulu_run.font.italic = True # 斜体
mulu_run.font.size = Pt(10)
def generater(key):
mbUrl = "https://api2.mubu.com/v3/doc/" + key
mbResponse = getResponse(mbUrl)
if mbResponse is not None:
text = mbResponse.text
# print(text)
docId = get_str_btw(text, "\"doc\":{\"id\":\"", "\",\"")
print("docId = " + docId)
docUrl = "https://mubu.com/api/document/view/get?docId=" + docId
mbDocResponse = getResponse(docUrl)
if mbDocResponse is not None:
mbDocJsonText = mbDocResponse.text
# print(mbDocJsonText)
try:
mbDocJson = json.loads(mbDocJsonText)
if mbDocJson['msg'] == "Success":
docName = mbDocJson['data']['name']
definition = mbDocJson['data']['definition']
definitionJson = json.loads(definition)
nodeList = definitionJson["nodes"]
# print(nodeList)
document = Document()
# 设置一个空白样式
style = document.styles['Normal']
# 设置默认字号
style.font.size = Pt(11)
# 设置西文字体
style.font.name = 'Times New Roman'
# 设置中文字体
style.element.rPr.rFonts.set(qn('w:eastAsia'), '微软雅黑')
# 获取段落样式
default_paragraph_format = style.paragraph_format
# 首行缩进0.74厘米即2个字符
# default_paragraph_format.first_line_indent = Cm(0.74)
# 生成文档封皮
generatePage(document, docName)
# 生成文档
generateDocx(document, nodeList, 1)
# 文件位置
file_path = '%s_%s.docx' % (docName, get_current_time())
# 保存
document.save(file_path)
print("文件生成完成")
return file_path
else:
print("返回值错误")
return None
except Exception as e:
print(e)
return None
else:
print("无响应")
return None
else:
print("无响应")
return None
@app.route('/mbdoc/<key>', methods=['GET'])
def index(key):
# url = request.args.get("url")
# mbUrl = "https://mubu.com/doc/5_8huyn130"
file_name = generater(key)
if file_name is not None:
filename = quote(file_name)
rv = send_file(ROOT + "\\" + file_name, as_attachment=True, attachment_filename=filename)
rv.headers['Content-Disposition'] += "; filename*=utf-8''{}".format(filename)
return rv
if __name__ == '__main__':
CORS(app, supports_credentials=True)
app.run(
host='0.0.0.0',
port=8080,
debug=False
)