0.5.9版本更新,更新内容详见change.md

This commit is contained in:
yangjian 2020-09-26 21:27:06 +08:00
parent 7bfae4bbf8
commit bcce8aa448
40 changed files with 2952 additions and 123 deletions

View File

@ -1,5 +1,15 @@
## 版本更新记录
### v0.5.9 2020-09-26
- 新增对Vditor编辑器的支持个人中心可选择编辑器
- 新增文档iframe域名白名单配置后台可设置允许使用的外站iframe视频
- 调整文集目录渲染方式,改为后端渲染;
- 新增文集目录定位跳转,在长目录下当前文档的目录显示在目录最顶端;
- 新增后台配置允许上传的附件格式和附件大小;
- 新增后台配置允许上传的图片大小;
- EditorMD编辑器模式下优化文档页面JS加载按需加载各类JS文件提高文档渲染速度
### v0.5.8 2020-08-30
- 优化和调整首页功能链接和样式;

View File

@ -40,7 +40,7 @@ SECRET_KEY = '5&71mt9@^58zdg*_!t(x6g14q*@84d%ptr%%s6e0l50zs0we3d'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = CONFIG.getboolean('site','debug')
VERSIONS = '0.5.8'
VERSIONS = '0.5.9'
ALLOWED_HOSTS = ['*']

View File

