添加文集协作功能并优化了一些细节

This commit is contained in:
yangjian 2020-04-03 21:05:27 +08:00
parent a037436f01
commit 5ab918c9ec
25 changed files with 597 additions and 123 deletions

View File

@ -4,6 +4,8 @@
- 添加基于用户的API模块支持通过用户Token获取文集、新建文档和上传图片
- 优化文档编辑页面布局;
- 添加文集协作者功能,文集支持多用户协同协作了;
- 修改文档阅读页面的文档内链接新窗口打开;
### v0.3.3 2020-03-21

View File

@ -1,4 +1,4 @@
# MrDoc - 记录文档,汇聚思想
## MrDoc - 记录文档,汇聚思想
![Mrdoc首页](./docs/mrdoc_2019080101.gif)
@ -8,14 +8,14 @@
MarkDown快速书写两栏式阅读布局清晰高效浏览。
当前版本为:**v0.3.4**,版本发布时间为**2020-03-29**
当前版本为:**v0.3.4**,版本发布时间为**2020-04-03**
完整更新记录详见:[CHANGES.md](./CHANGES.md)
MrDoc拥有以下特点
- 简洁的站点与用户系统
- 基于Django自带的用户模型实现简单高效的用户管理支持用户注册、用户登录、管理员等控制等功能;
- 支持用户注册、用户登录、用户管理、管理员等控制等功能;
- 支持全站关闭注册;
- 支持注册邀请码配置;
- 支持广告位自定义配置;
@ -29,6 +29,8 @@ MrDoc拥有以下特点
- 支持三级目录层级显示;
- 支持文集后台导出为markdown文本格式.md文件、前台导出为EPUB电子书
- 基于文集进行权限控制提供公开、私密、指定用户可见、访问码可见4种权限模式
- 支持基于账户的API接口可以借助账户token通过API获取文集、上传图片和创建文档
- 支持文集协作功能,一个文集可以拥有一个创建者和多个协作者,可灵活选择协作权限;
在开发过程中参考和借鉴了GitBook、ShowDoc、Wordbook等应用和网站的功能与样式并使用了众多开源组件、插件。

View File

@ -0,0 +1,31 @@
# Generated by Django 2.2.11 on 2020-03-30 21:14
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_doc', '0014_auto_20200322_1459'),
]
operations = [
migrations.CreateModel(
name='ProjectCollaborator',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('role', models.IntegerField(choices=[(0, 0), (1, 1)], default=0, verbose_name='协作模式')),
('create_time', models.DateTimeField(auto_now=True, verbose_name='添加时间')),
('modify_time', models.DateTimeField(auto_now_add=True, verbose_name='修改时间')),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app_doc.Project')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': '文集协作',
'verbose_name_plural': '文集协作',
},
),
]

View File

@ -26,21 +26,21 @@ class Project(models.Model):
"pro_id":self.pk}
)
# # 文集协作模型
# class ProjectCollaborator(models.Model):
# project = models.ForeignKey(Project,on_delete=models.CASCADE)
# user = models.ForeignKey(User,on_delete=models.CASCADE)
# # 用户的协作模式0表示可新建文档可修改删除自己新建的文档1表示可新建文档可修改删除所有文档
# role = models.IntegerField(choices=((0,0),(1,1)),default=0,verbose_name='协作模式')
# create_time = models.DateTimeField(auto_now=True,verbose_name='添加时间')
# modify_time = models.DateTimeField(auto_now_add=True,verbose_name='修改时间')
#
# def __str__(self):
# return self.project
#
# class Meta:
# verbose_name = '文集协作'
# verbose_name_plural = verbose_name
# 文集协作模型
class ProjectCollaborator(models.Model):
project = models.ForeignKey(Project,on_delete=models.CASCADE) # 文集
user = models.ForeignKey(User,on_delete=models.CASCADE) # 用户
# 用户的协作模式0表示可新建文档可修改删除自己新建的文档1表示可新建文档可删除自己创建的文档、可修改所有文档
role = models.IntegerField(choices=((0,0),(1,1)),default=0,verbose_name='协作模式')
create_time = models.DateTimeField(auto_now=True,verbose_name='添加时间')
modify_time = models.DateTimeField(auto_now_add=True,verbose_name='修改时间')
def __str__(self):
return self.project
class Meta:
verbose_name = '文集协作'
verbose_name_plural = verbose_name
# 文档模型
class Doc(models.Model):

View File

@ -15,6 +15,15 @@ def get_next_doc(value):
def get_doc_top(value):
return Project.objects.get(id=int(value))
# 获取用户是否为文集创建者
@register.filter(name='is_colla_pro')
def is_colla_pro(pro,user):
p = Project.objects.filter(id=pro,create_user=user)
if p.exists():
return ''
else:
return '【协作】'
# 获取文档的上级文档名称
@register.filter(name='get_doc_parent')
def get_doc_parent(value):

View File

@ -34,4 +34,10 @@ def get_report_status(value):
@register.filter(name='img_group_cnt')
def get_img_group_cnt(value):
cnt = Image.objects.filter(group_id=value).count()
return cnt
return cnt
# 获取文集的协作用户数
@register.filter(name='project_collaborator_cnt')
def get_project_collaborator_cnt(value):
cnt = ProjectCollaborator.objects.filter(project=value).count()
return cnt

