v0.3.0修复Bug,添加epub下载功能

This commit is contained in:
yangjian 2020-03-07 09:30:11 +08:00
parent 00e7c097c3
commit f463f9efed
61 changed files with 1125 additions and 115 deletions

View File

@ -1,5 +1,14 @@
## 版本更新记录
### v0.3.0 2020-03-07
- 优化MD文件导出逻辑修复文档中本地资源不存在引发异常的问题
- 个人中心文集管理页面文集MD文件导出的交互
- 去除首次请求的Cookie检查避免正常文档产生404的问题
- 优化首页文集列表样式,修复文集名称过长的显示问题,添加文集的最新文档;
- 添加文集的EPUB导出功能支持全站启停文集的前台导出和作者对单一文集的前台导出控制
- 升级Layui版本至2.5.6
### v0.2.12
- 优化Markdown编辑器的扩展工具栏按钮未选择文本时点击“楷”按钮光标移动到span标签中间

View File

@ -25,7 +25,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.2.12'
VERSIONS = '0.3.0'
ALLOWED_HOSTS = ['*']

View File

@ -18,7 +18,9 @@ from django.urls import path,include,re_path
from django.views.static import serve
from django.conf import settings
from django.contrib.sitemaps import views
from app_doc.sitemaps import all_sitemaps as sitemaps
from app_doc.sitemaps import all_sitemaps
sitemaps = all_sitemaps()
urlpatterns = [
path('admin/', admin.site.urls),

View File

@ -8,7 +8,7 @@
州的先生zmister.com自用并完全开源、基于Python编写的文档写作系统。
当前版本为:**v0.2.12**,版本发布时间为**2020-02-27**,更新记录详见:[CHANGES.md](./CHANGES.md)
当前版本为:**v0.3.0**,版本发布时间为**2020-03-07**,更新记录详见:[CHANGES.md](./CHANGES.md)
MrDoc拥有以下特点
@ -25,7 +25,7 @@ MrDoc拥有以下特点
- 提供文档模板功能,支持文档模板的创建、修改;
- 仿GitBook文档阅读页面支持文档阅读页面的字体缩放字体类型修改页面社交分享良好的移动端阅读体验
- 支持三级目录层级显示;
- 支持文集导出为markdown文本格式.md文件
- 支持文集后台导出为markdown文本格式.md文件、前台导出为EPUB电子书
- 基于文集进行权限控制提供公开、私密、指定用户可见、访问码可见4种权限模式
- 二次开发方便

View File

@ -34,9 +34,25 @@ def open_register(function):
def check_headers(function):
def _inner(request,*args,**kwargs):
metas = request.META
if 'HTTP_COOKIE' not in metas:
raise Http404
elif 'HTTP_USER_AGENT' not in metas:
# if 'HTTP_COOKIE' not in metas:
# raise Http404
if 'HTTP_USER_AGENT' not in metas:
raise Http404
return function(request, *args, **kwargs)
return _inner
# 开放前台文集导出
def allow_report_file(function):
def _inner(request,*args,**kwargs):
try:
status = SysSetting.objects.get(name='enable_project_report')
except:
# 如果不存在enable_project_report这个属性那么表示是禁止导出的
raise Http404
# 启用导出
if status.value == 'on':
return function(request, *args, **kwargs)
else:
raise Http404
return _inner

View File

@ -517,6 +517,7 @@ def admin_setting(request):
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) # 注册邀请码
enable_project_report = request.POST.get('enable_project_report',None) # 文集导出
# 更新开放注册状态
SysSetting.objects.update_or_create(
name='close_register',
@ -547,6 +548,11 @@ def admin_setting(request):
name = 'enable_register_code',
defaults= {'value': enable_register_code, 'types':'basic'}
)
# 更新文集导出状态
SysSetting.objects.update_or_create(
name = 'enable_project_report',
defaults={'value':enable_project_report,'types':'basic'}
)
return render(request,'app_admin/admin_setting.html',locals())
elif types == 'email':

View File

@ -0,0 +1,26 @@
# Generated by Django 2.1 on 2020-03-06 22:25
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('app_doc', '0008_auto_20191221_1055'),
]
operations = [
migrations.CreateModel(
name='ProjectReport',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('allow_epub', models.IntegerField(default=0, verbose_name='前台导出EPUB')),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app_doc.Project', unique=True)),
],
options={
'verbose_name': '文集导出',
'verbose_name_plural': '文集导出',
},
),
]

View File

@ -70,3 +70,17 @@ class DocTemp(models.Model):
class Meta:
verbose_name = '文档模板'
verbose_name_plural = verbose_name
# 文集导出模型
class ProjectReport(models.Model):
project = models.ForeignKey(Project,unique=True,on_delete=models.CASCADE)
# 允许导出默认为0-允许1-不允许
allow_epub = models.IntegerField(default=0,verbose_name="前台导出EPUB")
def __str__(self):
self.project.name
class Meta:
verbose_name = '文集导出'
verbose_name_plural = verbose_name

View File