@ -1,6 +1,6 @@
## MrDoc觅道文档 - 记录文档,汇聚思想 - [English](./README_ENG.md)
![mrdoc](https://img.shields.io/badge/MrDoc-v0.5.8-brightgreen.svg) ![python](https://img.shields.io/badge/Python-3.5+-blue.svg) ![mrdoc](https://img.shields.io/badge/Django-v2.2-important.svg)
![mrdoc](https://img.shields.io/badge/MrDoc-v0.5.9-brightgreen.svg) ![python](https://img.shields.io/badge/Python-3.5+-blue.svg) ![mrdoc](https://img.shields.io/badge/Django-v2.2-important.svg)
![Mrdoc首页](./captrue/mrdoc-index.webp)
@ -139,7 +139,7 @@ python manage.py runserver
加入MrDoc交流QQ群:
- 群1付费 **735507293** [![](http://pub.idqqimg.com/wpa/images/group.png "MrDoc交流群")](http://shang.qq.com/wpa/qunwpa?idkey=143c23a4ffbd0ba9137d2bce3ee86c83532c05259a0542a69527e36615e64dba)
- **735507293** [![](http://pub.idqqimg.com/wpa/images/group.png "MrDoc交流群")](http://shang.qq.com/wpa/qunwpa?idkey=143c23a4ffbd0ba9137d2bce3ee86c83532c05259a0542a69527e36615e64dba)
### 3、联系作者

View File

@ -1,6 +1,6 @@
## MrDoc - Writing documents, gathering ideas
![mrdoc](https://img.shields.io/badge/MrDoc-v0.5.8-brightgreen.svg) ![python](https://img.shields.io/badge/Python-3.5+-blue.svg) ![mrdoc](https://img.shields.io/badge/Django-v2.2-important.svg)
![mrdoc](https://img.shields.io/badge/MrDoc-v0.5.9-brightgreen.svg) ![python](https://img.shields.io/badge/Python-3.5+-blue.svg) ![mrdoc](https://img.shields.io/badge/Django-v2.2-important.svg)
![Mrdoc首页](./captrue/mrdoc-index.webp)

View File

@ -14,7 +14,7 @@ def sys_setting(request):
# 设置debug状态
setting_dict['debug'] = settings.DEBUG
# 获取系统设置状态
datas = SysSetting.objects.filter(types="basic")
datas = SysSetting.objects.filter(types__in=["basic","doc"])
for data in datas:
setting_dict[data.name] = data.value
return setting_dict

View File

@ -0,0 +1,28 @@
# Generated by Django 2.2.12 on 2020-09-05 22:25
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('app_admin', '0007_auto_20200222_1106'),
]
operations = [
migrations.CreateModel(
name='UserOptions',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('editor_mode', models.IntegerField(default=1, verbose_name='编辑器选项')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': '用户设置',
'verbose_name_plural': '用户设置',
},
),
]

View File

@ -8,7 +8,6 @@ class SysSetting(models.Model):
value = models.TextField(verbose_name="内容",null=True,blank=True)
types = models.CharField(verbose_name="类型",max_length=10,default="basic")
def __str__(self):
return self.name
@ -16,6 +15,21 @@ class SysSetting(models.Model):
verbose_name = '系统设置'
verbose_name_plural = verbose_name
# 用户选项配置
class UserOptions(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE)
# 用户配置的编辑器选项1表示Editormd编辑器2表示Vditor编辑器默认为1
editor_mode = models.IntegerField(default=1,verbose_name="编辑器选项")
def __str__(self):
return self.user
class Meta:
verbose_name = '用户设置'
verbose_name_plural = verbose_name
# 电子邮件验证码模型
class EmaiVerificationCode(models.Model):
email_name = models.EmailField(verbose_name="电子邮箱")

View File

@ -342,7 +342,7 @@ def admin_project(request):
search_kw = request.GET.get('kw','')
if search_kw == '':
project_list = Project.objects.all().order_by('-create_time')
paginator = Paginator(project_list,20)
paginator = Paginator(project_list,10)
page = request.GET.get('page',1)
try:
projects = paginator.page(page)
@ -352,7 +352,7 @@ def admin_project(request):
projects = paginator.page(paginator.num_pages)
else:
project_list = Project.objects.filter(intro__icontains=search_kw)
paginator = Paginator(project_list, 20)
paginator = Paginator(project_list, 10)
page = request.GET.get('page', 1)
try:
@ -625,6 +625,7 @@ def admin_setting(request):
)
return render(request,'app_admin/admin_setting.html',locals())
# 邮箱设置
elif types == 'email':
# 读取上传的参数
emailer = request.POST.get("send_emailer",None)
@ -679,3 +680,47 @@ def admin_setting(request):
email_ssl = email_settings.get(name="smtp_ssl")
email_pwd = email_settings.get(name="pwd")
return render(request, 'app_admin/admin_setting.html',locals())
# 文档全局设置
elif types == 'doc':
# iframe白名单
iframe_whitelist = request.POST.get('iframe_whitelist','')
SysSetting.objects.update_or_create(
name = 'iframe_whitelist',
defaults = {'value':iframe_whitelist,'types':'doc'}
)
# 上传图片大小
img_size = request.POST.get('img_size', 10)
try:
if int(img_size) == 0:
img_size = 50
else:
img_size = abs(int(img_size))
except Exception as e:
# print(repr(e))
img_size = 10
SysSetting.objects.update_or_create(
name='img_size',
defaults={'value': img_size, 'types': 'doc'}
)
# 附件格式白名单
attachment_suffix = request.POST.get('attachment_suffix','')
SysSetting.objects.update_or_create(
name = 'attachment_suffix',
defaults = {'value':attachment_suffix,'types':'doc'}
)
# 附件大小
attachment_size = request.POST.get('attachment_size',50)
try:
if int(attachment_size) == 0:
attachment_size = 50
else:
attachment_size = abs(int(attachment_size))
except Exception as e:
# print(repr(e))
attachment_size = 50
SysSetting.objects.update_or_create(
name='attachment_size',
defaults={'value': attachment_size, 'types': 'doc'}
)
return render(request, 'app_admin/admin_setting.html', locals())

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2.12 on 2020-09-05 22:25
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app_doc', '0024_doctag_tag'),
]
operations = [
migrations.AddField(
model_name='doc',
name='editor_mode',
field=models.IntegerField(default=1, max_length=20, verbose_name='编辑器模式'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2.12 on 2020-09-05 22:25
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app_doc', '0025_doc_editor_mode'),
]
operations = [
migrations.AlterField(
model_name='doc',
name='editor_mode',
field=models.IntegerField(default=1, verbose_name='编辑器模式'),
),
]

View File

@ -0,0 +1,26 @@
# Generated by Django 2.2.12 on 2020-09-12 21:14
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('app_doc', '0026_auto_20200905_2225'),
]
operations = [
migrations.CreateModel(
name='ProjectToc',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('value', models.TextField(verbose_name='文集文档层级目录')),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app_doc.Project')),
],
options={
'verbose_name': '文集目录',
'verbose_name_plural': '文集目录',
},
),
]

View File

@ -42,6 +42,18 @@ class ProjectCollaborator(models.Model):
verbose_name = '文集协作'
verbose_name_plural = verbose_name
# 文集目录模型
class ProjectToc(models.Model):
project = models.ForeignKey(Project,on_delete=models.CASCADE)
value = models.TextField(verbose_name="文集文档层级目录")
def __str__(self):
return self.project
class Meta:
verbose_name = '文集目录'
verbose_name_plural = verbose_name
# 文档模型
class Doc(models.Model):
name = models.CharField(verbose_name="文档标题",max_length=50)
@ -55,6 +67,8 @@ class Doc(models.Model):
modify_time = models.DateTimeField(auto_now=True)
# 文档状态说明0表示草稿状态1表示发布状态2表示删除状态
status = models.IntegerField(choices=((0,0),(1,1)),default=1,verbose_name='文档状态')
# 编辑器模式1表示Editormd编辑器2表示Vditor编辑器
editor_mode = models.IntegerField(default=1,verbose_name='编辑器模式')
def __str__(self):
return self.name

View File

@ -5,6 +5,7 @@ from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth.decorators import login_required # 登录需求装饰器
import datetime,time,json,base64,os,uuid
from app_doc.models import Image,ImageGroup
from app_admin.models import SysSetting
@login_required()
@csrf_exempt
@ -27,7 +28,7 @@ def upload_img(request):
else:
group_id = None
print('分组ID',group_id)
# print('分组ID',group_id)
if img:# 上传普通图片文件
result = img_upload(img, dir_name,request.user)
elif manage_upload:
@ -35,7 +36,7 @@ def upload_img(request):
elif base_img: # 上传base64编码图片
result = base_img_upload(base_img,dir_name,request.user)
else:
result = {"success": 0, "message": "出错信息"}
result = {"success": 0, "message": "上传出错"}
return HttpResponse(json.dumps(result), content_type="application/json")
# 目录创建
@ -50,13 +51,23 @@ def upload_generation_dir(dir_name=''):
# 普通图片上传
def img_upload(files, dir_name, user, group_id=None):
#允许上传文件类型
# 允许上传文件类型
allow_suffix =["jpg", "jpeg", "gif", "png", "bmp", "webp"]
file_suffix = files.name.split(".")[-1] # 提取图片格式
# 判断图片格式
if file_suffix.lower() not in allow_suffix:
return {"success": 0, "message": "图片格式不正确"}
# 判断图片的大小
try:
allow_image_size = SysSetting.objects.get(types='doc', name='img_size')
allow_img_size = int(allow_image_size.value) * 1048576
except Exception as e:
# print(repr(e))
allow_img_size = 10485760
if files.size > allow_img_size:
return {"success": 0, "message": "图片大小超出{}MB".format(allow_img_size / 1048576)}
relative_path = upload_generation_dir(dir_name)
file_name = files.name.replace(file_suffix,'').replace('.','') + '_' +str(int(time.time())) + '.' + file_suffix
path_file=os.path.join(relative_path, file_name)

View File

@ -14,8 +14,10 @@ from loguru import logger
import datetime
import traceback
import re
import json
import random
from app_doc.report_utils import *
from app_admin.models import UserOptions,SysSetting
from app_admin.decorators import check_headers,allow_report_file
import os.path
@ -25,6 +27,80 @@ def validateTitle(title):
new_title = re.sub(rstr, "_", title) # 替换为下划线
return new_title
# 获取文集的文档目录
def get_pro_toc(pro_id):
# try:
# project = Project.objects.get(id=pro_id)
# pro_toc = ProjectToc.objects.get(project=project)
# doc_list = json.loads(pro_toc.value)
# print("使用缓存")
# except:
# print("重新生成")
# 查询存在上级文档的文档
parent_id_list = Doc.objects.filter(top_doc=pro_id, status=1).exclude(parent_doc=0).values_list('parent_doc',
flat=True)
# 获取存在上级文档的上级文档ID
# print(parent_id_list)
doc_list = []
n = 0
# 获取一级文档
top_docs = Doc.objects.filter(top_doc=pro_id, parent_doc=0, status=1).values('id', 'name').order_by('sort')
# 遍历一级文档
for doc in top_docs:
top_item = {
'id': doc['id'],
'name': doc['name'],
# 'spread': True,
# 'level': 1
}
# 如果一级文档存在下级文档,查询其二级文档
if doc['id'] in parent_id_list:
# 获取二级文档
sec_docs = Doc.objects.filter(
top_doc=pro_id, parent_doc=doc['id'], status=1).values('id', 'name').order_by('sort')
top_item['children'] = []
for doc in sec_docs:
sec_item = {
'id': doc['id'],
'name': doc['name'],
# 'level': 2
}
# 如果二级文档存在下级文档,查询第三级文档
if doc['id'] in parent_id_list:
# 获取三级文档
thr_docs = Doc.objects.filter(
top_doc=pro_id, parent_doc=doc['id'], status=1).values('id','name').order_by('sort')
sec_item['children'] = []
for doc in thr_docs:
item = {
'id': doc['id'],
'name': doc['name'],
# 'level': 3
}
sec_item['children'].append(item)
n += 1
top_item['children'].append(sec_item)
n += 1
else:
top_item['children'].append(sec_item)
n += 1
doc_list.append(top_item)
n += 1
# 如果一级文档没有下级文档,直接保存
else:
doc_list.append(top_item)
n += 1
# 将文集的大纲目录写入数据库
# ProjectToc.objects.create(
# project = project,
# value = json.dumps(doc_list)
# )
# print(doc_list,n)
# if n > 999:
# return ([],n)
# else:
return (doc_list,n)
# 文集列表(首页)
@logger.catch()
def project_list(request):
@ -199,7 +275,6 @@ def create_project(request):
logger.exception("创建文集出错")
return JsonResponse({'status':False,'data':'出现异常,请检查输入值!'})
# 文集页
@require_http_methods(['GET'])
@check_headers
@ -208,6 +283,9 @@ def project_index(request,pro_id):
try:
# 获取文集信息
project = Project.objects.get(id=int(pro_id))
# 获取文集的文档目录
toc_list,toc_cnt = get_pro_toc(pro_id)
# toc_list,toc_cnt = ([],1000)
# 获取文集的协作用户信息
if request.user.is_authenticated: # 对登陆用户查询其协作文档信息
colla_user = ProjectCollaborator.objects.filter(project=project,user=request.user).count()
@ -262,24 +340,33 @@ def project_index(request,pro_id):
# 修改文集
@login_required()
@require_http_methods(['POST'])
@require_http_methods(['GET','POST'])
def modify_project(request):
try:
pro_id = request.POST.get('pro_id',None)
project = Project.objects.get(id=pro_id)
if request.method == 'GET':
pro_id = request.GET.get('pro_id', None)
pro = Project.objects.get(id=pro_id)
# 验证用户有权限修改文集
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 = validateTitle(name)
project.intro = content
project.save()
return JsonResponse({'status':True,'data':'修改成功'})
if (request.user == pro.create_user) or request.user.is_superuser:
return render(request,'app_doc/manage_project_options.html',locals())
else:
return JsonResponse({'status':False,'data':'非法请求'})
except Exception as e:
logger.exception("修改文集出错")
return JsonResponse({'status':False,'data':'请求出错'})
return Http404
elif request.method == 'POST':
try:
pro_id = request.POST.get('pro_id',None)
project = Project.objects.get(id=pro_id)
# 验证用户有权限修改文集
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 = validateTitle(name)
project.intro = content
project.save()
return JsonResponse({'status':True,'data':'修改成功'})
else:
return JsonResponse({'status':False,'data':'非法请求'})
except Exception as e:
logger.exception("修改文集出错")
return JsonResponse({'status':False,'data':'请求出错'})
# 修改文集权限
@ -529,6 +616,8 @@ def doc(request,pro_id,doc_id):
if pro_id != '' and doc_id != '':
# 获取文集信息
project = Project.objects.get(id=int(pro_id))
# 获取文集的文档目录
toc_list,toc_cnt = get_pro_toc(pro_id)
# 获取文集的协作用户信息
if request.user.is_authenticated:
colla_user = ProjectCollaborator.objects.filter(project=project,user=request.user)
@ -585,13 +674,26 @@ def doc(request,pro_id,doc_id):
@require_http_methods(['GET',"POST"])
@logger.catch()
def create_doc(request):
# 获取用户的编辑器模式
try:
user_opt = UserOptions.objects.get(user=request.user)
if user_opt.editor_mode == 1:
editor_mode = 1
elif user_opt.editor_mode == 2:
editor_mode = 2
except ObjectDoesNotExist:
editor_mode = 1
if request.method == 'GET':
try:
pid = request.GET.get('pid',-999)
project_list = Project.objects.filter(create_user=request.user) # 自己创建的文集列表
colla_project_list = ProjectCollaborator.objects.filter(user=request.user) # 协作的文集列表
doctemp_list = DocTemp.objects.filter(create_user=request.user).values('id','name','create_time')
return render(request,'app_doc/create_doc.html',locals())
# 根据编辑器模式返回不同的模板
if editor_mode == 1:
return render(request, 'app_doc/create_doc.html', locals())
elif editor_mode == 2:
return render(request, 'app_doc/create_doc_vditor.html', locals())
except Exception as e:
logger.exception("访问创建文档页面出错")
return render(request,'404.html')
@ -623,7 +725,8 @@ def create_doc(request):
top_doc= int(project),
sort = sort if sort != '' else 99,
create_user=request.user,
status = status
status = status,
editor_mode = editor_mode
)
# 设置文档标签
for t in doc_tags.split(","):
@ -653,6 +756,15 @@ def create_doc(request):
@login_required()
@require_http_methods(['GET',"POST"])
def modify_doc(request,doc_id):
# 获取用户的编辑器模式
try:
user_opt = UserOptions.objects.get(user=request.user)
if user_opt.editor_mode == 1:
editor_mode = 1
elif user_opt.editor_mode == 2:
editor_mode = 2
except ObjectDoesNotExist:
editor_mode = 1
if request.method == 'GET':
try:
doc = Doc.objects.get(id=doc_id) # 查询文档信息
@ -674,7 +786,12 @@ def modify_doc(request,doc_id):
doc_list = Doc.objects.filter(top_doc=project.id)
doctemp_list = DocTemp.objects.filter(create_user=request.user)
history_list = DocHistory.objects.filter(doc=doc).order_by('-create_time')
return render(request,'app_doc/modify_doc.html',locals())
# 获取用户的编辑器模式
if editor_mode == 1:
return render(request, 'app_doc/modify_doc.html', locals())
elif editor_mode == 2:
return render(request, 'app_doc/modify_doc_vditor.html', locals())
else:
return render(request,'403.html')
except Exception as e:
@ -722,7 +839,8 @@ def modify_doc(request,doc_id):
parent_doc=int(parent_doc) if parent_doc != '' else 0,
sort=sort if sort != '' else 99,
modify_time = datetime.datetime.now(),
status = status
status = status,
editor_mode = editor_mode
)
# 更新文档标签
doc_tag_list = doc_tags.split(",") if doc_tags != "" else []
@ -1196,8 +1314,20 @@ def fast_publish_doc(request):
@require_http_methods(['GET',"POST"])
def create_doctemp(request):
if request.method == 'GET':
# 获取用户的编辑器模式
try:
user_opt = UserOptions.objects.get(user=request.user)
if user_opt.editor_mode == 1:
editor_mode = 1
elif user_opt.editor_mode == 2:
editor_mode = 2
except ObjectDoesNotExist:
editor_mode = 1
doctemps = DocTemp.objects.filter(create_user=request.user)
return render(request,'app_doc/create_doctemp.html',locals())
if editor_mode == 1:
return render(request,'app_doc/create_doctemp.html',locals())
else:
return render(request, 'app_doc/create_doctemp_vditor.html', locals())
elif request.method == 'POST':
try:
name = request.POST.get('name','')
@ -1225,8 +1355,20 @@ def modify_doctemp(request,doctemp_id):
try:
doctemp = DocTemp.objects.get(id=doctemp_id)
if request.user.id == doctemp.create_user.id:
# 获取用户的编辑器模式
try:
user_opt = UserOptions.objects.get(user=request.user)
if user_opt.editor_mode == 1:
editor_mode = 1
elif user_opt.editor_mode == 2:
editor_mode = 2
except ObjectDoesNotExist:
editor_mode = 1
doctemps = DocTemp.objects.filter(create_user=request.user)
return render(request,'app_doc/modify_doctemp.html',locals())
if editor_mode == 1:
return render(request,'app_doc/modify_doctemp.html',locals())
else:
return render(request, 'app_doc/modify_doctemp_vditor.html', locals())
else:
return HttpResponse('非法请求')
except Exception as e:
@ -1863,6 +2005,7 @@ def manage_attachment(request):
if request.method == 'GET':
try:
search_kw = request.GET.get('kw', None)
# 搜索附件
if search_kw:
attachment_list = Attachment.objects.filter(
user=request.user,
@ -1877,6 +2020,7 @@ def manage_attachment(request):
except EmptyPage:
attachments = paginator.page(paginator.num_pages)
attachments.kw = search_kw
# 所有附件
else:
attachment_list = Attachment.objects.filter(user=request.user).order_by('-create_time')
paginator = Paginator(attachment_list, 15)
@ -1897,13 +2041,32 @@ def manage_attachment(request):
if types in ['0',0]:
attachment = request.FILES.get('attachment_upload',None)
if attachment:
attachment_name = attachment.name
attachment_size = sizeFormat(attachment.size)
# 限制附件大小在50mb以内
if attachment.size > 52428800:
attachment_name = attachment.name # 获取附件文件名
attachment_size = sizeFormat(attachment.size) # 获取附件文件大小
# 限制附件大小
# 获取系统设置的附件文件大小如果不存在默认50MB
try:
allow_attachment_size = SysSetting.objects.get(types='doc',name='attachment_size')
allow_attach_size = int(allow_attachment_size.value) * 1048576
except Exception as e:
# print(repr(e))
allow_attach_size = 52428800
if attachment.size > allow_attach_size:
return JsonResponse({'status':False,'data':'文件大小超出限制'})
# 限制附件为ZIP格式文件
if attachment_name.endswith('.zip'):
# 限制附件格式
# 获取系统设置允许的附件格式如果不存在默认仅允许zip格式文件
try:
attacement_suffix_list = SysSetting.objects.get(types='doc',name='attachment_suffix')
attacement_suffix_list = attacement_suffix_list.value.split(',')
except ObjectDoesNotExist:
attachment_suffix_list = ['zip']
allow_attachment = False
for suffix in attacement_suffix_list:
if attachment_name.split('.')[-1] in attacement_suffix_list:
allow_attachment = True
if allow_attachment:
a = Attachment.objects.create(
file_name = attachment_name,
file_size = attachment_size,
@ -2347,11 +2510,18 @@ def tag_doc(request,tag_id,doc_id):
def manage_self(request):
if request.method == 'GET':
user = User.objects.get_by_natural_key(request.user)
try:
user_opt = UserOptions.objects.get(user=request.user)
except ObjectDoesNotExist:
user_opt = []
return render(request,'app_doc/manage_self.html',locals())
elif request.method == 'POST':
first_name = request.POST.get('first_name','')
email = request.POST.get('email',None)
first_name = request.POST.get('first_name','') # 昵称
email = request.POST.get('email',None) # 电子邮箱
editor_mode = request.POST.get('editor_mode',1) # 编辑器
user = User.objects.get_by_natural_key(request.user)
if len(first_name) < 2 or len(first_name) > 10:
return JsonResponse({'status': False, 'data': '昵称长度不得小于2位大于10位'})
if User.objects.filter(first_name=first_name).count() > 0 and user.first_name != first_name:
return JsonResponse({'status':False,'data':'昵称已被使用'})
if User.objects.filter(email=email).count() > 0 and user.email != email:
@ -2360,6 +2530,10 @@ def manage_self(request):
user.email = email
user.first_name = first_name
user.save()
user_opt = UserOptions.objects.update_or_create(
user = user,
defaults={'editor_mode':editor_mode}
)
return JsonResponse({'status':True,'data':'ok'})
else:
return JsonResponse({'status':False,'data':'参数不正确'})

File diff suppressed because one or more lines are too long

View File

@ -3484,8 +3484,9 @@
var begin = "";
var end = "";
// console.log(href,title,text)
// console.log(iframe_whitelist)
if(/^=(.*?)/.test(text)){
console.log(text)
// console.log(text)
switch(text){
case '=video':
if(href.match(/^.+.(mp4|m4v|ogg|ogv|webm)$/)){
@ -3497,7 +3498,7 @@
return "<audio src='"+ href + "' controls='controls'></audio>"
}
break;
case '=video_iframe':
case '=video_iframe':
const youtubeMatch = href.match(/\/\/(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))([\w|-]{11})(?:(?:[\?&]t=)(\S+))?/);
const youkuMatch = href.match(/\/\/v\.youku\.com\/v_show\/id_(\w+)=*\.html/);
const qqMatch = href.match(/\/\/v\.qq\.com\/x\/cover\/.*\/([^\/]+)\.html\??.*/);
@ -3523,7 +3524,14 @@
return `<iframe height=400 width=500 frameborder=0 allowfullscreen src="//player.bilibili.com/player.html?bvid=${bilibiliMatch[1]}">`
} else if (tedMatch && tedMatch[1]) {
return `<iframe height=400 width=500 frameborder=0 allowfullscreen src="//embed.ted.com/talks/${tedMatch[1]}">`
}else{
for(var i = 0; i< iframe_whitelist.length; i++){
if(href.match(iframe_whitelist[i])){
return '<iframe height=400 width=500 src="' + href +'" frameborder=0 allowfullscreen />'
}
}
}
break;
// return '<iframe height=400 width=500 src="' + href +'" frameborder=0 allowfullscreen />'
}
}
@ -4130,7 +4138,7 @@
markdown : "",
markdownSourceCode : false,
htmlDecode : false,
autoLoadKaTeX : true,
autoLoadKaTeX : false, // 自动默认加载katex的js
pageBreak : true,
atLink : true, // for @link
emailLink : true, // for mail address auto link
@ -4232,22 +4240,49 @@
if (!editormd.isIE8)
{
// 渲染流程图
if (settings.flowChart) {
div.find(".flowchart").flowChart();
var has_flowchart = false;
div.find(".flowchart").each(function(){
console.log("渲染流程图");
has_flowchart = true;
})
if(has_flowchart){
editormd.loadScript('/static/editor.md/lib/flowchart.min',function(){
editormd.loadScript('/static/editor.md/lib/jquery.flowchart.min',function(){
div.find(".flowchart").flowChart();
})
})
}
}
// 渲染时序图
if (settings.sequenceDiagram) {
div.find(".sequence-diagram").sequenceDiagram({theme: "simple"});
var has_sequence_dia = false;
div.find(".sequence-diagram").each(function(){
console.log("渲染时序图");
has_sequence_dia = true;
})
if(has_sequence_dia){
editormd.loadScript('/static/editor.md/lib/sequence-diagram.min',function(){
div.find(".sequence-diagram").sequenceDiagram({theme: "simple"});
})
}
// div.find(".sequence-diagram").sequenceDiagram({theme: "simple"});
}
}
// 渲染公式
if (settings.tex)
{
var katexHandle = function() {
div.find("." + editormd.classNames.tex).each(function(){
var tex = $(this);
katex.render(tex.html().replace(/&lt;/g, "<").replace(/&gt;/g, ">"), tex[0]);
tex.find(".katex").css("font-size", "1.6em");
var tex = $(this);
editormd.loadKaTeX(function(){
editormd.$katex = katex;
editormd.kaTeXLoaded = true;
katex.render(tex.html().replace(/&lt;/g, "<").replace(/&gt;/g, ">"), tex[0]);
tex.find(".katex").css("font-size", "1.6em");
})
});
};
if (settings.autoLoadKaTeX && !editormd.$katex && !editormd.kaTeXLoaded)
@ -4269,9 +4304,18 @@
// console.log("前台渲染脑图")
var mindmapHandle = function(){
div.find(".mindmap").each(function(){
console.log("存在脑图")
var mmap = $(this);
var md_data = window.markmap.transform(mmap.text().trim());
window.markmap.markmap("svg#"+this.id,md_data)
var mmap_id = this.id;
editormd.loadScript('/static/mindmap/d3@5',function(){
editormd.loadScript('/static/mindmap/transform.min',function(){
editormd.loadScript('/static/mindmap/view.min',function(){
var md_data = window.markmap.transform(mmap.text().trim());
window.markmap.markmap("svg#"+mmap_id,md_data)
})
})
})
});
};
mindmapHandle();
@ -4279,20 +4323,26 @@
// 前台渲染 Echart
if(settings.echart){
// console.log("前台解析echart")
var echartHandle = function(){
div.find(".echart").each(function(){
// console.log("存在echart")
var echart = $(this);
if(echart.text() != ''){
var echart_data = eval("(" + echart.text() + ")");
echart.empty();
var myChart = echarts.init(document.getElementById(this.id),null,{renderer: 'svg'});
myChart.setOption(echart_data);
}
var echart_id = this.id
editormd.loadEcharts(
function(){
if(echart.text() != ''){
// console.log("渲染echarts")
var echart_data = eval("(" + echart.text() + ")");
echart.empty();
var myChart = echarts.init(document.getElementById(echart_id),null,{renderer: 'svg'});
myChart.setOption(echart_data);
}
}
);
});
};
echartHandle();
}
@ -4469,7 +4519,7 @@
*/
editormd.loadEcharts = function (callback) {
editormd.loadScript("/static/editor.md/lib/katex.min", callback || function(){});
editormd.loadScript("/static/editor.md/lib/echarts.min", callback || function(){});
};
/**

Binary file not shown.

View File

@ -1,6 +1,7 @@
(function () {
'use strict';
var toc_cnt = $(".markdown-toc-list").children().length;
// console.log(toc_cnt)
if(toc_cnt > 0){
// console.log('显示文档目录')
$(".tocMenu").show();
@ -32,14 +33,19 @@ function initSidebar(sidebarQuery, contentQuery) {
var scrollFlagTimer
sidebar.addEventListener('click', function (e) {
e.preventDefault()
console.log(e.target.dataset.id)
if (e.target.href) {
scrollFlag = 1
clearTimeout(scrollFlagTimer)
scrollFlagTimer = setTimeout(() => scrollFlag = 0, 1500)
setActive(e.target, sidebar)
var target = document.getElementById(e.target.getAttribute('href').slice(1))
//console.log(e,target)
//console.log(e.target.getAttribute('href').slice(1))
// console.log(e,target)
// console.log(e.target.getAttribute('href').slice(1))
target.scrollIntoView({ behavior: 'smooth', block: "start" })
}else if(e.target.dataset.id){
console.log('vditor目录')
var target = document.getElementById(e.target.dataset.id)
target.scrollIntoView({ behavior: 'smooth', block: "start" })
}
});

File diff suppressed because one or more lines are too long

10
static/viewerjs/viewer.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -7,6 +7,7 @@
<link rel="icon" href="{% static 'search/mrdoc_logo_300.png' %}" sizes="192x192" />
<link href="{% static 'layui/css/layui.css' %}?version={{mrdoc_version}}" rel="stylesheet">
<link href="{% static 'mrdoc/mrdoc-admin.css' %}?version={{mrdoc_version}}" rel="stylesheet">
<link href="{% static 'tagsInput/tagsinput.css' %}" rel="stylesheet" type="text/css"/>
<style>
</style>
@ -81,7 +82,7 @@
<div class="layui-footer" style="text-align:center;font-size: 12px;">
<!-- 底部固定区域 -->
© <a href="https://gitee.com/zmister/MrDoc" target="_blank">MrDoc 2019-2020</a>&nbsp;-&nbsp;
© <a href="https://zmister.com/mrdoc/" target="_blank">MrDoc 2019-2020</a>&nbsp;-&nbsp;
当前版本:<a href="https://gitee.com/zmister/MrDoc/tree/{{mrdoc_version}}/" target="_blank">{{mrdoc_version}}</a>&nbsp;-&nbsp;
<a href="https://github.com/zmister2016/MrDoc" target="_blank">GitHub</a>&nbsp;-&nbsp;
<a href="https://gitee.com/zmister/MrDoc" target="_blank">码云</a>&nbsp;-&nbsp;
@ -91,6 +92,7 @@
<script src="{% static 'jquery/3.1.1/jquery.min.js' %}"></script>
<script src="{% static 'layui/layui.all.js' %}"></script>
<script src="{% static '/tagsInput/tagsinput.js' %}" type="text/javascript" charset="utf-8"></script>
<script>
var form = layui.form;
$.ajaxSetup({

View File

@ -20,7 +20,7 @@
</form>
</div>
<div class="layui-row" >
<table class="layui-table" id="doctemp-list" lay-skin="nob" lay-size='sm' lay-even>
<table class="layui-table" id="doctemp-list" lay-skin="nob" lay-size='' lay-even>
<colgroup>
<col width="90">
<col width="120">

View File

@ -13,7 +13,7 @@
<ul class="layui-tab-title">
<li class="layui-this">基础设置</li>
<li>邮箱设置</li>
<!--<li>广告设置</li>-->
<li>文档设置</li>
</ul>
<div class="layui-tab-content">
<!-- 网站设置 -->
@ -152,9 +152,60 @@
</form>
</div>
<!-- 邮箱设置结束 -->
<!-- 广告设置 -->
<div class="layui-tab-item">内容3</div>
<!-- 广告设置结束 -->
<!-- 全局文档设置 -->
<div class="layui-tab-item">
<form action="" method="post" class="layui-form">
{% csrf_token %}
<input type="text" name="type" hidden value="doc">
<div class="layui-form-item" style="" id="role-user">
<label class="layui-form-label">ifrme白名单</label>
<div class="layui-input-inline">
<div class="tagsinput-primary form-group">
<input name="iframe_whitelist" id="iframe_whitelist" class="tagsinput" data-role="tagsinput" value="{% if iframe_whitelist != '' %}{{iframe_whitelist}}{% endif %}" placeholder="请输入域名">
</div>
</div>
<div class="layui-form-mid layui-word-aux">默认支持YouTube、优酷、QQ视频、Facebook、哔哩哔哩、TED网站仅用于EditorMD编辑器模式</div>
</div>
<div class="layui-form-item" style="" id="role-user">
<label class="layui-form-label">图片大小</label>
<div class="layui-input-inline">
<div class="tagsinput-primary form-group">
<input class="layui-input" type="number" name="img_size" id="img_size" value="{% if img_size != '' %}{{img_size}}{% endif %}" placeholder="">
</div>
</div>
<div class="layui-form-mid layui-word-aux">默认限制图片大小10MB单位MB</div>
</div>
<div class="layui-form-item" style="" id="role-user">
<label class="layui-form-label">附件格式</label>
<div class="layui-input-inline">
<div class="tagsinput-primary form-group">
<input name="attachment_suffix" id="attachment_suffix" class="tagsinput" data-role="tagsinput" value="{% if attachment_suffix != '' %}{{attachment_suffix}}{% endif %}" placeholder="不带.号的格式后缀">
</div>
</div>
<div class="layui-form-mid layui-word-aux">默认支持.zip文件格式</div>
</div>
<div class="layui-form-item" style="" id="role-user">
<label class="layui-form-label">附件大小</label>
<div class="layui-input-inline">
<div class="tagsinput-primary form-group">
<input class="layui-input" type="number" name="attachment_size" id="attachment_size" value="{% if attachment_size != '' %}{{attachment_size}}{% endif %}" placeholder="">
</div>
</div>
<div class="layui-form-mid layui-word-aux">默认限制附件文件大小50MB单位MB</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>
</form>
</div>
<!-- 全局文档设置结束 -->
</div>
</div>
</div>

View File

@ -178,7 +178,10 @@
</div>
<!-- 右侧编辑器结束 -->
</div>
<script>
// 视频iframe域名白名单
var iframe_whitelist = '{{ iframe_whitelist }}'.split(',')
</script>
<script src="{% static 'jquery/3.1.1/jquery.min.js' %}"></script>
<script src="{% static 'layui/layui.all.js' %}"></script>
<!-- <script src="{% static 'editor.md/lib/marked.min.js' %}"></script> -->
@ -203,6 +206,7 @@
$.ajaxSetup({
data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
});
// console.log('{{ iframe_whitelist }}')
var tree = layui.tree;
//加载页面时执行一次
changeSidebar();
@ -261,7 +265,7 @@
var editor = editormd("editor-md", {
width : "100%",
height : "800px",
placeholder : "开始使用Markdown书写MrDoc文档编辑器支持以下功能\n1.粘贴上传图片\n2.六级标题\n3.代码高亮\n4.本地图片和外链图片\n5.表格\n6.多级列表和任务列表\n7.Katex公式\n8.流程图\n9.时序图\n……",
placeholder : "道友,开始吧……",
toolbarIcons : function() {
return [
"undo", "redo", "|",
@ -665,7 +669,7 @@
<!-- 选择和上传附件div -->
<div id="upload-attach" style="display:none;margin:20px;">
<span>* 仅支持.zip格式的压缩文件作为附件文件大小不超过50Mb</span>
<span>* 仅支持 {% if attachment_suffix != '' %}{{attachment_suffix}}{% else %}zip{% endif %} 格式文件,文件大小不超过 {% if attachment_size != '' %}{{attachment_size}}{% else %}50{% endif %}MB</span>
<div style="margin: 10px 0 0 10px;">
<button class="layui-btn layui-btn-normal layui-btn-sm" id="upload_attachment"><i class="layui-icon layui-icon-upload"></i> 点击上传附件</button>
<a class="layui-btn layui-btn-normal layui-btn-sm" href="{% url 'manage_attachment' %}" target="_blank"><i class="fa fa-cubes"></i> 管理附件</a>
@ -766,13 +770,16 @@
layer.msg("上传成功");
}else{
layer.closeAll();
layer.msg("上传出错,请重试!")
layer.msg(res.message)
}
},
error:function(){
layer.closeAll('loading'); //关闭loading
layer.msg("系统异常,请稍后再试!")
},
accept: 'images', //允许上传的文件类型
acceptMime:'image/*',
field:'manage_upload',
size: 5120, //最大允许上传的图片大小
});
// 按钮选择上传附件
@ -795,9 +802,7 @@
}
},
accept: 'file', //允许上传的文件类型
exts:'zip', //允许上传zip压缩文件
field:'attachment_upload',
size: 51200, //最大允许上传的文件大小
})
//修改预览div中a标签链接新窗口打开
@ -816,7 +821,7 @@
function looksLikeTable(data) {
return true
};
// 编辑器侦听paste粘贴事件
// 表格输入框侦听paste粘贴事件
var pasteExcel = document.getElementById('pasteExcel')
pasteExcel.addEventListener("paste", function(event) {
console.log('粘贴Excel')

View File

@ -0,0 +1,807 @@
{% load staticfiles %}
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edgechrome=1">
<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="referrer" content="no-referrer">
<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>
<link href="{% static 'layui/css/layui.css' %}?version={{mrdoc_version}}" rel="stylesheet">
<link rel="stylesheet" href="{% static 'editor.md/css/font-awesome.min.css' %}?version={{mrdoc_version}}" />
<link rel="stylesheet" href="{% static 'vditor/dist/index.css' %}?version={{mrdoc_version}}" />
<link rel="icon" href="{% static 'favicon_16.png' %}"/>
<link href="{% static 'mrdoc/mrdoc.css' %}?version={{mrdoc_version}}" rel="stylesheet">
<link href="{% static 'tagsInput/tagsinput.css' %}" rel="stylesheet" type="text/css"/>
<style>
/* 编辑器图标样式 */
.editormd-menu i{
color: #333;
font-size: 16px;
}
ul.editormd-menu{
margin-bottom: 0;
}
/* 编辑器预览列表样式 */
.markdown-body ul li{
list-style:disc;
}
.markdown-body ul > li > ul > li{
list-style-type: circle;
}
.markdown-body ol li{
list-style-type: decimal;
}
.markdown-body ol ol ul,.markdown-body ol ul ul,.markdown-body ul ol ul,.markdown-body ul ul ul li{
list-style-type: square;
}
/* 选择上级文档样式 */
.selected-parent-doc{
text-decoration-line: underline;
font-weight: 700;
color: black;
}
/* 选择图片 - 图片列表样式 */
.select-img-list{
cursor: pointer;
position: relative;
display:flex;
float: left;
align-items:center;
width: 120px;
height:120px;
margin: 0 20px 30px 0;
text-align: center;
overflow: hidden;
}
.select-img-list:hover{
background-color: #EAFFEA;
}
.select-img-list-i{
display: block;
width: 100%;
height: auto;
-webkit-background-size: contain;
border: 1px solid transparent;
border-radius: 3px;
overflow: hidden;
}
/* layui分页组件样式 */
.layui-laypage .layui-laypage-curr .layui-laypage-em{
background-color: #2176ff !important;
}
.layui-form-select dl dd.layui-this{
background-color: #2176ff !important;
}
/* layui单选样式 */
.layui-form-radio>i:hover, .layui-form-radioed>i{
color: #2176ff;
}
/* HTML预览样式 */
.markdown-body h1{
font-size: 1.7em;
}
.markdown-body h2{
font-size: 1.5em;
}
.markdown-body h3{
font-size: 1.25em;
}
.markdown-body h4{
font-size: 1em;
}
.markdown-body h5{
font-size: .875em;
}
.markdown-body h6{
font-size: .85em;
}
/* 编辑器行号宽度 */
.CodeMirror-linenumber{
width: auto !important;
}
li.L1, li.L3, li.L5, li.L7, li.L9 {
background: none !important;
}
/* layui 折叠面板 边框颜色 - 用在左侧文集结构 */
.layui-badge-rim, .layui-colla-content, .layui-colla-item, .layui-collapse, .layui-elem-field, .layui-form-pane .layui-form-item[pane], .layui-form-pane .layui-form-label, .layui-input, .layui-layedit, .layui-layedit-tool, .layui-quote-nm, .layui-select, .layui-tab-bar, .layui-tab-card, .layui-tab-title, .layui-tab-title .layui-this:after, .layui-textarea{
border-color: #f8f8f8;
}
.layui-colla-content{
padding: 0px;
}
/* 预览代码宽度 */
ol.linenums li{
width: max-content;
}
#doc-tree{
margin-bottom: 5px;
}
</style>
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="doc layui-fluid" style="padding-left:0px;">
<!-- 左侧工具栏 -->
<div class="doc-summary">
<div class="project-title"><i class="fa fa-edit"></i> MrDoc文档编辑器<br>
<span style="font-size: 14px;">你正在:{% block editor_type %}{% endblock %}</span>
</div>
<hr>
{% block left_opera %}
{% endblock %}
</div>
<!-- 左侧工具栏结束 -->
<!-- 右侧编辑器栏 -->
<div class="doc-body">
<!-- 文档导航 -->
<div class="doc-header" role="navigation">
<a class="btn pull-left js-toolbar-action" aria-label="" href="javascript:void(0);" title="切换侧边栏">
<i class="fa fa-align-justify"></i>
</a>
<!-- 顶部工具栏 -->
{% block head_toolbar %}
{% endblock %}
<a class="btn pull-right" aria-label="" href="{% url 'pro_list' %}">
<i class="fa fa-home"></i> <span class="layui-hide-xs">首页</span>
</a>
</div>
<!-- 文档主体 -->
<div class="doc-body-content" style="padding-left: 15px;">
<div class="mrdoc-body-content-div">
<!-- 文档内容 -->
<div class="mrdoc-editor-content">
<!-- 正文开始 -->
<div class="markdown-body" id="content">
{% block content %}
{% endblock %}
</div>
<!-- 正文结束 -->
</div>
</div>
</div>
</div>
<!-- 右侧编辑器结束 -->
</div>
<script src="{% static 'jquery/3.1.1/jquery.min.js' %}"></script>
<script src="{% static 'layui/layui.all.js' %}"></script>
<script src="{% static 'vditor/dist/index.min.js' %}?version={{mrdoc_version}}"></script>
<script src="{% static 'mrdoc/mrdoc.editor.js' %}"></script>
<script src="{% static 'mrdoc/mrdoc.js' %}?version={{mrdoc_version}}"></script>
<!-- 标签输入 -->
<script src="{% static '/tagsInput/tagsinput.js' %}" type="text/javascript" charset="utf-8"></script>
<script>
$.ajaxSetup({
data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
});
var tree = layui.tree;
//加载页面时执行一次
changeSidebar();
//监听浏览器宽度的改变
window.onresize = function(){
changeSidebar();
};
function changeSidebar(){
// 获取匹配指定的媒体查询
var screen_width = window.matchMedia('(max-width: 768px)');
//判断匹配状态
if(screen_width.matches){
//如果匹配到,切换侧边栏
//console.log('小屏幕')
$("body").addClass("big-page");
}else{
$("body").removeClass("big-page");
}
}
</script>
<!-- 切换隐藏侧边栏 -->
<script>
// 切换侧边栏
$(function(){
$(".js-toolbar-action").click(toggleSidebar);
});
//切换侧边栏显示隐藏
function toggleSidebar(){
console.log("切换侧边栏")
$("body").toggleClass("big-page");
return false;
}
</script>
<!-- 展开收起左边目录 -->
<script>
$(function(){
$(".switch-toc").click(SwitchToc);
});
function SwitchToc(i){
var $me = $(this);
$(this).parent().next("ul").toggleClass("toc-close"); //切换展开收起样式
$(this).toggleClass("fa-chevron-left fa-chevron-down");//切换图标
};
</script>
<script>
$.ajaxSetup({
data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
});
var layer = layui.layer;
var form = layui.form;
var element = layui.element;
var laypage = layui.laypage;
var md_changed = false; //初始化一个变量,用于判断编辑器是否修改
//初始化vditor
var editor = new Vditor('editor-md',{
"cdn":"{% static 'vditor' %}",
"toolbar": [
"emoji",
"headings",
"bold",
"italic",
"strike",
"link",
"|",
"list",
"ordered-list",
"check",
"outdent",
"indent",
"|",
"quote",
"line",
"code",
"inline-code",
"insert-before",
"insert-after",
"|",
// "upload",
{
name: 'insert-img',
tipPosition: 's',
tip: '图片',
className: 'right',
tipPosition:'nw',
icon:'<svg t="1599747832593" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4027" xmlns:xlink="http://www.w3.org/1999/xlink" width="256" height="256"><defs><style type="text/css"></style></defs><path d="M864.05 128.46H129.97c-17.68 0-32 14.33-32 32v639.61c0 17.67 14.32 32 32 32h734.08c17.68 0 32-14.33 32-32V160.46c0-17.67-14.32-32-32-32z m-32 639.61H161.97V192.46h670.08v575.61z" p-id="4028"></path><path d="M795.58 691.57a32.007 32.007 0 0 1-27.33 15.34H225.77c-12.01 0-23-6.72-28.48-17.4a31.988 31.988 0 0 1 2.5-33.28l125.3-174.17c10.17-14.13 29.78-17.54 44.12-7.67l101.77 70.03 129.73-165.51a31.995 31.995 0 0 1 28.21-12.11 31.99 31.99 0 0 1 25.42 17.2L796.7 660.26a32.018 32.018 0 0 1-1.12 31.31z" p-id="4029"></path><path d="M320.03 321.34a64.03 64.83 0 1 0 128.06 0 64.03 64.83 0 1 0-128.06 0Z" p-id="4030"></path></svg>',
click () {
layer.ready(function(){
element.init();
});
layer.open({
type:'1',
title:'添加图片',
area:['800px','600px'],
id:'uploadImg',//配置ID,
content:$('#upload-img'),
})
},
},
// "record",
{
name: 'insert-attachment',
tipPosition: 's',
tip: '附件',
className: 'right',
tipPosition:'nw',
icon:'<svg t="1599964518089" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4929" xmlns:xlink="http://www.w3.org/1999/xlink" width="256" height="256"><defs><style type="text/css"></style></defs><path d="M633.553 251.102c15.993-12.795 38.385-12.795 55.978 1.6 15.993 15.993 15.993 38.384 0 54.378L347.264 647.747c-22.39 20.792-22.39 57.577 0 81.568 20.792 22.391 57.578 22.391 81.568 0l401.444-403.042c55.978-55.979 55.978-148.742 0-204.72s-148.742-55.979-204.72 0l-47.982 47.98-12.795 12.796-369.455 369.455c-91.165 91.165-91.165 236.708 0 327.872 91.164 91.165 236.707 91.165 327.872 0L894.25 511.8c6.397-3.199 9.596-7.997 12.795-12.795 15.993-15.994 38.385-15.994 54.378 0s15.994 38.385 0 54.379l-3.198 3.199c-3.2 1.599-6.398 6.397-9.597 9.596L577.574 934.035c-119.953 119.953-316.676 119.953-436.63 0s-119.952-316.676 0-436.63l430.233-431.83c86.366-86.367 227.111-86.367 315.077 0 86.366 86.366 86.366 227.11 0 315.076L483.21 783.694c-52.78 52.78-139.145 52.78-190.325 0-52.78-52.78-52.78-139.146 0-190.326l340.667-342.266z m0 0" fill="#333333" p-id="4930"></path></svg>',
click () {
layer.ready(function(){
element.init();
});
layer.open({
type:'1',
title:'添加附件',
area:['800px','600px'],
id:'uploadAttach',//配置ID,
content:$('#upload-attach'),
success: function(layero, index){
layer.load(1);
$.post('{% url "manage_attachment" %}',{types:2},function(r){
$("#attach_table tbody").empty()
if(r.status){
//调用分页显示
laypage.render({
elem: 'select-attach-page',//分页的div
count: r.data.length, //数据总数
limit:10, //单页数
jump: function(obj){
//渲染HTML
$("#attach_table tbody").empty();
var thisData = r.data.concat().splice(obj.curr*obj.limit - obj.limit, obj.limit);
layui.each(thisData, function(k, v){
var row = "<tr><td>" + v.filename + "</td><td>"+ v.filesize +"</td><td>"+ v.filetime +"</td><td><button class='layui-btn layui-btn-normal layui-btn-sm' data-name='"+ v.filename +"' data-path='"+ v.filepath +"' onclick='insertAttach(this)'>选择</button></td></tr>"
// arr.push(row);
$("#attach_table tbody").append(row)
});
}
});
layer.closeAll("loading");//关闭加载提示
}else{
layer.closeAll("loading");//关闭加载提示
layer.msg("获取附件失败,请稍后重试!")
}
})
}
})
},
},
"table",
"|",
"undo",
"redo",
"|",
"fullscreen",
"edit-mode",
{
name: "more",
toolbar: [
"both",
"code-theme",
"content-theme",
"export",
"outline",
"preview",
"devtools",
"info",
"help",
],
}],
"height":800,
"width":'100%',
"mode":"sv",
"placeholder":"道友,开始吧……",
"counter":{
enable:true, // 启用计数
},
"cache": {
"enable": false, // 禁用缓存
},
"preview": {
"markdown": {
"autoSpace": true,// 自动空格
"chinesePunct": true,// 矫正标点
"mark": true,//Mark标记
},
"hljs":{
"lineNumber":true,//代码行号
}
},
"upload":{
fieldName:"editormd-image-file[]",
linkToImgUrl:"{% url 'upload_doc_img' %}",
linkToImgCallback(responseText){
console.log(responseText)
},
handler(files){
console.log(files)
}
}
});
//粘贴上传图片
$("#editor-md").on('paste', function (ev) {
console.log("粘贴上传图片")
var data = ev.clipboardData;
var items = (event.clipboardData || event.originalEvent.clipboardData).items;
for (var index in items) {
var item = items[index];
if (item.kind === 'file') {
var blob = item.getAsFile();
var reader = new FileReader();
reader.onload = function (event) {
var base64 = event.target.result;
//ajax上传图片
layer.load(1);
$.post("{% url 'upload_doc_img' %}",{base:base64}, function (ret) {
layer.msg(ret.message);
if (ret.success === 1) {
//新一行的图片显示
layer.closeAll("loading");
editor.insertValue("\n![](" + ret.url + ")");
editor.focus()
}else{
layer.closeAll("loading");
layer.msg("粘贴图片失败!")
}
});
}; // data url!
var url = reader.readAsDataURL(blob);
}
}
});
//未保存离开提示
window.onbeforeunload =function() {
   if(md_changed){
return 1;
}else{
return null;
}
};
//监听图片Tab选项卡切换
element.on('tab(img-tab)', function(data){
//console.log(this); //当前Tab标题所在的原始DOM元素
//console.log(data.index); //得到当前Tab的所在下标
//console.log(data.elem); //得到当前的Tab大容器
if(data.index == 1){
layer.load(1);
console.log('选择图片')
$("#select-img-group").empty(); //删除已有分组按钮
//请求新的分组数据
$.post("{% url 'manage_img_group' %}",{'types':3},function(r){
if(r.status){
group_btn_str = ''
for(var i in r.data){
group_btn_str += '<button class="layui-btn layui-btn-normal layui-btn-sm" onclick="switchImgGroup(' + r.data[i].group_id +')">' + r.data[i].group_name + '(' + r.data[i].group_cnt + ')</button>'
};
$("#select-img-group").append(group_btn_str)
}
});
//请求全部图片数据
$.post("{% url 'manage_image' %}",{'types':2,'group_id':0},function(r){
if(r.status){
//调用分页显示
laypage.render({
elem: 'select-img-page',//分页的div
count: r.data.length, //数据总数
limit:15, //单页数
jump: function(obj){
//渲染HTML
document.getElementById('select-img').innerHTML = function(){
var arr = []
var thisData = r.data.concat().splice(obj.curr*obj.limit - obj.limit, obj.limit);
layui.each(thisData, function(index, item){
arr.push('<li class="select-img-list"><img class="select-img-list-i" onclick="insertImg(this);" src="' + item.path + '" title="' + item.name + '" /></li>');
});
return arr.join('');
}();
}
});
layer.closeAll("loading");
}else{
layer.closeAll("loading");
layer.msg("获取图片失败")
}
})
}
});
// 插入选择的图片到编辑器
insertImg = function(e){
console.log(e.src);
editor.insertValue("\n![](" + e.src + ")");
editor.focus()
};
// 按钮点击插入输入框图片链接
insertImgUrl = function(){
editor.insertValue("\n![](" + $("#img_url_input").val() + ")");
$("#img_url_input").val("")
layer.closeAll();
editor.focus()
};
// 切换图片分组
switchImgGroup = function(e){
layer.load(1);
$.post("{% url 'manage_image' %}", {
'types': 2,
'group_id': e
},
function(r) {
if (r.status) {
//调用分页显示
laypage.render({
elem: 'select-img-page',//分页的div
count: r.data.length,//数据总数
limit: 15,//单页数
jump: function(obj) {
//渲染HTML
document.getElementById('select-img').innerHTML = function() {
var arr = []
var thisData = r.data.concat().splice(obj.curr * obj.limit - obj.limit, obj.limit);
layui.each(thisData,
function(index, item) {
arr.push('<li class="select-img-list"><img class="select-img-list-i" onclick="insertImg(this);" src="' + item.path + '" title="' + item.name + '" /></li>');
});
return arr.join('');
} ();
}
});
layer.closeAll("loading"); //关闭加载提示
} else {
layer.closeAll("loading");
layer.msg("获取分组图片失败")
}
})
};
// 插入选择的附件到编辑器
insertAttach = function(e){
editor.insertValue("\n[【附件】"+ $(e).data('name') + "](/media/" + $(e).data('path') + ")");
layer.closeAll();
}
// 插入音视频到编辑器
insertMultimedia = function(e){
if(e === 'audio'){
editor.insertValue("\n![=audio](" + $("#audio_input").val() + ")");
}else if(e === 'video'){
editor.insertValue("\n![=video](" + $("#video_input").val() + ")");
}else if(e === 'video_iframe'){
editor.insertValue("\n![=video_iframe](" + $("#video_iframe_input").val() + ")");
}
$("#audio_input").val('')
$("#video_input").val('')
$("#video_iframe_input").val('')
layer.closeAll();
editor.focus()
}
</script>
{% block custom_script %}
{% endblock %}
</body>
{% block custom_div %}
{% endblock %}
<!-- 选择和上传图片div -->
<div id="upload-img" style="display:none;margin:20px;">
<div class="layui-tab" lay-filter="img-tab">
<ul class="layui-tab-title">
<li class="layui-this">上传图片</li>
<li>选择图片</li>
</ul>
<div class="layui-tab-content">
<div class="layui-tab-item layui-show">
<div class="layui-row">
<button class="layui-btn layui-btn-normal layui-btn-fluid" id="upload_img"><i class="layui-icon layui-icon-upload"></i> 点击上传图片</button>
</div>
<fieldset class="layui-elem-field layui-field-title" style="text-align: center;">
<legend style="font-size: 12px;">或 插入外链图片链接</legend>
</fieldset>
<div class="layui-row" style="margin-top: 10px;">
<input type="text" class="layui-input" placeholder="输入图片URL" id="img_url_input" style="margin-bottom: 5px;"/>
<button type="button" class="layui-btn layui-btn-primary" onclick="insertImgUrl()">插入图片链接</button>
</div>
</div>
<div class="layui-tab-item">
<div class="layui-row" id="select-img-group">
</div><hr>
<div class="layui-row" id="select-img"></div>
<div id="select-img-page"></div>
</div>
</div>
</div>
</div>
<!-- 选择和上传附件div -->
<div id="upload-attach" style="display:none;margin:20px;">
<span>* 仅支持.zip格式的压缩文件作为附件文件大小不超过50Mb</span>
<div style="margin: 10px 0 0 10px;">
<button class="layui-btn layui-btn-normal layui-btn-sm" id="upload_attachment"><i class="layui-icon layui-icon-upload"></i> 点击上传附件</button>
<a class="layui-btn layui-btn-normal layui-btn-sm" href="{% url 'manage_attachment' %}" target="_blank"><i class="fa fa-cubes"></i> 管理附件</a>
</div>
<table class="layui-table" id="attach_table" style="margin: 10px;width:90%;">
<thead>
<th>附件名称</th>
<th>附件大小</th>
<th>上传时间</th>
<th>操作</th>
</thead>
<tbody>
</tbody>
</table>
<div id="select-attach-page"></div>
</div>
<!-- 添加表格div -->
<div id="layer-table" style="display: none;margin: 10px;">
<div class="layui-tab" lay-filter="table-tab" id="insert-table-div">
<ul class="layui-tab-title">
<li class="layui-this" lay-id="generaTable">生成表格</li>
<li lay-id="pasteTable">粘贴表格</li>
</ul>
<div class="layui-tab-content">
<div class="layui-tab-item layui-show" >
<div class="layui-row" style="margin: 10px;">
<div class="layui-form-item">
<div class="layui-inline">
<div class="layui-input-inline" style="width: 50px;">
<input type="number" placeholder="行" id="row" class="layui-input" value="3">
</div>
<div class="layui-form-mid">x</div>
<div class="layui-input-inline" style="width: 50px;">
<input type="number" placeholder="列" id="col" class="layui-input" value="3">
</div>
<div class="layui-form-mid" style="width: 100px;">
<button class="layui-btn layui-btn-normal layui-btn-xs" onclick="addtable(1)" >生成表格</button>
</div>
</div>
</div>
</div>
<div class="layui-row" style="margin:10px;" id="TableGroup"></div>
</div>
<div class="layui-tab-item" >
<textarea placeholder="粘贴Excel或在线电子表格的内容" class="layui-textarea" style="height: 200px;" id="pasteExcel"></textarea>
</div>
</div>
</div>
</div>
<!-- 添加音视频div -->
<div id="insertMultimedia" style="display: none;margin:10px;">
<div class="layui-row">
<fieldset class="layui-elem-field">
<legend>插入音频链接</legend>
<div class="layui-field-box">
<input class="layui-input" type="url" id="audio_input" placeholder="填入音频文件链接支持文件后缀格式为mp3、wav、flac、m4a" style="margin-bottom: 5px;">
<button type="button" class="layui-btn layui-btn-sm layui-btn-normal" onclick="insertMultimedia('audio')"><i class="fa fa-music"></i> 插入音频</button>
</div>
</fieldset>
</div>
<div class="layui-row">
<fieldset class="layui-elem-field">
<legend>插入视频链接</legend>
<div class="layui-field-box">
<input class="layui-input" type="url" id="video_input" placeholder="填入视频文件链接支持文件后缀格式为mp4、m4v、ogg、ogv、webm" style="margin-bottom: 5px;">
<button type="button" class="layui-btn layui-btn-sm layui-btn-normal" onclick="insertMultimedia('video')"><i class="fa fa-video-camera"></i> 插入视频</button>
</div>
</fieldset>
</div>
<div class="layui-row">
<fieldset class="layui-elem-field">
<legend>插入视频网站链接</legend>
<div class="layui-field-box">
<input class="layui-input" type="url" id="video_iframe_input" placeholder="填入视频网站视频播放页链接支持YouTube、优酷、QQ视频、Facebook、哔哩哔哩、TED网站" style="margin-bottom: 5px;">
<button type="button" class="layui-btn layui-btn-sm layui-btn-normal" onclick="insertMultimedia('video_iframe')"><i class="fa fa-youtube-play"></i> 插入视频网站视频</button>
</div>
</fieldset>
</div>
</div>
<script>
//按钮选择上传图片
var upload = layui.upload;
upload.render({
elem: '#upload_img',
url: '{% url "upload_doc_img" %}',
before: function(obj){ //obj参数包含的信息跟 choose回调完全一致可参见上文。
layer.load(1); //上传loading
},
done: function(res, index, upload){ //上传后的回调
//上传成功
if(res.success == 1){
editor.insertValue("\n![](" + res.url + ")");
layer.closeAll();
layer.msg("上传成功");
}else{
layer.closeAll();
layer.msg(res.message)
}
},
error:function(){
layer.closeAll('loading'); //关闭loading
layer.msg("系统异常,请稍后再试!")
},
accept: 'images', //允许上传的文件类型
acceptMime:'image/*',
field:'manage_upload',
});
// 按钮选择上传附件
var upload_attach = layui.upload;
upload_attach.render({
elem: '#upload_attachment',
url: '{% url "manage_attachment" %}',
data:{types:0,csrfmiddlewaretoken: '{{ csrf_token }}'},
before: function(obj){ //obj参数包含的信息跟 choose回调完全一致可参见上文。
layer.load(1); //上传loading
},
done: function(res, index, upload){ //上传后的回调
//上传成功,刷新页面
if(res.status){
editor.insertValue("\n[【附件】"+ res.data.name + "](/media/" + res.data.url + ")");
layer.closeAll();
layer.msg("上传成功");
}else{
layer.msg("上传出错,请重试!")
}
},
error:function(){
layer.closeAll('loading'); //关闭loading
layer.msg("系统异常,请稍后再试!")
},
accept: 'file', //允许上传的文件类型
field:'attachment_upload',
})
//修改预览div中a标签链接新窗口打开
$('div.editormd-preview').on('click','a',function(e){
e.target.target = '_blank';
});
// 粘贴表格文本框侦听paste粘贴事件
// 列宽的函数
function columnWidth(rows, columnIndex) {
return Math.max.apply(null, rows.map(function(row) {
return row[columnIndex].length
}))
};
// 检查是否是个表格
function looksLikeTable(data) {
return true
};
// 编辑器侦听paste粘贴事件
var pasteExcel = document.getElementById('pasteExcel')
pasteExcel.addEventListener("paste", function(event) {
console.log('粘贴Excel')
var clipboard = event.clipboardData
var data = clipboard.getData('text/plain')
data = data.replace(/(?:[\n\u0085\u2028\u2029]|\r\n?)$/, '');
if(looksLikeTable(data)) {
event.preventDefault()
}else{
return
}
// 行
var rows = data.split((/[\n\u0085\u2028\u2029]|\r\n?/g)).map(function(row) {
console.log(row)
return row.split("\t")
})
// 列对齐
var colAlignments = []
// 列宽
var columnWidths = rows[0].map(function(column, columnIndex) {
var alignment = "l"
var re = /^(\^[lcr])/i
var m = column.match(re)
if (m) {
var align = m[1][1].toLowerCase()
if (align === "c") {
alignment = "c"
} else if (align === "r") {
alignment = "r"
}
}
colAlignments.push(alignment)
column = column.replace(re, "")
rows[0][columnIndex] = column
return columnWidth(rows, columnIndex)
})
var markdownRows = rows.map(function(row, rowIndex) {
return "| " + row.map(function(column, index) {
return column + Array(columnWidths[index] - column.length + 1).join(" ")
}).join(" | ") + " |"
row.map
})
markdownRows.splice(1, 0, "|" + columnWidths.map(function(width, index) {
var prefix = ""
var postfix = ""
var adjust = 0
var alignment = colAlignments[index]
if (alignment === "r") {
postfix = ":"
adjust = 1
} else if (alignment == "c") {
prefix = ":"
postfix = ":"
adjust = 2
}
return prefix + Array(columnWidths[index] + 3 - adjust).join("-") + postfix
}).join("|") + "|")
event.target.value = markdownRows.join("\n")
return false
});
</script>
</html>

View File

@ -65,7 +65,7 @@
<div class="layui-row">
<div class="layui-col-md12" style="margin-bottom: 10px;">
<span>点击文档树选择上级(可选)或</span>
<button class="layui-btn layui-btn-xs layui-btn-normal" id="clearParentDoc">取消上级</button>
<button class="layui-btn layui-btn-xs layui-btn-primary" id="clearParentDoc">取消上级</button>
<input type="text" id="parent-doc" hidden>
</div>
<div class="layui-col-md12">

View File

@ -0,0 +1,448 @@
{% extends 'app_doc/create_base_vditor.html' %}
{% load staticfiles %}
{% block title %}新建文档{% endblock %}
{% block editor_type %}新建文档{% endblock %}
{% block head_toolbar %}
<a class="btn pull-left" aria-label="" href="{% url 'create_doc' %}?pid={{project.id}}" target="_blank">
<i class="fa fa-plus-square"></i> <span class="layui-hide-xs">新建文档</span>
</a>
<a class="btn pull-left" aria-label="" href="{% url 'manage_doc' %}?pid={{project.id}}" target="_blank">
<i class="fa fa-cubes"></i> <span class="layui-hide-xs">管理文档</span>
</a>
<a class="btn pull-left" aria-label="" href="{% url 'manage_project' %}" target="_blank">
<i class="fa fa-cubes"></i> <span class="layui-hide-xs">管理文集</span>
</a>
{% endblock %}
{% block left_opera %}
<div class="layui-form" style="padding: 0 10px 10px 10px;">
<div class="layui-row">
<div class="layui-btn-container" style="margin-bottom: 0px;">
<!-- <button class="layui-btn layui-btn-primary layui-btn-sm mrdoc-btn-default" id="sel-doctemp" title="插入模板内容">
<i class="fa fa-clipboard"></i> 选择模板
</button> -->
<!-- <input type="file" id="insert-local-file" onchange="insertLocalFile(this)" style="display:none;">
<button class="layui-btn layui-btn-primary layui-btn-sm mrdoc-btn-default" id="sel-local" onclick="selectLocalFile()" title="插入本地文本文件内容">
<i class="fa fa-upload"></i> 导入文本
</button> -->
</div>
<div class="layui-col-md12" style="margin-bottom: 10px;">
<div class="layui-input-inblock">
<select name="pro_id" lay-verify="required" lay-filter="project" id="project">
<option value="">请选择一个文集(必选)</option>
<option value="-1">新建文集</option>
<!-- 自己的文集 -->
<optgroup label="自有文集" id="self-project">
{% for p in project_list %}
{% if p.role == 1 %}
<option value="{{ p.id }}">[私密]《{{ p.name }}》</option>
{% elif p.role == 2 %}
<option value="{{ p.id }}" >[指定用户]《{{ p.name }}》</option>
{% elif p.role == 3 %}
<option value="{{ p.id }}" >[访问码]《{{ p.name }}》</option>
{% else %}
<option value="{{ p.id }}" >[公开]《{{ p.name }}》</option>
{% endif %}
{% endfor %}
</optgroup>
<!-- 协作的文集 -->
{% if colla_project_list.count > 0 %}
<optgroup label="协作文集">
{% for p in colla_project_list %}
<option value="{{ p.project.id }}">[协作]《{{ p.project.name }}》</option>
{% endfor %}
</optgroup>
{% endif %}
</select>
</div>
</div>
<div class="layui-row">
<div class="layui-col-md12" style="margin-bottom: 10px;">
<span>点击文档树选择上级(可选)或</span>
<button class="layui-btn layui-btn-xs layui-btn-primary" id="clearParentDoc">取消上级</button>
<input type="text" id="parent-doc" hidden>
</div>
<div class="layui-col-md12">
<input type="number" class="layui-input" placeholder="输入文档排序值默认99" id="sort">
</div>
</div>
<div class="layui-collapse" style="margin-top: 10px;margin-bottom: 10px;">
<div class="layui-colla-item">
<h2 class="layui-colla-title">文档结构树</h2>
<div class="layui-colla-content layui-show" style="max-height: 400px;overflow: hidden;overflow-y: scroll;overflow-x: scroll;">
<div id="doc-tree"></div>
</div>
</div>
</div>
<hr>
<!-- 标签输入框 -->
<div class="layui-collapse" style="margin-top: 10px;margin-bottom: 10px;">
<div class="layui-colla-item">
<h2 class="layui-colla-title">标签</h2>
<div class="layui-colla-content layui-show">
<div class="layui-row layui-col-space5" style="padding: 5px;background-color: #fff;">
<input name="tagsinput" id="tagsinputval" class="tagsinput" data-role="tagsinput" value="" placeholder="输入标签名">
</div>
</div>
</div>
</div>
<!-- 发布按钮 -->
<div class="layui-collapse" style="margin-top: 10px;margin-bottom: 10px;">
<div class="layui-colla-item">
<h2 class="layui-colla-title">发布</h2>
<div class="layui-colla-content layui-show">
<div class="layui-row layui-col-space5" style="padding: 5px;background-color: #fff;">
<button class="layui-btn layui-btn-primary mrdoc-btn-default" onclick="saveDoc()" title="保存当前内容为草稿文档">
<i class="fa fa-save"></i> 保存为草稿
</button>
<button class="layui-btn layui-btn-normal" onclick="createDoc()" id="create_doc" title="发布当前内容">
<i class="fa fa-save"></i> 发布文档
</button>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block content %}
<div class="create-doc-form">
<div class="layui-form">
<!-- 标题 -->
<div style="padding-bottom:10px;">
<div class="layui-input-block" style="margin-left:0px;">
<input type="text" name="doc-name" id="doc-name" required lay-verify="required" placeholder="请输入文档标题……" autocomplete="off" class="layui-input">
</div>
</div>
</div>
</div>
<div id="editor-md" class="layui-col-xs12">
<textarea style="display:none;"></textarea>
<textarea class="editormd-html-textarea" name="$id-html-code"></textarea>
</div>
{% endblock %}
{% block custom_script %}
<script>
var tree = layui.tree;
//选择文集
form.on('select(project)', function(data){
console.log('选择文集:',data.value); //得到被选中的值
if(data.value == -1){ //新建文集
layer.open({
type:1,
title:'新建文集',
area:'300px;',
id:'createPro',//配置ID
content: $('#create-project-div'),
btn:['确定','取消'], //添加按钮
btnAlign:'c', //按钮居中
yes:function (index,layero) {
data = {
'pname':$("#pname").val(),
'desc':$("#desc").val(),
'role':$("#project-role").val(),
}
$.post("{% url 'create_project' %}",data,function(r){
if(r.status){
//创建成功更新文集select
$("#self-project").append("<option value="+r.data.id+">《"+r.data.name+"》</option>");
form.render();
layer.close(index)
}else{
//创建失败,提示
console.log(r)
}
})
},
});
}else{//获取文集的下级文档
$.post("{% url 'get_pro_doc_tree' %}",{'pro_id':data.value},function(r){
if(r.status){
var doc_tree = tree.render({
elem:"#doc-tree",
id:'docTree',
// showCheckbox:true,
onlyIconControl:true,
data:r.data,
text: {
defaultNodeName: '未命名' //节点默认名称
,none: '文集暂无文档' //数据为空时的提示文本
},
click: function(obj){
//console.log(obj.data); //得到当前点击的节点数据
// console.log(obj.state); //得到当前节点的展开状态open、close、normal
// console.log(obj.elem); //得到当前节点元素
if(obj.data.level != 3){
$('#parent-doc').val(obj.data.id);// 设置上级文档
$("div.layui-tree-set").each(function(i){
var $me = $(this)
if($me.data('id') == obj.data.id){
// console.log('点击了')
layer.msg("你选择了上级文档:"+obj.data.title)
$me.find('span.layui-tree-txt').first().addClass('selected-parent-doc')
}else{
$me.find('span.layui-tree-txt').first().removeClass('selected-parent-doc')
}
});
}else{
layer.msg("第三级文档不能作为上级文档")
}
}
});
}else{
layer.msg("获取下级文档失败!")
}
});
}
});
//带pid参数自动选择文集
var sel_pro_list = $('dl.layui-anim dd');
for(var i = 0;i < sel_pro_list.length; i++){
if(sel_pro_list[i].getAttribute('lay-value') == '{{pid}}'){
var sel_pro = 'dd[lay-value=' + sel_pro_list[i].getAttribute('lay-value') + ']';
$('#project').siblings("div.layui-form-select").find('dl').find(sel_pro).click();
}
};
//发布文档
createDoc = function(){
$('button.layui-btn').attr("disabled",true);
$('button.layui-btn').addClass('layui-btn-disabled');
var data = {
'project':$("#project").val(),
'parent_doc':$("#parent-doc").val(),
'doc_name':$("#doc-name").val(),
'doc_tag':$("#tagsinputval").val(),
'content':editor.getHTML(),//获取editor解析的HTML
'pre_content':editor.getValue(),
'sort':$("#sort").val(),
}
console.log(data)
if(data.doc_name == ""){
layer.msg('请输入文档标题!');
$('button.layui-btn').attr("disabled",false);
$('button.layui-btn').removeClass('layui-btn-disabled');
}
else if(data.project == ""){
layer.msg('请选择文集!');
$('button.layui-btn').attr("disabled",false);
$('button.layui-btn').removeClass('layui-btn-disabled');
}
else{
//发布按钮设为禁用
$("#create_doc").attr({"disabled":"disabled"});
layer.load(); // 加载提示
$.post("{% url 'create_doc' %}",data,function(r){
if(r.status){
//创建成功
layer.closeAll("loading"); //关闭加载层
layer.msg('发布文档成功,即将跳转到文档页面',function(){
md_changed = false;
//跳转到发布的文档
window.location.href = "/project-" + r.data.pro + "/doc-" + r.data.doc
});
}else{
//创建失败
layer.closeAll("loading"); //关闭加载层
layer.msg('发布文档失败:'+r.data);
//恢复按钮状态
$('button.layui-btn').attr("disabled",false);
$('button.layui-btn').removeClass('layui-btn-disabled');
}
});
}
};
//保存草稿
saveDoc = function(){
$('button.layui-btn').attr("disabled",true);
$('button.layui-btn').addClass('layui-btn-disabled');
var data = {
'project':$("#project").val(),
'parent_doc':$("#parent-doc").val(),
'doc_name':$("#doc-name").val(),
'doc_tag':$("#tagsinputval").val(),
'content':editor.getHTML(),
'pre_content':editor.getValue(),
'sort':$("#sort").val(),
'status':0
}
console.log(data)
if(data.doc_name == ""){
layer.msg('请输入文档标题!');
$('button.layui-btn').attr("disabled",false);
$('button.layui-btn').removeClass('layui-btn-disabled');
}
else if(data.project == ""){
layer.msg('请选择文集!');
$('button.layui-btn').attr("disabled",false);
$('button.layui-btn').removeClass('layui-btn-disabled');
}
else{
layer.load(1);
$.post("{% url 'create_doc' %}",data,function(r){
if(r.status){
//保存成功
layer.closeAll("loading");
md_changed = false;
layer.msg('保存草稿成功',function(){
window.location.href = "/modify_doc/"+r.data.doc+"/";
});
}else{
//创建失败
layer.closeAll("loading");
layer.msg('保存草稿失败:'+r.data);
$('button.layui-btn').attr("disabled",false);
$('button.layui-btn').removeClass('layui-btn-disabled');
}
});
}
};
//选择文档模板
$("#sel-doctemp").click(function(){
layer.open({
type: 1,
id:'temp-div',
content: $('#doctemp-list'),
//area:['530px','300px'],
area:['50%','50%'],
});
});
//清除所选上级文档
$("#clearParentDoc").click(function(){
$('#parent-doc').val("");
$("span.layui-tree-txt").each(function(i){
var $me = $(this)
$me.removeClass('selected-parent-doc')
});
layer.msg("你取消了当前文档的上级文档")
});
//插入模板
insertTemp = function(doctemp_id){
$.post("{% url 'get_doctemp' %}",{'doctemp_id':doctemp_id},function(r){
if(r.status){
console.log(r.data)
editor.insertValue(r.data);
layer.closeAll()
}else{
layer.msg(r.data)
}
});
};
//删除模板
delTemp = function(doctemp_id){
layer.open({
title:'删除模板',
content:'确认删除此模板?',
btn:['确定','取消'],
yes:function(index,layero){
},
});
};
//插入本地文本文件
function insertLocalFile(input) {
var file = input.files[0];
//filename = file.name.split(".")[0]; // 文件名
//支持chrome IE10
if (window.FileReader) {
var reader = new FileReader();
reader.onload = function() {
console.log(this.result);
editor.insertValue(this.result);
}
reader.readAsText(file);
}
//支持IE 7 8 9 10
else if (typeof window.ActiveXObject != 'undefined'){
var xmlDoc;
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async = false;
// xmlDoc.load(input.value);
// console.log(xmlDoc.xml);
editor.insertValue(xmlDoc.xml);
}
//支持FF
else if (document.implementation && document.implementation.createDocument) {
var xmlDoc;
xmlDoc = document.implementation.createDocument("", "", null);
xmlDoc.async = false;
xmlDoc.load(input.value);
console.log(xmlDoc.xml);
editor.insertValue(xmlDoc.xml);
} else {
alert('error');
}
};
//选择本地文本文件
function selectLocalFile(){
$("#insert-local-file").trigger("click");
};
</script>
{% endblock %}
{% block custom_div %}
<!-- 插入文档模板div块 -->
<div class="doctemp-list " id="doctemp-list" style="display: none;padding:5px;">
<div style="margin: 10px 0 0 10px;">
<a class="layui-btn layui-btn-normal layui-btn-sm" href="{% url 'create_doctemp' %}" target="_blank">新建模板</a>
<a class="layui-btn layui-btn-normal layui-btn-sm" href="{% url 'manage_doctemp' %}" target="_blank">管理模板</a>
</div>
<table class="layui-table" style="margin: 10px;width:90%;">
<colgroup>
<col width="">
<col width="">
<col>
</colgroup>
<thead>
<tr>
<th>模板名称</th>
<th class="layui-hide-xs">创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for temp in doctemp_list %}
<tr>
<td>{{ temp.name }}</td>
<td class="layui-hide-xs">{{ temp.create_time }}</td>
<td>
<a class="layui-btn layui-btn-normal layui-btn-sm" href="javascript:void(0);" onclick="insertTemp('{{temp.id}}');">选择模板</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- 结束插入文档模板div块 -->
<!-- 新建文集div块 -->
<div style="padding: 20px;display:none;" id="create-project-div">
<input class="layui-input" type="text" id="pname" style="margin-bottom:10px;" placeholder="输入文集名" required lay-verify="required">
<textarea name="desc" id="desc" placeholder="输入文集简介不超过100个字超出将被截断" maxlength="100" class="layui-textarea"></textarea>
<div class="layui-form-item" style="margin-top:10px;">
<label class="layui-form-label" style="text-align:left;padding:9px 0px;">文集权限</label>
<div class="layui-input-block">
<select name="project-role" lay-verify="" class="layui-select" id="project-role">
<!--<option value="">选择文集权限</option>-->
<option value="0">公开</option>
<option value="1">私密</option>
</select>
</div>
</div>
<div style="color:red;font-size:12px;">*在可后台对文集权限进行进一步控制</div>
</div>
<!-- 结束新建文集div块 -->
{% endblock %}

View File

@ -0,0 +1,87 @@
{% extends 'app_doc/create_base_vditor.html' %}
{% load staticfiles %}
{% block title %}新建文档模板{% endblock %}
{% block editor_type %}新建模板{% endblock %}
{% block head_toolbar %}
<a class="btn pull-left" aria-label="" href="{% url 'create_doc' %}?pid={{project.id}}" target="_blank">
<i class="fa fa-plus-square"></i> <span class="layui-hide-xs">新建模板</span>
</a>
<a class="btn pull-left" aria-label="" href="{% url 'manage_doctemp' %}?pid={{project.id}}" target="_blank">
<i class="fa fa-cubes"></i> <span class="layui-hide-xs">管理模板</span>
</a>
<a class="btn pull-left" aria-label="" href="{% url 'manage_project' %}" target="_blank">
<i class="fa fa-cubes"></i> <span class="layui-hide-xs">管理文集</span>
</a>
{% endblock %}
{% block left_opera %}
<div class="layui-form" style="padding: 10px;">
<div class="layui-row">
<div class="layui-col-md12" style="margin-bottom: 10px;">
<label class="doc-form-label">
<button class="layui-btn layui-btn-normal layui-btn-fluid" onclick="createDocTemp()">
<i class="fa fa-save"></i> 保存模板
</button>
</label>
</div>
</div>
<!-- 已有模板 -->
<div class="layui-row">
<div class="layui-card">
<div class="layui-card-header">现有模板</div>
<div class="layui-card-body">
{% for temp in doctemps %}
<li><a href="{% url 'modify_doctemp' temp.id %}" target="_blank" title="点击查看修改《{{temp.name}}》的内容"><i class="fa fa-file"></i> {{temp.name}}</a></li>
{% endfor %}
</div>
</div>
</div>
</div>
{% endblock %}
{% block content %}
<div class="create-doc-form">
<div class="layui-form" style="padding-bottom:10px;">
<div class="layui-input-block" style="margin-left:0px;">
<input type="text" name="doc-name" id="doctemp-name" required lay-verify="required" placeholder="请输入模板标题" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div id="editor-md">
<textarea style="display:none;"></textarea>
<textarea class="editormd-html-textarea" name="$id-html-code"></textarea>
</div>
{% endblock %}
{% block custom_script %}
<script>
//保存文档模板
createDocTemp = function(){
$('button.layui-btn').attr("disabled",true);
$('button.layui-btn').addClass('layui-btn-disabled');
layer.load();
var data = {
'name':$("#doctemp-name").val(),
'content':editor.getValue(),
}
$.post("{% url 'create_doctemp' %}",data,function(r){
if(r.status){
//创建成功
layer.closeAll("loading");
layer.msg('保存成功',function(){
md_changed = false;
window.location.href = "{% url 'manage_doctemp' %}";
});
}else{
//创建失败
layer.closeAll("loading");
layer.msg('保存失败');
$('button.layui-btn').attr("disabled",false);
$('button.layui-btn').removeClass('layui-btn-disabled');
}
});
};
</script>
{% endblock %}

View File

@ -117,7 +117,7 @@
</div>
</div>
<script src="{% static 'toc/doctoc.js' %}"></script>
<script src="{% static 'viewerjs/viewer.js' %}"></script>
<script src="{% static 'viewerjs/viewer.min.js' %}"></script>
<script>
var layer = layui.layer;
// 手机屏幕上默认最小化目录

View File

@ -15,7 +15,11 @@
<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}}" />
<!-- <link rel="stylesheet" href="{% static 'katex/katex.min.css' %}?version={{mrdoc_version}}" /> -->
{% if doc.editor_mode == 2 %}
<link rel="stylesheet" href="{% static 'vditor/dist/index.css' %}?version={{mrdoc_version}}" />
{% endif %}
<!-- <link href="{% static 'viewerjs/viewer.css' %}?version={{mrdoc_version}}" rel="stylesheet"> -->
<link href="{% static 'viewerjs/viewer.min.css' %}?version={{mrdoc_version}}" rel="stylesheet">
<link rel="icon" href="{% static 'search/mrdoc_logo_300.png' %}" sizes="192x192" />
@ -56,7 +60,7 @@
padding-left:15px;
}
ul.markdown-toc-list a{
text-decoration: underline!important;
/* text-decoration: underline!important; */
}
/* 块级代码和行内代码去除边框 */
.markdown-body p code{
@ -105,6 +109,12 @@
.layui-tab-brief>.layui-tab-title .layui-this{
color: #333;
}
/* 覆盖vditor样式 */
.vditor-outline__item{
padding: 0;
padding-bottom: 5px;
color: #333;
}
</style>
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
@ -142,12 +152,55 @@
</div> -->
<!-- 遍历文集大纲 -->
<div style="text-align: center;" id='loading-project-toc'><i class="fa fa-spinner fa-pulse"></i>文集大纲加载中……</div>
{% load doc_filter %}
<!-- 如果文集的文档数量超过999使用异步加载文集目录 -->
{% if toc_cnt > 999 %}
<div style="text-align: center;" id='loading-project-toc'><i class="fa fa-spinner fa-pulse"></i>文集大纲加载中……</div>
{% load doc_filter %}
<nav>
<ul class="summary" id="project-toc"></ul>
</nav>
{% else %}
<!-- 文档数量小于999使用同步加载文集目录 -->
<nav>
<!-- <div id="project-toc"></div> -->
<ul class="summary" id="project-toc"></ul>
<ul class="summary">
<!-- 一级目录 -->
{% for docs in toc_list %}
<li>
{% if docs.children %}
<div style="display:flex;justify-content:space-between;">
<a href="{% url 'doc' pro_id=pro_id doc_id=docs.id %}" title="{{docs.name}}">{{ docs.name }}</a>
<i class="fa fa-chevron-left switch-toc" style="padding:15px;"></i>
</div>
<ul class="sub-menu toc-close">
<!-- 二级目录 -->
{% for node in docs.children %}
<li>
{% if node.id|get_next_doc %}
<div style="display:flex;justify-content:space-between;">
<a href="{% url 'doc' pro_id=pro_id doc_id=node.id %}" title="{{node.name}}">{{ node.name }}</a>
<i class="fa fa-chevron-left switch-toc" style="padding:15px;"></i>
</div>
<ul class="sub-menu toc-close">
<!-- 三级目录 -->
{% for doc in node.children %}
<li><a href="{% url 'doc' pro_id=pro_id doc_id=doc.id %}" title="{{doc.name}}">{{ doc.name }}</a></li>
{% endfor %}
</ul>
{% else %}
<a href="{% url 'doc' pro_id=pro_id doc_id=node.id %}" title="{{node.name}}">{{ node.name }}</a>
{% endif %}
</li>
{% endfor %}
</ul>
{% else %}
<a href="{% url 'doc' pro_id=pro_id doc_id=docs.id %}" title="{{docs.name}}">{{ docs.name }}</a>
{% endif %}
</li>
{% endfor %}
</ul>
</nav>
{% endif %}
<div class="bq">
<a href="javascript:void(0);" class="mrdoc-link" id="dashang">本文档使用MrDoc发布</a>
</div>
@ -248,13 +301,14 @@
<script src="{% static 'jquery/3.1.1/jquery.min.js' %}"></script>
<script src="{% static 'layui/layui.all.js' %}"></script>
<!-- 生成文集目录大纲 -->
<script>
$.ajaxSetup({
data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
});
// 生成文集目录
// 视频iframe域名白名单
var iframe_whitelist = '{{ iframe_whitelist }}'.split(',')
// 异步生成文集目录
getProjectToc = function(){
$.post("{% url 'get_pro_doc_tree' %}",{'pro_id':'{{project.id}}'},function(r){
$("#loading-project-toc").hide();
@ -302,7 +356,9 @@
}
});
};
getProjectToc();
{% if toc_cnt > 999 %}
getProjectToc();
{% endif %}
//为当前页面的目录链接添加蓝色样式
tagCurrentDoc = function(){
@ -313,6 +369,7 @@
if (lochref.indexOf(mehref) != -1) {
// console.log($me,lochref,mehref)
$me.closest("li").addClass("active");
this.scrollIntoView({ behavior: 'auto', block: "start" });
//展开当前文档的上级目录
$me.parent("li").parent('ul.sub-menu').toggleClass("toc-close toc-open"); //展开二级目录
$me.parent("div").parent('li').parent('ul.sub-menu').toggleClass("toc-close toc-open"); //展开还有子级的二级目录
@ -324,6 +381,7 @@
}
});
};
tagCurrentDoc();
</script>
<!-- 小屏自动收起左侧文集大纲 -->
@ -348,42 +406,87 @@
}
</script>
{% if doc.editor_mode == 2 %}
<script src="{% static 'vditor/dist/index.min.js' %}?version={{mrdoc_version}}"></script>
{% elif doc.editor_mode == 1 %}
<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 'editor.md/lib/echarts.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 'editor.md/lib/echarts.min.js' %}"></script> -->
<!-- 脑图开始 -->
<script src="{% static 'mindmap/d3@5.js' %}"></script>
<script src="{% static 'mindmap/transform.min.js' %}"></script>
<script src="{% static 'mindmap/view.min.js' %}"></script>
<!-- <script src="{% static 'mindmap/d3@5.js' %}"></script> -->
<!-- <script src="{% static 'mindmap/transform.min.js' %}"></script> -->
<!-- <script src="{% static 'mindmap/view.min.js' %}"></script> -->
<!-- 脑图结束 -->
<!-- <script src="{% static 'editor.md/editormd.min.js' %}?version={{mrdoc_version}}"></script> -->
<script src="{% static 'editor.md/editormd.js' %}?version={{mrdoc_version}}"></script>
{% endif %}
<script src="{% static 'qrcodejs/qrcode.min.js' %}"></script>
<!-- 解析Markdown -->
<script>
//解析Markdown为HTML
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,//禁用@链接
// EditorMD模式
{% if doc.editor_mode == 1 %}
//解析Markdown为HTML
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,//禁用@链接
});
});
// Vditor模式
{% elif doc.editor_mode == 2 %}
// 渲染Markdown
const initRender = () => {
const md_content = $("#content textarea").val()
Vditor.preview(document.getElementById('content'),
md_content, {
speech: {
enable: true,
},
anchor: 1,
after () {
// if (window.innerWidth <= 768) {
// return
// }
const outlineElement = document.getElementById('toc-container')
var sub_ele = "<div class='markdown-toc editormd-markdown-toc'><ul class='markdown-toc-list'></ul></div>"
$("#toc-container").append(sub_ele)
var toc_elem = $("#toc-container div ul.markdown-toc-list")
Vditor.outlineRender(document.getElementById('content'), toc_elem[0])
if (outlineElement.innerText.trim() !== '') {
// 去除vditor默认添加的空格字符
var toc_html = $("#toc-container");
toc_html.html(toc_html.html().replace('',''))
var toc_cnt = $(".markdown-toc-list").children().length;
//console.log(toc_cnt)
if(toc_cnt > 0){
//console.log('显示文档目录')
$(".tocMenu").show();
initSidebar('.sidebar', '.doc-content');
}
}else{
console.log("无目录")
}
},
})
}
initRender();
{% endif %}
// 显示分享弹出框
$("#share").click(function(r){
var layer = layui.layer;

View File

@ -1,9 +1,7 @@
<div class="layui-footer" style="border-top: 1px #e6e6e6 solid;text-align:center;margin-top:10px;width:100%;">
<div style="margin-top:10px;">
© <a href="/">MrDoc 2019-2020</a>&nbsp;|&nbsp;
<!-- <span class="layui-hide-xs">基于<a href="https://www.djangoproject.com/" target="_blank">Django</a>&nbsp;|&nbsp;</span> -->
© <a href="https://zmister.com/mrdoc/">MrDoc 2019-2020</a>&nbsp;|&nbsp;
<a href="https://zmister.com" target="_blank">州的先生</a>出品 |
<a href="{% url 'sitemap' %}" target="_blank">网站地图</a>
</div>
</div>

View File

@ -91,11 +91,11 @@
if(res.status == 1){
window.location.reload();
}else{
layer.msg("上传出错,请重试!")
layer.msg(res.data)
}
},
accept: 'file', //允许上传的文件类型
exts:'zip', //允许上传zip压缩文件
//exts:'zip', //允许上传zip压缩文件
field:'attachment_upload',
size: 50000, //最大允许上传的文件大小

View File

@ -87,7 +87,7 @@
<div class="layui-footer" style="text-align:center;font-size: 12px;">
<!-- 底部固定区域 -->
© <a href="https://gitee.com/zmister/MrDoc" target="_blank">MrDoc 2019-2020</a>&nbsp;-&nbsp;
© <a href="https://zmister.com/mrdoc/" target="_blank">MrDoc 2019-2020</a>&nbsp;-&nbsp;
当前版本:<a href="https://gitee.com/zmister/MrDoc/tree/{{mrdoc_version}}/" target="_blank">{{mrdoc_version}}</a>&nbsp;-&nbsp;
<a href="https://github.com/zmister2016/MrDoc" target="_blank">GitHub</a>&nbsp;-&nbsp;
<a href="https://gitee.com/zmister/MrDoc" target="_blank">码云</a>&nbsp;-&nbsp;

View File

@ -72,7 +72,7 @@
</div>
{% endblock %}
{% block custom_script %}
<script src="{% static 'viewerjs/viewer.js' %}"></script>
<script src="{% static 'viewerjs/viewer.min.js' %}"></script>
<script>
var form = layui.form;
var flow = layui.flow;
@ -213,7 +213,7 @@
if(res.success == 1){
window.location.reload();
}else{
layer.msg("上传出错,请重试!")
layer.msg(res.message)
}
},
error:function(){
@ -223,7 +223,6 @@
accept: 'images', //允许上传的文件类型
acceptMime:'image/*',
field:'manage_upload',
size: 5000, //最大允许上传的文件大小
})
</script>