View File

@ -15,6 +15,8 @@ urlpatterns = [
path('modify_pro_role/<int:pro_id>/',views.modify_project_role,name="modify_pro_role"),# 修改文集权限
path('modify_pro_download/<int:pro_id>/', views.modify_project_download, name="modify_pro_download"), # 修改文集前台下载权限
path('check_viewcode/',views.check_viewcode,name='check_viewcode'),# 文集访问码验证
path('manage_project_colla/<int:pro_id>/',views.manage_project_collaborator,name="manage_pro_colla"), # 管理文集协作
path('manage_pro_colla_self/',views.manage_pro_colla_self,name="manage_pro_colla_self"), # 我协作的文集
#################文档相关
path('project-<int:pro_id>/doc-<int:doc_id>/', views.doc, name='doc'), # 文档浏览页
path('create_doc/', views.create_doc, name="create_doc"), # 新建文档

View File

@ -26,8 +26,14 @@ def validateTitle(title):
def project_list(request):
# 登录用户
if request.user.is_authenticated:
# 用户的协作文集
colla_list = [i.project.id for i in ProjectCollaborator.objects.filter(user=request.user)]
# 查询所有可显示的文集
project_list = Project.objects.filter(
Q(role__in=[0,3]) | Q(role=2,role_value__contains=str(request.user.username)) | Q(create_user=request.user)
Q(role__in=[0,3]) | \
Q(role=2,role_value__contains=str(request.user.username)) | \
Q(create_user=request.user) | \
Q(id__in=colla_list)
)
else:
# 非登录用户只显示公开文集和需要访问码的文集
@ -72,6 +78,11 @@ def project_index(request,pro_id):
try:
# 获取文集信息
project = Project.objects.get(id=int(pro_id))
# 获取文集的协作用户信息
if request.user.is_authenticated: # 对登陆用户查询其协作文档信息
colla_user = ProjectCollaborator.objects.filter(project=project,user=request.user).count()
else:
colla_user = 0
# 获取问价文集前台下载权限
try:
@ -79,21 +90,23 @@ def project_index(request,pro_id):
except ObjectDoesNotExist:
allow_epub_download = 0
# 私密文集并且访问者非创建者
if project.role == 1 and request.user != project.create_user:
# 私密文集并且访问者非创建者非协作者
if (project.role == 1) and (request.user != project.create_user) and (colla_user == 0):
return render(request,'404.html')
# 指定用户可见文集
elif project.role == 2:
user_list = project.role_value
if request.user.is_authenticated: # 认证用户判断是否在许可用户列表中
if request.user.username not in user_list and request.user != project.create_user: # 访问者不在指定用户之中
if (request.user.username not in user_list) and \
(request.user != project.create_user) and \
(colla_user == 0): # 访问者不在指定用户之中
return render(request, '404.html')
else:# 游客直接返回404
return render(request, '404.html')
# 访问码可见
elif project.role == 3:
# 浏览用户不为创建者
if request.user != project.create_user:
# 浏览用户不为创建者、协作者
if request.user != project.create_user and colla_user == 0:
viewcode = project.role_value
viewcode_name = 'viewcode-{}'.format(project.id)
r_viewcode = request.COOKIES[viewcode_name] if viewcode_name in request.COOKIES.keys() else 0 # 从cookie中获取访问码
@ -121,6 +134,7 @@ def modify_project(request):
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)
@ -288,6 +302,81 @@ def modify_project_download(request,pro_id):
return render(request,'app_doc/manage_project_download.html',locals())
# 文集协作管理
@login_required()
def manage_project_collaborator(request,pro_id):
project = Project.objects.filter(id=pro_id, create_user=request.user)
if project.exists() is False:
return Http404
if request.method == 'GET':
pro = project[0]
collaborator = ProjectCollaborator.objects.filter(project=pro)
return render(request, 'app_doc/manage_project_collaborator.html', locals())
elif request.method == 'POST':
# type类型0表示新增协作者、1表示删除协作者、2表示修改协作者
types = request.POST.get('types','')
try:
types = int(types)
except:
return JsonResponse({'status':False,'data':'参数错误'})
# 添加文集协作者
if int(types) == 0:
colla_user = request.POST.get('username','')
role = request.POST.get('role',0)
user = User.objects.filter(username=colla_user)
if user.exists():
if user[0] == project[0].create_user: # 用户为文集的创建者
return JsonResponse({'status':False,'data':'文集创建者无需添加'})
elif ProjectCollaborator.objects.filter(user=user[0],project=project[0]).exists():
return JsonResponse({'status':False,'data':'用户已存在'})
else:
ProjectCollaborator.objects.create(
project = project[0],
user = user[0],
role = role if role in ['1',1] else 0
)
return JsonResponse({'status':True,'data':'添加成功'})
else:
return JsonResponse({'status':False,'data':'用户不存在'})
# 删除文集协作者
elif int(types) == 1:
username = request.POST.get('username','')
try:
user = User.objects.get(username=username)
pro_colla = ProjectCollaborator.objects.get(project=project[0],user=user)
pro_colla.delete()
return JsonResponse({'status':True,'data':'删除成功'})
except:
if settings.DEBUG:
print(traceback.print_exc())
return JsonResponse({'status':False,'data':'删除出错'})
# 修改协作权限
elif int(types) == 2:
username = request.POST.get('username', '')
role = request.POST.get('role','')
try:
user = User.objects.get(username=username)
pro_colla = ProjectCollaborator.objects.filter(project=project[0], user=user)
pro_colla.update(role=role)
return JsonResponse({'status':True,'data':'修改成功'})
except:
if settings.DEBUG:
print(traceback.print_exc())
return JsonResponse({'status':False,'data':'修改失败'})
else:
return JsonResponse({'status':False,'data':'无效的类型'})
# 我协作的文集
@login_required()
def manage_pro_colla_self(request):
colla_pros = ProjectCollaborator.objects.filter(user=request.user)
return render(request,'app_doc/manage_project_self_colla.html',locals())
# 文档浏览页页
@require_http_methods(['GET'])
def doc(request,pro_id,doc_id):
@ -295,22 +384,35 @@ def doc(request,pro_id,doc_id):
if pro_id != '' and doc_id != '':
# 获取文集信息
project = Project.objects.get(id=int(pro_id))
# 获取文集的协作用户信息
if request.user.is_authenticated:
colla_user = ProjectCollaborator.objects.filter(project=project,user=request.user)
if colla_user.exists():
colla_user_role = colla_user[0].role
colla_user = colla_user.count()
else:
colla_user = colla_user.count()
else:
colla_user = 0
# 私密文集并且访问者非创建者
if project.role == 1 and request.user != project.create_user:
# 私密文集且访问者非创建者、协作者 - 不能访问
if (project.role == 1) and (request.user != project.create_user) and (colla_user == 0):
return render(request, '404.html')
# 指定用户可见文集
elif project.role == 2:
user_list = project.role_value
if request.user.is_authenticated: # 认证用户判断是否在许可用户列表中
if request.user.username not in user_list and request.user != project.create_user: # 访问者不在指定用户之中
if (request.user.username not in user_list) and \
(request.user != project.create_user) and \
(colla_user == 0): # 访问者不在指定用户之中,也不是协作者
return render(request, '404.html')
else: # 游客直接返回404
return render(request, '404.html')
# 访问码可见
elif project.role == 3:
# 浏览用户不为创建者
if request.user != project.create_user:
# 浏览用户不为创建者和协作者 - 需要访问码
if (request.user != project.create_user) and (colla_user == 0):
viewcode = project.role_value
viewcode_name = 'viewcode-{}'.format(project.id)
r_viewcode = request.COOKIES[
@ -342,8 +444,8 @@ def create_doc(request):
if request.method == 'GET':
try:
pid = request.GET.get('pid',-999)
# doc_list = Doc.objects.filter(create_user=request.user)
project_list = Project.objects.filter(create_user=request.user)
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())
except Exception as e:
@ -360,19 +462,26 @@ def create_doc(request):
sort = request.POST.get('sort','')
status = request.POST.get('status',1)
if project != '' and doc_name != '' and project != '-1':
doc = Doc.objects.create(
name=doc_name,
content = doc_content,
pre_content= pre_content,
parent_doc= int(parent_doc) if parent_doc != '' else 0,
top_doc= int(project),
sort = sort if sort != '' else 99,
create_user=request.user,
status = status
)
return JsonResponse({'status':True,'data':{'pro':project,'doc':doc.id}})
# 验证请求者是否有文集的权限
check_project = Project.objects.filter(id=project,create_user=request.user)
colla_project = ProjectCollaborator.objects.filter(project=project,user=request.user)
if check_project.count() > 0 or colla_project.count() > 0:
# 创建文档
doc = Doc.objects.create(
name=doc_name,
content = doc_content,
pre_content= pre_content,
parent_doc= int(parent_doc) if parent_doc != '' else 0,
top_doc= int(project),
sort = sort if sort != '' else 99,
create_user=request.user,
status = status
)
return JsonResponse({'status':True,'data':{'pro':project,'doc':doc.id}})
else:
return JsonResponse({'status':False,'data':'无权操作此文集'})
else:
return JsonResponse({'status':False,'data':'参数错误'})
return JsonResponse({'status':False,'data':'请确认文档标题、文集正确'})
except Exception as e:
if settings.DEBUG:
print(traceback.print_exc())
@ -387,13 +496,15 @@ def modify_doc(request,doc_id):
if request.method == 'GET':
try:
doc = Doc.objects.get(id=doc_id)
if request.user == doc.create_user:
project = Project.objects.get(id=doc.top_doc)
project = Project.objects.get(id=doc.top_doc)
pro_colla = ProjectCollaborator.objects.get(project=project,user=request.user)
if request.user == doc.create_user or pro_colla.role == 1:
doc_list = Doc.objects.filter(top_doc=project.id)
doctemp_list = DocTemp.objects.filter(create_user=request.user)
return render(request,'app_doc/modify_doc.html',locals())
else:
return HttpResponse("非法请求")
# return HttpResponse("非法的请求")
return render(request,'403.html')
except Exception as e:
if settings.DEBUG:
print(traceback.print_exc())
@ -408,18 +519,25 @@ def modify_doc(request,doc_id):
pre_content = request.POST.get('pre_content', '') # 文档Markdown格式内容
sort = request.POST.get('sort', '') # 文档排序
status = request.POST.get('status',1) # 文档状态
if doc_id != '' and project != '' and doc_name != '' and project != '-1':
# 更新文档内容
Doc.objects.filter(id=int(doc_id)).update(
name=doc_name,
content=doc_content,
pre_content=pre_content,
parent_doc=int(parent_doc) if parent_doc != '' else 0,
sort=sort if sort != '' else 99,
modify_time = datetime.datetime.now(),
status = status
)
return JsonResponse({'status': True,'data':'修改成功'})
doc = Doc.objects.get(id=doc_id)
pro_colla = ProjectCollaborator.objects.get(project=project, user=request.user)
# 验证用户有权限修改文档 - 文档的创建者或文集的高级协作者
if (request.user == doc.create_user) or (pro_colla.role == 1):
# 更新文档内容
Doc.objects.filter(id=int(doc_id)).update(
name=doc_name,
content=doc_content,
pre_content=pre_content,
parent_doc=int(parent_doc) if parent_doc != '' else 0,
sort=sort if sort != '' else 99,
modify_time = datetime.datetime.now(),
status = status
)
return JsonResponse({'status': True,'data':'修改成功'})
else:
return JsonResponse({'status':False,'data':'未授权请求'})
else:
return JsonResponse({'status': False,'data':'参数错误'})
except Exception as e:
@ -495,7 +613,7 @@ def manage_doc(request):
status = 0
).order_by('-modify_time')
# 分页处理
paginator = Paginator(doc_list, 10)
paginator = Paginator(doc_list, 20)
page = request.GET.get('page', 1)
try:
docs = paginator.page(page)
@ -537,7 +655,7 @@ def manage_doc(request):
else:
doc_list = Doc.objects.filter(create_user=request.user).order_by('-modify_time')
# 分页处理
paginator = Paginator(doc_list, 10)
paginator = Paginator(doc_list, 20)
page = request.GET.get('page', 1)
try:
docs = paginator.page(page)