@ -5,12 +5,23 @@
# 博客地址zmister.com
# MrDoc文集文档导出相关功能代码
from django.conf import settings
from app_doc.models import *
import subprocess
import datetime
import datetime,time
import re
import os
import os,sys
import shutil
from bs4 import BeautifulSoup
from django.core.wsgi import get_wsgi_application
sys.path.extend([r'F:\pythonproject\MrDoc',])
os.environ.setdefault("DJANGO_SETTINGS_MODULE","MrDoc.settings")
application = get_wsgi_application()
import django
django.setup()
from app_doc.models import *
import traceback
import time
# 导出MD文件压缩包
class ReportMD():
@ -80,7 +91,12 @@ class ReportMD():
files.write(md_content_3)
# 压缩文件
shutil.make_archive(self.project_path,'zip',self.project_path)
md_file = shutil.make_archive(
base_name=self.project_path,
format='zip',
root_dir=self.project_path
)
print(md_file)
# 删除文件夹
shutil.rmtree(self.project_path)
@ -106,7 +122,10 @@ class ReportMD():
# 替换MD内容的静态文件链接
md_content = md_content.replace(media_filename, "." + media_filename)
# 复制静态文件到指定文件夹
shutil.copy(settings.BASE_DIR + media_filename, self.media_path+sub_folder)
try:
shutil.copy(settings.BASE_DIR + media_filename, self.media_path+sub_folder)
except FileNotFoundError:
pass
# 不存在本地静态文件直接返回MD内容
# else:
# print("没有本地静态文件")
@ -115,8 +134,571 @@ class ReportMD():
else:
return md_content
# 导出EPUB
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)
# 创建相关目录
if os.path.exists(self.base_path + '/OEBPS') is False:
os.makedirs(self.base_path + '/OEBPS')
if os.path.exists(self.base_path + '/OEBPS/Images') is False:
os.makedirs(self.base_path + '/OEBPS/Images')
if os.path.exists(self.base_path + '/OEBPS/Text') is False:
os.makedirs(self.base_path + '/OEBPS/Text')
if os.path.exists(self.base_path + '/OEBPS/Styles') is False:
os.makedirs(self.base_path + '/OEBPS/Styles')
if os.path.exists(self.base_path + '/META-INF') is False:
os.makedirs(self.base_path + '/META-INF')
# 复制样式文件到相关目录
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/report_epub/epub_cover1.jpg',self.base_path + '/OEBPS/Images/epub_cover1.jpg')
# 将文档内容写入HTML文件
def write_html(self, d, html_str):
# 使用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)
# 添加css样式标签
style_link = html_soup.new_tag(name='link',href="../Styles/style.css",rel="stylesheet",type="text/css")
katex_link = html_soup.new_tag(name='link',href='../Styles/katex.css',rel="stylesheet",type="text/css")
editormd_link = html_soup.new_tag(name='link',href='../Styles/editormd.css',rel="stylesheet",type="text/css")
html_soup.body.insert_before(style_link)
html_soup.body.insert_before(katex_link)
# html_soup.body.insert_before(editormd_link)
# 添加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"
# 替换HTML文本中静态文件的相对链接为绝对链接
for src in src_tag:
if src['src'].startswith("/"):
src_path = src['src'] # 媒体文件原始路径
src_filename = src['src'].split("/")[-1] # 媒体文件名
src['src'] = '../Images/' + src_filename # 媒体文件在EPUB中的路径
# 复制文件到epub的Images文件夹
try:
shutil.copyfile(
src= settings.BASE_DIR + src_path,
dst= self.base_path + '/OEBPS/Images/' + src_filename
)
except FileNotFoundError as e:
pass
# 替换code标签的内容
# for code in code_tag:
# code_str = code.get_text()
# code.clear()
# code['class'] = ''
# code.string = code_str
# 创建写入临时HTML文件
temp_file_path = self.base_path + '/OEBPS/Text/{0}.xhtml'.format(d.id)
with open(temp_file_path, 'a+', encoding='utf-8') as htmlfile:
htmlfile.write('<?xml version="1.0" encoding="UTF-8"?>' + str(html_soup))
# 生成文档HTML
def generate_html(self):
# 查询文档
data = Doc.objects.filter(top_doc=self.project.id, parent_doc=0, status=1).order_by("sort")
self.toc_list = [
{
'id': 0,
'link': 'Text/toc_summary.xhtml',
'pid': 0,
'title': '目录'
}
]
nav_str = '''<navMap>'''
toc_summary_str = '''<ul>'''
nav_num = 1
# content.opf相关
manifest = '''<item id="book_cover" href="Text/book_cover.xhtml" media-type="application/xhtml+xml"/>
<item id="book_title" href="Text/book_title.xhtml" media-type="application/xhtml+xml"/>
<item id="book_desc" href="Text/book_desc.xhtml" media-type="application/xhtml+xml"/>
<item id="toc_summary" href="Text/toc_summary.xhtml" media-type="application/xhtml+xml"/>
'''
spine = '<itemref idref="book_cover" linear="no"/><itemref idref="book_title"/><itemref idref="book_desc"/><itemref idref="toc_summary"/>'
for d in data:
# 拼接HTML字符串
html_str = "<h1 style='page-break-before: always;'>{}</h1>".format(d.name)
html_str += d.content
self.write_html(d=d,html_str=html_str) # 生成HTML
# 生成HTML的目录位置
toc = {
'id':d.id,
'link':'{}.xhtml'.format(d.id),
'pid':d.parent_doc,
'title':d.name
}
self.toc_list.append(toc)
# nav
toc_nav = '''<navPoint id="np_{nav_num}" playOrder="{nav_num}">
<navLabel><text>{title}</text></navLabel>
<content src="Text/{file}"/>
'''.format(nav_num=nav_num,title=d.name,file=toc['link'])
nav_str += toc_nav
# toc_summary
toc_summary_str += '''<li><a href="./{}">{}</a>'''.format(toc['link'],toc['title'])
# content.opf
manifest += '<item id="{}" href="Text/{}.xhtml" media-type="application/xhtml+xml"/>'.format(d.id, d.id)
spine += '<itemref idref="{}"/>'.format(d.id)
nav_num += 1
# 获取第二级文档
data_2 = Doc.objects.filter(parent_doc=d.id,status=1).order_by("sort")
if data_2.count() > 0:
toc_summary_str += '<ul>'
for d2 in data_2:
html_str = "<h1>{}</h1>".format(d2.name)
html_str += d2.content
self.write_html(d=d2,html_str=html_str)
# 生成HTML的目录位置
toc = {
'id': d2.id,
'link': '{}.xhtml'.format(d2.id),
'pid': d2.parent_doc,
'title': d2.name
}
self.toc_list.append(toc)
toc_nav = '''<navPoint id="np_{nav_num}" playOrder="{nav_num}">
<navLabel><text>{title}</text></navLabel>
<content src="Text/{file}"/>
'''.format(nav_num=nav_num, title=d2.name, file=toc['link'])
nav_str += toc_nav
# toc_summary
toc_summary_str += '''<li><a href="./{}">{}</a>'''.format(toc['link'], toc['title'])
# content.opf
manifest += '<item id="{}" href="Text/{}.xhtml" media-type="application/xhtml+xml"/>'.format(d2.id, d2.id)
spine += '<itemref idref="{}"/>'.format(d2.id)
nav_num += 1
# 获取第三级文档
data_3 = Doc.objects.filter(parent_doc=d2.id,status=1).order_by("sort")
if data_3.count() > 0:
toc_summary_str += '<ul>'
for d3 in data_3:
html_str = "<h1>{}</h1>".format(d3.name)
html_str += d3.content
self.write_html(d=d3,html_str=html_str)
# 生成HTML的目录位置
toc = {
'id': d3.id,
'link': '{}.xhtml'.format(d3.id),
'pid': d3.parent_doc,
'title': d3.name
}
self.toc_list.append(toc)
toc_nav = '''<navPoint id="np_{nav_num}" playOrder="{nav_num}">
<navLabel><text>{title}</text></navLabel>
<content src="Text/{file}"/>
</navPoint>
'''.format(nav_num=nav_num, title=d3.name, file=toc['link'])
nav_str += toc_nav
# toc_summary
toc_summary_str += '''<li><a href="./{}">{}</a></li>'''.format(toc['link'], toc['title'])
# content.opf
manifest += '<item id="{}" href="Text/{}.xhtml" media-type="application/xhtml+xml"/>'.format(d3.id,
d3.id)
spine += '<itemref idref="{}"/>'.format(d3.id)
nav_num += 1
nav_str += "</navPoint>"
if data_3.count() > 0:
toc_summary_str += "</ul></li>"
else:
toc_summary_str += "</li>"
nav_str += "</navPoint>"
if data_2.count() > 0:
toc_summary_str += "</ul></li>"
else:
toc_summary_str += "</li>"
nav_str += '</navMap>'
toc_summary_str += '</ul>'
# print(nav_str)
# print(toc_summary_str)
self.nav_str = nav_str
self.toc_summary_str = toc_summary_str
# self.config_json['toc'] = self.toc_list
self.manifest = manifest
self.spine = spine
# 生成书籍标题的描述HTML文件
def generate_title_html(self):
title_str = '''<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>书籍标题</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
<link href="../Styles/style.css" rel="stylesheet" type="text/css"/>
</head>
<body class="bookname">
<div class="main">
<h1 class="title"">{title}</h1>
<p class="author"><b>{author} </b></p><br>
<p class="author">{create_time}</p>
<p class="book-src">本书籍由<a href='http://mrdoc.zmister.com'>MrDoc(mrdoc.zmister.com)</a>生成</p>
</div>
</body>
</html>
'''.format(
title=self.project.name,
author=self.project.create_user,
create_time = time.strftime('%Y{y}%m{m}%d{d}').format(y='',m='',d='')
)
with open(self.base_path+'/OEBPS/Text/book_title.xhtml','a+',encoding='utf-8') as file:
file.write(title_str)
desc_str = '''<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>简介</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
<link href="../Styles/style.css" rel="stylesheet" type="text/css"/>
</head>
<body class="bookdesc">
<div class="main">
<p class="title">书籍简介</p>
<p class="subtitle">{desc}</p>
</div>
</body>
</html>
'''.format(desc=self.project.intro)
with open(self.base_path+'/OEBPS/Text/book_desc.xhtml','a+',encoding='utf-8') as file:
file.write(desc_str)
# 生成元信息container.xml文件
def generate_metainfo(self):
xml = '''<?xml version="1.0" encoding="UTF-8"?>
<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container" >
<rootfiles>
<rootfile full-path="OEBPS/content.opf" media-type="application/oebps-package+xml" />
</rootfiles>
</container>
'''
folder = self.base_path + '/META-INF'
with open(folder+'/container.xml','a+',encoding='utf-8') as metafile:
metafile.write(xml)
# 生成元类型mimetype文件
def generate_metatype(self):
with open(self.base_path+'/mimetype','a+',encoding='utf-8') as metatype:
metatype.write('application/epub+zip')
# 生成封面
def generate_cover(self):
xml_str = '''<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh">
<head>
<title>封面</title>
<style type="text/css">
svg {padding: 0pt; margin:0pt}
body { text-align: center; padding:0pt; margin: 0pt; }
</style>
</head>
<body>
<div>
<svg xmlns="http://www.w3.org/2000/svg" height="100%" preserveAspectRatio="xMidYMid meet" version="1.1" viewBox="0 0 628 892" width="100%" xmlns:xlink="http://www.w3.org/1999/xlink">
<image height="892" width="628" xlink:href="../Images/epub_cover1.jpg"/>
</svg>
</div>
</body>
</html>
'''
with open(self.base_path + '/OEBPS/Text/book_cover.xhtml','a+', encoding='utf-8') as cover:
cover.write(xml_str)
# 生成文档目录.ncx文件
def generate_toc_ncx(self):
ncx = '''
<?xml version='1.0' encoding='utf-8'?>
<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1" xml:lang="zh-CN">
<head>
<meta name="dtb:uid" content="urn:uuid:12345"/>
<meta name="dtb:depth" content="1"/>
<meta name="dtb:totalPageCount" content="0"/>
<meta name="dtb:maxPageNumber" content="0"/>
</head>
<docTitle>
<text>{title}</text>
</docTitle>
{nav_map}
</ncx>
'''.format(title=self.project.name,nav_map=self.nav_str)
with open(self.base_path+'/OEBPS/toc.ncx','a+',encoding='utf-8') as file:
file.write(ncx)
# 生成文档目录toc_summary.html文件
def generate_toc_html(self):
summary = '''<?xml version="1.0" encoding="UTF-8"?>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>目录</title>
<style>
body{margin: 0px;padding: 0px;}h1{text-align: center;padding: 0px;margin: 0px;}ul,li{list-style: none;}ul{padding-left:0px;}li>ul{padding-left: 2em;}
a{text-decoration: none;color: #4183c4;text-decoration: none;font-size: 16px;line-height: 28px;}
</style>
</head>
<body>
<h1>&nbsp;&nbsp;&nbsp;&nbsp;</h1>
%s
</body>
</html>
''' % (self.toc_summary_str)
with open(self.base_path+'/OEBPS/Text/toc_summary.xhtml','a+',encoding='utf-8') as file:
file.write(summary)
# 生成content.opf文件
def generate_opf(self):
content_info = '''<?xml version="1.0" encoding="utf-8" ?>
<package version="2.0" xmlns="http://www.idpf.org/2007/opf" unique-identifier="uid" >
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
<dc:title>{title}</dc:title>
<dc:language>zh</dc:language>
<dc:creator>{creator}</dc:creator>
<dc:identifier id="bookid">urn:uuid:12345</dc:identifier>
<dc:publisher>MrDoc制作</dc:publisher>
<dc:date opf:event="publication">{create_time}</dc:date>
<dc:description>{desc}</dc:description>
<meta name="cover" content="cover_img" />
<meta name="output encoding" content="utf-8" />
<meta name="primary-writing-mode" content="horizontal-lr" />
</metadata>
<manifest>
{manifest}
<item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml"/>
<item id="css" href="stylesheet.css" media-type="text/css"/>
<item id="cover_img" media-type="image/jpeg" href="Images/epub_cover1.jpg" />
</manifest>
<spine toc="ncx">
{spine}
</spine>
<guide>
<reference type="toc" title="目录" href="Text/toc_summary.xhtml" />
<reference href="Text/book_cover.xhtml" type="cover" title="封面"/>
</guide>
</package>
'''
with open(self.base_path+'/OEBPS/content.opf','a+',encoding='utf-8') as file:
file.write(
content_info.format(
title = self.project.name,
creator = self.project.create_user,
create_time = str(datetime.date.today()),
desc=self.project.intro,
manifest=self.manifest,
spine = self.spine,
)
)
# 生成epub文件
def generate_epub(self):
try:
# 生成ZIP压缩文件
zipfile_name = settings.MEDIA_ROOT + '/report/{}'.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)
)
# print(zip_name)
# 修改zip压缩文件后缀为EPUB
os.rename(zip_name,zipfile_name+'.epub')
# 删除生成的临时文件夹
shutil.rmtree(self.base_path)
return zipfile_name
except Exception as e:
if settings.DEBUG:
print(traceback.print_exc())
return None
def work(self):
self.generate_html() # 生成HTML
self.generate_metainfo() # 生成元信息
self.generate_metatype() # 生成元类型
self.generate_toc_ncx() # 生成目录ncx
self.generate_toc_html() # 生成目录html
self.generate_cover() # 生成封面html
self.generate_title_html() # 生产书籍的标题页和简介页
self.generate_opf() # 生成content.opf
epub_file = self.generate_epub()
return epub_file
# 导出Docx
class ReportDocx():
def __init__(self,project_id):
self.project = Project.objects.get(id=project_id)
self.base_path = settings.MEDIA_ROOT + '/report/{}/'.format(project_id)
self.content_str = ""
self.doc_str = """<html xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:w="urn:schemas-microsoft-com:office:word"
xmlns="http://www.w3.org/TR/REC-html40">
<head><meta http-equiv=Content-Type content="text/html; charset=utf-8">
<style type="text/css">
table
{
border-collapse: collapse;
border: none;
width: 100%;
}
td,tr
{
border: solid #CCC 1px;
padding:3px;
font-size:9pt;
}
.codestyle{
word-break: break-all;
mso-highlight:rgb(252, 252, 252);
padding-left: 5px; background-color: rgb(252, 252, 252); border: 1px solid rgb(225, 225, 232);
}
img {
width:100;
}
/*预格式*/
pre {
padding: 10px;
background: #f6f6f6;
border: 1px solid #ddd;
white-space: pre-wrap;
word-wrap: break-word;
white-space: -moz-pre-wrap;
white-space: -o-pre-wrap;
}
/*块代码*/
pre code {
border: none;
background: none;
}
pre ol {
padding-left: 2.5em;
margin: 0;
}
/*行内代码*/
code {
border: 1px solid #ddd;
background: #f6f6f6;
padding: 3px;
border-radius: 3px;
font-size: 14px;
}
/* 引用块 */
blockquote {
color: #666;
border-left: 4px solid #ddd;
padding-left: 20px;
margin-left: 0;
font-size: 14px;
font-style: italic;
}
/* 表格 */
table {
display: block;
width: 100%;
overflow: auto;
word-break: normal;
word-break: keep-all;
margin-bottom: 16px;
}
thead {
display: table-header-group;
vertical-align: middle;
border-color: inherit;
}
table thead tr {
background-color: #F8F8F8;
}
table th, table td {
padding: 6px 13px;
border: 1px solid #ddd;
}
/*公式*/
p.editormd-tex {
text-align: center;
}
</style>
<meta name=ProgId content=Word.Document>
<meta name=Generator content="Microsoft Word 11">
<meta name=Originator content="Microsoft Word 11">
<xml><w:WordDocument><w:View>Print</w:View></xml></head>
<body>
"""
def work(self):
# 拼接HTML字符串
data = Doc.objects.filter(top_doc=self.project.id,parent_doc=0).order_by("sort")
for d in data:
# print(d.name,d.content)
self.content_str += "<h1 style='page-break-before: always;'>{}</h1>".format(d.name)
self.content_str += d.content
# 获取第二级文档
data_2 = Doc.objects.filter(parent_doc=d.id).order_by("sort")
for d2 in data_2:
self.content_str += "<h1>{}</h1>".format(d2.name)
self.content_str += d2.content
# 获取第三级文档
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 += "<h1>{}</h1>".format(d3.name)
self.content_str += d3.content
# 使用BeautifulSoup解析拼接好的HTML文本
soup = BeautifulSoup(self.content_str,'lxml')
src_tag = soup.find_all(lambda tag:tag.has_attr("src")) # 查找所有包含src的标签
print(src_tag)
# 替换HTML文本中静态文件的相对链接为绝对链接
for src in src_tag:
if src['src'].startswith("/"):
src['src'] = settings.BASE_DIR + src['src']
is_folder = os.path.exists(self.base_path)
# 创建文件夹
if is_folder is False:
os.mkdir(self.base_path)
temp_file_name = str(datetime.datetime.today()).replace(':', '-').replace(' ', '-').replace('.', '')
temp_file_path = self.base_path + '/{0}.docx'.format(temp_file_name)
with open(temp_file_path, 'a+', encoding='utf-8') as htmlfile:
htmlfile.write(self.doc_str + self.content_str + "</body></html>")
if __name__ == '__main__':
app = ReportMD(
project_id=7
)
# app = ReportMD(
# project_id=7
# )
# app.work()
app = ReportEPUB(project_id=20)
app.work()
# app = ReportDocx(project_id=20)
# app.work()

