forked from mirror/MrDoc
觅道文档,新增PDF导出下载,优化EPUB导出下载,支持思维导图自定义高度等
This commit is contained in:
parent
9bcf043027
commit
7382b8bbbb
11
CHANGES.md
11
CHANGES.md
@ -1,5 +1,16 @@
|
||||
## 版本更新记录
|
||||
|
||||
### v.0.5.0 2020-05-02
|
||||
|
||||
- MrDoc正式中文取名:觅道文档;
|
||||
- 文档编辑器添加Markdown折叠功能;
|
||||
- 思维导图支持图形高度设置;
|
||||
- 优化文集导出EPUB文件功能;
|
||||
- 新增PDF文件导出功能;
|
||||
- 新增一个广告位;
|
||||
- 优化文集名称字符验证;
|
||||
|
||||
|
||||
### v0.4.2 2020-04-20
|
||||
|
||||
- 添加思维导图功能的支持,可以在文档编辑器通过图标和`mindmap`标识代码块来创建脑图;
|
||||
|
@ -1,3 +1,4 @@
|
||||
# coding:utf-8
|
||||
"""
|
||||
Django settings for MrDoc project.
|
||||
|
||||
@ -25,7 +26,7 @@ SECRET_KEY = '5&71mt9@^58zdg*_!t(x6g14q*@84d%ptr%%s6e0l50zs0we3d'
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = False
|
||||
|
||||
VERSIONS = '0.4.2'
|
||||
VERSIONS = '0.5.0'
|
||||
|
||||
ALLOWED_HOSTS = ['*']
|
||||
|
||||
|
14
README.md
14
README.md
@ -1,4 +1,4 @@
|
||||
## MrDoc - 记录文档,汇聚思想
|
||||
## 觅道文档MrDoc - 记录文档,汇聚思想
|
||||
|
||||
![Mrdoc首页](./captrue/mrdoc-index.png)
|
||||
|
||||
@ -28,13 +28,13 @@
|
||||
- 支持**思维导图**,以Markdown的语法创建思维导图
|
||||
- 支持流程图、时序图的绘制;
|
||||
- 两栏式**文档阅读**页面、三级目录层级显示,文档阅读字体缩放,字体类型切换,页面社交分享,移动端阅读优化;
|
||||
- 支持文集后台**导出打包**`markdown`文本格式`.md`文件、前台导出为`EPUB`等格式文件;
|
||||
- 支持文集**导出打包**,包括`markdown`文本格式`.md`文件、`EPUB`电子书格式文件和PDF格式文件;
|
||||
- 基于文集进行**文档权限**控制,提供公开、私密、指定用户可见、访问码可见4种权限模式;
|
||||
- 支持基于账户的**`API`接口**,可以借助账户`token`通过`API`获取文集、上传图片和创建文档;
|
||||
- 支持**文集协作**功能,一个文集可以拥有一个创建者和多个协作者,可灵活选择协作权限;
|
||||
- 支持**文档历史版本**功能,可以查看和对比历史版本与现有版本的差异,恢复某个历史版本为当前版本;
|
||||
|
||||
当前版本为:**v0.4.2**,版本发布时间为**2020-04-20**
|
||||
当前版本为:**v0.5.0**,版本发布时间为**2020-05-02**
|
||||
|
||||
完整更新记录详见:[CHANGES.md](./CHANGES.md)
|
||||
|
||||
@ -57,7 +57,10 @@ pip install -r requirements.txt
|
||||
|
||||
默认情况下,MrDoc使用Django的SQLite数据库,如果你使用Sqlite数据库,则无需另外配置数据库。
|
||||
|
||||
如果有配置其他数据库的需求,请在/MrDoc/MrDoc目录下打开settings.py文件,在约80行的位置,将如下代码:
|
||||
如果有配置其他数据库的需求,请首先按照Django官方的[数据库支持说明](https://docs.djangoproject.com/zh-hans/2.2/ref/databases/),安装特定数据库的Python绑定库,
|
||||
|
||||
然后在/MrDoc/MrDoc目录下打开settings.py文件,在约80行的位置,将如下代码:
|
||||
|
||||
```python
|
||||
DATABASES = {
|
||||
'default': {
|
||||
@ -66,7 +69,9 @@ DATABASES = {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
按照自己数据库的信息,将其修改如下格式,下面以MySQL为例:
|
||||
|
||||
```python
|
||||
DATABASES = {
|
||||
'default': {
|
||||
@ -79,6 +84,7 @@ DATABASES = {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3、初始化数据库
|
||||
|
||||
在安装完所需的第三方库并配置好数据库信息之后,我们需要对数据库进行初始化。
|
||||
|
@ -12,19 +12,25 @@ import json,datetime,hashlib,random
|
||||
from app_doc.models import *
|
||||
from app_admin.models import *
|
||||
from app_admin.utils import *
|
||||
import traceback
|
||||
|
||||
|
||||
# 返回验证码图片
|
||||
def check_code(request):
|
||||
import io
|
||||
from . import check_code as CheckCode
|
||||
stream = io.BytesIO()
|
||||
# img图片对象,code在图像中写的内容
|
||||
img, code = CheckCode.create_validate_code()
|
||||
img.save(stream, "png")
|
||||
# 图片页面中显示,立即把session中的CheckCode更改为目前的随机字符串值
|
||||
request.session["CheckCode"] = code
|
||||
return HttpResponse(stream.getvalue())
|
||||
try:
|
||||
import io
|
||||
from . import check_code as CheckCode
|
||||
stream = io.BytesIO()
|
||||
# img图片对象,code在图像中写的内容
|
||||
img, code = CheckCode.create_validate_code()
|
||||
img.save(stream, "png")
|
||||
# 图片页面中显示,立即把session中的CheckCode更改为目前的随机字符串值
|
||||
request.session["CheckCode"] = code
|
||||
return HttpResponse(stream.getvalue())
|
||||
except Exception as e:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return HttpResponse("请求异常:{}".format(repr(e)))
|
||||
|
||||
|
||||
# 登录视图
|
||||
@ -54,6 +60,8 @@ def log_in(request):
|
||||
errormsg = '用户名或密码错误!'
|
||||
return render(request, 'login.html', locals())
|
||||
except Exception as e:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return HttpResponse('请求出错')
|
||||
|
||||
|
||||
@ -136,8 +144,8 @@ def log_out(request):
|
||||
try:
|
||||
logout(request)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
# logger.error(e)
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return redirect(request.META['HTTP_REFERER'])
|
||||
|
||||
|
||||
@ -165,7 +173,8 @@ def forget_pwd(request):
|
||||
errormsg = "验证码已过期"
|
||||
return render(request, 'forget_pwd.html', locals())
|
||||
except Exception as e:
|
||||
print(repr(e))
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
errormsg = "验证码错误"
|
||||
return render(request,'forget_pwd.html',locals())
|
||||
|
||||
@ -514,7 +523,8 @@ def admin_setting(request):
|
||||
if types == 'basic':
|
||||
close_register = request.POST.get('close_register',None) # 禁止注册
|
||||
static_code = request.POST.get('static_code',None) # 统计代码
|
||||
ad_code = request.POST.get('ad_code',None) # 广告代码
|
||||
ad_code = request.POST.get('ad_code',None) # 广告位1
|
||||
ad_code_2 = request.POST.get('ad_code_2',None) # 广告位2
|
||||
beian_code = request.POST.get('beian_code',None) # 备案号
|
||||
enbale_email = request.POST.get("enable_email",None) # 启用邮箱
|
||||
enable_register_code = request.POST.get('enable_register_code',None) # 注册邀请码
|
||||
@ -534,6 +544,10 @@ def admin_setting(request):
|
||||
name = 'ad_code',
|
||||
defaults={'value':ad_code,'types':'basic'}
|
||||
)
|
||||
SysSetting.objects.update_or_create(
|
||||
name='ad_code_2',
|
||||
defaults={'value': ad_code_2, 'types': 'basic'}
|
||||
)
|
||||
# 更新备案号
|
||||
SysSetting.objects.update_or_create(
|
||||
name='beian_code',
|
||||
|
29
app_doc/migrations/0020_projectreportfile.py
Normal file
29
app_doc/migrations/0020_projectreportfile.py
Normal file
@ -0,0 +1,29 @@
|
||||
# Generated by Django 2.2.12 on 2020-04-26 11:15
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('app_doc', '0019_dochistory_create_user'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ProjectReportFile',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('file_type', models.CharField(choices=[('epub', 'epub'), ('pdf', 'pdf'), ('docx', 'docx')], max_length=10, verbose_name='文件类型')),
|
||||
('file_name', models.CharField(max_length=100, verbose_name='文件名称')),
|
||||
('file_path', models.CharField(max_length=250, verbose_name='文件路径')),
|
||||
('create_time', models.DateTimeField(auto_now_add=True)),
|
||||
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app_doc.Project')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '附件管理',
|
||||
'verbose_name_plural': '附件管理',
|
||||
},
|
||||
),
|
||||
]
|
18
app_doc/migrations/0021_projectreport_allow_pdf.py
Normal file
18
app_doc/migrations/0021_projectreport_allow_pdf.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 2.2.12 on 2020-05-01 10:10
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('app_doc', '0020_projectreportfile'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='projectreport',
|
||||
name='allow_pdf',
|
||||
field=models.IntegerField(default=0, verbose_name='前台导出PDF'),
|
||||
),
|
||||
]
|
@ -106,6 +106,7 @@ class ProjectReport(models.Model):
|
||||
project = models.OneToOneField(Project,unique=True,on_delete=models.CASCADE)
|
||||
# 允许导出,默认为0-允许,1-不允许
|
||||
allow_epub = models.IntegerField(default=0,verbose_name="前台导出EPUB")
|
||||
allow_pdf = models.IntegerField(default=0, verbose_name="前台导出PDF")
|
||||
|
||||
def __str__(self):
|
||||
return self.project.name
|
||||
@ -114,6 +115,22 @@ class ProjectReport(models.Model):
|
||||
verbose_name = '文集导出'
|
||||
verbose_name_plural = verbose_name
|
||||
|
||||
|
||||
# 文集导出文集模型
|
||||
class ProjectReportFile(models.Model):
|
||||
project = models.ForeignKey(Project, on_delete=models.CASCADE) # 外键关联文集
|
||||
file_type = models.CharField(choices=(('epub', 'epub'), ('pdf', 'pdf'), ('docx', 'docx')), verbose_name='文件类型',max_length=10)
|
||||
file_name = models.CharField(max_length=100, verbose_name='文件名称')
|
||||
file_path = models.CharField(max_length=250, verbose_name='文件路径')
|
||||
create_time = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.file_name
|
||||
|
||||
class Meta:
|
||||
verbose_name = '附件管理'
|
||||
verbose_name_plural = verbose_name
|
||||
|
||||
# 图片分组模型
|
||||
class ImageGroup(models.Model):
|
||||
user = models.ForeignKey(User,on_delete=models.CASCADE)
|
||||
|
@ -21,6 +21,125 @@ django.setup()
|
||||
from app_doc.models import *
|
||||
import traceback
|
||||
import time
|
||||
from pyppeteer import launch
|
||||
import asyncio
|
||||
# import PyPDF2
|
||||
# from pdfminer import high_level
|
||||
|
||||
# 动态脑图转静态图片
|
||||
def genera_mindmap_img(html_path,img_path):
|
||||
async def main():
|
||||
browser = await launch(headless=True,handleSIGINT=False,handleSIGTERM=False,handleSIGHUP=False)
|
||||
page = await browser.newPage()
|
||||
await page.goto('file://' + html_path, {'waitUntil': 'networkidle0'})
|
||||
element = await page.querySelector('.mindmap')
|
||||
await element.screenshot({'type': 'jpeg', 'quality': 100, 'path': img_path})
|
||||
await browser.close()
|
||||
|
||||
# asyncio.new_event_loop().run_until_complete(main())
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
loop = asyncio.get_event_loop()
|
||||
try:
|
||||
loop.run_until_complete(main())
|
||||
finally:
|
||||
loop.close()
|
||||
|
||||
|
||||
# 公式转图片
|
||||
def genera_tex_img(html_path,img_path):
|
||||
async def main():
|
||||
browser = await launch(headless=True,handleSIGINT=False,handleSIGTERM=False,handleSIGHUP=False)
|
||||
page = await browser.newPage()
|
||||
await page.goto('file://' + html_path, {'waitUntil': 'networkidle0'})
|
||||
element = await page.querySelector('.editormd-tex')
|
||||
await element.screenshot({'type': 'jpeg', 'quality': 100, 'path': img_path})
|
||||
await browser.close()
|
||||
|
||||
# asyncio.new_event_loop().run_until_complete(main())
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
loop = asyncio.get_event_loop()
|
||||
try:
|
||||
loop.run_until_complete(main())
|
||||
finally:
|
||||
loop.close()
|
||||
|
||||
# 流程图转图片
|
||||
def genera_flowchart_img(html_path,img_path):
|
||||
async def main():
|
||||
browser = await launch(headless=True,handleSIGINT=False,handleSIGTERM=False,handleSIGHUP=False)
|
||||
page = await browser.newPage()
|
||||
await page.goto('file://' + html_path, {'waitUntil': 'networkidle0'})
|
||||
element = await page.querySelector('.flowchart')
|
||||
await element.screenshot({'type': 'jpeg', 'quality': 100, 'path': img_path})
|
||||
await browser.close()
|
||||
|
||||
# asyncio.new_event_loop().run_until_complete(main())
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
loop = asyncio.get_event_loop()
|
||||
try:
|
||||
loop.run_until_complete(main())
|
||||
finally:
|
||||
loop.close()
|
||||
|
||||
# 时序图转图片
|
||||
def genera_seque_img(html_path,img_path):
|
||||
async def main():
|
||||
browser = await launch(headless=True,handleSIGINT=False,handleSIGTERM=False,handleSIGHUP=False)
|
||||
page = await browser.newPage()
|
||||
await page.goto('file://' + html_path, {'waitUntil': 'networkidle0'})
|
||||
element = await page.querySelector('.sequence-diagram')
|
||||
await element.screenshot({'type': 'jpeg', 'quality': 100, 'path': img_path})
|
||||
await browser.close()
|
||||
|
||||
# asyncio.new_event_loop().run_until_complete(main())
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
loop = asyncio.get_event_loop()
|
||||
try:
|
||||
loop.run_until_complete(main())
|
||||
finally:
|
||||
loop.close()
|
||||
|
||||
# HTML转PDF
|
||||
def html_to_pdf(html_path,pdf_path):
|
||||
async def main():
|
||||
browser = await launch(
|
||||
headless=True,
|
||||
handleSIGINT=False,
|
||||
handleSIGTERM=False,
|
||||
handleSIGHUP=False,
|
||||
ignoreHTTPSErrors = True,
|
||||
)
|
||||
page = await browser.newPage()
|
||||
await page.goto('file://' + html_path, {'waitUntil': 'networkidle0'})
|
||||
await page.pdf({
|
||||
'path':pdf_path,
|
||||
'format':'A4',
|
||||
'displayHeaderFooter':True,
|
||||
'headerTemplate':'<div></div>',
|
||||
'footerTemplate':'<div style="text-align:center;width:297mm;font-size: 8px;"><span class="pageNumber"></span>/<span class="totalPages"></span></div>',
|
||||
'margin':{
|
||||
'top':'1cm',
|
||||
'right':'1cm',
|
||||
'bottom':'1cm',
|
||||
'left':'1cm'
|
||||
}
|
||||
|
||||
})
|
||||
await browser.close()
|
||||
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
loop = asyncio.get_event_loop()
|
||||
try:
|
||||
loop.run_until_complete(main())
|
||||
except:
|
||||
loop.run_until_complete(main())
|
||||
finally:
|
||||
loop.close()
|
||||
|
||||
# 导出MD文件压缩包
|
||||
class ReportMD():
|
||||
@ -55,7 +174,7 @@ class ReportMD():
|
||||
def work(self):
|
||||
# 读取指定文集的文档数据
|
||||
data = Doc.objects.filter(top_doc=self.pro_id, parent_doc=0).order_by("sort")
|
||||
# 遍历文档
|
||||
# 遍历一级文档
|
||||
for d in data:
|
||||
md_name = d.name
|
||||
md_content = d.pre_content
|
||||
@ -70,7 +189,6 @@ class ReportMD():
|
||||
for d2 in data_2:
|
||||
md_name_2 = d2.name
|
||||
md_content_2 = d2.pre_content
|
||||
|
||||
md_content_2 = self.operat_md_media(md_content_2)
|
||||
|
||||
# 新建MD文件
|
||||
@ -138,7 +256,7 @@ class ReportMD():
|
||||
class ReportEPUB():
|
||||
def __init__(self,project_id):
|
||||
self.project = Project.objects.get(id=project_id)
|
||||
self.base_path = settings.MEDIA_ROOT + '/report/{}/'.format(project_id)
|
||||
self.base_path = settings.MEDIA_ROOT + '/report_epub/{}/'.format(project_id)
|
||||
|
||||
# 创建相关目录
|
||||
if os.path.exists(self.base_path + '/OEBPS') is False:
|
||||
@ -155,7 +273,7 @@ class ReportEPUB():
|
||||
# 复制样式文件到相关目录
|
||||
shutil.copyfile(settings.BASE_DIR+'/static/report_epub/style.css',self.base_path + '/OEBPS/Styles/style.css')
|
||||
shutil.copyfile(settings.BASE_DIR+'/static/katex/katex.min.css',self.base_path + '/OEBPS/Styles/katex.css')
|
||||
shutil.copyfile(settings.BASE_DIR+'/static/editor.md/css/editormd.min.css/',self.base_path + '/OEBPS/Styles/editormd.css')
|
||||
shutil.copyfile(settings.BASE_DIR+'/static/editor.md/css/editormd.min.css',self.base_path + '/OEBPS/Styles/editormd.css')
|
||||
# 复制封面图片到相关目录
|
||||
shutil.copyfile(settings.BASE_DIR+'/static/report_epub/epub_cover1.jpg',self.base_path + '/OEBPS/Images/epub_cover1.jpg')
|
||||
|
||||
@ -164,8 +282,11 @@ class ReportEPUB():
|
||||
# 使用BeautifulSoup解析拼接好的HTML文本
|
||||
html_soup = BeautifulSoup(html_str, 'lxml')
|
||||
src_tag = html_soup.find_all(lambda tag: tag.has_attr("src")) # 查找所有包含src的标签
|
||||
code_tag = html_soup.find_all(name="code")
|
||||
# print(src_tag)
|
||||
mindmap_tag = html_soup.select('svg.mindmap') # 查找所有脑图的SVG标签
|
||||
tex_tag = html_soup.select('.editormd-tex') # 查找所有公式标签
|
||||
flowchart_tag = html_soup.select('.flowchart') # 查找所有流程图标签
|
||||
seque_tag = html_soup.select('.sequence-diagram') # 查找所有时序图标签
|
||||
code_tag = html_soup.find_all(name="code") # 查找code代码标签
|
||||
|
||||
# 添加css样式标签
|
||||
style_link = html_soup.new_tag(name='link',href="../Styles/style.css",rel="stylesheet",type="text/css")
|
||||
@ -177,6 +298,7 @@ class ReportEPUB():
|
||||
|
||||
# 添加xlm标签声明
|
||||
# html_soup.html.insert_before('<?xml version="1.0" encoding="UTF-8"?>')
|
||||
|
||||
# 添加html标签的xmlns属性
|
||||
html_soup.html['xmlns'] = "http://www.w3.org/1999/xhtml"
|
||||
|
||||
@ -195,6 +317,160 @@ class ReportEPUB():
|
||||
except FileNotFoundError as e:
|
||||
pass
|
||||
|
||||
# 替换HTML文本中的脑图为静态图片
|
||||
for mindmap in mindmap_tag:
|
||||
print('转换脑图')
|
||||
html_str = '''<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Markmap</title>
|
||||
<script src="../../static/jquery/3.1.1/jquery.min.js"></script>
|
||||
<script src="../../static/mindmap/d3@5.js"></script>
|
||||
<script src="../../static/mindmap/transform.js"></script>
|
||||
<script src="../../static/mindmap/view.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
{svg_content}
|
||||
<script>
|
||||
var mmap = $('svg.mindmap');
|
||||
var md_data = window.markmap.transform(mmap.text().trim());
|
||||
window.markmap.markmap("svg.mindmap",md_data)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
'''.format(svg_content=mindmap)
|
||||
# 脑图HTML文件路径
|
||||
temp_mindmap_html = settings.BASE_DIR +'/media/report_epub/mindmap_{}.html'.format(str(time.time()))
|
||||
mindmap_img_filename = 'mindmap_{}.jpg'.format(str(time.time()))
|
||||
mindmap_img_path = self.base_path + '/OEBPS/Images/' + mindmap_img_filename
|
||||
with open(temp_mindmap_html,'w+',encoding='utf-8') as mindmap_html:
|
||||
mindmap_html.write(html_str)
|
||||
genera_mindmap_img(temp_mindmap_html,mindmap_img_path)
|
||||
# 将图片标签设置进去
|
||||
mindmap.name = 'img'
|
||||
mindmap['src'] = '../Images/' + mindmap_img_filename
|
||||
mindmap.string = ''
|
||||
os.remove(temp_mindmap_html) # 删除临时的HTML
|
||||
|
||||
# 替换公式为静态图片
|
||||
for tex in tex_tag:
|
||||
print('转换公式')
|
||||
html_str = '''<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<link rel="stylesheet" href="../../static/katex/katex.min.css" />
|
||||
<title>Markmap</title>
|
||||
<script src="../../static/jquery/3.1.1/jquery.min.js"></script>
|
||||
<script src="../../static/editor.md/editormd.js"></script>
|
||||
<script src="../../static/katex/katex.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
{content}
|
||||
</body>
|
||||
<script>
|
||||
var tex = $('.editormd-tex');
|
||||
katex.render(tex.html().replace(/</g, "<").replace(/>/g, ">"), tex[0]);
|
||||
tex.find(".katex").css("font-size", "1.6em");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
'''.format(content=tex)
|
||||
# 公式HTML文件路径
|
||||
temp_tex_html = settings.BASE_DIR + '/media/report_epub/tex_{}.html'.format(str(time.time()))
|
||||
tex_img_filename = 'tex_{}.jpg'.format(str(time.time()))
|
||||
tex_img_path = self.base_path + '/OEBPS/Images/' + tex_img_filename
|
||||
with open(temp_tex_html, 'w+', encoding='utf-8') as tex_html:
|
||||
tex_html.write(html_str)
|
||||
genera_tex_img(temp_tex_html, tex_img_path)
|
||||
# 将图片标签添加进去
|
||||
# tex.name = 'img'
|
||||
# tex['src'] = '../Images/' + tex_img_filename
|
||||
tex.string = ''
|
||||
tex_img_tag = html_soup.new_tag(name='img',src='../Images/' + tex_img_filename)
|
||||
tex.insert(0,tex_img_tag)
|
||||
os.remove(temp_tex_html) # 删除临时的HTML
|
||||
|
||||
# 替换流程图为静态图片
|
||||
for flowchart in flowchart_tag:
|
||||
print("转换流程图")
|
||||
html_str = '''<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<link rel="stylesheet" href="../../static/katex/katex.min.css" />
|
||||
<title>Markmap</title>
|
||||
<script src="../../static/jquery/3.1.1/jquery.min.js"></script>
|
||||
<script src="../../static/editor.md/lib/raphael.min.js"></script>
|
||||
<script src="../../static/editor.md/lib/flowchart.min.js"></script>
|
||||
<script src="../../static/editor.md/lib/jquery.flowchart.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
{content}
|
||||
</body>
|
||||
<script>
|
||||
$(".flowchart").flowChart();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
'''.format(content=flowchart)
|
||||
# 流程图HTML文件路径
|
||||
temp_flow_html = settings.BASE_DIR + '/media/report_epub/flow_{}.html'.format(str(time.time()))
|
||||
flow_img_filename = 'flow_{}.jpg'.format(str(time.time()))
|
||||
flow_img_path = self.base_path + '/OEBPS/Images/' + flow_img_filename
|
||||
with open(temp_flow_html, 'w+', encoding='utf-8') as flow_html:
|
||||
flow_html.write(html_str)
|
||||
genera_flowchart_img(temp_flow_html, flow_img_path)
|
||||
# 将图片标签添加进去
|
||||
flowchart.string = ''
|
||||
flow_img_tag = html_soup.new_tag(name='img', src='../Images/' + flow_img_filename)
|
||||
flowchart.insert(0, flow_img_tag)
|
||||
os.remove(temp_flow_html) # 删除临时的HTML
|
||||
|
||||
# 替换时序图为静态图片
|
||||
for seque in seque_tag:
|
||||
print("转换时序图")
|
||||
html_str = '''<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Markmap</title>
|
||||
<script src="../../static/jquery/3.1.1/jquery.min.js"></script>
|
||||
<script src="../../static/editor.md/lib/raphael.min.js"></script>
|
||||
<script src="../../static/editor.md/lib/underscore.min.js"></script>
|
||||
<script src="../../static/editor.md/lib/sequence-diagram.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
{content}
|
||||
</body>
|
||||
<script>
|
||||
$(".sequence-diagram").sequenceDiagram({{theme: "simple"}});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
'''.format(content=seque)
|
||||
# 时序图HTML文件路径
|
||||
temp_seque_html = settings.BASE_DIR + '/media/report_epub/seque_{}.html'.format(str(time.time()))
|
||||
seque_img_filename = 'seque_{}.jpg'.format(str(time.time()))
|
||||
seque_img_path = self.base_path + '/OEBPS/Images/' + seque_img_filename
|
||||
with open(temp_seque_html, 'w+', encoding='utf-8') as seque_html:
|
||||
seque_html.write(html_str)
|
||||
genera_seque_img(temp_seque_html, seque_img_path)
|
||||
# 将图片标签添加进去
|
||||
seque.string = ''
|
||||
seque_img_tag = html_soup.new_tag(name='img', src='../Images/' + seque_img_filename)
|
||||
seque.insert(0, seque_img_tag)
|
||||
os.remove(temp_seque_html) # 删除临时的HTML
|
||||
|
||||
# 替换code标签的内容
|
||||
# for code in code_tag:
|
||||
# code_str = code.get_text()
|
||||
@ -521,11 +797,11 @@ class ReportEPUB():
|
||||
def generate_epub(self):
|
||||
try:
|
||||
# 生成ZIP压缩文件
|
||||
zipfile_name = settings.MEDIA_ROOT + '/report/{}'.format(self.project.name)+'_'+str(int(time.time()))
|
||||
zipfile_name = settings.MEDIA_ROOT + '/report_epub/{}'.format(self.project.name)+'_'+str(int(time.time()))
|
||||
zip_name = shutil.make_archive(
|
||||
base_name = zipfile_name,
|
||||
format='zip',
|
||||
root_dir= settings.MEDIA_ROOT + '/report/{}'.format(self.project.id)
|
||||
root_dir= settings.MEDIA_ROOT + '/report_epub/{}'.format(self.project.id)
|
||||
)
|
||||
# print(zip_name)
|
||||
# 修改zip压缩文件后缀为EPUB
|
||||
@ -550,6 +826,186 @@ class ReportEPUB():
|
||||
epub_file = self.generate_epub()
|
||||
return epub_file
|
||||
|
||||
|
||||
# 导出PDF
|
||||
class ReportPDF():
|
||||
def __init__(self,project_id):
|
||||
# 查询文集信息
|
||||
self.pro_id = project_id
|
||||
self.html_str = '''
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>{title}</title>
|
||||
<link rel="stylesheet" href="../../static/editor.md/css/editormd.css" />
|
||||
<link rel="stylesheet" href="../../static/katex/katex.min.css" />
|
||||
<script src="../../static/jquery/3.1.1/jquery.min.js"></script>
|
||||
<script src="../../static/editor.md/lib/marked.min.js"></script>
|
||||
<script src="../../static/editor.md/lib/prettify.min.js"></script>
|
||||
<script src="../../static/editor.md/lib/raphael.min.js"></script>
|
||||
<script src="../../static/editor.md/lib/underscore.min.js"></script>
|
||||
<script src="../../static/editor.md/lib/sequence-diagram.min.js"></script>
|
||||
<script src="../../static/editor.md/lib/flowchart.min.js"></script>
|
||||
<script src="../../static/editor.md/lib/jquery.flowchart.min.js"></script>
|
||||
<script src="../../static/mindmap/d3@5.js"></script>
|
||||
<script src="../../static/mindmap/transform.js"></script>
|
||||
<script src="../../static/mindmap/view.js"></script>
|
||||
<script src="../../static/katex/katex.min.js"></script>
|
||||
<script src="../../static/editor.md/editormd.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div style="position: fixed;font-size:8px; bottom: 5px; right: 10px; background: red; z-index: 10000">
|
||||
本文档由觅道文档(MrDoc)生成
|
||||
</div>
|
||||
<div style="text-align:center;margin-top:400px;">
|
||||
<h1>{project_name}</h1>
|
||||
<p>作者:{author}</p>
|
||||
<p>日期:{create_time}</p>
|
||||
</div>\n
|
||||
<div class="markdown-body" id="content" style="padding:0px;font-family:宋体;">
|
||||
<textarea style="display: none;">{pre_content}</textarea>
|
||||
</div>
|
||||
<script>
|
||||
editormd.markdownToHTML("content", {{
|
||||
htmlDecode : "style,script,iframe",
|
||||
emoji : true, //emoji表情
|
||||
taskList : true, // 任务列表
|
||||
tex : true, // 科学公式
|
||||
flowChart : true, // 流程图
|
||||
sequenceDiagram : true, // 时序图
|
||||
tocm : true, //目录
|
||||
toc :true,
|
||||
tocContainer : "#toc-container",
|
||||
tocDropdown : false,
|
||||
atLink : false,//禁用@链接
|
||||
|
||||
}});
|
||||
$('html').find(".editormd-tex").each(function(){{
|
||||
var tex = $(this);
|
||||
katex.render(tex.html().replace(/</g, "<").replace(/>/g, ">"), tex[0]);
|
||||
tex.find(".katex").css("font-size", "1.6em");
|
||||
}});
|
||||
$('img.emoji').each(function(){{
|
||||
var img = $(this);
|
||||
if(img[0].src.indexOf("/static/editor.md/")){{
|
||||
var src = img[0].src.split('static');
|
||||
img[0].src = '../../static' + src[1];
|
||||
}}
|
||||
}})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
'''
|
||||
self.content_str = ""
|
||||
|
||||
def work(self):
|
||||
try:
|
||||
project = Project.objects.get(pk=self.pro_id)
|
||||
except:
|
||||
return
|
||||
# 拼接文档的HTML字符串
|
||||
data = Doc.objects.filter(top_doc=self.pro_id,parent_doc=0).order_by("sort")
|
||||
toc_list = {'1':[],'2':[],'3':[]}
|
||||
for d in data:
|
||||
self.content_str += "<h1 style='page-break-before: always;'>{}</h1>\n\n".format(d.name)
|
||||
self.content_str += d.pre_content + '\n'
|
||||
toc_list['1'].append({'id':d.id,'name':d.name})
|
||||
# 获取第二级文档
|
||||
data_2 = Doc.objects.filter(parent_doc=d.id).order_by("sort")
|
||||
for d2 in data_2:
|
||||
self.content_str += "\n\n<h1 style='page-break-before: always;'>{}</h1>\n\n".format(d2.name)
|
||||
self.content_str += d2.pre_content + '\n'
|
||||
toc_list['2'].append({'id':d2.id,'name':d2.name,'parent':d.id})
|
||||
# 获取第三级文档
|
||||
data_3 = Doc.objects.filter(parent_doc=d2.id).order_by("sort")
|
||||
for d3 in data_3:
|
||||
# print(d3.name,d3.content)
|
||||
self.content_str += "\n\n<h1 style='page-break-before: always;'>{}</h1>\n\n".format(d3.name)
|
||||
self.content_str += d3.pre_content +'\n'
|
||||
toc_list['3'].append({'id':d3.id,'name':d3.name,'parent':d2.id})
|
||||
|
||||
# 替换所有媒体文件链接
|
||||
self.content_str = self.content_str.replace('![](/media//','![](../../media/')
|
||||
# print(self.html_str.format(pre_content=self.content_str))
|
||||
|
||||
# 创建写入临时HTML文件
|
||||
report_pdf_folder = settings.MEDIA_ROOT+'/report_pdf'
|
||||
is_folder = os.path.exists(report_pdf_folder)
|
||||
# 创建文件夹
|
||||
if is_folder is False:
|
||||
os.mkdir(report_pdf_folder)
|
||||
# 临时HTML和PDF文件名
|
||||
temp_file_name = '{}_{}'.format(
|
||||
project.name,
|
||||
str(datetime.datetime.today()).replace(' ', '-').replace(':', '-')
|
||||
)
|
||||
# 临时HTML文件路径
|
||||
temp_file_path = report_pdf_folder + '/{0}.html'.format(temp_file_name)
|
||||
# PDF文件路径
|
||||
report_file_path = report_pdf_folder + '/{0}.pdf'.format(temp_file_name)
|
||||
# output_pdf_path = report_pdf_folder + '/{}_{}.pdf'.format(
|
||||
# project.name,
|
||||
# str(datetime.datetime.today()).replace(' ','-').replace(':','-')
|
||||
# )
|
||||
# 写入HTML文件
|
||||
with open(temp_file_path, 'w', encoding='utf-8') as htmlfile:
|
||||
htmlfile.write(
|
||||
self.html_str.format(
|
||||
title=project.name,
|
||||
pre_content=self.content_str,
|
||||
project_name=project.name,
|
||||
author=project.create_user,
|
||||
create_time=str(datetime.date.today())
|
||||
)
|
||||
)
|
||||
|
||||
# 执行HTML转PDF
|
||||
html_to_pdf(temp_file_path,report_file_path)
|
||||
# 处理PDF文件
|
||||
if os.path.exists(report_file_path):
|
||||
# output = PyPDF2.PdfFileWriter() # 实例化一个PDF写入文件类,用于保存最后的PDF文件
|
||||
# tmp_pdf_file = open(report_file_path, 'rb') # 打开临时PDF
|
||||
# input = PyPDF2.PdfFileReader(tmp_pdf_file) # 打开临时PDF文件
|
||||
# pdf_pages = input.getNumPages() # 获取临时PDF的页数
|
||||
# for p in range(pdf_pages):
|
||||
# page = input.getPage(p)
|
||||
# output.addPage(page) # 添加一页
|
||||
# page_content = high_level.extract_text(report_file_path, page_numbers=[p]) # 提取某页的文本
|
||||
# first_line_text = page_content.split('\n') # 获取某页的第一行文本
|
||||
# # 添加第一层级文档书签
|
||||
# for i1 in toc_list['1']:
|
||||
# if i1['name'] in first_line_text:
|
||||
# bookmark_1 = output.addBookmark(i1['name'], p, parent=None) # 添加书签
|
||||
# else:
|
||||
# bookmark_1 = None
|
||||
# # 添加第二层文档书签
|
||||
# for i2 in toc_list['2']:
|
||||
# if i2['name'] in first_line_text:
|
||||
# bookmark_2 = output.addBookmark(i2['name'], p, parent=bookmark_1) # 添加书签
|
||||
# # 添加第三层文档书签
|
||||
# for i3 in toc_list['3']:
|
||||
# if i3['name'] in first_line_text:
|
||||
# bookmark_3 = output.addBookmark(i3['name'], p, parent=bookmark_2) # 添加书签
|
||||
#
|
||||
# output.setPageMode("/UseOutlines") # 默认打开书签
|
||||
# with open(output_pdf_path, 'wb') as output_pdf_file:
|
||||
# output.write(output_pdf_file)
|
||||
|
||||
# output_pdf_file.close()
|
||||
|
||||
# 删除临时HTML文件和临时PDF文件
|
||||
# tmp_pdf_file.close() # 关闭临时PDF文件
|
||||
os.remove(temp_file_path)
|
||||
# os.remove(report_file_path)
|
||||
# print(report_file_path)
|
||||
return report_file_path
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
# 导出Docx
|
||||
class ReportDocx():
|
||||
def __init__(self,project_id):
|
||||
@ -697,7 +1153,12 @@ if __name__ == '__main__':
|
||||
# project_id=7
|
||||
# )
|
||||
# app.work()
|
||||
app = ReportEPUB(project_id=20)
|
||||
|
||||
# app = ReportEPUB(project_id=20)
|
||||
# app.work()
|
||||
|
||||
app = ReportPDF(project_id=20)
|
||||
app.work()
|
||||
|
||||
# app = ReportDocx(project_id=20)
|
||||
# app.work()
|
@ -19,9 +19,9 @@ def get_new_doc(value):
|
||||
new_doc = '它还没有文档……'
|
||||
return new_doc
|
||||
|
||||
# 获取文集的开放导出状态
|
||||
@register.filter(name='get_report_status')
|
||||
def get_report_status(value):
|
||||
# 获取文集的EPUB开放导出状态
|
||||
@register.filter(name='report_status_epub')
|
||||
def get_report_status_epub(value):
|
||||
try:
|
||||
project = Project.objects.get(id=int(value))
|
||||
status = ProjectReport.objects.get(project=project).allow_epub
|
||||
@ -30,6 +30,17 @@ def get_report_status(value):
|
||||
status = 0
|
||||
return status
|
||||
|
||||
# 获取文集的PDF开放导出状态
|
||||
@register.filter(name='report_status_pdf')
|
||||
def get_report_status_pdf(value):
|
||||
try:
|
||||
project = Project.objects.get(id=int(value))
|
||||
status = ProjectReport.objects.get(project=project).allow_pdf
|
||||
except Exception as e:
|
||||
# print(repr(e))
|
||||
status = 0
|
||||
return status
|
||||
|
||||
# 获取图片分组的图片数量
|
||||
@register.filter(name='img_group_cnt')
|
||||
def get_img_group_cnt(value):
|
||||
|
@ -12,6 +12,7 @@ urlpatterns = [
|
||||
path('manage_project',views.manage_project,name="manage_project"), # 管理文集
|
||||
path('del_project/',views.del_project,name='del_project'), # 删除文集
|
||||
path('report_project_md/',views.report_md,name='report_md'), # 导出文集MD文件
|
||||
path('genera_project_file/',views.genera_project_file,name='genera_project_file'), # 个人中心生成文集文件(epub\docx\pdf等)
|
||||
path('report_project_file/',views.report_file,name='report_file'), # 导出文集文件(epub、docx等)
|
||||
path('modify_pro_role/<int:pro_id>/',views.modify_project_role,name="modify_pro_role"),# 修改文集权限
|
||||
path('modify_pro_download/<int:pro_id>/', views.modify_project_download, name="modify_pro_download"), # 修改文集前台下载权限
|
||||
|
301
app_doc/views.py
301
app_doc/views.py
@ -9,6 +9,7 @@ from django.core.exceptions import PermissionDenied,ObjectDoesNotExist
|
||||
from app_doc.models import Project,Doc,DocTemp
|
||||
from django.contrib.auth.models import User
|
||||
from django.db.models import Q
|
||||
from django.db import transaction
|
||||
import datetime
|
||||
import traceback
|
||||
import re
|
||||
@ -18,7 +19,7 @@ import os.path
|
||||
|
||||
# 替换前端传来的非法字符
|
||||
def validateTitle(title):
|
||||
rstr = r"[\/\\\:\*\?\"\<\>\|]" # '/ \ : * ? " < > |'
|
||||
rstr = r"[\/\\\:\*\?\"\<\>\|\[\]]" # '/ \ : * ? " < > |'
|
||||
new_title = re.sub(rstr, "_", title) # 替换为下划线
|
||||
return new_title
|
||||
|
||||
@ -181,7 +182,7 @@ def create_project(request):
|
||||
role_list = ['0','1','2','3',0,1,2,3]
|
||||
if name != '':
|
||||
project = Project.objects.create(
|
||||
name=name,
|
||||
name=validateTitle(name),
|
||||
intro=desc[:100],
|
||||
create_user=request.user,
|
||||
role = int(role) if role in role_list else 0
|
||||
@ -214,9 +215,9 @@ def project_index(request,pro_id):
|
||||
|
||||
# 获取问价文集前台下载权限
|
||||
try:
|
||||
allow_epub_download = ProjectReport.objects.get(project=project).allow_epub
|
||||
allow_download = ProjectReport.objects.get(project=project)
|
||||
except ObjectDoesNotExist:
|
||||
allow_epub_download = 0
|
||||
allow_download = False
|
||||
|
||||
# 私密文集并且访问者非创建者非协作者
|
||||
if (project.role == 1) and (request.user != project.create_user) and (colla_user == 0):
|
||||
@ -266,7 +267,7 @@ def modify_project(request):
|
||||
if (request.user == project.create_user) or request.user.is_superuser:
|
||||
name = request.POST.get('name',None)
|
||||
content = request.POST.get('desc',None)
|
||||
project.name = name
|
||||
project.name = validateTitle(name)
|
||||
project.intro = content
|
||||
project.save()
|
||||
return JsonResponse({'status':True,'data':'修改成功'})
|
||||
@ -415,18 +416,30 @@ def modify_project_download(request,pro_id):
|
||||
if (pro.create_user != request.user) and (request.user.is_superuser is False):
|
||||
return render(request,'403.html')
|
||||
else:
|
||||
project_files = ProjectReportFile.objects.filter(project=pro)
|
||||
if request.method == 'GET':
|
||||
return render(request,'app_doc/manage_project_download.html',locals())
|
||||
elif request.method == 'POST':
|
||||
download_epub = request.POST.get('download_epub',None)
|
||||
download_pdf = request.POST.get('download_pdf', None)
|
||||
# print("epub状态:",download_epub)
|
||||
# EPUB下载权限
|
||||
if download_epub == 'on':
|
||||
epub_status = 1
|
||||
else:
|
||||
epub_status = 0
|
||||
# PDF下载权限
|
||||
if download_pdf == 'on':
|
||||
pdf_status = 1
|
||||
else:
|
||||
pdf_status = 0
|
||||
# 写入数据库
|
||||
ProjectReport.objects.update_or_create(
|
||||
project = pro,defaults={'allow_epub':epub_status}
|
||||
)
|
||||
ProjectReport.objects.update_or_create(
|
||||
project=pro, defaults={'allow_pdf': pdf_status}
|
||||
)
|
||||
return render(request,'app_doc/manage_project_download.html',locals())
|
||||
|
||||
|
||||
@ -526,7 +539,6 @@ def doc(request,pro_id,doc_id):
|
||||
# 私密文集且访问者非创建者、协作者 - 不能访问
|
||||
if (project.role == 1) and (request.user != project.create_user) and (colla_user == 0):
|
||||
return render(request, '404.html')
|
||||
|
||||
# 指定用户可见文集
|
||||
elif project.role == 2:
|
||||
user_list = project.role_value
|
||||
@ -842,6 +854,7 @@ def diff_doc(request,doc_id,his_id):
|
||||
print(traceback.print_exc())
|
||||
return JsonResponse({'status':False,'data':'获取异常'})
|
||||
|
||||
|
||||
# 管理文档历史版本
|
||||
@login_required()
|
||||
def manage_doc_history(request,doc_id):
|
||||
@ -1106,7 +1119,6 @@ def get_pro_doc_tree(request):
|
||||
def handle_404(request):
|
||||
return render(request,'404.html')
|
||||
|
||||
|
||||
# 导出文集MD文件
|
||||
@login_required()
|
||||
def report_md(request):
|
||||
@ -1133,43 +1145,252 @@ def report_md(request):
|
||||
else:
|
||||
return Http404
|
||||
|
||||
# 导出文集文件
|
||||
# 生成文集文件 - 个人中心 - 文集管理
|
||||
@login_required()
|
||||
def genera_project_file(request):
|
||||
if request.method == 'POST':
|
||||
report_type = request.POST.get('types',None) # 获取前端传入到导出文件类型参数
|
||||
# 导出EPUB文件
|
||||
|
||||
pro_id = request.POST.get('pro_id')
|
||||
try:
|
||||
project = Project.objects.get(id=int(pro_id))
|
||||
# 获取文集的协作用户信息
|
||||
if request.user.is_authenticated:
|
||||
colla_user = ProjectCollaborator.objects.filter(project=project, user=request.user)
|
||||
if colla_user.exists():
|
||||
colla_user_role = colla_user[0].role
|
||||
colla_user = colla_user.count()
|
||||
else:
|
||||
colla_user = colla_user.count()
|
||||
else:
|
||||
colla_user = 0
|
||||
|
||||
# 公开的文集 - 可以直接导出
|
||||
if project.role == 0:
|
||||
allow_export = True
|
||||
|
||||
# 私密文集 - 非创建者和协作者不可导出
|
||||
elif (project.role == 1):
|
||||
if (request.user != project.create_user) and (colla_user == 0):
|
||||
allow_export = False
|
||||
else:
|
||||
allow_export = True
|
||||
|
||||
# 指定用户可见文集 - 指定用户、文集创建者和协作者可导出
|
||||
elif project.role == 2:
|
||||
user_list = project.role_value
|
||||
if request.user.is_authenticated: # 认证用户判断是否在许可用户列表中
|
||||
if (request.user.username not in user_list) and \
|
||||
(request.user != project.create_user) and \
|
||||
(colla_user == 0): # 访问者不在指定用户之中,也不是协作者
|
||||
allow_export = False
|
||||
else:
|
||||
allow_export = True
|
||||
else: # 游客直接返回404
|
||||
allow_export = False
|
||||
|
||||
# 访问码可见文集 - 文集创建者、协作者和通过验证即可导出
|
||||
elif project.role == 3:
|
||||
# 浏览用户不为创建者和协作者 - 需要访问码
|
||||
if (request.user != project.create_user) and (colla_user == 0):
|
||||
viewcode = project.role_value
|
||||
viewcode_name = 'viewcode-{}'.format(project.id)
|
||||
r_viewcode = request.COOKIES[
|
||||
viewcode_name] if viewcode_name in request.COOKIES.keys() else 0 # 从cookie中获取访问码
|
||||
if viewcode != r_viewcode: # cookie中的访问码不等于文集访问码,不可导出
|
||||
allow_export = False
|
||||
else:
|
||||
allow_export = True
|
||||
else:
|
||||
allow_export = True
|
||||
else:
|
||||
allow_export = False
|
||||
|
||||
# 允许被导出
|
||||
if allow_export:
|
||||
# 导出EPUB
|
||||
if report_type in ['epub']:
|
||||
try:
|
||||
report_project = ReportEPUB(
|
||||
project_id=project.id
|
||||
).work()
|
||||
# print(report_project)
|
||||
report_file_path = report_project.split('media', maxsplit=1)[-1] # 导出文件的路径
|
||||
epub_file = '/media' + report_file_path + '.epub' # 文件相对路径
|
||||
# 查询文集是否存在导出文件
|
||||
report_cnt = ProjectReportFile.objects.filter(project=project,file_type='epub')
|
||||
# 存在文件删除
|
||||
if report_cnt.count() != 0:
|
||||
for r in report_cnt:
|
||||
is_exist = os.path.exists(settings.BASE_DIR + r.file_path)
|
||||
if is_exist:
|
||||
os.remove(settings.BASE_DIR + r.file_path)
|
||||
report_cnt.delete() # 删除数据库记录
|
||||
|
||||
# 创建数据库记录
|
||||
ProjectReportFile.objects.create(
|
||||
project=project,
|
||||
file_type='epub',
|
||||
file_name=epub_file,
|
||||
file_path=epub_file
|
||||
)
|
||||
|
||||
return JsonResponse({'status': True, 'data': epub_file})
|
||||
except Exception as e:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return JsonResponse({'status': False, 'data': '生成出错'})
|
||||
# 导出PDF
|
||||
elif report_type in ['pdf']:
|
||||
try:
|
||||
report_project = ReportPDF(
|
||||
project_id=project.id
|
||||
).work()
|
||||
if report_project is False:
|
||||
return JsonResponse({'status':False,'data':'生成出错'})
|
||||
report_file_path = report_project.split('media', maxsplit=1)[-1] # 导出文件的路径
|
||||
pdf_file = '/media' + report_file_path # 文件相对路径
|
||||
# 查询文集是否存在导出文件
|
||||
report_cnt = ProjectReportFile.objects.filter(project=project, file_type='pdf')
|
||||
# 存在文件删除
|
||||
if report_cnt.count() != 0:
|
||||
for r in report_cnt:
|
||||
is_exist = os.path.exists(settings.BASE_DIR + r.file_path)
|
||||
if is_exist:
|
||||
os.remove(settings.BASE_DIR + r.file_path)
|
||||
report_cnt.delete() # 删除数据库记录
|
||||
|
||||
# 创建数据库记录
|
||||
ProjectReportFile.objects.create(
|
||||
project=project,
|
||||
file_type='pdf',
|
||||
file_name=pdf_file,
|
||||
file_path=pdf_file
|
||||
)
|
||||
|
||||
return JsonResponse({'status': True, 'data': pdf_file})
|
||||
|
||||
except Exception as e:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return JsonResponse({'status': False, 'data': '生成出错'})
|
||||
else:
|
||||
return JsonResponse({'status': False, 'data': '不支持的类型'})
|
||||
# 不允许被导出
|
||||
else:
|
||||
return JsonResponse({'status':False,'data':'无权限导出'})
|
||||
|
||||
except ObjectDoesNotExist:
|
||||
return JsonResponse({'status':False,'data':'文集不存在'})
|
||||
|
||||
except Exception as e:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return JsonResponse({'status':False,'data':'系统异常'})
|
||||
else:
|
||||
return Http404
|
||||
|
||||
|
||||
# 获取文集前台导出文件
|
||||
@allow_report_file
|
||||
def report_file(request):
|
||||
if request.method == 'POST':
|
||||
report_type = request.POST.get('types',None)
|
||||
if report_type in ['epub']:
|
||||
pro_id = request.POST.get('pro_id')
|
||||
try:
|
||||
project = Project.objects.get(id=int(pro_id))
|
||||
# 公开的文集 - 可以直接导出
|
||||
if project.role == 0:
|
||||
report_project = ReportEPUB(
|
||||
project_id=project.id
|
||||
).work()
|
||||
# print(report_project)
|
||||
report_file_path = report_project.split('media',maxsplit=1)[-1]
|
||||
epub_file = '/media' + report_file_path + '.epub'
|
||||
return JsonResponse({'status':True,'data':epub_file})
|
||||
# 私密文集 - 拥有者可导出
|
||||
elif project.role == 1:
|
||||
pass
|
||||
# 指定用户可见文集 - 指定用户可导出
|
||||
elif project.role == 2:
|
||||
pass
|
||||
# 访问码可见文集 - 通过验证即可导出
|
||||
elif project.role == 3:
|
||||
pass
|
||||
report_type = request.POST.get('types',None) # 获取前端传入到导出文件类型参数
|
||||
|
||||
pro_id = request.POST.get('pro_id')
|
||||
try:
|
||||
project = Project.objects.get(id=int(pro_id))
|
||||
|
||||
# 获取文集的协作用户信息
|
||||
if request.user.is_authenticated:
|
||||
colla_user = ProjectCollaborator.objects.filter(project=project, user=request.user)
|
||||
if colla_user.exists():
|
||||
colla_user_role = colla_user[0].role
|
||||
colla_user = colla_user.count()
|
||||
else:
|
||||
return JsonResponse({'status':False,'data':'不存在的文集权限'})
|
||||
except ObjectDoesNotExist:
|
||||
return JsonResponse({'status':False,'data':'文集不存在'})
|
||||
except Exception as e:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return JsonResponse({'status':False,'data':'系统异常'})
|
||||
else:
|
||||
return JsonResponse({'status':False,'data':'不支持的类型'})
|
||||
colla_user = colla_user.count()
|
||||
else:
|
||||
colla_user = 0
|
||||
|
||||
# 公开的文集 - 可以直接导出
|
||||
if project.role == 0:
|
||||
allow_export = True
|
||||
|
||||
# 私密文集 - 非创建者和协作者不可导出
|
||||
elif (project.role == 1):
|
||||
if (request.user != project.create_user) and (colla_user == 0):
|
||||
allow_export = False
|
||||
else:
|
||||
allow_export = True
|
||||
|
||||
# 指定用户可见文集 - 指定用户、文集创建者和协作者可导出
|
||||
elif project.role == 2:
|
||||
user_list = project.role_value
|
||||
if request.user.is_authenticated: # 认证用户判断是否在许可用户列表中
|
||||
if (request.user.username not in user_list) and \
|
||||
(request.user != project.create_user) and \
|
||||
(colla_user == 0): # 访问者不在指定用户之中,也不是协作者
|
||||
allow_export = False
|
||||
else:
|
||||
allow_export = True
|
||||
else: # 游客直接返回404
|
||||
allow_export = False
|
||||
# 访问码可见文集 - 文集创建者、协作者和通过验证即可导出
|
||||
elif project.role == 3:
|
||||
# 浏览用户不为创建者和协作者 - 需要访问码
|
||||
if (request.user != project.create_user) and (colla_user == 0):
|
||||
viewcode = project.role_value
|
||||
viewcode_name = 'viewcode-{}'.format(project.id)
|
||||
r_viewcode = request.COOKIES[
|
||||
viewcode_name] if viewcode_name in request.COOKIES.keys() else 0 # 从cookie中获取访问码
|
||||
if viewcode != r_viewcode: # cookie中的访问码不等于文集访问码,不可导出
|
||||
allow_export = False
|
||||
else:
|
||||
allow_export = True
|
||||
else:
|
||||
allow_export = True
|
||||
else:
|
||||
allow_export = False
|
||||
# return JsonResponse({'status':False,'data':'不存在的文集权限'})
|
||||
if allow_export:
|
||||
# 导出EPUB文件
|
||||
if report_type in ['epub']:
|
||||
try:
|
||||
try:
|
||||
report_project = ProjectReportFile.objects.get(project=project,file_type='epub')
|
||||
except ObjectDoesNotExist:
|
||||
return JsonResponse({'status':False,'data':'无可用文件,请联系文集创建者'})
|
||||
# print(report_project)
|
||||
return JsonResponse({'status': True, 'data': report_project.file_path})
|
||||
except Exception as e:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return JsonResponse({'status': False, 'data': '导出出错'})
|
||||
# 导出PDF
|
||||
elif report_type in ['pdf']:
|
||||
try:
|
||||
try:
|
||||
report_project = ProjectReportFile.objects.get(project=project,file_type='pdf')
|
||||
except ObjectDoesNotExist:
|
||||
return JsonResponse({'status':False,'data':'无可用文件,请联系文集创建者'})
|
||||
# print(report_project)
|
||||
return JsonResponse({'status': True, 'data': report_project.file_path})
|
||||
except Exception as e:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return JsonResponse({'status': False, 'data': '导出出错'})
|
||||
else:
|
||||
return JsonResponse({'status': False, 'data': '不支持的类型'})
|
||||
else:
|
||||
return JsonResponse({'status':False,'data':'无权限导出'})
|
||||
except ObjectDoesNotExist:
|
||||
return JsonResponse({'status':False,'data':'文集不存在'})
|
||||
except Exception as e:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return JsonResponse({'status':False,'data':'系统异常'})
|
||||
|
||||
else:
|
||||
return Http404
|
||||
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 170 KiB After Width: | Height: | Size: 181 KiB |
@ -1,5 +1,5 @@
|
||||
beautifulsoup4==4.8.2
|
||||
django==2.2.12
|
||||
beautifulsoup4==4.8.2
|
||||
lxml
|
||||
pillow==6.2.2
|
||||
pytz==2019.1
|
||||
sqlparse==0.3.0
|
||||
pyppeteer==0.0.25
|
@ -3672,7 +3672,15 @@
|
||||
}
|
||||
// var map_id = lang.split('>')[1];
|
||||
// console.log(map_id)
|
||||
return "<svg class='mindmap' style='width:100%;min-height=150px;' id='mindmap-"+ map_id +"'>"+code+"</svg>";
|
||||
var custom_height;
|
||||
var h = lang.split('>')[1];
|
||||
if(h != undefined){
|
||||
custom_height = h;
|
||||
}else{
|
||||
custom_height = 150;
|
||||
}
|
||||
|
||||
return "<svg class='mindmap' style='width:100%;min-height:150px;height:"+ custom_height +"px;' id='mindmap-"+ map_id +"'>"+code+"</svg>";
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -3952,7 +3960,7 @@
|
||||
taskList : false, // Github Flavored Markdown task lists
|
||||
emoji : false,
|
||||
flowChart : false,
|
||||
mindMap : true, //百度脑图
|
||||
mindMap : true, //脑图
|
||||
sequenceDiagram : false,
|
||||
previewCodeHighlight : true
|
||||
};
|
||||
|
BIN
static/logo.jpg
Normal file
BIN
static/logo.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
Binary file not shown.
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 39 KiB |
@ -3,7 +3,7 @@
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>拒绝访问 - MrDoc</title>
|
||||
<title>拒绝访问 - 觅道文档MrDoc</title>
|
||||
<link href="{% static 'layui/css/layui.css' %}" rel="stylesheet">
|
||||
<link href="{% static 'mrdoc.css' %}" rel="stylesheet">
|
||||
</head>
|
||||
|
@ -3,7 +3,7 @@
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>404 页面未找到 - MrDoc</title>
|
||||
<title>404 页面未找到 - 觅道文档MrDoc</title>
|
||||
<link href="{% static 'layui/css/layui.css' %}" rel="stylesheet">
|
||||
<link href="{% static 'mrdoc.css' %}" rel="stylesheet">
|
||||
</head>
|
||||
|
@ -3,7 +3,7 @@
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{% block title %}{% endblock %} - 后台管理 - MrDoc</title>
|
||||
<title>{% block title %}{% endblock %} - 后台管理 - 觅道文档MrDoc</title>
|
||||
<link rel="icon" href="{% static 'favicon_16.png' %}"/>
|
||||
<link href="{% static 'layui/css/layui.css' %}?version={{mrdoc_version}}" rel="stylesheet">
|
||||
<style>
|
||||
|
@ -38,11 +38,11 @@
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">文集导出</label>
|
||||
<label class="layui-form-label">文集下载</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="checkbox" name="enable_project_report" lay-skin="switch" lay-text="开启|关闭" {% if enable_project_report %}checked{% endif %}>
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">开启此选项,文集允许导出为EPUB和DOCX等格式文件,文集拥有者可进行进一步控制文集是否开放导出</div>
|
||||
<div class="layui-form-mid layui-word-aux">开启此选项,文集允许导出为EPUB和DOCX等格式文件以供下载,文集拥有者可进行进一步控制特定文集是否开放导出</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
@ -61,11 +61,17 @@
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">广告代码</label>
|
||||
<label class="layui-form-label">广告位1</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="ad_code" placeholder="如果需要在文档正文上方添加广告,请将广告相关代码输入至此,可以包含<script>标签" class="layui-textarea">{{ad_code}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-form-text">
|
||||
<label class="layui-form-label">广告位2</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="ad_code_2" placeholder="此广告位位于文档下方、分享按钮上方,可以包含<script>标签" class="layui-textarea">{{ad_code_2}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
|
@ -7,6 +7,7 @@
|
||||
<meta http-equiv="Cache-Control" content="no-transform" />
|
||||
<meta http-equiv="Cache-Control" content="no-siteapp" />
|
||||
<meta http-equiv="Cache-Control" content="max-age=7200" />
|
||||
<link rel="icon" href="{% static 'favicon_16.png' %}"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<title>请输入访问码 - MrDoc</title>
|
||||
<meta charset="utf-8" />
|
||||
|
@ -10,7 +10,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<meta name="keywords" content="{% block keyword %}{% endblock %}mrdoc"/>
|
||||
<meta name="description" content="{% block description %}{% endblock %}" />
|
||||
<title>{% block title %}{% endblock %} - MrDoc</title>
|
||||
<title>{% block title %}{% endblock %} - 觅道文档MrDoc</title>
|
||||
<link href="{% static 'layui/css/layui.css' %}?version={{mrdoc_version}}" rel="stylesheet">
|
||||
<link rel="stylesheet" href="{% static 'editor.md/css/editormd.css' %}?version={{mrdoc_version}}" />
|
||||
<link rel="stylesheet" href="{% static 'katex/katex.min.css' %}?version={{mrdoc_version}}" />
|
||||
@ -215,7 +215,7 @@
|
||||
return [
|
||||
"undo", "redo", "|",
|
||||
"bold", "del", "italic", "quote","kaiSpan", "|",
|
||||
"h1", "h2", "h3", "h4", "|",
|
||||
"h1", "h2", "h3", "|",
|
||||
"list-ul", "list-ol", "hr", "link", "reference-link", "|",
|
||||
"mindmap","imgUpload", "attachment" ,"code", "code-block", "htmltable", "|","datetime", "emoji", "html-entities", "pagebreak", "|",
|
||||
"watch", "preview", "|",
|
||||
@ -383,6 +383,7 @@
|
||||
flowChart : true, //开启流程图
|
||||
sequenceDiagram : true, //开启序列图
|
||||
imageUpload : true, //开启图片上传
|
||||
codeFold :true, //代码折叠
|
||||
htmlDecode : "link,style,script,iframe|on*", //解析部分HTML标签
|
||||
imageFormats : ["jpg", "jpeg", "gif", "png", "bmp", "webp"],
|
||||
imageUploadURL : "{% url 'upload_doc_img' %}",
|
||||
|
@ -10,7 +10,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<meta name="keywords" content="{% block keyword %}{% endblock %}mrdoc"/>
|
||||
<meta name="description" content="{% block description %}{% endblock %}" />
|
||||
<title>{% block title %}{% endblock %} - MrDoc</title>
|
||||
<title>{% block title %}{% endblock %} - 觅道文档MrDoc</title>
|
||||
<link href="{% static 'layui/css/layui.css' %}?version={{mrdoc_version}}" rel="stylesheet">
|
||||
<link rel="stylesheet" href="{% static 'editor.md/css/editormd.css' %}?version={{mrdoc_version}}" />
|
||||
<link rel="stylesheet" href="{% static 'katex/katex.min.css' %}?version={{mrdoc_version}}" />
|
||||
@ -204,6 +204,17 @@
|
||||
<!-- 正文结束 -->
|
||||
</div>
|
||||
|
||||
<!-- 广告代码开始 -->
|
||||
{% if debug %}
|
||||
{% else %}
|
||||
{% if ad_code %}
|
||||
<div class="ad-code">
|
||||
{{ ad_code_2 | safe }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<!-- 广告代码结束 -->
|
||||
|
||||
{% block doc_previous_next %}{% endblock %}
|
||||
<!-- 社交分享 -->
|
||||
<div class="share-div" style="margin-top: 10px;padding:10px;text-align: center;background-color: #fafafa">
|
||||
|
@ -1,9 +1,11 @@
|
||||
{% load staticfiles %}
|
||||
<div class="layui-header layui-fluid">
|
||||
<div class="" style="display:flex;flex-direction:row;justify-content:space-between;">
|
||||
<!-- LOGO -->
|
||||
<div class="">
|
||||
<a class="logo" href="{% url 'pro_list' %}">
|
||||
<h1><strong>MrDoc</strong></h1>
|
||||
<img src="{% static 'logo.jpg' %}" style="height: 32px;width: auto;">
|
||||
<!-- <h1><strong>MrDoc</strong></h1> -->
|
||||
</a>
|
||||
</div>
|
||||
<!-- 搜索框 -->
|
||||
|
@ -4,7 +4,7 @@
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{% block title %}{% endblock %} - 个人中心 - MrDoc</title>
|
||||
<title>{% block title %}{% endblock %} - 个人中心 - 觅道文档MrDoc</title>
|
||||
<link href="{% static 'layui/css/layui.css' %}?version={{mrdoc_version}}" rel="stylesheet">
|
||||
<link href="{% static 'mrdoc-admin.css' %}?version={{mrdoc_version}}" rel="stylesheet">
|
||||
<link href="{% static 'viewerjs/viewer.css' %}?version={{mrdoc_version}}" rel="stylesheet">
|
||||
@ -36,10 +36,19 @@
|
||||
.layui-input{
|
||||
height: 30px !important;
|
||||
}
|
||||
/* layui引用文本样式 */
|
||||
.layui-elem-quote{
|
||||
border-left: 5px solid #1E9FFF !important;
|
||||
}
|
||||
/* layui单选框样式 */
|
||||
.layui-form-radio>i:hover, .layui-form-radioed>i{
|
||||
color: #1E9FFF;
|
||||
}
|
||||
/* 开关样式 */
|
||||
.layui-form-onswitch{
|
||||
border-color: #1E9FFF;
|
||||
background-color: #1E9FFF;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="layui-layout-body">
|
||||
|
@ -53,10 +53,11 @@
|
||||
<td>{{ pro.id | get_doc_count }}</td>
|
||||
<td>{{ pro.create_time }}</td>
|
||||
<td>
|
||||
{% if pro.id|get_report_status == 1 %}
|
||||
<span>允许</span> <a href="{% url 'modify_pro_download' pro.id %}" title="修改前台下载"><i class="layui-icon layui-icon-edit"></i></a>
|
||||
{% if pro.id|report_status_epub == 1 or pro.id|report_status_pdf == 1 %}
|
||||
|
||||
<span style="color: #01AAED;">允许</span> <a href="{% url 'modify_pro_download' pro.id %}" title="修改前台下载"><i class="layui-icon layui-icon-edit"></i></a>
|
||||
{% else %}
|
||||
<span>禁止</span> <a href="{% url 'modify_pro_download' pro.id %}" title="修改前台下载"><i class="layui-icon layui-icon-edit"></i></a>
|
||||
<span style="color: hotpink;">禁止</span> <a href="{% url 'modify_pro_download' pro.id %}" title="修改前台下载"><i class="layui-icon layui-icon-edit"></i></a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
|
@ -1,10 +1,10 @@
|
||||
{% extends 'app_doc/manage_base.html' %}
|
||||
{% load staticfiles %}
|
||||
{% block title %}文集下载状态管理{% endblock %}
|
||||
{% block title %}文集下载状态管理 - {{pro.name}}{% endblock %}
|
||||
{% block content %}
|
||||
{% if enable_project_report %}
|
||||
{% else %}
|
||||
<blockquote class="layui-elem-quote">当前站点未启用前台文集下载功能,修改操作将在功能启用后生效!</blockquote>
|
||||
<blockquote class="layui-elem-quote">站点管理员未启用文集导出下载文件功能,相关操作将在此功能启用后生效!</blockquote>
|
||||
{% endif %}
|
||||
<div class="layui-row" style="margin-bottom: 10px;padding-left:15px;">
|
||||
<span class="layui-breadcrumb" lay-separator=">">
|
||||
@ -33,22 +33,76 @@
|
||||
<label class="layui-form-label">EPUB下载</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="checkbox" name="download_epub"
|
||||
{% if pro.id|get_report_status == 1 %} checked {%endif%}
|
||||
{% if pro.id|report_status_epub == 1 %} checked {%endif%}
|
||||
lay-skin="switch" lay-text="允许|禁止">
|
||||
<!-- 判断后台是否开启导出,如果开启,则显示 -->
|
||||
{% if enable_project_report %}
|
||||
<a href="javascript:void(0);" onclick="reportFile('{{pro.id}}','epub')" style=""><i class="layui-icon layui-icon-refresh"></i><u>生成或更新EPUB文件</u></a>
|
||||
{% if project_files %}
|
||||
{% for file in project_files %}
|
||||
{% if file.file_type == 'epub' %}
|
||||
| <a href="{{file.file_path}}" target="_blank"><i class="layui-icon layui-icon-download-circle"></i><u>下载文集EPUB文件</u></a>
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
| <span style="color: hotpink;">未生成文集导出文件</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">PDF下载</label>
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="formDemo">立即修改</button>
|
||||
<input type="checkbox" name="download_pdf"
|
||||
{% if pro.id|report_status_pdf == 1 %} checked {%endif%}
|
||||
lay-skin="switch" lay-text="允许|禁止">
|
||||
<!-- 判断后台是否开启导出,如果开启,则显示 -->
|
||||
{% if enable_project_report %}
|
||||
<a href="javascript:void(0);" onclick="reportFile('{{pro.id}}','pdf')" style=""><i class="layui-icon layui-icon-refresh"></i><u>生成或更新PDF文件</u></a>
|
||||
{% if project_files %}
|
||||
{% for file in project_files %}
|
||||
{% if file.file_type == 'pdf' %}
|
||||
| <a href="{{file.file_path}}" target="_blank"><i class="layui-icon layui-icon-download-circle"></i><u>下载文集PDF文件</u></a>
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
| <span style="color: hotpink;">未生成文集导出文件</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn layui-btn-normal layui-btn-sm" lay-submit lay-filter="formDemo">立即修改</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<blockquote class="layui-elem-quote">注意:开启某类型文件下载后,请先点击“生成或更新XXX文件”,文集文档中如果包含公式、流程图、时序图、脑图等内容,将会延长生成时间,请耐心等待</blockquote>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block custom_script %}
|
||||
<script>
|
||||
var form = layui.form;
|
||||
|
||||
reportFile = function(pro_id,types){
|
||||
layer.load(1)
|
||||
var data = {'pro_id':pro_id,'types':types};
|
||||
$.post("{% url 'genera_project_file' %}",data,function(r){
|
||||
layer.closeAll('loading');
|
||||
if(r.status){
|
||||
layer.msg("生成完成")
|
||||
window.location.reload();
|
||||
}else{
|
||||
layer.msg("生成出错,请稍后重试")
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
@ -57,7 +57,7 @@
|
||||
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit lay-filter="formDemo">立即修改</button>
|
||||
<button class="layui-btn layui-btn-normal layui-btn-sm" lay-submit lay-filter="formDemo">立即修改</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -7,10 +7,10 @@
|
||||
<meta http-equiv="Cache-Control" content="no-transform" />
|
||||
<meta http-equiv="Cache-Control" content="no-siteapp" />
|
||||
<meta http-equiv="Cache-Control" content="max-age=7200" />
|
||||
<meta name="keywords" content="mrdoc,markdown,文档写作,在线教程,Python文档系统,django应用"/>
|
||||
<meta name="description" content="MrDoc是由州的先生(zmister.com)开发,基于Python的Django框架的在线文档写作系统,适合作为个人和小型团队的文档、笔记和知识管理工具。" />
|
||||
<meta name="keywords" content="觅道文档,mrdoc,markdown,文档写作,在线教程,Python文档系统,django应用"/>
|
||||
<meta name="description" content="觅道文档(MrDoc)是由州的先生(zmister.com)开发,基于Python的Django框架的在线文档系统,适合作为个人和小型团队的文档、笔记和知识管理工具。" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<title>MrDoc - 一个简单的文档写作系统</title>
|
||||
<title>觅道文档(MrDoc) - 一个简单的在线文档系统</title>
|
||||
<link href="{% static 'layui/css/layui.css' %}" rel="stylesheet">
|
||||
<link href="{% static 'mrdoc.css' %}?version={{mrdoc_version}}" rel="stylesheet">
|
||||
<link rel="icon" href="{% static 'favicon_16.png' %}"/>
|
||||
|
@ -74,10 +74,15 @@
|
||||
<h3>文集下载:</h3>
|
||||
<p>
|
||||
<span class="layui-breadcrumb" lay-separator="|">
|
||||
{% if allow_epub_download == 1 %}
|
||||
<a href="javascript:void(0);" onclick="reportFile('{{project.id}}','epub')"><i class="fa fa-download"></i> <u>EPUB电子书</u></a>
|
||||
{% if allow_download %}
|
||||
{% if allow_download.allow_epub == 1 %}
|
||||
<a href="javascript:void(0);" onclick="reportFile('{{project.id}}','epub')"><i class="fa fa-download"></i> <u>EPUB电子书</u></a>
|
||||
{% endif %}
|
||||
{% if allow_download.allow_pdf == 1 %}
|
||||
<a href="javascript:void(0);" onclick="reportFile('{{project.id}}','pdf')"><i class="fa fa-download"></i> <u>PDF电子书</u></a>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<a>文集作者未开放此文集的任何格式下载!</a>
|
||||
<a>文集作者未开放此文集的任何格式下载!</a>
|
||||
{% endif %}
|
||||
<!--<a href=""><i class="fa fa-download"></i> <u>DOCX文档</u></a>-->
|
||||
</span>
|
||||
@ -85,13 +90,15 @@
|
||||
</div>
|
||||
<script>
|
||||
reportFile = function(pro_id,types){
|
||||
layer.load(1)
|
||||
var data = {'pro_id':pro_id,'types':types};
|
||||
$.post("{% url 'report_file' %}",data,function(r){
|
||||
layer.closeAll('loading');
|
||||
if(r.status){
|
||||
//文件下载提示
|
||||
downloadFile(r.data)
|
||||
}else{
|
||||
layer.msg("导出文件出错")
|
||||
layer.msg(r.data)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -102,7 +109,7 @@
|
||||
title:"下载导出文档",
|
||||
area:"300px",
|
||||
id:"downloadMd",
|
||||
content:'<p style="text-align:center;color:red;">请尽快下载,避免失效!</p><br><a class="layui-btn layui-btn-fluid download-md-link" href="'+ download_link + '" download="" >点击下载文件</a>',
|
||||
content:'<p style="text-align:center;color:red;">请尽快下载,避免失效!</p><br><a class="layui-btn layui-btn-normal layui-btn-fluid download-md-link" href="'+ download_link + '" download="" >点击下载文件</a>',
|
||||
//btn:['确定','取消'], //添加按钮
|
||||
//btnAlign:'c', //按钮居中
|
||||
success: function (layero, index) {
|
||||
|
Loading…
Reference in New Issue
Block a user