View File

@ -2,11 +2,11 @@
{% load staticfiles %}
{% block title %}仪表盘{% endblock %}
{% block content %}
<!-- <div class="layui-card-header" style="margin-bottom: 10px;">
<div class="layui-card-header" style="margin-bottom: 10px;">
<div class="layui-row">
<span style="font-size:18px;">个人中心</span>
<span style="font-size:18px;">工作台</span>
</div>
</div> -->
</div>
<div class="layui-row layui-col-space20">
<div class="layui-col-md4">
<div class="layui-collapse">

View File

@ -77,7 +77,10 @@
<td>
<a href="javascript:void(0);" title="修改文集" onclick="modifyProject('{{pro.id}}','{{pro.name}}','{{pro.intro}}')" class="layui-btn layui-btn-xs layui-btn-normal">
<i class="layui-icon layui-icon-edit"></i>
</a>
</a>
<!-- <a href="{% url 'modify_project' %}?pro_id={{pro.id}}" title="修改文集" class="layui-btn layui-btn-xs layui-btn-normal">
<i class="layui-icon layui-icon-edit"></i>
</a> -->
<a href="javascript:void(0);" title="导出文集" onclick="reportMd('{{pro.id}}')" class="layui-btn layui-btn-xs layui-btn-normal">
<i class="layui-icon layui-icon-export"></i>
</a>