View File

@ -41,16 +41,18 @@ class DocSitemap(Sitemap):
def lastmod(self,obj):
return obj.modify_time
all_sitemaps = {}
all_sitemaps['home'] = HomeSitemap()
for project in Project.objects.filter(role=0):
info_dict = {
'queryset': Doc.objects.filter(status=1,top_doc=project.id),
}
# sitemap = GenericSitemap(info_dict,priority=0.6)
sitemap = DocSitemap(pro=project.id)
# dict key is provided as 'section' in sitemap index view
all_sitemaps[str(project.id)] = sitemap
# print(all_sitemaps)
def all_sitemaps():
all_sitemap = {}
all_sitemap['home'] = HomeSitemap()
all_project = ProjectSitemap()
# print("所有文集:",all_project.items())
for project in all_project.items():
# for project in Project.objects.filter(role=0):
info_dict = {
'queryset': Doc.objects.filter(status=1,top_doc=project.id),
}
# sitemap = GenericSitemap(info_dict,priority=0.6)
sitemap = DocSitemap(pro=project.id)
all_sitemap[str(project.id)] = sitemap
# print(all_sitemaps)
return all_sitemap

View File

@ -10,3 +10,20 @@ register = template.Library()
@register.filter(name='get_doc_count')
def get_doc_count(value):
return Doc.objects.filter(top_doc=int(value)).count()
# 获取文集下最新的文档及其修改时间
@register.filter(name='get_new_doc')
def get_new_doc(value):
new_doc = Doc.objects.filter(top_doc=int(value),status=1).order_by('-modify_time').first()
return new_doc
# 获取文集的开放导出状态
@register.filter(name='get_report_status')
def get_report_status(value):
try:
project = Project.objects.get(id=int(value))
status = ProjectReport.objects.get(project=project).allow_epub
except Exception as e:
# print(repr(e))
status = 0
return status

View File

@ -11,7 +11,9 @@ 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('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"), # 修改文集前台下载权限
path('check_viewcode/',views.check_viewcode,name='check_viewcode'),# 文集访问码验证
#################文档相关
path('project/<int:pro_id>/<int:doc_id>/', views.doc, name='doc'), # 文档浏览页

View File

@ -11,7 +11,7 @@ from django.db.models import Q
import datetime
import traceback
from app_doc.report_utils import *
from app_admin.decorators import check_headers
from app_admin.decorators import check_headers,allow_report_file
# 文集列表
@ -19,11 +19,11 @@ def project_list(request):
# 登录用户
if request.user.is_authenticated:
project_list = Project.objects.filter(
Q(role=0) | Q(role=2,role_value__contains=str(request.user.username)) | Q(create_user=request.user)
Q(role__in=[0,3]) | Q(role=2,role_value__contains=str(request.user.username)) | Q(create_user=request.user)
)
else:
# 非登录用户只显示公开文集
project_list = Project.objects.filter(role=0)
# 非登录用户只显示公开文集和需要访问码的文集
project_list = Project.objects.filter(role__in=[0,3])
return render(request, 'app_doc/pro_list.html', locals())
@ -61,6 +61,12 @@ def project_index(request,pro_id):
# 获取文集信息
project = Project.objects.get(id=int(pro_id))
# 获取问价文集前台下载权限
try:
allow_epub_download = ProjectReport.objects.get(project=project).allow_epub
except ObjectDoesNotExist:
allow_epub_download = 0
# 私密文集并且访问者非创建者
if project.role == 1 and request.user != project.create_user:
return render(request,'404.html')
@ -91,8 +97,9 @@ def project_index(request,pro_id):
return render(request,'app_doc/project_doc_search.html',locals())
return render(request, 'app_doc/project.html', locals())
except Exception as e:
print(traceback.print_exc())
print(repr(e))
if settings.DEBUG:
print(traceback.print_exc())
print(repr(e))
return HttpResponse('请求出错')
@ -121,7 +128,10 @@ def modify_project(request):
# 修改文集权限
@login_required()
def modify_project_role(request,pro_id):
pro = Project.objects.get(id=pro_id)
try:
pro = Project.objects.get(id=pro_id)
except ObjectDoesNotExist:
return Http404
if (pro.create_user != request.user) and (request.user.is_superuser is False):
return render(request,'403.html')
else:
@ -236,6 +246,34 @@ def manage_project(request):
return HttpResponse('方法不允许')
# 修改文集前台下载权限
@login_required()
def modify_project_download(request,pro_id):
try:
pro = Project.objects.get(id=pro_id)
except ObjectDoesNotExist:
return Http404
if (pro.create_user != request.user) and (request.user.is_superuser is False):
return render(request,'403.html')
else:
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)
# print("epub状态:",download_epub)
if download_epub == 'on':
epub_status = 1
else:
epub_status = 0
ProjectReport.objects.update_or_create(
project = pro,defaults={'allow_epub':epub_status}
)
return render(request,'app_doc/manage_project_download.html',locals())
# 文档浏览页页
@require_http_methods(['GET'])
def doc(request,pro_id,doc_id):
@ -270,6 +308,8 @@ def doc(request,pro_id,doc_id):
try:
doc = Doc.objects.get(id=int(doc_id),status=1)
except ObjectDoesNotExist:
if settings.DEBUG:
print(traceback.print_exc())
return render(request, '404.html')
# 获取文集下一级文档
project_docs = Doc.objects.filter(top_doc=doc.top_doc, parent_doc=0, status=1).order_by('sort')
@ -456,7 +496,7 @@ def manage_doc(request):
doc_status = request.GET.get('status','all')
if len(doc_status) == 0:
doc_status = 'all'
print('status:', doc_status,type(doc_status))
# print('status:', doc_status,type(doc_status))
# 返回所有文档
if doc_status == 'all':
doc_list = Doc.objects.filter(create_user=request.user).order_by('-modify_time')
@ -675,8 +715,50 @@ def report_md(request):
return JsonResponse({'status':True,'data':md_file})
else:
return JsonResponse({'status':False,'data':'无权限'})
except:
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
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':'不支持的类型'})
else:
return Http404

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
/** layui-v2.5.4 MIT License By https://www.layui.com */
/** layui-v2.5.6 MIT License By https://www.layui.com */
html #layuicss-skincodecss{display:none;position:absolute;width:1989px}.layui-code-h3,.layui-code-view{position:relative;font-size:12px}.layui-code-view{display:block;margin:10px 0;padding:0;border:1px solid #e2e2e2;border-left-width:6px;background-color:#F2F2F2;color:#333;font-family:Courier New}.layui-code-h3{padding:0 10px;height:32px;line-height:32px;border-bottom:1px solid #e2e2e2}.layui-code-h3 a{position:absolute;right:10px;top:0;color:#999}.layui-code-view .layui-code-ol{position:relative;overflow:auto}.layui-code-view .layui-code-ol li{position:relative;margin-left:45px;line-height:20px;padding:0 5px;border-left:1px solid #e2e2e2;list-style-type:decimal-leading-zero;*list-style-type:decimal;background-color:#fff}.layui-code-view pre{margin:0}.layui-code-notepad{border:1px solid #0C0C0C;border-left-color:#3F3F3F;background-color:#0C0C0C;color:#C2BE9E}.layui-code-notepad .layui-code-h3{border-bottom:none}.layui-code-notepad .layui-code-ol li{background-color:#3F3F3F;border-left:none}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 277 KiB