View File

@ -12,7 +12,7 @@
{% include 'app_doc/head_base.html' %}
<!-- 页头结束 -->
<div class="layui-main">
<div style="text-align: center;margin-top: 40px;">
<div style="text-align: center;">
<img src="{% static '404.png' %}">
<p><a href="{% url 'pro_list' %}" >返回首页</a></p>
</div>

View File

@ -18,8 +18,8 @@
</div>
<div class="layui-form-item">
<label class="layui-form-label">操作</label>
<button class="layui-btn layui-btn-normal" type="button" id="copy-token" onclick="copyToken()">复制</button>
<button class="layui-btn layui-btn-normal" type="button" onclick="generaToken()">重新生成Token</button>
<button class="layui-btn" type="button" id="copy-token" onclick="copyToken()">复制</button>
<button class="layui-btn" type="button" onclick="generaToken()">重新生成Token</button>
</div>
</form>
</div><hr>

View File

@ -95,7 +95,7 @@
"bold", "del", "italic", "quote", "ucwords", "uppercase", "lowercase","kaiSpan", "|",
"h1", "h2", "h3", "h4", "h5", "h6", "|",
"list-ul", "list-ol", "hr", "|",
"link", "reference-link","imgUpload", "code", "preformatted-text", "code-block", "table", "datetime", "emoji", "html-entities", "pagebreak", "|",
"link", "reference-link","imgUpload", "code", "code-block", "table", "datetime", "emoji", "html-entities", "pagebreak", "|",
"watch", "preview", "|",
"help"
]