View File

@ -0,0 +1,205 @@
{% extends 'app_doc/manage_base.html' %}
{% load staticfiles %}
{% block title %}文集设置{% endblock %}
{% block content %}
<link href="{% static 'tagsInput/tagsinput.css' %}" rel="stylesheet" type="text/css"/>
<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;">文集:{{pro.name}}
</span>
</div>
</div>
<!-- 文集基本信息 -->
<div class="layui-row" style="margin-top: 10px;">
<div class="layui-collapse">
<div class="layui-colla-item">
<h2 class="layui-colla-title">基本信息</h2>
<div class="layui-colla-content layui-show">
<div>
<div class="layui-form-item">
<label class="layui-form-label">文集名称</label>
<div class="layui-input-block">
<input class="layui-input" type="text" id="pname" style="margin-bottom:10px;" placeholder="输入文集名" required lay-verify="required" value="{{pro.name}}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">文集简介</label>
<div class="layui-input-block">
<textarea name="desc" id="desc" placeholder="输入文集简介" class="layui-textarea">{{pro.intro}}</textarea>
</div>
</div>
<div class="layui-form-item" style="margin-top: 10px;">
<div class="layui-input-block">
<button class="layui-btn layui-btn-primary layui-btn-sm"><i class="layui-icon layui-icon-edit"></i>修改</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 文集权限配置 -->
<div class="layui-row" style="margin-top: 10px;">
<div class="layui-collapse">
<div class="layui-colla-item">
<h2 class="layui-colla-title">权限控制</h2>
<div class="layui-colla-content layui-show">
<form action="{% url 'modify_pro_role' 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="radio" name="role" value="0" title="公开" {% if pro.role == 0 %} checked {%endif%} lay-filter="role">
<input type="radio" name="role" value="1" title="私密" {% if pro.role == 1 %} checked {%endif%} lay-filter="role">
<input type="radio" name="role" value="2" title="指定用户可见" {% if pro.role == 2 %} checked {%endif%} lay-filter="role">
<input type="radio" name="role" value="3" title="访问码可见" {% if pro.role == 3 %} checked {%endif%} lay-filter="role">
</div>
</div>
<div class="layui-form-item" style="{% if pro.role == 3 %}{% else %}display:none;{% endif %}" id="role-pwd">
<label class="layui-form-label">访问码</label>
<div class="layui-input-inline">
<input type="text" name="viewcode" placeholder="请输入访问码" autocomplete="off" class="layui-input" value="{% if pro.role_value != None %}{{pro.role_value}}{% endif %}">
</div>
<div class="layui-form-mid layui-word-aux">不少于4位数</div>
</div>
<div class="layui-form-item" style="{% if pro.role == 2 %}{% else %}display:none;{% endif %}" id="role-user">
<label class="layui-form-label">允许用户</label>
<div class="layui-input-block">
<div class="tagsinput-primary form-group">
<input name="tagsinput" id="tagsinputval" class="tagsinput" data-role="tagsinput" value="{% if pro.role_value != None %}{{pro.role_value}}{% endif %}" placeholder="请输入用户名,回车输入多个用户">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn layui-btn-primary layui-btn-sm" lay-submit lay-filter="formDemo">保存权限</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- 文集下载和导出配置 -->
<div class="layui-row" style="margin-top: 10px;">
<div class="layui-collapse">
<div class="layui-colla-item">
<h2 class="layui-colla-title">下载和导出</h2>
<div class="layui-colla-content layui-show">
<form action="{% url 'modify_pro_download' pro.id %}" method="post" class="layui-form">
{% csrf_token %}
{% load project_filter %}
<div class="layui-form-item">
<blockquote class="layui-elem-quote">注意开启某类型文件下载后请先点击“生成或更新XXX文件”文集文档中如果包含公式、流程图、时序图、脑图等内容将会延长生成时间请耐心等待</blockquote>
</div>
<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|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: #ff213b;">未生成文集导出文件</span>
{% endif %}
{% endif %}
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">PDF下载</label>
<div class="layui-input-block">
<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: #ff213b;">未生成文集导出文件</span>
{% endif %}
{% endif %}
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn layui-btn-primary layui-btn-sm" lay-submit lay-filter="formDemo">保存文集导出配置</button>
<button class="layui-btn layui-btn-primary layui-btn-sm">导出Markdown</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- 删除文集 -->
<div class="layui-row" style="margin-top: 10px;">
<div class="layui-collapse">
<div class="layui-colla-item">
<h2 class="layui-colla-title">删除文集</h2>
<div class="layui-colla-content layui-show">
<div>
<div class="layui-form-item" style="margin-top: 10px;">
<button class="layui-btn layui-btn-warm layui-btn-sm"><i class="layui-icon layui-icon-delete"></i>删除文集</button>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_script %}
<script src="{% static '/tagsInput/tagsinput.js' %}" type="text/javascript" charset="utf-8"></script>
<script>
$.ajaxSetup({
data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
});
var form = layui.form;
//监听单选事件
form.on('radio(role)', function(data){
console.log(data.elem); //得到radio原始DOM对象
console.log(data.value); //被点击的radio的value值
if(data.value in [0,1]){
$("#role-pwd").css("display","none");
$("#role-user").css("display","none");
}else if(data.value == 2){
$("#role-user").css("display","block");
$("#role-pwd").css("display","none");
}else if(data.value == 3){
$("#role-user").css("display","none");
$("#role-pwd").css("display","block");
}
});
</script>
{% endblock %}