After

Width:  |  Height:  |  Size: 299 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,2 +1,2 @@
/** layui-v2.5.4 MIT License By https://www.layui.com */
/** layui-v2.5.6 MIT License By https://www.layui.com */
;layui.define("jquery",function(e){"use strict";var i=layui.$,n=(layui.hint(),layui.device(),{config:{},set:function(e){var n=this;return n.config=i.extend({},n.config,e),n},on:function(e,i){return layui.onevent.call(this,t,e,i)}}),t="carousel",a="layui-this",l=">*[carousel-item]>*",o="layui-carousel-left",r="layui-carousel-right",d="layui-carousel-prev",s="layui-carousel-next",u="layui-carousel-arrow",c="layui-carousel-ind",m=function(e){var t=this;t.config=i.extend({},t.config,n.config,e),t.render()};m.prototype.config={width:"600px",height:"280px",full:!1,arrow:"hover",indicator:"inside",autoplay:!0,interval:3e3,anim:"",trigger:"click",index:0},m.prototype.render=function(){var e=this,n=e.config;n.elem=i(n.elem),n.elem[0]&&(e.elemItem=n.elem.find(l),n.index<0&&(n.index=0),n.index>=e.elemItem.length&&(n.index=e.elemItem.length-1),n.interval<800&&(n.interval=800),n.full?n.elem.css({position:"fixed",width:"100%",height:"100%",zIndex:9999}):n.elem.css({width:n.width,height:n.height}),n.elem.attr("lay-anim",n.anim),e.elemItem.eq(n.index).addClass(a),e.elemItem.length<=1||(e.indicator(),e.arrow(),e.autoplay(),e.events()))},m.prototype.reload=function(e){var n=this;clearInterval(n.timer),n.config=i.extend({},n.config,e),n.render()},m.prototype.prevIndex=function(){var e=this,i=e.config,n=i.index-1;return n<0&&(n=e.elemItem.length-1),n},m.prototype.nextIndex=function(){var e=this,i=e.config,n=i.index+1;return n>=e.elemItem.length&&(n=0),n},m.prototype.addIndex=function(e){var i=this,n=i.config;e=e||1,n.index=n.index+e,n.index>=i.elemItem.length&&(n.index=0)},m.prototype.subIndex=function(e){var i=this,n=i.config;e=e||1,n.index=n.index-e,n.index<0&&(n.index=i.elemItem.length-1)},m.prototype.autoplay=function(){var e=this,i=e.config;i.autoplay&&(clearInterval(e.timer),e.timer=setInterval(function(){e.slide()},i.interval))},m.prototype.arrow=function(){var e=this,n=e.config,t=i(['<button class="layui-icon '+u+'" lay-type="sub">'+("updown"===n.anim?"&#xe619;":"&#xe603;")+"</button>",'<button class="layui-icon '+u+'" lay-type="add">'+("updown"===n.anim?"&#xe61a;":"&#xe602;")+"</button>"].join(""));n.elem.attr("lay-arrow",n.arrow),n.elem.find("."+u)[0]&&n.elem.find("."+u).remove(),n.elem.append(t),t.on("click",function(){var n=i(this),t=n.attr("lay-type");e.slide(t)})},m.prototype.indicator=function(){var e=this,n=e.config,t=e.elemInd=i(['<div class="'+c+'"><ul>',function(){var i=[];return layui.each(e.elemItem,function(e){i.push("<li"+(n.index===e?' class="layui-this"':"")+"></li>")}),i.join("")}(),"</ul></div>"].join(""));n.elem.attr("lay-indicator",n.indicator),n.elem.find("."+c)[0]&&n.elem.find("."+c).remove(),n.elem.append(t),"updown"===n.anim&&t.css("margin-top",-(t.height()/2)),t.find("li").on("hover"===n.trigger?"mouseover":n.trigger,function(){var t=i(this),a=t.index();a>n.index?e.slide("add",a-n.index):a<n.index&&e.slide("sub",n.index-a)})},m.prototype.slide=function(e,i){var n=this,l=n.elemItem,u=n.config,c=u.index,m=u.elem.attr("lay-filter");n.haveSlide||("sub"===e?(n.subIndex(i),l.eq(u.index).addClass(d),setTimeout(function(){l.eq(c).addClass(r),l.eq(u.index).addClass(r)},50)):(n.addIndex(i),l.eq(u.index).addClass(s),setTimeout(function(){l.eq(c).addClass(o),l.eq(u.index).addClass(o)},50)),setTimeout(function(){l.removeClass(a+" "+d+" "+s+" "+o+" "+r),l.eq(u.index).addClass(a),n.haveSlide=!1},300),n.elemInd.find("li").eq(u.index).addClass(a).siblings().removeClass(a),n.haveSlide=!0,layui.event.call(this,t,"change("+m+")",{index:u.index,prevIndex:c,item:l.eq(u.index)}))},m.prototype.events=function(){var e=this,i=e.config;i.elem.data("haveEvents")||(i.elem.on("mouseenter",function(){clearInterval(e.timer)}).on("mouseleave",function(){e.autoplay()}),i.elem.data("haveEvents",!0))},n.render=function(e){var i=new m(e);return i},e(t,n)});

View File