View File

@ -21,17 +21,28 @@
<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 %}
{% 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>
@ -110,7 +121,7 @@
$.post("{% url 'create_project' %}",data,function(r){
if(r.status){
//创建成功更新文集select
$("#project").append("<option value="+r.data.id+">《"+r.data.name+"》</option>");
$("#self-project").append("<option value="+r.data.id+">《"+r.data.name+"》</option>");
form.render();
//window.location.reload();
layer.close(index)
@ -208,9 +219,10 @@
else{
$.post("{% url 'create_doc' %}",data,function(r){
if(r.status){
//创建成功
//保存成功
md_changed = false;
layer.msg('保存草稿成功',function(){
window.location.href = "/modify_doc/"+r.data+"/";
window.location.href = "/modify_doc/"+r.data.doc+"/";
});
}else{
//创建失败

View File

@ -9,11 +9,25 @@
{% block head_toolbar %}
{% if request.user == doc.create_user %}
<span class="btn pull-left">|</span>
<a class="btn pull-left" aria-label="" href="{% url 'modify_doc' doc_id=doc.id %}">
<i class="fa fa-edit"></i> 修改
<i class="fa fa-edit"></i> <span class="layui-hide-xs">修改</span>
</a>
<a class="btn pull-left" aria-label="" href="{% url 'create_doc' %}?pid={{project.id}}" target="_blank">
<i class="fa fa-file"></i> 新建
<i class="fa fa-file"></i> <span class="layui-hide-xs">添加</span>
</a>
<a class="btn pull-left" aria-label="" href="{% url 'manage_doc' %}" target="_blank">
<i class="fa fa-file"></i> <span class="layui-hide-xs">管理</span>
</a>
{% elif colla_user > 0 %}
<span class="btn pull-left">|</span>
{% if colla_user_role == 1 %}
<a class="btn pull-left" aria-label="" href="{% url 'modify_doc' doc_id=doc.id %}">
<i class="fa fa-edit"></i> <span class="layui-hide-xs">修改</span>
</a>
{% endif %}
<a class="btn pull-left" aria-label="" href="{% url 'create_doc' %}?pid={{project.id}}" target="_blank">
<i class="fa fa-file"></i> <span class="layui-hide-xs">添加</span>
</a>
{% endif %}
<!-- 文档目录 -->
@ -61,6 +75,7 @@
{% block custom_script %}
<script>
var layer = layui.layer;
//初始化悬浮目录
var toc = $("#toc-container").find('li');
if(toc.length > 0){
layer.open({
@ -72,7 +87,10 @@
shade: 0,
content: $("#toc-container"),
});
}
};
//修改a标签链接新窗口打开
$('#content').on('click','a',function(e){
e.target.target = '_blank';
});
</script>
{% endblock %}

View File

@ -55,6 +55,10 @@
ul.markdown-toc-list a{
text-decoration: underline!important;
}
/* 块级代码和行内代码去除边框 */
.markdown-body p code{
border:none;
}
</style>
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
@ -76,9 +80,14 @@
<div class="project-title">
<a href="{% url 'pro_index' pro_id=project.id %}">{{ project.name }}
{% if project.role == 1 %}
<i class="layui-icon layui-icon-password"></i>
<i class="layui-icon layui-icon-password" title="私密文档"></i>
{% endif %}
</a>
<p>
{% if colla_user > 0 %}
<span style="font-size:12px;color:gray;font-weight:100;">* 此为协作文集</span>
{% endif %}
</p>
</div>
<hr>
<!-- 遍历文集大纲 -->

View File

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

View File

@ -20,23 +20,12 @@
<div class="layui-input-inline" style="float:inherit;">
<input type="text" name="kw" id="kw" placeholder="输入文档内容" autocomplete="off" class="layui-input">
</div>
<button class="layui-btn layui-btn-normal" type="submit">搜索</button>
<button class="layui-btn layui-btn-normal"><a href="{% url 'create_doc' %}" target="_blank">新建文档</a></button>
<button class="layui-btn" type="submit">搜索</button>
<button class="layui-btn"><a href="{% url 'create_doc' %}" target="_blank">新建文档</a></button>
</div>
</form>
</div>
<div class="layui-row">
<form action="{% url 'manage_doc' %}" method="get" class="layui-form">
<div class="layui-form-item">
<!--<span class="layui-breadcrumb doc_status_condition" lay-separator="|">-->
<!--<a href="{% url 'manage_doc' %}?status=all" class="{% if doc_status == 'all' %}current{% endif %}">全部({{all_cnt}}</a>-->
<!--<a href="{% url 'manage_doc' %}?status=published" class="{% if doc_status == 'published' %}current{% endif %}">已发布({{published_doc_cnt}}</a>-->
<!--<a href="{% url 'manage_doc' %}?status=draft" class="{% if doc_status == 'draft' %}current{% endif %}">草稿({{draft_doc_cnt}}</a>-->
<!--</span>-->
</div>
</form>
</div>
<div class="layui-row" lay-skin="line">
<table class="layui-table" id="doctemp-list" lay-skin="">
<thead>
@ -62,11 +51,13 @@
</td>
{% endif %}
<td>{{ doc.parent_doc|get_doc_parent }}</td>
<td>{{ doc.top_doc|get_doc_top }}</td>
<td>
{{ doc.top_doc|is_colla_pro:doc.create_user }}{{ doc.top_doc|get_doc_top }}
</td>
<td>{{ doc.create_time }}</td>
<td>
<a href="{% url 'modify_doc' doc_id=doc.id %}" target="_blank" class="layui-btn layui-btn-warm layui-btn-xs">修改</a>
<a href="javascript:void(0);" onclick="delDoc('{{doc.id}}');" class="layui-btn layui-btn-danger layui-btn-xs">删除</a>
<a href="{% url 'modify_doc' doc_id=doc.id %}" target="_blank" class="layui-btn layui-btn-xs">修改</a>
<a href="javascript:void(0);" onclick="delDoc('{{doc.id}}');" class="layui-btn layui-btn-xs">删除</a>
</td>
</tr>
{% endfor %}
@ -78,13 +69,13 @@
<div class="pagination">
<span class="step-links">
{% if docs.has_previous %}
<a href="?page={{ docs.previous_page_number }}&kw={{docs.kw}}&status={{docs.status}}" class="layui-btn layui-btn-normal layui-btn-xs">上一页</a>
<a href="?page={{ docs.previous_page_number }}&kw={{docs.kw}}&status={{docs.status}}" class="layui-btn layui-btn-xs">上一页</a>
{% endif %}
<span class="current">
当前页: {{ docs.number }} 共 {{ docs.paginator.num_pages }} 页
</span>
{% if docs.has_next %}
<a href="?page={{ docs.next_page_number }}&kw={{docs.kw}}&status={{docs.status}}" class="layui-btn layui-btn-normal layui-btn-xs">下一页</a>
<a href="?page={{ docs.next_page_number }}&kw={{docs.kw}}&status={{docs.status}}" class="layui-btn layui-btn-xs">下一页</a>
{% endif %}
</span>
</div>

View File

@ -14,8 +14,8 @@
<div class="layui-input-inline">
<input type="text" name="kw" id="kw" placeholder="输入文档模板内容" autocomplete="off" class="layui-input">
</div>
<button class="layui-btn layui-btn-normal" type="submit">搜索</button>
<button class="layui-btn layui-btn-normal" type="button"><a href="{% url 'create_doctemp' %}" target="_blank">新建文档模板</a></button>
<button class="layui-btn" type="submit">搜索</button>
<button class="layui-btn" type="button"><a href="{% url 'create_doctemp' %}" target="_blank">新建文档模板</a></button>
</div>
</form>
</div>
@ -40,8 +40,8 @@
<td>{{ temp.create_time }}</td>
<td>
{# <a href="javascript:void(0);" onclick="insertTemp('{{temp.id}}');">查看</a>#}
<a href="{% url 'modify_doctemp' doctemp_id=temp.id %}" target="_blank" class="layui-btn layui-btn-warm layui-btn-xs">修改</a>
<a href="javascript:void(0);" onclick="delTemp('{{temp.id}}');" class="layui-btn layui-btn-danger layui-btn-xs">删除</a>
<a href="{% url 'modify_doctemp' doctemp_id=temp.id %}" target="_blank" class="layui-btn layui-btn-xs">修改</a>
<a href="javascript:void(0);" onclick="delTemp('{{temp.id}}');" class="layui-btn layui-btn-xs">删除</a>
</td>
</tr>
{% endfor %}
@ -53,13 +53,13 @@
<div class="pagination">
<span class="step-links">
{% if doctemps.has_previous %}
<a href="?page={{ doctemps.previous_page_number }}&kw={{doctemps.kw}}" class="layui-btn layui-btn-normal layui-btn-xs">上一页</a>
<a href="?page={{ doctemps.previous_page_number }}&kw={{doctemps.kw}}" class="layui-btn layui-btn-xs">上一页</a>
{% endif %}
<span class="current">
当前页: {{ doctemps.number }} 共 {{ doctemps.paginator.num_pages }} 页
</span>
{% if doctemps.has_next %}
<a href="?page={{ doctemps.next_page_number }}&kw={{doctemps.kw}}" class="layui-btn layui-btn-normal layui-btn-xs">下一页</a>
<a href="?page={{ doctemps.next_page_number }}&kw={{doctemps.kw}}" class="layui-btn layui-btn-xs">下一页</a>
{% endif %}
</span>
</div>

View File

@ -14,10 +14,10 @@
<!--<div class="layui-input-inline">-->
<!--<input type="text" name="kw" id="kw" placeholder="搜索图片" autocomplete="off" class="layui-input">-->
<!--</div>-->
<!--<button class="layui-btn layui-btn-normal" type="submit">搜索</button>-->
<button class="layui-btn layui-btn-normal" type="button" id="upload_img">上传图片</button>
<button class="layui-btn layui-btn-normal" type="button" onclick="createImgGroup()">新建分组</button>
<a class="layui-btn layui-btn-normal" href="{% url 'manage_img_group' %}">分组管理</a>
<!--<button class="layui-btn" type="submit">搜索</button>-->
<button class="layui-btn" type="button" id="upload_img">上传图片</button>
<button class="layui-btn" type="button" onclick="createImgGroup()">新建分组</button>
<a class="layui-btn" href="{% url 'manage_img_group' %}">分组管理</a>
</div>
</form>
@ -56,13 +56,13 @@
<div class="pagination">
<span class="step-links">
{% if images.has_previous %}
<a href="?page={{ images.previous_page_number }}&group={{images.group}}" class="layui-btn layui-btn-normal layui-btn-xs">上一页</a>
<a href="?page={{ images.previous_page_number }}&group={{images.group}}" class="layui-btn layui-btn-xs">上一页</a>
{% endif %}
<span class="current">
当前页: {{ images.number }} 共 {{ images.paginator.num_pages }} 页
</span>
{% if images.has_next %}
<a href="?page={{ images.next_page_number }}&group={{images.group}}" class="layui-btn layui-btn-normal layui-btn-xs">下一页</a>
<a href="?page={{ images.next_page_number }}&group={{images.group}}" class="layui-btn layui-btn-xs">下一页</a>
{% endif %}
</span>
</div>

View File

@ -42,8 +42,8 @@
<td>{{ group.group_name }}</td>
<td>{{ group.id | img_group_cnt }}</td>
<td>
<a href="javascript:void(0);" onclick="modifyGroup('{{group.id}}')" class="layui-btn layui-btn-warm layui-btn-xs">修改</a>
<a href="javascript:void(0);" onclick="delGroup('{{group.id}}');" class="layui-btn layui-btn-danger layui-btn-xs">删除</a>
<a href="javascript:void(0);" onclick="modifyGroup('{{group.id}}')" class="layui-btn layui-btn-xs">修改</a>
<a href="javascript:void(0);" onclick="delGroup('{{group.id}}');" class="layui-btn layui-btn-xs">删除</a>
</td>
</tr>
{% endfor %}

View File

@ -14,8 +14,9 @@
<div class="layui-input-inline">
<input type="text" name="kw" id="kw" placeholder="输入文集内容" autocomplete="off" class="layui-input">
</div>
<button class="layui-btn layui-btn-normal" type="submit">搜索</button>
<button class="layui-btn layui-btn-normal" onclick="createProject()" type="button">新建文集</button>
<button class="layui-btn" type="submit">搜索</button>
<button class="layui-btn" onclick="createProject()" type="button">新建文集</button>
<a class="layui-btn" href="{% url 'manage_pro_colla_self' %}">我协作的文集</a>
</div>
</form>
</div>
@ -23,11 +24,12 @@
<table class="layui-table" id="doctemp-list" lay-skin="">
<colgroup>
<col width="100">
<col width="400">
<col width="50">
<col width="200">
<col width="45">
<col width="100">
<col width="50">
<col width="100">
<col width="100">
<col width="150">
</colgroup>
<thead>
@ -38,6 +40,7 @@
<th>创建时间</th>
<th>前台下载</th>
<th>阅读权限</th>
<th>协作人数</th>
<th>操作</th>
</tr>
</thead>
@ -69,11 +72,12 @@
{% endif %}
</div>
</td>
<td>{{ pro.id | project_collaborator_cnt }} <a href="{% url 'manage_pro_colla' pro.id %}" title="管理文集协作"><i class="layui-icon layui-icon-edit"></i></a></td>
<td>
<!--<a href="{% url 'pro_index' pro_id=pro.id %}" target="_blank" class="layui-btn layui-btn-normal layui-btn-xs">查看</a>-->
<a href="javascript:void(0);" onclick="modifyProject('{{pro.id}}','{{pro.name}}','{{pro.intro}}')" class="layui-btn layui-btn-warm layui-btn-xs">修改</a>
<a href="javascript:void(0);" onclick="delProject('{{pro.id}}');" class="layui-btn layui-btn-danger layui-btn-xs">删除</a>
<a href="javascript:void(0);" onclick="reportMd('{{pro.id}}')" class="layui-btn layui-btn-normal layui-btn-xs">导出</a>
<a href="javascript:void(0);" onclick="modifyProject('{{pro.id}}','{{pro.name}}','{{pro.intro}}')" class="layui-btn layui-btn-xs">修改</a>
<a href="javascript:void(0);" onclick="delProject('{{pro.id}}');" class="layui-btn layui-btn-xs">删除</a>
<a href="javascript:void(0);" onclick="reportMd('{{pro.id}}')" class="layui-btn layui-btn-xs">导出</a>
</td>
</tr>
{% endfor %}

View File

@ -0,0 +1,200 @@
{% 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;">管理文集<strong>《{{pro.name}}》</strong>的协作者
</span>
</div>
</div>
<div class="layui-row">
<form class="layui-form">
{% csrf_token %}
{% load project_filter %}
<div class="layui-form-item">
<label class="layui-form-label">文集名称</label>
<div class="layui-input-block">
<input type="text" name="title" required value="{{pro.name}}" disabled class="layui-input">
<!--<span>{{pro.name}}</span>-->
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">协作人数:</label>
<div class="layui-input-inline">
<input type="text" value="{{ pro.id | project_collaborator_cnt }}人" class="layui-input" disabled>
</div>
<div class="layui-form-mid layui-word-aux">
<button class="layui-btn layui-btn-xs" type="button" onclick="addProjectColla({{pro.id}})">添加</button>
</div>
</div>
</form>
</div>
{% if collaborator.count != 0 %}
<div class="layui-row">
<table class="layui-table">
<thead>
<tr>
<th>用户名</th>
<th>协作权限</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for colla in collaborator %}
<tr>
<td>{{ colla.user }}</td>
<td>
{% if colla.role == 0 %}
新建文档,修改、删除新建的文档
{% else %}
可操作所有文档
{% endif %}
</td>
<td>
<a href="javascript:void(0);" onclick="modifyProjectColla('{{colla.user}}')" class="layui-btn layui-btn-xs">修改</a>
<a href="javascript:void(0);" onclick="delProColla('{{colla.user}}')" class="layui-btn layui-btn-xs">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
{% 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;
//添加文集协作者
addProjectColla = function(pid){
layer.open({
type:1,
title:'添加文集协作者',
area:'300px;',
id:'addProColla',//配置ID
//content:'<div style="margin:10px;"><input type="text" id="username" class="layui-input" placeholder="输入用户名" /></div>',
content:$('#add-pro-colla-layer'),
btn:['确定','取消'], //添加按钮
btnAlign:'c', //按钮居中
success : function(index, layero) { // 成功弹出后回调
form.render('radio'); // 刷新checkbox开关渲染(否则开关按钮会不显示)
},
yes:function (index,layero) {
data = {
'types':0,
'username':$("#username").val(),
'role': $('input[name="add-role"]:checked').val()
}
$.post("{% url 'manage_pro_colla' pro.id %}",data,function(r){
if(r.status){
//添加成功
window.location.reload();
//layer.close(index)
}else{
//添加失败,提示
console.log(r)
layer.msg(r.data)
}
})
},
})
};
// 删除文集协作者
delProColla = function(user){
layer.open({
type:1,
title:'删除文集协作者',
area:'300px;',
id:'delProColla',//配置ID
content:'<div style="margin:10px;">确定将用户' + user+ '从文集协作者中删除?</div>',
btn:['确定','取消'], //添加按钮
btnAlign:'c', //按钮居中
yes:function (index,layero) {
data = {
'types':1,
'username':user,
}
$.post("{% url 'manage_pro_colla' pro.id %}",data,function(r){
if(r.status){
//删除成功
window.location.reload();
//layer.close(index)
}else{
//删除失败,提示
console.log(r)
layer.msg(r.data)
}
})
},
})
};
// 修改文集协作者
modifyProjectColla = function(user){
layer.open({
type:1,
title:'修改'+ user + '的协作权限',
area:'300px;',
id:'modifyProColla',//配置ID
content:$('#modify-pro-colla-layer'),
btn:['确定','取消'], //添加按钮
btnAlign:'c', //按钮居中
success : function(index, layero) { // 成功弹出后回调
form.render('radio'); // 刷新checkbox开关渲染(否则开关按钮会不显示)
},
yes:function (index,layero) {
data = {
'types':2,
'username':user,
'role': $('input[name="modify-role"]:checked').val()
}
$.post("{% url 'manage_pro_colla' pro.id %}",data,function(r){
if(r.status){
//修改成功
window.location.reload();
//layer.close(index)
}else{
//修改失败,提示
console.log(r)
layer.msg(r.data)
}
})
},
})
};
</script>
<!-- 添加文集协作者layer弹出框 -->
<div id="add-pro-colla-layer" style="display:none;">
<div style="margin:10px;" class="layui-form">
<input type="text" id="username" class="layui-input" placeholder="输入用户名" />
<div class="layui-form-item">
<div class="layui-input-inline">
<input type="radio" name="add-role" value="0" title="初级权限" checked>
<input type="radio" name="add-role" value="1" title="高级权限" >
</div>
</div>
</div>
</div>
<!-- 修改文集协作者权限layer弹出框 -->
<div id="modify-pro-colla-layer" style="display:none;">
<div style="margin:10px;" class="layui-form">
<div class="layui-form-item">
<div class="layui-input-inline">
<input type="radio" name="modify-role" value="0" title="初级权限" checked>
<input type="radio" name="modify-role" value="1" title="高级权限" >
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,64 @@
{% 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;">协作的文集列表
</span>
</div>
</div>
{% if colla_pros.count != 0 %}
<div class="layui-row">
<table class="layui-table">
<thead>
<tr>
<th>文集名称</th>
<th>作者</th>
<th>权限</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for colla in colla_pros %}
<tr>
<td>{{ colla.project }}</td>
<td>{{ colla.project.create_user }}</td>
<td>
{% if colla.role == 0 %}
初级 - 可新建文档、修改和删除自己创建的文档
{% else %}
高级 - 可新建文档、修改所有文档、删除自己创建的文档
{% endif %}
</td>
<td>
<a href="{% url 'pro_index' colla.project.id %}" target="_blank" class="layui-btn layui-btn-xs">查看</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="layui-row">
你还没有成为任何文集的协作者
</div>
{% endif %}
{% 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;
</script>
{% endblock %}

View File

@ -6,8 +6,9 @@
{% block title %}{{ project.name }}{% endblock %}
{% block head_toolbar %}
{% if request.user == project.create_user %}
<a class="btn pull-left" aria-label="" href="{% url 'create_doc' %}?pid={{project.id}}" target="_blank">
{% if request.user == project.create_user or colla_user > 0 %}
<span class="btn pull-left">|</span>
<a class="btn pull-left" href="{% url 'create_doc' %}?pid={{project.id}}" target="_blank">
<i class="fa fa-edit"></i> 添加文档
</a>
{% endif %}

View File

@ -12,6 +12,7 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="{% static 'layui/css/layui.css' %}" crossorigin="anonymous">
<link rel="icon" href="{% static 'favicon_16.png' %}"/>
<style>
body{
background-color: #fafafa;
@ -83,6 +84,7 @@
<a href="{% url 'forget_pwd' %}" class="register-link">忘记密码</a>
{% endif %}
<a href="{% url 'pro_list' %}" class="register-link">返回首页</a>
</form>
</div>
</div>

View File

@ -6,6 +6,7 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="{% static 'layui/css/layui.css' %}" crossorigin="anonymous">
<link rel="icon" href="{% static 'favicon_16.png' %}"/>
<style>
body{
background-color: #fafafa;
@ -91,6 +92,8 @@
<button class="layui-btn layui-btn-fluid layui-btn-radius layui-btn-normal" lay-submit lay-filter="formDemo" type="submit">注册并登录</button>
</div>
</div>
<a href="{% url 'login' %}" class="register-link">返回登录</a>
<a href="{% url 'pro_list' %}" class="register-link">返回首页</a>
</form>
</div>
</div>