View File

@ -33,6 +33,19 @@
<div class="layui-form-mid layui-word-aux"><button class="layui-btn layui-btn-primary layui-btn-xs" onclick="changePwd();">点击修改密码</button></div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">编辑器</label>
<div class="layui-input-block">
{% if user_opt.editor_mode == 2 %}
<input type="radio" name="editor_mode" value="1" title="EditorMD" >
<input type="radio" name="editor_mode" value="2" title="Vditor" checked>
{% else %}
<input type="radio" name="editor_mode" value="1" title="EditorMD" checked>
<input type="radio" name="editor_mode" value="2" title="Vditor" >
{% endif %}
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn layui-btn-normal" onclick="updateUser();">更新个人资料</button>
@ -73,11 +86,13 @@
},
})
};
// 更新用户选项
updateUser = function(){
layer.load(1)
data = {
'first_name':$("#first_name").val(),
'email':$("#email").val(),
'editor_mode':$(':radio[name="editor_mode"]:checked').val()
}
$.post("{% url 'manage_self' %}",data,function(r){
layer.closeAll("loading");

View File

@ -0,0 +1,591 @@
{% extends 'app_doc/create_base_vditor.html' %}
{% load staticfiles %}
{% block title %}修改文档{% endblock %}
{% block editor_type %}修改文档{% endblock %}
{% block custom_style %}
<style>
ul li{
list-style:disc;
}
ul > li > ul > li{
list-style-type: circle;
}
ol li{
list-style-type: decimal;
}
</style>
{% endblock %}
{% block head_toolbar %}
<a class="btn pull-left" aria-label="" href="{% url 'create_doc' %}?pid={{project.id}}" target="_blank">
<i class="fa fa-plus-square"></i> <span class="layui-hide-xs">新建文档</span>
</a>
<a class="btn pull-left" aria-label="" href="{% url 'manage_doc' %}?pid={{project.id}}" target="_blank">
<i class="fa fa-cubes"></i> <span class="layui-hide-xs">管理文档</span>
</a>
<a class="btn pull-left" aria-label="" href="{% url 'manage_project' %}" target="_blank">
<i class="fa fa-cubes"></i> <span class="layui-hide-xs">管理文集</span>
</a>
{% endblock %}
{% block left_opera %}
<div class="layui-form" style="padding:0 10px 10px 10px;">
<div class="layui-row">
<div class="doc-form-label" style="margin-bottom: 10px;">
{% if doc.status == 0 %}
<strong>*当前文档状态:草稿</strong>
{% elif doc.status == 1 %}
<strong>*当前文档状态:已发布 </strong>
<a class="layui-btn layui-btn-xs layui-btn-normal" target="_blank" href="{% url 'doc' doc.top_doc doc.id %}" style="background-color: #2176ff;">
<i class="fa fa-book"></i> 查看
</a>
<button class="layui-btn layui-btn-xs layui-btn-normal" id="doc-history">
<i class="fa fa-history"></i> 历史
</button>
{% endif %}
</div>
<div class="layui-col-md12" style="margin-bottom: 10px;">
<!-- <label class="doc-form-label" style="margin-right:0px;">
<button class="layui-btn layui-btn-primary layui-btn-sm mrdoc-btn-default" id="sel-doctemp" title="插入文档模板">
<i class="fa fa-clipboard"></i> 选择模板
</button>
</label>
<label class="doc-form-label" style="margin-right:0px;">
<input type="file" id="insert-local-file" onchange="insertLocalFile(this)" style="display:none;">
<button class="layui-btn layui-btn-primary layui-btn-sm mrdoc-btn-default" id="sel-local" onclick="selectLocalFile()" title="插入本地文本文件内容">
<i class="fa fa-upload"></i> 导入文本
</button>
</label> -->
</div>
<div class="layui-col-md12" style="margin-bottom: 10px;">
<div class="layui-input-inblock">
<select name="pro_id" lay-verify="required" lay-filter="project" id="project">
<option value="{{ project.id }}">{{ project.name }}</option>
</select>
</div>
</div>
<div class="layui-row">
<div class="layui-col-md12" style="margin-bottom: 10px;">
<span>点击文档树选择上级(可选)或</span>
<button class="layui-btn layui-btn-xs layui-btn-primary" id="clearParentDoc">取消上级</button>
<input type="text" id="parent-doc" hidden>
</div>
<div class="layui-col-md12">
<input type="number" class="layui-input" placeholder="输入文档排序值默认99" id="sort" value="{{doc.sort}}">
</div>
</div>
<div class="layui-collapse" style="margin-top: 10px;margin-bottom: 10px;">
<div class="layui-colla-item">
<h2 class="layui-colla-title">文档结构树</h2>
<div class="layui-colla-content layui-show" style="max-height: 400px;overflow: hidden;overflow-y: scroll;overflow-x: scroll;">
<div id="doc-tree"></div>
</div>
</div>
</div>
<hr>
<!-- 标签输入框 -->
<div class="layui-collapse" style="margin-top: 10px;margin-bottom: 10px;">
<div class="layui-colla-item">
<h2 class="layui-colla-title">标签</h2>
<div class="layui-colla-content layui-show">
<div class="layui-row layui-col-space5" style="padding: 5px;background-color: #fff;">
<input name="tagsinput" id="tagsinputval" class="tagsinput" data-role="tagsinput" value="{{doc_tags}}" placeholder="输入标签名">
</div>
</div>
</div>
</div>
<!-- 发布按钮 -->
<div class="layui-collapse" style="margin-top: 10px;margin-bottom: 10px;">
<div class="layui-colla-item">
<h2 class="layui-colla-title">发布</h2>
<div class="layui-colla-content layui-show">
<div class="layui-row layui-col-space5" style="padding: 5px;background-color: #fff;">
<div class="layui-row" style="margin-top: 5px;">
<button class="layui-btn layui-btn-primary layui-btn-fluid mrdoc-btn-default" onclick="saveDoc()" title="保存当前内容为草稿文档">
<i class="fa fa-save"></i> 保存为草稿
</button>
</div>
<div class="layui-row" style="margin-top: 5px;">
<button class="layui-btn layui-btn-normal layui-btn-fluid" onclick="createDoc()" id="create_doc" title="发布当前内容">
<i class="fa fa-save"></i> 发布文档
</button>
</div>
<div class="layui-row" style="margin-top: 5px;">
<button class="layui-btn layui-btn-warm layui-btn-fluid" onclick="moveDoc()" title="复制或移动此文档到其他文集"><i class="fa fa-copy"></i> 复制/移动文档</button>
</div>
<div class="layui-row" style="margin-top: 5px;">
<button class="layui-btn layui-btn-danger layui-btn-fluid" onclick="delDoc()" title="删除此文档"><i class="fa fa-trash"></i> 删除文档</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block content %}
<div class="create-doc-form">
<div class="layui-form">
<!-- 标题 -->
<div class="layui-input-block" style="margin-left:0;">
<input type="text" name="doc-name" id="doc-name" required lay-verify="required" placeholder="请输入文档标题" value="{{ doc.name }}" class="layui-input">
</div>
<br>
</div>
</div>
<div id="editor-md">
<textarea style="display:none;">{{ doc.pre_content }}</textarea>
<textarea class="editormd-html-textarea" name="$id-html-code"></textarea>
</div>
{% endblock %}
{% block custom_script %}
<script>
//获取文档数和上级文档信息
$(function(){
layer.load(1);
var doc_parent_id = '{{ doc.parent_doc }}';
$.post("{% url 'get_pro_doc_tree' %}",{'pro_id':$("#project").val()},function(r){
if(r.status){
layer.closeAll("loading");
var doc_tree = tree.render({
elem:"#doc-tree",
id:'docTree',
onlyIconControl:true,
data:r.data,
click: function(obj){
if(obj.data.level != 3){
console.log(obj.data.id,doc_parent_id)
if(obj.data.id != '{{ doc.id }}' ){
$('#parent-doc').val(obj.data.id);// 设置上级文档
$("div.layui-tree-set").each(function(i){
var $me = $(this)
if($me.data('id') == obj.data.id){
// console.log('点击了')
layer.msg("你选择了上级文档:"+obj.data.title)
$me.find('span.layui-tree-txt').first().addClass('selected-parent-doc')
}else{
$me.find('span.layui-tree-txt').first().removeClass('selected-parent-doc')
}
});
}else{
layer.msg("不可选择自己作为上级")
};
}else{
layer.msg("第三级文档不能作为上级文档")
};
}
});
$('#parent-doc').val(doc_parent_id);// 设置上级文档
$("div.layui-tree-set").each(function(i){
var $me = $(this)
if($me.data('id') == doc_parent_id){
$me.find('span.layui-tree-txt').first().addClass('selected-parent-doc')
}else{
$me.find('span.layui-tree-txt').first().removeClass('selected-parent-doc')
}
});
}else{
layer.msg("获取下级文档失败!")
}
});
});
//发布文档
createDoc = function(){
$('button.layui-btn').attr("disabled",true);
$('button.layui-btn').addClass('layui-btn-disabled');
layer.load(1);
var data = {
'doc_id':'{{ doc.id }}',
'project':$("#project").val(),
'parent_doc':$("#parent-doc").val(),
'doc_tag':$("#tagsinputval").val(),
'doc_name':$("#doc-name").val(),
'content':editor.getHTML(),
'pre_content':editor.getValue(),
'sort':$("#sort").val(),
};
$.post("{% url 'modify_doc' doc_id=doc.id %}",data,function(r){
layer.closeAll("loading");
if(r.status){
//修改成功
layer.msg('发布成功,即将跳转',function(){
md_changed = false;
window.location.href = "{% url 'doc' pro_id=doc.top_doc doc_id=doc.id %}";
});
}else{
//修改失败
layer.msg('保存失败');
$('button.layui-btn').attr("disabled",false);
$('button.layui-btn').removeClass('layui-btn-disabled');
}
});
};
//保存草稿
saveDoc = function(){
$('button.layui-btn').attr("disabled",true);
$('button.layui-btn').addClass('layui-btn-disabled');
layer.load(1);
var data = {
'doc_id':'{{ doc.id }}',
'project':$("#project").val(),
'doc_tag':$("#tagsinputval").val(),
'parent_doc':$("#parent-doc").val(),
'doc_name':$("#doc-name").val(),
'content':editor.getHTML(),
'pre_content':editor.getValue(),
'sort':$("#sort").val(),
'status':0
}
$.post("{% url 'modify_doc' doc_id=doc.id %}",data,function(r){
layer.closeAll("loading");
if(r.status){
//修改成功
layer.msg('保存成功',function(){
md_changed = false;
window.location.href = "{% url 'modify_doc' doc.id %}";
});
}else{
//修改失败
layer.msg('保存失败');
$('button.layui-btn').attr("disabled",false);
$('button.layui-btn').removeClass('layui-btn-disabled');
}
});
};
//选择文档模板
$("#sel-doctemp").click(function(){
layer.open({
type: 1,
id:'temp-div',
content: $('#doctemp-list'),
area:['530px','400px'],
});
});
//插入模板
insertTemp = function(doctemp_id){
layer.load();
$.post("{% url 'get_doctemp' %}",{'doctemp_id':doctemp_id},function(r){
if(r.status){
editor.insertValue(r.data);
layer.closeAll()
}else{
layer.closeAll("loading");
layer.msg(r.data)
}
});
};
//插入本地文本文件
function insertLocalFile(input) {
var file = input.files[0];
//filename = file.name.split(".")[0]; // 文件名
//支持chrome IE10
if (window.FileReader) {
var reader = new FileReader();
reader.onload = function() {
console.log(this.result);
editor.insertValue(this.result);
}
reader.readAsText(file);
}
//支持IE 7 8 9 10
else if (typeof window.ActiveXObject != 'undefined'){
var xmlDoc;
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async = false;
xmlDoc.load(input.value);
console.log(xmlDoc.xml);
editor.insertValue(xmlDoc.xml);
}
//支持FF
else if (document.implementation && document.implementation.createDocument) {
var xmlDoc;
xmlDoc = document.implementation.createDocument("", "", null);
xmlDoc.async = false;
xmlDoc.load(input.value);
console.log(xmlDoc.xml);
editor.insertValue(xmlDoc.xml);
} else {
alert('error');
}
};
//选择本地文本文件
function selectLocalFile(){
$("#insert-local-file").trigger("click");
};
// 查看历史记录
$("#doc-history").click(function(){
layer.open({
type: 1,
title:'查看当前文档的历史版本',
id:'history-div',
content: $('#history-list'),
area:['530px','300px'],
});
});
//清除所选上级文档
$("#clearParentDoc").click(function(){
$('#parent-doc').val("");
$("span.layui-tree-txt").each(function(i){
var $me = $(this)
$me.removeClass('selected-parent-doc')
});
});
// 插入历史版本
insertHistory = function(doc_id,history_id){
layer.load(1);
var url = "{% url 'diff_doc' 0 1 %}";
url = url.replace(0,doc_id).replace(1,history_id)
$.post(url,function(r){
layer.closeAll("loading");
if(r.status){
editor.setMarkdown(r.data);
}else{
layer.msg(r.data)
}
});
};
// 删除文档
delDoc = function(doc_id){
layer.open({
type:1,
title:'删除文档',
area:'300px;',
id:'delPro',//配置ID
content:'<div style="margin-left:10px;">警告:此操作将删除此文档!</div>',
btn:['确定','取消'], //添加按钮
btnAlign:'c', //按钮居中
yes:function (index,layero) {
layer.load(1);
data = {
'doc_id':'{{ doc.id }}',
};
$.post("{% url 'del_doc' %}",data,function(r){
layer.closeAll('loading')
if(r.status){
//修改成功
layer.msg("文档已删除,即将跳转至文集")
// window.location.reload();
window.location.href = "{% url 'pro_index' doc.top_doc %}"
//layer.close(index)
}else{
//修改失败,提示
// console.log(r)
layer.msg(r.data)
}
})
},
});
};
// 移动文档
moveDoc = function(doc_id){
layer.open({
type:1,
title:'复制或移动此文档到指定文集',
id:'moveDoc',
area:'450px;',
content:$('#move-project'),
success:function(layero,index){
form.render(null, 'move-projects'); // 重新渲染弹出框的表单
// 移动文集 - 侦听选择文集 - 获取文集的文档
form.on('select(moveProject)', function(data){
// console.log(data.value); //得到被选中的值
$('#move-parent-id').val(0);
//获取文集的下级文档
$.post("{% url 'get_pro_doc_tree' %}",{'pro_id':data.value},function(r){
if(r.status){
var doc_tree = tree.render({
elem:"#move-doc-tree",
id:'moveDocTree',
onlyIconControl:true,
data:r.data,
text: {
defaultNodeName: '未命名' //节点默认名称
,none: '文集暂无文档' //数据为空时的提示文本
},
click: function(obj){
if(obj.data.level != 3){
$('#move-parent-id').val(obj.data.id);// 设置上级文档
$("div.layui-tree-set").each(function(i){
var $me = $(this)
if($me.data('id') == obj.data.id){
// console.log('点击了')
layer.msg("选择了上级文档:"+obj.data.title)
$me.find('span.layui-tree-txt').first().addClass('selected-parent-doc')
}else{
$me.find('span.layui-tree-txt').first().removeClass('selected-parent-doc')
}
});
}else{
layer.msg("第三级文档不能作为上级文档")
}
}
});
}else{
layer.msg("获取下级文档失败!")
}
});
});
},
})
};
// 提交移动文档
submitMoveDoc = function(){
var data = {
move_type:$("input:radio[name='move-type']:checked").val(),
pro_id:$("#moveProject").val(),
parent_id:$("#move-parent-id").val(),
doc_id:'{{doc.id}}'
};
if(data.pro_id === ''){
layer.msg("必须选择一个文集")
return
}
console.log(data)
layer.load(1)
$.post("{% url 'move_doc' %}",data,function(r){
layer.closeAll('loading')
if(r.status){
window.location.href = '/project-'+r.data.pro_id + '/doc-' + r.data.doc_id + '/'
}else{
layer.msg(r.data)
}
});
};
</script>
{% endblock %}
{% block custom_div %}
<!-- 模板div块 -->
<div class="doctemp-list" id="doctemp-list" style="display: none;width: 500px;">
<div style="margin: 10px 0 0 10px;">
<a class="layui-btn layui-btn-normal layui-btn-sm" href="{% url 'create_doctemp' %}" target="_blank">创建新模板</a>
<a class="layui-btn layui-btn-normal layui-btn-sm" href="{% url 'manage_doctemp' %}" target="_blank">管理文档模板</a>
</div>
<table class="layui-table" style="margin: 10px;">
<colgroup>
<col width="150">
<col width="200">
<col>
</colgroup>
<thead>
<tr>
<th>模板名称</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for temp in doctemp_list %}
<tr>
<td>{{ temp.name }}</td>
<td>{{ temp.create_time }}</td>
<td>
<a href="javascript:void(0);" class="layui-btn layui-btn-normal layui-btn-sm" onclick="insertTemp('{{temp.id}}');">选择模板</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- 文档历史div块 -->
<div class="history-list" id="history-list" style="display: none;width: 500px;">
<table class="layui-table" style="margin: 10px;" lay-size='sm'>
<thead>
<tr>
<th>创建时间</th>
<th>用户</th>
<th>对比</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for history in history_list %}
<tr>
<td>{{ history.create_time }}</td>
<td>{{ history.create_user }}</td>
<td>
<a href="{% url 'diff_doc' history.doc.id history.id %}" class="layui-btn layui-btn-primary layui-btn-sm" target="_blank">查看版本差异</a>
</td>
<td>
<a href="javascript:void(0);" class="layui-btn layui-btn-normal layui-btn-sm" onclick="insertHistory('{{history.doc.id}}','{{history.id}}');">恢复此版本</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- 移动文档div块 -->
<div class="layui-form" id="move-project" style="display: none;width: 400px;height: 500px;" lay-filter='move-projects'>
<div class="layui-col-md12" style="margin: 10px;">
<div class="layui-form-item">
<!-- <label class="layui-form-label">操作类型</label> -->
<div class="layui-input-block" style="margin-left: 0px;">
<input type="radio" name="move-type" value="0" title="复制" checked>
<input type="radio" name="move-type" value="1" title="移动">
<input type="radio" name="move-type" value="2" title="移动(含下级文档)">
</div>
</div>
<input id="move-parent-id" hidden value="0" />
<div class="layui-input-inblock">
<select name="move_pro_id" lay-filter="moveProject" id="moveProject">
<option value="">请选择一个文集(必选)</option>
<!-- 自己的文集 -->
<optgroup label="自有文集" id="self-project">
{% for p in project_list %}
{% if p.role == 1 %}
<option value="{{ p.id }}">[私密]《{{ p.name }}》</option>
{% elif p.role == 2 %}
<option value="{{ p.id }}" >[指定用户]《{{ p.name }}》</option>
{% elif p.role == 3 %}
<option value="{{ p.id }}" >[访问码]《{{ p.name }}》</option>
{% else %}
<option value="{{ p.id }}" >[公开]《{{ p.name }}》</option>
{% endif %}
{% endfor %}
</optgroup>
<!-- 协作的文集 -->
{% if colla_project_list.count > 0 %}
<optgroup label="协作文集">
{% for p in colla_project_list %}
<option value="{{ p.project.id }}">[协作]《{{ p.project.name }}》</option>
{% endfor %}
</optgroup>
{% endif %}
</select>
</div>
</div>
<div class="layui-col-md12" style="max-height: 380px;overflow: hidden;overflow-y: scroll;overflow-x: scroll;">
<div id="move-doc-tree"></div>
</div>
<div class="layui-col-md12" style="margin: 10px;">
<button class="layui-btn layui-btn-normal layui-btn-fluid" onclick="submitMoveDoc()">确认操作</button>
</div>
<div class="layui-col-md12" style="margin: 10px;">
<span style="font-size: 12px;color:mediumvioletred;">警告MrDoc仅支持3级目录显示若移动的下级文档层级在目标文集中超过3层将不会显示在文集目录中</span>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,87 @@
{% extends 'app_doc/create_base_vditor.html' %}
{% load staticfiles %}
{% block title %}修改文档模板{% endblock %}
{% block editor_type %}修改文档模板{% endblock %}
{% block head_toolbar %}
<a class="btn pull-left" aria-label="" href="{% url 'create_doctemp' %}?pid={{project.id}}" target="_blank">
<i class="fa fa-plus-square"></i> <span class="layui-hide-xs">新建模板</span>
</a>
<a class="btn pull-left" aria-label="" href="{% url 'manage_doctemp' %}?pid={{project.id}}" target="_blank">
<i class="fa fa-cubes"></i> <span class="layui-hide-xs">管理模板</span>
</a>
<a class="btn pull-left" aria-label="" href="{% url 'manage_project' %}" target="_blank">
<i class="fa fa-cubes"></i> <span class="layui-hide-xs">管理文集</span>
</a>
{% endblock %}
{% block left_opera %}
<div class="layui-form" style="padding: 10px;">
<div class="layui-row">
<div class="layui-col-md12" style="margin-bottom: 10px;">
<label class="doc-form-label">
<button class="layui-btn layui-btn-normal layui-btn-fluid" onclick="modifyDocTemp()">
<i class="fa fa-save"></i> 保存模板
</button>
</label>
</div>
</div>
<!-- 已有模板 -->
<div class="layui-row">
<div class="layui-card">
<div class="layui-card-header">现有模板</div>
<div class="layui-card-body">
{% for temp in doctemps %}
<li><a href="{% url 'modify_doctemp' temp.id %}" target="_blank" title="点击查看修改《{{temp.name}}》的内容"><i class="fa fa-file"></i> {{temp.name}}</a></li>
{% endfor %}
</div>
</div>
</div>
</div>
{% endblock %}
{% block content %}
<div class="create-doc-form">
<div class="layui-form" style="padding-bottom:10px;">
<div class="layui-input-block" style="margin-left:0px;">
<input type="text" name="doc-name" id="doctemp-name" required lay-verify="required" value="{{doctemp.name}}" placeholder="请输入模板名称" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div id="editor-md">
<textarea style="display:none;">{{doctemp.content}}</textarea>
<textarea class="editormd-html-textarea" name="$id-html-code"></textarea>
</div>
{% endblock %}
{% block custom_script %}
<script>
//修改文档模板
modifyDocTemp = function(){
$('button.layui-btn').attr("disabled",true);
$('button.layui-btn').addClass('layui-btn-disabled');
layer.load(1);
var data = {
'doctemp_id':'{{ doctemp.id }}',
'name':$("#doctemp-name").val(),
'content':editor.getValue(),
}
$.post("{% url 'modify_doctemp' doctemp_id=doctemp.id %}",data,function(r){
layer.closeAll("loading");
if(r.status){
//修改成功
layer.msg('修改成功,即将跳转',function(){
md_changed = false;
window.location.href = "{% url 'manage_doctemp' %}";
});
}else{
//创建失败
layer.msg('保存失败');
$('button.layui-btn').attr("disabled",false);
$('button.layui-btn').removeClass('layui-btn-disabled');
}
});
};
</script>
{% endblock %}