@ -1,2 +1,2 @@
/** layui-v2.5.4 MIT License By https://www.layui.com */
/** layui-v2.5.6 MIT License By https://www.layui.com */
;layui.define("jquery",function(e){"use strict";var a=layui.$,l="http://www.layui.com/doc/modules/code.html";e("code",function(e){var t=[];e=e||{},e.elem=a(e.elem||".layui-code"),e.about=!("about"in e)||e.about,e.elem.each(function(){t.push(this)}),layui.each(t.reverse(),function(t,i){var c=a(i),o=c.html();(c.attr("lay-encode")||e.encode)&&(o=o.replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/'/g,"&#39;").replace(/"/g,"&quot;")),c.html('<ol class="layui-code-ol"><li>'+o.replace(/[\r\t\n]+/g,"</li><li>")+"</li></ol>"),c.find(">.layui-code-h3")[0]||c.prepend('<h3 class="layui-code-h3">'+(c.attr("lay-title")||e.title||"code")+(e.about?'<a href="'+l+'" target="_blank">layui.code</a>':"")+"</h3>");var d=c.find(">.layui-code-ol");c.addClass("layui-box layui-code-view"),(c.attr("lay-skin")||e.skin)&&c.addClass("layui-code-"+(c.attr("lay-skin")||e.skin)),(d.find("li").length/100|0)>0&&d.css("margin-left",(d.find("li").length/100|0)+"px"),(c.attr("lay-height")||e.height)&&d.css("max-height",c.attr("lay-height")||e.height)})})}).addcss("modules/code.css","skincodecss");

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
/** layui-v2.5.4 MIT License By https://www.layui.com */
;layui.define("jquery",function(e){"use strict";var l=layui.$,o=function(e){},t='<i class="layui-anim layui-anim-rotate layui-anim-loop layui-icon ">&#xe63e;</i>';o.prototype.load=function(e){var o,i,n,r,a=this,c=0;e=e||{};var f=l(e.elem);if(f[0]){var m=l(e.scrollElem||document),u=e.mb||50,s=!("isAuto"in e)||e.isAuto,v=e.end||"没有更多了",y=e.scrollElem&&e.scrollElem!==document,d="<cite>加载更多</cite>",h=l('<div class="layui-flow-more"><a href="javascript:;">'+d+"</a></div>");f.find(".layui-flow-more")[0]||f.append(h);var p=function(e,t){e=l(e),h.before(e),t=0==t||null,t?h.html(v):h.find("a").html(d),i=t,o=null,n&&n()},g=function(){o=!0,h.find("a").html(t),"function"==typeof e.done&&e.done(++c,p)};if(g(),h.find("a").on("click",function(){l(this);i||o||g()}),e.isLazyimg)var n=a.lazyimg({elem:e.elem+" img",scrollElem:e.scrollElem});return s?(m.on("scroll",function(){var e=l(this),t=e.scrollTop();r&&clearTimeout(r),i||(r=setTimeout(function(){var i=y?e.height():l(window).height(),n=y?e.prop("scrollHeight"):document.documentElement.scrollHeight;n-t-i<=u&&(o||g())},100))}),a):a}},o.prototype.lazyimg=function(e){var o,t=this,i=0;e=e||{};var n=l(e.scrollElem||document),r=e.elem||"img",a=e.scrollElem&&e.scrollElem!==document,c=function(e,l){var o=n.scrollTop(),r=o+l,c=a?function(){return e.offset().top-n.offset().top+o}():e.offset().top;if(c>=o&&c<=r&&!e.attr("src")){var m=e.attr("lay-src");layui.img(m,function(){var l=t.lazyimg.elem.eq(i);e.attr("src",m).removeAttr("lay-src"),l[0]&&f(l),i++})}},f=function(e,o){var f=a?(o||n).height():l(window).height(),m=n.scrollTop(),u=m+f;if(t.lazyimg.elem=l(r),e)c(e,f);else for(var s=0;s<t.lazyimg.elem.length;s++){var v=t.lazyimg.elem.eq(s),y=a?function(){return v.offset().top-n.offset().top+m}():v.offset().top;if(c(v,f),i=s,y>u)break}};if(f(),!o){var m;n.on("scroll",function(){var e=l(this);m&&clearTimeout(m),m=setTimeout(function(){f(null,e)},50)}),o=!0}return f},e("flow",new o)});
/** layui-v2.5.6 MIT License By https://www.layui.com */
;layui.define("jquery",function(e){"use strict";var l=layui.$,o=function(e){},t='<i class="layui-anim layui-anim-rotate layui-anim-loop layui-icon ">&#xe63e;</i>';o.prototype.load=function(e){var o,i,n,r,a=this,c=0;e=e||{};var f=l(e.elem);if(f[0]){var m=l(e.scrollElem||document),u=e.mb||50,s=!("isAuto"in e)||e.isAuto,v=e.end||"没有更多了",y=e.scrollElem&&e.scrollElem!==document,d="<cite>加载更多</cite>",h=l('<div class="layui-flow-more"><a href="javascript:;">'+d+"</a></div>");f.find(".layui-flow-more")[0]||f.append(h);var p=function(e,t){e=l(e),h.before(e),t=0==t||null,t?h.html(v):h.find("a").html(d),i=t,o=null,n&&n()},g=function(){o=!0,h.find("a").html(t),"function"==typeof e.done&&e.done(++c,p)};if(g(),h.find("a").on("click",function(){l(this);i||o||g()}),e.isLazyimg)var n=a.lazyimg({elem:e.elem+" img",scrollElem:e.scrollElem});return s?(m.on("scroll",function(){var e=l(this),t=e.scrollTop();r&&clearTimeout(r),!i&&f.width()&&(r=setTimeout(function(){var i=y?e.height():l(window).height(),n=y?e.prop("scrollHeight"):document.documentElement.scrollHeight;n-t-i<=u&&(o||g())},100))}),a):a}},o.prototype.lazyimg=function(e){var o,t=this,i=0;e=e||{};var n=l(e.scrollElem||document),r=e.elem||"img",a=e.scrollElem&&e.scrollElem!==document,c=function(e,l){var o=n.scrollTop(),r=o+l,c=a?function(){return e.offset().top-n.offset().top+o}():e.offset().top;if(c>=o&&c<=r&&!e.attr("src")){var m=e.attr("lay-src");layui.img(m,function(){var l=t.lazyimg.elem.eq(i);e.attr("src",m).removeAttr("lay-src"),l[0]&&f(l),i++})}},f=function(e,o){var f=a?(o||n).height():l(window).height(),m=n.scrollTop(),u=m+f;if(t.lazyimg.elem=l(r),e)c(e,f);else for(var s=0;s<t.lazyimg.elem.length;s++){var v=t.lazyimg.elem.eq(s),y=a?function(){return v.offset().top-n.offset().top+m}():v.offset().top;if(c(v,f),i=s,y>u)break}};if(f(),!o){var m;n.on("scroll",function(){var e=l(this);m&&clearTimeout(m),m=setTimeout(function(){f(null,e)},50)}),o=!0}return f},e("flow",new o)});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
/** layui-v2.5.4 MIT License By https://www.layui.com */
/** layui-v2.5.6 MIT License By https://www.layui.com */
;layui.define(function(e){"use strict";var a=document,t="getElementById",n="getElementsByTagName",i="laypage",r="layui-disabled",u=function(e){var a=this;a.config=e||{},a.config.index=++s.index,a.render(!0)};u.prototype.type=function(){var e=this.config;if("object"==typeof e.elem)return void 0===e.elem.length?2:3},u.prototype.view=function(){var e=this,a=e.config,t=a.groups="groups"in a?0|a.groups:5;a.layout="object"==typeof a.layout?a.layout:["prev","page","next"],a.count=0|a.count,a.curr=0|a.curr||1,a.limits="object"==typeof a.limits?a.limits:[10,20,30,40,50],a.limit=0|a.limit||10,a.pages=Math.ceil(a.count/a.limit)||1,a.curr>a.pages&&(a.curr=a.pages),t<0?t=1:t>a.pages&&(t=a.pages),a.prev="prev"in a?a.prev:"&#x4E0A;&#x4E00;&#x9875;",a.next="next"in a?a.next:"&#x4E0B;&#x4E00;&#x9875;";var n=a.pages>t?Math.ceil((a.curr+(t>1?1:0))/(t>0?t:1)):1,i={prev:function(){return a.prev?'<a href="javascript:;" class="layui-laypage-prev'+(1==a.curr?" "+r:"")+'" data-page="'+(a.curr-1)+'">'+a.prev+"</a>":""}(),page:function(){var e=[];if(a.count<1)return"";n>1&&a.first!==!1&&0!==t&&e.push('<a href="javascript:;" class="layui-laypage-first" data-page="1" title="&#x9996;&#x9875;">'+(a.first||1)+"</a>");var i=Math.floor((t-1)/2),r=n>1?a.curr-i:1,u=n>1?function(){var e=a.curr+(t-i-1);return e>a.pages?a.pages:e}():t;for(u-r<t-1&&(r=u-t+1),a.first!==!1&&r>2&&e.push('<span class="layui-laypage-spr">&#x2026;</span>');r<=u;r++)r===a.curr?e.push('<span class="layui-laypage-curr"><em class="layui-laypage-em" '+(/^#/.test(a.theme)?'style="background-color:'+a.theme+';"':"")+"></em><em>"+r+"</em></span>"):e.push('<a href="javascript:;" data-page="'+r+'">'+r+"</a>");return a.pages>t&&a.pages>u&&a.last!==!1&&(u+1<a.pages&&e.push('<span class="layui-laypage-spr">&#x2026;</span>'),0!==t&&e.push('<a href="javascript:;" class="layui-laypage-last" title="&#x5C3E;&#x9875;" data-page="'+a.pages+'">'+(a.last||a.pages)+"</a>")),e.join("")}(),next:function(){return a.next?'<a href="javascript:;" class="layui-laypage-next'+(a.curr==a.pages?" "+r:"")+'" data-page="'+(a.curr+1)+'">'+a.next+"</a>":""}(),count:'<span class="layui-laypage-count">共 '+a.count+" 条</span>",limit:function(){var e=['<span class="layui-laypage-limits"><select lay-ignore>'];return layui.each(a.limits,function(t,n){e.push('<option value="'+n+'"'+(n===a.limit?"selected":"")+">"+n+" 条/页</option>")}),e.join("")+"</select></span>"}(),refresh:['<a href="javascript:;" data-page="'+a.curr+'" class="layui-laypage-refresh">','<i class="layui-icon layui-icon-refresh"></i>',"</a>"].join(""),skip:function(){return['<span class="layui-laypage-skip">&#x5230;&#x7B2C;','<input type="text" min="1" value="'+a.curr+'" class="layui-input">','&#x9875;<button type="button" class="layui-laypage-btn">&#x786e;&#x5b9a;</button>',"</span>"].join("")}()};return['<div class="layui-box layui-laypage layui-laypage-'+(a.theme?/^#/.test(a.theme)?"molv":a.theme:"default")+'" id="layui-laypage-'+a.index+'">',function(){var e=[];return layui.each(a.layout,function(a,t){i[t]&&e.push(i[t])}),e.join("")}(),"</div>"].join("")},u.prototype.jump=function(e,a){if(e){var t=this,i=t.config,r=e.children,u=e[n]("button")[0],l=e[n]("input")[0],p=e[n]("select")[0],c=function(){var e=0|l.value.replace(/\s|\D/g,"");e&&(i.curr=e,t.render())};if(a)return c();for(var o=0,y=r.length;o<y;o++)"a"===r[o].nodeName.toLowerCase()&&s.on(r[o],"click",function(){var e=0|this.getAttribute("data-page");e<1||e>i.pages||(i.curr=e,t.render())});p&&s.on(p,"change",function(){var e=this.value;i.curr*e>i.count&&(i.curr=Math.ceil(i.count/e)),i.limit=e,t.render()}),u&&s.on(u,"click",function(){c()})}},u.prototype.skip=function(e){if(e){var a=this,t=e[n]("input")[0];t&&s.on(t,"keyup",function(t){var n=this.value,i=t.keyCode;/^(37|38|39|40)$/.test(i)||(/\D/.test(n)&&(this.value=n.replace(/\D/,"")),13===i&&a.jump(e,!0))})}},u.prototype.render=function(e){var n=this,i=n.config,r=n.type(),u=n.view();2===r?i.elem&&(i.elem.innerHTML=u):3===r?i.elem.html(u):a[t](i.elem)&&(a[t](i.elem).innerHTML=u),i.jump&&i.jump(i,e);var s=a[t]("layui-laypage-"+i.index);n.jump(s),i.hash&&!e&&(location.hash="!"+i.hash+"="+i.curr),n.skip(s)};var s={render:function(e){var a=new u(e);return a.index},index:layui.laypage?layui.laypage.index+1e4:0,on:function(e,a,t){return e.attachEvent?e.attachEvent("on"+a,function(a){a.target=a.srcElement,t.call(e,a)}):e.addEventListener(a,t,!1),this}};e(i,s)});

View File

@ -1,2 +1,2 @@
/** layui-v2.5.4 MIT License By https://www.layui.com */
/** layui-v2.5.6 MIT License By https://www.layui.com */
;layui.define(function(e){"use strict";var r={open:"{{",close:"}}"},c={exp:function(e){return new RegExp(e,"g")},query:function(e,c,t){var o=["#([\\s\\S])+?","([^{#}])*?"][e||0];return n((c||"")+r.open+o+r.close+(t||""))},escape:function(e){return String(e||"").replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/'/g,"&#39;").replace(/"/g,"&quot;")},error:function(e,r){var c="Laytpl Error";return"object"==typeof console&&console.error(c+e+"\n"+(r||"")),c+e}},n=c.exp,t=function(e){this.tpl=e};t.pt=t.prototype,window.errors=0,t.pt.parse=function(e,t){var o=this,p=e,a=n("^"+r.open+"#",""),l=n(r.close+"$","");e=e.replace(/\s+|\r|\t|\n/g," ").replace(n(r.open+"#"),r.open+"# ").replace(n(r.close+"}"),"} "+r.close).replace(/\\/g,"\\\\").replace(n(r.open+"!(.+?)!"+r.close),function(e){return e=e.replace(n("^"+r.open+"!"),"").replace(n("!"+r.close),"").replace(n(r.open+"|"+r.close),function(e){return e.replace(/(.)/g,"\\$1")})}).replace(/(?="|')/g,"\\").replace(c.query(),function(e){return e=e.replace(a,"").replace(l,""),'";'+e.replace(/\\/g,"")+';view+="'}).replace(c.query(1),function(e){var c='"+(';return e.replace(/\s/g,"")===r.open+r.close?"":(e=e.replace(n(r.open+"|"+r.close),""),/^=/.test(e)&&(e=e.replace(/^=/,""),c='"+_escape_('),c+e.replace(/\\/g,"")+')+"')}),e='"use strict";var view = "'+e+'";return view;';try{return o.cache=e=new Function("d, _escape_",e),e(t,c.escape)}catch(u){return delete o.cache,c.error(u,p)}},t.pt.render=function(e,r){var n,t=this;return e?(n=t.cache?t.cache(e,c.escape):t.parse(t.tpl,e),r?void r(n):n):c.error("no data")};var o=function(e){return"string"!=typeof e?c.error("Template not found"):new t(e)};o.config=function(e){e=e||{};for(var c in e)r[c]=e[c]},o.v="1.2.0",e("laytpl",o)});

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
/** layui-v2.5.4 MIT License By https://www.layui.com */
/** layui-v2.5.6 MIT License By https://www.layui.com */
;layui.define("jquery",function(e){"use strict";var a=layui.jquery,i={config:{},index:layui.rate?layui.rate.index+1e4:0,set:function(e){var i=this;return i.config=a.extend({},i.config,e),i},on:function(e,a){return layui.onevent.call(this,n,e,a)}},l=function(){var e=this,a=e.config;return{setvalue:function(a){e.setvalue.call(e,a)},config:a}},n="rate",t="layui-rate",o="layui-icon-rate",s="layui-icon-rate-solid",u="layui-icon-rate-half",r="layui-icon-rate-solid layui-icon-rate-half",c="layui-icon-rate-solid layui-icon-rate",f="layui-icon-rate layui-icon-rate-half",v=function(e){var l=this;l.index=++i.index,l.config=a.extend({},l.config,i.config,e),l.render()};v.prototype.config={length:5,text:!1,readonly:!1,half:!1,value:0,theme:""},v.prototype.render=function(){var e=this,i=e.config,l=i.theme?'style="color: '+i.theme+';"':"";i.elem=a(i.elem),parseInt(i.value)!==i.value&&(i.half||(i.value=Math.ceil(i.value)-i.value<.5?Math.ceil(i.value):Math.floor(i.value)));for(var n='<ul class="layui-rate" '+(i.readonly?"readonly":"")+">",u=1;u<=i.length;u++){var r='<li class="layui-inline"><i class="layui-icon '+(u>Math.floor(i.value)?o:s)+'" '+l+"></i></li>";i.half&&parseInt(i.value)!==i.value&&u==Math.ceil(i.value)?n=n+'<li><i class="layui-icon layui-icon-rate-half" '+l+"></i></li>":n+=r}n+="</ul>"+(i.text?'<span class="layui-inline">'+i.value+"星":"")+"</span>";var c=i.elem,f=c.next("."+t);f[0]&&f.remove(),e.elemTemp=a(n),i.span=e.elemTemp.next("span"),i.setText&&i.setText(i.value),c.html(e.elemTemp),c.addClass("layui-inline"),i.readonly||e.action()},v.prototype.setvalue=function(e){var a=this,i=a.config;i.value=e,a.render()},v.prototype.action=function(){var e=this,i=e.config,l=e.elemTemp,n=l.find("i").width();l.children("li").each(function(e){var t=e+1,v=a(this);v.on("click",function(e){if(i.value=t,i.half){var o=e.pageX-a(this).offset().left;o<=n/2&&(i.value=i.value-.5)}i.text&&l.next("span").text(i.value+"星"),i.choose&&i.choose(i.value),i.setText&&i.setText(i.value)}),v.on("mousemove",function(e){if(l.find("i").each(function(){a(this).addClass(o).removeClass(r)}),l.find("i:lt("+t+")").each(function(){a(this).addClass(s).removeClass(f)}),i.half){var c=e.pageX-a(this).offset().left;c<=n/2&&v.children("i").addClass(u).removeClass(s)}}),v.on("mouseleave",function(){l.find("i").each(function(){a(this).addClass(o).removeClass(r)}),l.find("i:lt("+Math.floor(i.value)+")").each(function(){a(this).addClass(s).removeClass(f)}),i.half&&parseInt(i.value)!==i.value&&l.children("li:eq("+Math.floor(i.value)+")").children("i").addClass(u).removeClass(c)})})},v.prototype.events=function(){var e=this;e.config},i.render=function(e){var a=new v(e);return l.call(a)},e(n,i)});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
/** layui-v2.5.4 MIT License By https://www.layui.com */
;layui.define("jquery",function(t){"use strict";var e=layui.$,i={fixbar:function(t){var i,n,a="layui-fixbar",o="layui-fixbar-top",r=e(document),l=e("body");t=e.extend({showHeight:200},t),t.bar1=t.bar1===!0?"&#xe606;":t.bar1,t.bar2=t.bar2===!0?"&#xe607;":t.bar2,t.bgcolor=t.bgcolor?"background-color:"+t.bgcolor:"";var c=[t.bar1,t.bar2,"&#xe604;"],g=e(['<ul class="'+a+'">',t.bar1?'<li class="layui-icon" lay-type="bar1" style="'+t.bgcolor+'">'+c[0]+"</li>":"",t.bar2?'<li class="layui-icon" lay-type="bar2" style="'+t.bgcolor+'">'+c[1]+"</li>":"",'<li class="layui-icon '+o+'" lay-type="top" style="'+t.bgcolor+'">'+c[2]+"</li>","</ul>"].join("")),s=g.find("."+o),u=function(){var e=r.scrollTop();e>=t.showHeight?i||(s.show(),i=1):i&&(s.hide(),i=0)};e("."+a)[0]||("object"==typeof t.css&&g.css(t.css),l.append(g),u(),g.find("li").on("click",function(){var i=e(this),n=i.attr("lay-type");"top"===n&&e("html,body").animate({scrollTop:0},200),t.click&&t.click.call(this,n)}),r.on("scroll",function(){clearTimeout(n),n=setTimeout(function(){u()},100)}))},countdown:function(t,e,i){var n=this,a="function"==typeof e,o=new Date(t).getTime(),r=new Date(!e||a?(new Date).getTime():e).getTime(),l=o-r,c=[Math.floor(l/864e5),Math.floor(l/36e5)%24,Math.floor(l/6e4)%60,Math.floor(l/1e3)%60];a&&(i=e);var g=setTimeout(function(){n.countdown(t,r+1e3,i)},1e3);return i&&i(l>0?c:[0,0,0,0],e,g),l<=0&&clearTimeout(g),g},timeAgo:function(t,e){var i=this,n=[[],[]],a=(new Date).getTime()-new Date(t).getTime();return a>6912e5?(a=new Date(t),n[0][0]=i.digit(a.getFullYear(),4),n[0][1]=i.digit(a.getMonth()+1),n[0][2]=i.digit(a.getDate()),e||(n[1][0]=i.digit(a.getHours()),n[1][1]=i.digit(a.getMinutes()),n[1][2]=i.digit(a.getSeconds())),n[0].join("-")+" "+n[1].join(":")):a>=864e5?(a/1e3/60/60/24|0)+"天前":a>=36e5?(a/1e3/60/60|0)+"小时前":a>=12e4?(a/1e3/60|0)+"分钟前":a<0?"未来":"刚刚"},digit:function(t,e){var i="";t=String(t),e=e||2;for(var n=t.length;n<e;n++)i+="0";return t<Math.pow(10,e)?i+(0|t):t},toDateString:function(t,e){var i=this,n=new Date(t||new Date),a=[i.digit(n.getFullYear(),4),i.digit(n.getMonth()+1),i.digit(n.getDate())],o=[i.digit(n.getHours()),i.digit(n.getMinutes()),i.digit(n.getSeconds())];return e=e||"yyyy-MM-dd HH:mm:ss",e.replace(/yyyy/g,a[0]).replace(/MM/g,a[1]).replace(/dd/g,a[2]).replace(/HH/g,o[0]).replace(/mm/g,o[1]).replace(/ss/g,o[2])},escape:function(t){return String(t||"").replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/'/g,"&#39;").replace(/"/g,"&quot;")},event:function(t,n,a){n=i.event[t]=e.extend(!0,i.event[t],n)||{},e("body").on(a||"click","*["+t+"]",function(){var i=e(this),a=i.attr(t);n[a]&&n[a].call(this,i)})}};!function(t,e,i){"$:nomunge";function n(){a=e[l](function(){o.each(function(){var e=t(this),i=e.width(),n=e.height(),a=t.data(this,g);(i!==a.w||n!==a.h)&&e.trigger(c,[a.w=i,a.h=n])}),n()},r[s])}var a,o=t([]),r=t.resize=t.extend(t.resize,{}),l="setTimeout",c="resize",g=c+"-special-event",s="delay",u="throttleWindow";r[s]=250,r[u]=!0,t.event.special[c]={setup:function(){if(!r[u]&&this[l])return!1;var e=t(this);o=o.add(e),t.data(this,g,{w:e.width(),h:e.height()}),1===o.length&&n()},teardown:function(){if(!r[u]&&this[l])return!1;var e=t(this);o=o.not(e),e.removeData(g),o.length||clearTimeout(a)},add:function(e){function n(e,n,o){var r=t(this),l=t.data(this,g)||{};l.w=n!==i?n:r.width(),l.h=o!==i?o:r.height(),a.apply(this,arguments)}if(!r[u]&&this[l])return!1;var a;return t.isFunction(e)?(a=e,n):(a=e.handler,void(e.handler=n))}}}(e,window),t("util",i)});
/** layui-v2.5.6 MIT License By https://www.layui.com */
;layui.define("jquery",function(e){"use strict";var t=layui.$,i={fixbar:function(e){var i,n,a="layui-fixbar",o="layui-fixbar-top",r=t(document),l=t("body");e=t.extend({showHeight:200},e),e.bar1=e.bar1===!0?"&#xe606;":e.bar1,e.bar2=e.bar2===!0?"&#xe607;":e.bar2,e.bgcolor=e.bgcolor?"background-color:"+e.bgcolor:"";var c=[e.bar1,e.bar2,"&#xe604;"],u=t(['<ul class="'+a+'">',e.bar1?'<li class="layui-icon" lay-type="bar1" style="'+e.bgcolor+'">'+c[0]+"</li>":"",e.bar2?'<li class="layui-icon" lay-type="bar2" style="'+e.bgcolor+'">'+c[1]+"</li>":"",'<li class="layui-icon '+o+'" lay-type="top" style="'+e.bgcolor+'">'+c[2]+"</li>","</ul>"].join("")),g=u.find("."+o),s=function(){var t=r.scrollTop();t>=e.showHeight?i||(g.show(),i=1):i&&(g.hide(),i=0)};t("."+a)[0]||("object"==typeof e.css&&u.css(e.css),l.append(u),s(),u.find("li").on("click",function(){var i=t(this),n=i.attr("lay-type");"top"===n&&t("html,body").animate({scrollTop:0},200),e.click&&e.click.call(this,n)}),r.on("scroll",function(){clearTimeout(n),n=setTimeout(function(){s()},100)}))},countdown:function(e,t,i){var n=this,a="function"==typeof t,o=new Date(e).getTime(),r=new Date(!t||a?(new Date).getTime():t).getTime(),l=o-r,c=[Math.floor(l/864e5),Math.floor(l/36e5)%24,Math.floor(l/6e4)%60,Math.floor(l/1e3)%60];a&&(i=t);var u=setTimeout(function(){n.countdown(e,r+1e3,i)},1e3);return i&&i(l>0?c:[0,0,0,0],t,u),l<=0&&clearTimeout(u),u},timeAgo:function(e,t){var i=this,n=[[],[]],a=(new Date).getTime()-new Date(e).getTime();return a>26784e5?(a=new Date(e),n[0][0]=i.digit(a.getFullYear(),4),n[0][1]=i.digit(a.getMonth()+1),n[0][2]=i.digit(a.getDate()),t||(n[1][0]=i.digit(a.getHours()),n[1][1]=i.digit(a.getMinutes()),n[1][2]=i.digit(a.getSeconds())),n[0].join("-")+" "+n[1].join(":")):a>=864e5?(a/1e3/60/60/24|0)+"天前":a>=36e5?(a/1e3/60/60|0)+"小时前":a>=18e4?(a/1e3/60|0)+"分钟前":a<0?"未来":"刚刚"},digit:function(e,t){var i="";e=String(e),t=t||2;for(var n=e.length;n<t;n++)i+="0";return e<Math.pow(10,t)?i+(0|e):e},toDateString:function(e,t){var i=this,n=new Date(e||new Date),a=[i.digit(n.getFullYear(),4),i.digit(n.getMonth()+1),i.digit(n.getDate())],o=[i.digit(n.getHours()),i.digit(n.getMinutes()),i.digit(n.getSeconds())];return t=t||"yyyy-MM-dd HH:mm:ss",t.replace(/yyyy/g,a[0]).replace(/MM/g,a[1]).replace(/dd/g,a[2]).replace(/HH/g,o[0]).replace(/mm/g,o[1]).replace(/ss/g,o[2])},escape:function(e){return String(e||"").replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/'/g,"&#39;").replace(/"/g,"&quot;")},event:function(e,n,a){var o=t("body");return a=a||"click",n=i.event[e]=t.extend(!0,i.event[e],n)||{},i.event.UTIL_EVENT_CALLBACK=i.event.UTIL_EVENT_CALLBACK||{},o.off(a,"*["+e+"]",i.event.UTIL_EVENT_CALLBACK[e]),i.event.UTIL_EVENT_CALLBACK[e]=function(){var i=t(this),a=i.attr(e);"function"==typeof n[a]&&n[a].call(this,i)},o.on(a,"*["+e+"]",i.event.UTIL_EVENT_CALLBACK[e]),n}};!function(e,t,i){"$:nomunge";function n(){a=t[l](function(){o.each(function(){var t=e(this),i=t.width(),n=t.height(),a=e.data(this,u);(i!==a.w||n!==a.h)&&t.trigger(c,[a.w=i,a.h=n])}),n()},r[g])}var a,o=e([]),r=e.resize=e.extend(e.resize,{}),l="setTimeout",c="resize",u=c+"-special-event",g="delay",s="throttleWindow";r[g]=250,r[s]=!0,e.event.special[c]={setup:function(){if(!r[s]&&this[l])return!1;var t=e(this);o=o.add(t),e.data(this,u,{w:t.width(),h:t.height()}),1===o.length&&n()},teardown:function(){if(!r[s]&&this[l])return!1;var t=e(this);o=o.not(t),t.removeData(u),o.length||clearTimeout(a)},add:function(t){function n(t,n,o){var r=e(this),l=e.data(this,u)||{};l.w=n!==i?n:r.width(),l.h=o!==i?o:r.height(),a.apply(this,arguments)}if(!r[s]&&this[l])return!1;var a;return e.isFunction(t)?(a=t,n):(a=t.handler,void(t.handler=n))}}}(t,window),e("util",i)});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -50,7 +50,7 @@
.project-item{
/*float: left;*/
/*width: 200px;*/
height: 140px;
height: 170px;
margin-top: 20px;
margin-left: 20px;
border: 1px solid #ddd;

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -0,0 +1,65 @@
.bookname, .bookdesc {
text-align: center;
}
/*预格式*/
pre {
padding: 10px;
background: #f6f6f6;
border: 1px solid #ddd;
white-space: pre-wrap;
word-wrap: break-word;
white-space: -moz-pre-wrap;
white-space: -o-pre-wrap;
}
/*块代码*/
pre code {
border: none;
background: none;
}
pre ol {
padding-left: 2.5em;
margin: 0;
}
/*行内代码*/
code {
border: 1px solid #ddd;
background: #f6f6f6;
padding: 3px;
border-radius: 3px;
font-size: 14px;
}
/* 引用块 */
blockquote {
color: #666;
border-left: 4px solid #ddd;
padding-left: 20px;
margin-left: 0;
font-size: 14px;
font-style: italic;
}
/* 表格 */
table {
display: block;
width: 100%;
overflow: auto;
word-break: normal;
word-break: keep-all;
margin-bottom: 16px;
}
thead {
display: table-header-group;
vertical-align: middle;
border-color: inherit;
}
table thead tr {
background-color: #F8F8F8;
}
table th, table td {
padding: 6px 13px;
border: 1px solid #ddd;
}
/*公式*/
p.editormd-tex {
text-align: center;
}

View File

@ -5,7 +5,7 @@
<meta charset="UTF-8">
<title>{% block title %}{% endblock %} - 后台管理 - MrDoc</title>
<link rel="icon" href="{% static 'favicon_16.png' %}"/>
<link href="{% static 'layui/css/layui.css' %}" rel="stylesheet">
<link href="{% static 'layui/css/layui.css' %}?version={{mrdoc_version}}" rel="stylesheet">
<style>
.logo img{
height: 30px;
@ -54,12 +54,12 @@
<li class="layui-nav-item layui-nav-itemed">
<a href="{% url 'user_manage' %}"><i class="layui-icon layui-icon-user"></i> 用户管理</a>
</li>
<li class="layui-nav-item layui-nav-itemed">
<a href="{% url 'sys_setting' %}"><i class="layui-icon layui-icon-set-sm"></i> 站点设置</a>
</li>
<li class="layui-nav-item layui-nav-itemed">
<a href="{% url 'register_code_manage' %}"><i class="layui-icon layui-icon-engine"></i> 注册码管理</a>
</li>
<li class="layui-nav-item layui-nav-itemed">
<a href="{% url 'sys_setting' %}"><i class="layui-icon layui-icon-set-sm"></i> 站点设置</a>
</li>
{% endif %}
</ul>
</div>
@ -82,7 +82,7 @@
</div>
</div>
<script src="https://cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>
<script src="{% static 'jquery/3.1.1/jquery.min.js' %}"></script>
<script src="{% static 'layui/layui.all.js' %}"></script>
{% block custom_script %}
{% endblock %}

View File

@ -37,13 +37,13 @@
<div class="layui-form-mid layui-word-aux">开启此选项,新用户注册将需要填写注册码</div>
</div>
<!--<div class="layui-form-item">-->
<!--<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>-->
<div class="layui-form-item">
<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>
<div class="layui-form-item">
<label class="layui-form-label">启用邮箱</label>

View File

@ -15,7 +15,7 @@
<style>
body{
background-color: #fafafa;
text-align: center;
/*text-align: center;*/
}
.container{
display: flex;
@ -55,7 +55,8 @@
<form class="layui-form" action="" method='POST'>
{% csrf_token %}
<div class="layui-form-item">
<h4>你正在访问:<strong><u>{{ project.name }}</u></strong></h4>
<h4>你正在访问:</h4><br>
<strong><u>{{ project.name }}</u></strong>
<br><span style='color:red;margin-bottom: 10px;'>{{ errormsg }}</span>
</div>
<div class="layui-form-item">

View File

@ -9,8 +9,8 @@
<meta http-equiv="Cache-Control" content="max-age=7200" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>{% block title %}{% endblock %} - MrDoc</title>
<link href="{% static 'layui/css/layui.css' %}" rel="stylesheet">
<link rel="stylesheet" href="{% static 'editor.md/css/editormd.css' %}" />
<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 href="{% static 'mrdoc.css' %}?version={{mrdoc_version}}" rel="stylesheet">
<link rel="icon" href="{% static 'favicon_16.png' %}"/>
<style>
@ -160,7 +160,7 @@
}
}
</script>
<script src="{% static 'mrdoc.js' %}"></script>
<script src="{% static 'mrdoc.js?version={{mrdoc_version}}' %}"></script>
{% block custom_script %}
{% endblock %}
</body>

View File

@ -88,7 +88,6 @@
{% block custom_script %}
<script>
//选择文集
form.on('select(project)', function(data){
console.log(data.value); //得到被选中的值
@ -154,8 +153,8 @@
'project':$("#project").val(),
'parent_doc':$("#parent-doc").val(),
'doc_name':$("#doc-name").val(),
//'content':editor.getHTML(),//获取editor解析的HTML
'content':editor.getPreviewedHTML(),//获取预览的HTML
'content':editor.getHTML(),//获取editor解析的HTML
//'content':editor.getPreviewedHTML(),//获取预览的HTML
'pre_content':editor.getMarkdown(),
'sort':$("#sort").val(),
}
@ -188,7 +187,7 @@
});
}
};
//保存文档草稿
//保存草稿
saveDoc = function(){
var data = {
'project':$("#project").val(),

View File

@ -11,11 +11,11 @@
<meta name="keywords" content="{% block keyword %}{% endblock %}mrdoc"/>
<meta name="description" content="{% block description %}{% endblock %}" />
<title>{% block title %}{% endblock %} - MrDoc</title>
<link href="{% static 'layui/css/layui.css' %}" rel="stylesheet">
<link rel="stylesheet" href="{% static 'editor.md/css/editormd.css' %}" />
<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 'prism/prism.css' %}" />-->
<link rel="stylesheet" href="{% static 'katex/katex.min.css' %}" />
<link rel="stylesheet" href="{% static 'share.js/css/share.min.css' %}" />
<link rel="stylesheet" href="{% static 'katex/katex.min.css' %}?version={{mrdoc_version}}" />
<link rel="stylesheet" href="{% static 'share.js/css/share.min.css' %}?version={{mrdoc_version}}" />
<link rel="icon" href="{% static 'favicon_16.png' %}"/>
<link href="{% static 'mrdoc.css' %}?version={{mrdoc_version}}" rel="stylesheet">
<style>

View File

@ -61,7 +61,7 @@
<dd>
<a href="{% url 'manage_doc' %}">
<i class="layui-icon layui-icon-app layui-hide-md"></i>
<span class="layui-hide-xs">管理文档</span>
<span class="layui-hide-xs">个人中心</span>
</a>
</dd>
<dd>

View File

@ -5,7 +5,7 @@
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %} - 个人中心 - MrDoc</title>
<link href="{% static 'layui/css/layui.css' %}" rel="stylesheet">
<link href="{% static 'layui/css/layui.css' %}?version={{mrdoc_version}}" rel="stylesheet">
<link rel="icon" href="{% static 'favicon_16.png' %}"/>
<style>
.logo img{
@ -75,7 +75,7 @@
</div>
</div>
<script src="https://cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>
<script src="{% static 'jquery/3.1.1/jquery.min.js' %}"></script>
<script src="{% static 'layui/layui.all.js' %}"></script>
<script>
var form = layui.form;

View File

@ -26,6 +26,7 @@
<col width="400">
<col width="50">
<col width="100">
<col width="50">
<col width="100">
<col width="150">
</colgroup>
@ -35,7 +36,8 @@
<th>文集简介</th>
<th>文档数量</th>
<th>创建时间</th>
<th>权限</th>
<th>前台下载</th>
<th>阅读权限</th>
<th>操作</th>
</tr>
</thead>
@ -47,6 +49,13 @@
{% load project_filter %}
<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>
{% else %}
<span>禁止</span> <a href="{% url 'modify_pro_download' pro.id %}" title="修改前台下载"><i class="layui-icon layui-icon-edit"></i></a>
{% endif %}
</td>
<td>
<div class="layui-input-inline">
{% if pro.role == 0 %}
@ -56,7 +65,7 @@
{% elif pro.role == 2 %}
<i class="layui-icon layui-icon-group"></i> 指定用户可见 <a href="{% url 'modify_pro_role' pro.id %}" title="修改文集权限"><i class="layui-icon layui-icon-edit"></i></a>
{% elif pro.role == 3 %}
<i class="layui-icon layui-icon-password"></i> 访问码可见 <a href="{% url 'modify_pro_role' pro.id %}" title="修改文集权限"><i class="layui-icon layui-icon-edit"></i></a>
<i class="layui-icon layui-icon-key"></i> 访问码可见 <a href="{% url 'modify_pro_role' pro.id %}" title="修改文集权限"><i class="layui-icon layui-icon-edit"></i></a>
{% endif %}
</div>
</td>
@ -218,9 +227,14 @@
title:"下载导出文档",
area:"300px",
id:"downloadMd",
content:'<p style="text-align:center;color:red;">请尽快下载,避免失效!</p><br><a class="layui-btn layui-btn-fluid" href="'+ download_link + '" download="mrdoc_report_md.zip" >点击下载文件(zip)</a>',
content:'<p style="text-align:center;color:red;">请尽快下载,避免失效!</p><br><a class="layui-btn layui-btn-fluid download-md-link" href="'+ download_link + '" download="mrdoc_report_md.zip" >点击下载文件(zip)</a>',
//btn:['确定','取消'], //添加按钮
//btnAlign:'c', //按钮居中
success: function (layero, index) {
$(layero).find('.download-md-link').click(function () {
layer.close(index);
})
}
})
};
//修改文集权限

View File

@ -0,0 +1,54 @@
{% extends 'app_doc/manage_base.html' %}
{% load staticfiles %}
{% block title %}文集下载状态管理{% endblock %}
{% block content %}
{% if enable_project_report %}
{% else %}
<blockquote class="layui-elem-quote">当前站点未启用前台文集下载功能,修改操作将在功能启用后生效!</blockquote>
{% endif %}
<div class="layui-row" style="margin-bottom: 10px;padding-left:15px;">
<span class="layui-breadcrumb" lay-separator=">">
<a href="{% url 'manage_project' %}">文集管理</a>
<a><cite>下载状态管理</cite></a>
</span>
</div>
<div class="layui-card-header" style="margin-bottom: 10px;">
<div class="layui-row">
<span style="font-size:18px;">修改文集前台下载导出权限
</span>
</div>
</div>
<div class="layui-row">
<form action="{% url 'modify_pro_download' pro.id %}" method="post" class="layui-form">
{% csrf_token %}
<div class="layui-form-item">
<label class="layui-form-label">文集名称</label>
<div class="layui-input-block">
<input type="text" name="title" required value="{{pro.name}}" disabled class="layui-input">
</div>
</div>
{% load project_filter %}
<div class="layui-form-item">
<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%}
lay-skin="switch" lay-text="允许|禁止">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="formDemo">立即修改</button>
</div>
</div>
</form>
</div>
{% endblock %}
{% block custom_script %}
<script>
var form = layui.form;
</script>
{% endblock %}

View File

@ -108,8 +108,8 @@
'project':$("#project").val(),
'parent_doc':$("#parent-doc").val(),
'doc_name':$("#doc-name").val(),
//'content':editor.getHTML(),
'content':editor.getPreviewedHTML(),
'content':editor.getHTML(),
//'content':editor.getPreviewedHTML(),
'pre_content':editor.getMarkdown(),
'sort':$("#sort").val(),
}
@ -126,7 +126,7 @@
}
});
};
//保存文档草稿
//保存草稿
saveDoc = function(){
var data = {
'doc_id':{{ doc.id }},

View File

@ -23,15 +23,18 @@
<!-- 主体 -->
<div class="layui-container project-list-content" style="display:flex;flex-wrap:wrap;">
<!-- 遍历文集列表 -->
{% load project_filter %}
{% for p in project_list %}
<div class="project-item layui-col-md3 layui-col-xs12">
<a href="{% url 'pro_index' p.id %}">
<a href="{% url 'pro_index' p.id %}" title="{{p.name}}">
<div class="layui-card">
<div class="layui-card-header">
<div class="layui-card-header" style="overflow:hidden;white-space: nowrap;text-overflow: ellipsis;">
{% if p.role == 1 %}
<strong><i class="layui-icon layui-icon-password"></i> {{ p.name }}</strong>
{% elif p.role == 2 %}
<strong><i class="layui-icon layui-icon-user"></i> {{ p.name }}</strong>
{% elif p.role == 3 %}
<strong><i class="layui-icon layui-icon-key"></i> {{ p.name }}</strong>
{% else %}
<strong>{{ p.name }}</strong>
{% endif %}
@ -39,6 +42,7 @@
</div>
<div class="layui-card-body">
<p>作者:{{p.create_user}}</p>
<p>最新:<u>{{p.id | get_new_doc}}</u></p>
<p class="tooltip">简介:
{% if p.intro == "" %}
<span class="">此文集没有填写简介</span>

View File

@ -57,4 +57,50 @@
{% endfor %}
</ul>
</div>
{% if enable_project_report %}
<div class="layui-row">
<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>
{% else %}
<a>文集作者未开放此文集的任何格式下载!</a>
{% endif %}
<!--<a href=""><i class="fa fa-download"></i> <u>DOCX文档</u></a>-->
</span>
</p>
</div>
<script>
reportFile = function(pro_id,types){
var data = {'pro_id':pro_id,'types':types};
$.post("{% url 'report_file' %}",data,function(r){
if(r.status){
//文件下载提示
downloadFile(r.data)
}else{
layer.msg("导出文件出错")
}
})
}
//下载文件弹出框
downloadFile = function(download_link){
layer.open({
type:1,
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>',
//btn:['确定','取消'], //添加按钮
//btnAlign:'c', //按钮居中
success: function (layero, index) {
$(layero).find('.download-md-link').click(function () {
layer.close(index);
})
}
})
};
</script>
{% endif %}
{% endblock %}