添加图片管理功能、优化目录、修复错误
This commit is contained in:
parent
d828e73b8d
commit
2df88d8717
11
CHANGES.md
11
CHANGES.md
@ -1,5 +1,16 @@
|
||||
## 版本更新记录
|
||||
|
||||
### v0.3.3
|
||||
|
||||
- 修复后台管理无法删除文档的错误;
|
||||
- 修复后台新建无法新建文集的错误;
|
||||
- 优化图片上传逻辑,新增后台图片管理功能,前端编辑器替换Editor.md自带的图片上传组件;
|
||||
- 优化首页无文集时的样式,添加默认显示的图片;
|
||||
- 优化首页文集无文档时,显示默认提示文字;
|
||||
- 优化404页面,更换统一风格的404图片;
|
||||
- 调整文档阅读页面目录使用悬浮弹出框显示;
|
||||
- 增强安全性,替换前端请求字符串值中的特殊符号;
|
||||
|
||||
### v0.3.2 2020-03-12
|
||||
|
||||
- 修复访问码跳转文档404的错误;
|
||||
|
||||
@ -25,7 +25,7 @@ SECRET_KEY = '5&71mt9@^58zdg*_!t(x6g14q*@84d%ptr%%s6e0l50zs0we3d'
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = False
|
||||
|
||||
VERSIONS = '0.3.2'
|
||||
VERSIONS = '0.3.3'
|
||||
|
||||
ALLOWED_HOSTS = ['*']
|
||||
|
||||
@ -85,6 +85,9 @@ DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||
'OPTIONS':{
|
||||
'timeout':20,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
36
README.md
36
README.md
@ -1,4 +1,4 @@
|
||||
# MrDoc - 记录文档,汇聚思想,一个简单的文档记录和阅读应用
|
||||
# MrDoc - 记录文档,汇聚思想,一个简单的文档记录和管理应用
|
||||
|
||||
**PC端文档阅读界面:**
|
||||
|
||||
@ -6,11 +6,20 @@
|
||||
|
||||
## 介绍
|
||||
|
||||
州的先生(https://zmister.com)自用并完全开源、基于Python编写的文档写作系统。
|
||||
州的先生 - https://zmister.com - 自用并完全开源、基于Python编写的文档写作系统。
|
||||
|
||||
当前版本为:**v0.3.2**,版本发布时间为**2020-03-12**,此版本主要更新了如下内容:
|
||||
使用MarkDown快速记录你所思所想,仿GitBook两栏式阅读界面,清晰高效浏览。
|
||||
|
||||
- 紧急修复访问码跳转文档404的错误;
|
||||
当前版本为:**v0.3.3**,版本发布时间为**2020-03-21**,此版本主要更新了如下内容:
|
||||
|
||||
- 修复后台管理无法删除文档的错误;
|
||||
- 修复后台新建无法新建文集的错误;
|
||||
- 优化图片上传逻辑,新增后台图片管理功能,前端编辑器替换Editor.md自带的图片上传组件,支持上传图片和从已有图片中选择图片;
|
||||
- 优化首页无文集时的样式,添加默认显示的图片;
|
||||
- 优化首页文集无文档时,显示默认提示文字;
|
||||
- 优化404页面,更换统一风格的404图片;
|
||||
- 调整文档阅读页面目录使用悬浮弹出框显示;
|
||||
- 增强安全性,替换前端请求字符串值中的特殊符号;
|
||||
|
||||
完整更新记录详见:[CHANGES.md](./CHANGES.md)
|
||||
|
||||
@ -31,23 +40,14 @@ MrDoc拥有以下特点:
|
||||
- 支持三级目录层级显示;
|
||||
- 支持文集后台导出为markdown文本格式.md文件、前台导出为EPUB电子书;
|
||||
- 基于文集进行权限控制,提供公开、私密、指定用户可见、访问码可见4种权限模式;
|
||||
|
||||
- 二次开发方便
|
||||
- 使用Django传统的MTV开发模式,路由、视图函数、模型易于理解;
|
||||
- 使用非前端工程化构建前端页面,主要使用Layui进行页面布局和展示,方便改动;
|
||||
|
||||
|
||||
在开发过程中,参考和借鉴了GitBook、ShowDoc、Wordbook等应用和网站的功能与样式。
|
||||
在开发过程中,参考和借鉴了GitBook、ShowDoc、Wordbook等应用和网站的功能与样式,并使用了众多开源组件、插件。
|
||||
|
||||
## 网站架构
|
||||
## 应用核心依赖环境
|
||||
|
||||
- 编程语言:Python 3
|
||||
- 后端Web框架:Django 2.1
|
||||
- 前端UI库:Layui 2.5.4
|
||||
- JS库:Jquery
|
||||
- MarkDown编辑器:Editormd
|
||||
- 页面社交分享:Share.js
|
||||
- Markdown科学公式:Katex.js
|
||||
- 编程语言:Python 3+
|
||||
- Django框架:2.0+
|
||||
|
||||
## 安装教程
|
||||
|
||||
@ -128,7 +128,7 @@ python manage.py runserver
|
||||
|
||||
## 版本更新
|
||||
|
||||
关注州的先生微信公众号(ID:zmister2016)、博客 https://zmister.com,及时获取MrDoc版本更新信息。
|
||||
关注州的先生微信公众号(ID:zmister2016)、博客 https://zmister.com 及时获取MrDoc版本更新信息。
|
||||
|
||||
## 更多截图
|
||||
|
||||
|
||||
52
app_doc/migrations/0011_auto_20200313_2143.py
Normal file
52
app_doc/migrations/0011_auto_20200313_2143.py
Normal file
@ -0,0 +1,52 @@
|
||||
# Generated by Django 2.1 on 2020-03-13 21:43
|
||||
|
||||
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', '0010_auto_20200310_2032'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Image',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('file_path', models.CharField(max_length=250, verbose_name='图片路径')),
|
||||
('remark', models.CharField(blank=True, default='图片描述', max_length=250, null=True, verbose_name='图片备注')),
|
||||
('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('modify_time', models.DateTimeField(auto_now=True, verbose_name='修改时间')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '素材图片',
|
||||
'verbose_name_plural': '素材图片',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ImageGroup',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('group_name', models.CharField(default='默认分组', max_length=50, verbose_name='图片分组')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '图片分组',
|
||||
'verbose_name_plural': '图片分组',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='image',
|
||||
name='group',
|
||||
field=models.ForeignKey(default=0, on_delete=django.db.models.deletion.SET_DEFAULT, to='app_doc.ImageGroup', verbose_name='图片分组'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='image',
|
||||
name='user',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
||||
19
app_doc/migrations/0012_auto_20200313_2204.py
Normal file
19
app_doc/migrations/0012_auto_20200313_2204.py
Normal file
@ -0,0 +1,19 @@
|
||||
# Generated by Django 2.1 on 2020-03-13 22:04
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('app_doc', '0011_auto_20200313_2143'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='image',
|
||||
name='group',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='app_doc.ImageGroup', verbose_name='图片分组'),
|
||||
),
|
||||
]
|
||||
18
app_doc/migrations/0013_image_file_name.py
Normal file
18
app_doc/migrations/0013_image_file_name.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 2.1 on 2020-03-15 08:21
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('app_doc', '0012_auto_20200313_2204'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='image',
|
||||
name='file_name',
|
||||
field=models.CharField(blank=True, max_length=250, null=True, verbose_name='图片名称'),
|
||||
),
|
||||
]
|
||||
@ -71,7 +71,6 @@ class DocTemp(models.Model):
|
||||
verbose_name = '文档模板'
|
||||
verbose_name_plural = verbose_name
|
||||
|
||||
|
||||
# 文集导出模型
|
||||
class ProjectReport(models.Model):
|
||||
project = models.OneToOneField(Project,unique=True,on_delete=models.CASCADE)
|
||||
@ -83,4 +82,30 @@ class ProjectReport(models.Model):
|
||||
|
||||
class Meta:
|
||||
verbose_name = '文集导出'
|
||||
verbose_name_plural = verbose_name
|
||||
|
||||
# 图片分组模型
|
||||
class ImageGroup(models.Model):
|
||||
user = models.ForeignKey(User,on_delete=models.CASCADE)
|
||||
group_name = models.CharField(verbose_name="图片分组",max_length=50,default="默认分组")
|
||||
|
||||
def __str__(self):
|
||||
return self.group_name
|
||||
|
||||
class Meta:
|
||||
verbose_name = '图片分组'
|
||||
verbose_name_plural = verbose_name
|
||||
|
||||
# 图片模型
|
||||
class Image(models.Model):
|
||||
user = models.ForeignKey(User,on_delete=models.CASCADE)
|
||||
file_path = models.CharField(verbose_name="图片路径",max_length=250)
|
||||
file_name = models.CharField(verbose_name="图片名称",max_length=250,null=True,blank=True)
|
||||
group = models.ForeignKey(ImageGroup,on_delete=models.SET_NULL,null=True,verbose_name="图片分组")
|
||||
remark = models.CharField(verbose_name="图片备注",null=True,blank=True,max_length=250,default="图片描述")
|
||||
create_time = models.DateTimeField(verbose_name='创建时间',auto_now_add=True)
|
||||
modify_time = models.DateTimeField(verbose_name='修改时间',auto_now=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = '素材图片'
|
||||
verbose_name_plural = verbose_name
|
||||
@ -15,6 +15,8 @@ def get_doc_count(value):
|
||||
@register.filter(name='get_new_doc')
|
||||
def get_new_doc(value):
|
||||
new_doc = Doc.objects.filter(top_doc=int(value),status=1).order_by('-modify_time').first()
|
||||
if new_doc is None:
|
||||
new_doc = '它还没有文档……'
|
||||
return new_doc
|
||||
|
||||
# 获取文集的开放导出状态
|
||||
@ -27,3 +29,9 @@ def get_report_status(value):
|
||||
# print(repr(e))
|
||||
status = 0
|
||||
return status
|
||||
|
||||
# 获取图片分组的图片数量
|
||||
@register.filter(name='img_group_cnt')
|
||||
def get_img_group_cnt(value):
|
||||
cnt = Image.objects.filter(group_id=value).count()
|
||||
return cnt
|
||||
@ -27,6 +27,9 @@ urlpatterns = [
|
||||
path('get_doctemp/',views.get_doctemp,name='get_doctemp'), # 获取某一个文档模板内容
|
||||
path('del_doctemp/',views.del_doctemp,name="del_doctemp"), # 删除某一个文档模板
|
||||
path('modify_doctemp/<int:doctemp_id>/',views.modify_doctemp,name="modify_doctemp"), # 修改文档模板
|
||||
#################文件管理相关
|
||||
path('manage_image/',views.manage_image,name="manage_image"), # 图片管理
|
||||
path('manage_image_group/',views.manage_img_group,name="manage_img_group"), # 图片分组管理
|
||||
################其他功能相关
|
||||
path('upload_doc_img/',util_upload_img.upload_img,name="upload_doc_img"), # 上传图片
|
||||
]
|
||||
@ -2,48 +2,52 @@
|
||||
from django.http import HttpResponse
|
||||
from django.conf import settings
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
import os
|
||||
import uuid
|
||||
import json
|
||||
import datetime as dt
|
||||
import base64
|
||||
from django.contrib.auth.decorators import login_required # 登录需求装饰器
|
||||
import datetime,time,json,base64,os,uuid
|
||||
from app_doc.models import Image,ImageGroup
|
||||
|
||||
@login_required()
|
||||
@csrf_exempt
|
||||
def upload_img(request):
|
||||
##################
|
||||
# {"success": 0, "message": "出错信息"}
|
||||
# {"success": 1, "url": "图片地址"}
|
||||
##################
|
||||
files = request.FILES.get("editormd-image-file", None)
|
||||
img = request.FILES.get("editormd-image-file", None) # 编辑器上传
|
||||
manage_upload = request.FILES.get('manage_upload',None) # 图片管理上传
|
||||
dir_name = request.POST.get('dirname','')
|
||||
base_img = request.POST.get('base',None)
|
||||
if files:# 上传普通图片文件
|
||||
result = file_upload(files, dir_name)
|
||||
if img:# 上传普通图片文件
|
||||
result = img_upload(img, dir_name,request.user)
|
||||
elif manage_upload:
|
||||
result = img_upload(manage_upload, dir_name, request.user)
|
||||
elif base_img: # 上传base64编码图片
|
||||
result = base_img_upload(base_img,dir_name)
|
||||
result = base_img_upload(base_img,dir_name,request.user)
|
||||
else:
|
||||
result = {"success": 0, "message": "出错信息"}
|
||||
return HttpResponse(json.dumps(result), content_type="application/json")
|
||||
|
||||
# 目录创建
|
||||
def upload_generation_dir(dir_name=''):
|
||||
today = dt.datetime.today()
|
||||
today = datetime.datetime.today()
|
||||
dir_name = dir_name + '/%d%02d/' %(today.year,today.month)
|
||||
print("dir_name:",dir_name)
|
||||
# print("dir_name:",dir_name)
|
||||
if not os.path.exists(settings.MEDIA_ROOT + dir_name):
|
||||
print("创建目录")
|
||||
# print("创建目录")
|
||||
os.makedirs(settings.MEDIA_ROOT + dir_name)
|
||||
return dir_name
|
||||
|
||||
# 普通图片上传
|
||||
def file_upload(files, dir_name):
|
||||
def img_upload(files, dir_name, user):
|
||||
#允许上传文件类型
|
||||
allow_suffix =["jpg", "jpeg", "gif", "png", "bmp", "webp"]
|
||||
file_suffix = files.name.split(".")[-1]
|
||||
file_suffix = files.name.split(".")[-1] # 提取图片格式
|
||||
# 判断图片格式
|
||||
if file_suffix not in allow_suffix:
|
||||
return {"success": 0, "message": "图片格式不正确"}
|
||||
|
||||
relative_path = upload_generation_dir(dir_name)
|
||||
file_name = str(dt.datetime.today()).replace(':','').replace(' ','').replace('.','')+files.name
|
||||
file_name = files.name.replace(file_suffix,'').replace('.','') + '_' +str(int(time.time())) + '.' + file_suffix
|
||||
path_file=os.path.join(relative_path, file_name)
|
||||
path_file = settings.MEDIA_ROOT + path_file
|
||||
print('文件路径:',path_file)
|
||||
@ -52,14 +56,20 @@ def file_upload(files, dir_name):
|
||||
with open(path_file, 'wb') as f:
|
||||
for chunk in files.chunks():
|
||||
f.write(chunk) # 保存文件
|
||||
Image.objects.create(
|
||||
user=user,
|
||||
file_path=file_url,
|
||||
file_name=file_name,
|
||||
remark='本地上传',
|
||||
)
|
||||
return {"success": 1, "url": file_url,'message':'上传图片成功'}
|
||||
|
||||
# base64编码图片上传
|
||||
def base_img_upload(files,dir_name):
|
||||
def base_img_upload(files,dir_name, user):
|
||||
files_str = files.split(';base64,')[-1] # 截取图片正文
|
||||
files_base = base64.b64decode(files_str) # 进行base64编码
|
||||
relative_path = upload_generation_dir(dir_name)
|
||||
file_name = str(dt.datetime.today()).replace(':', '').replace(' ', '').replace('.', '') + '.png'
|
||||
file_name = str(datetime.datetime.today()).replace(':', '').replace(' ', '_').split('.')[0] + '.png' # 日期时间
|
||||
path_file = os.path.join(relative_path, file_name)
|
||||
path_file = settings.MEDIA_ROOT + path_file
|
||||
print('文件路径:', path_file)
|
||||
@ -67,4 +77,10 @@ def base_img_upload(files,dir_name):
|
||||
print("文件URL:", file_url)
|
||||
with open(path_file, 'wb') as f:
|
||||
f.write(files_base) # 保存文件
|
||||
Image.objects.create(
|
||||
user = user,
|
||||
file_path = file_url,
|
||||
file_name=file_name,
|
||||
remark = '粘贴上传',
|
||||
)
|
||||
return {"success": 1, "url": file_url, 'message': '上传图片成功'}
|
||||
207
app_doc/views.py
207
app_doc/views.py
@ -11,9 +11,16 @@ from django.contrib.auth.models import User
|
||||
from django.db.models import Q
|
||||
import datetime
|
||||
import traceback
|
||||
import re
|
||||
from app_doc.report_utils import *
|
||||
from app_admin.decorators import check_headers,allow_report_file
|
||||
import os.path
|
||||
|
||||
# 替换前端传来的非法字符
|
||||
def validateTitle(title):
|
||||
rstr = r"[\/\\\:\*\?\"\<\>\|]" # '/ \ : * ? " < > |'
|
||||
new_title = re.sub(rstr, "_", title) # 替换为下划线
|
||||
return new_title
|
||||
|
||||
# 文集列表
|
||||
def project_list(request):
|
||||
@ -34,23 +41,27 @@ def create_project(request):
|
||||
if request.method == 'POST':
|
||||
try:
|
||||
name = request.POST.get('pname','')
|
||||
name = validateTitle(name)
|
||||
desc = request.POST.get('desc','')
|
||||
role = request.POST.get('role','')
|
||||
role = request.POST.get('role',0)
|
||||
role_list = ['0','1','2','3',0,1,2,3]
|
||||
if name != '':
|
||||
project = Project.objects.create(
|
||||
name=name,
|
||||
intro=desc[:100],
|
||||
create_user=request.user,
|
||||
role = int(role)
|
||||
role = int(role) if role in role_list else 0
|
||||
)
|
||||
project.save()
|
||||
return JsonResponse({'status':True,'data':{'id':project.id,'name':project.name}})
|
||||
else:
|
||||
return JsonResponse({'status':False})
|
||||
return JsonResponse({'status':False,'data':'文集名称不能为空!'})
|
||||
except Exception as e:
|
||||
return JsonResponse({'status':False})
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return JsonResponse({'status':False,'data':'出现异常,请检查输入值!'})
|
||||
else:
|
||||
return JsonResponse({'status':False})
|
||||
return JsonResponse({'status':False,'data':'请求方法不允许'})
|
||||
|
||||
|
||||
# 文集页
|
||||
@ -100,7 +111,6 @@ def project_index(request,pro_id):
|
||||
except Exception as e:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
print(repr(e))
|
||||
return HttpResponse('请求出错')
|
||||
|
||||
|
||||
@ -121,6 +131,8 @@ def modify_project(request):
|
||||
else:
|
||||
return JsonResponse({'status':False,'data':'非法请求'})
|
||||
except Exception as e:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return JsonResponse({'status':False,'data':'请求出错'})
|
||||
else:
|
||||
return JsonResponse({'status':False,'data':'方法不允许'})
|
||||
@ -186,7 +198,8 @@ def check_viewcode(request):
|
||||
errormsg = "访问码错误"
|
||||
return render(request, 'app_doc/check_viewcode.html', locals())
|
||||
except Exception as e:
|
||||
print(repr(e))
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return render(request,'404.html')
|
||||
|
||||
|
||||
@ -209,6 +222,8 @@ def del_project(request):
|
||||
else:
|
||||
return JsonResponse({'status':False,'data':'参数错误'})
|
||||
except Exception as e:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return JsonResponse({'status':False,'data':'请求出错'})
|
||||
|
||||
|
||||
@ -241,6 +256,8 @@ def manage_project(request):
|
||||
pros = paginator.page(paginator.num_pages)
|
||||
return render(request,'app_doc/manage_project.html',locals())
|
||||
except Exception as e:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return HttpResponse('请求出错')
|
||||
else:
|
||||
return HttpResponse('方法不允许')
|
||||
@ -314,6 +331,8 @@ def doc(request,pro_id,doc_id):
|
||||
else:
|
||||
return HttpResponse('参数错误')
|
||||
except Exception as e:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return HttpResponse('请求出错')
|
||||
|
||||
|
||||
@ -328,7 +347,8 @@ def create_doc(request):
|
||||
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:
|
||||
print(repr(e))
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return HttpResponse('请求出错')
|
||||
elif request.method == 'POST':
|
||||
try:
|
||||
@ -354,7 +374,8 @@ def create_doc(request):
|
||||
else:
|
||||
return JsonResponse({'status':False,'data':'参数错误'})
|
||||
except Exception as e:
|
||||
print(repr(e))
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return JsonResponse({'status':False,'data':'请求出错'})
|
||||
else:
|
||||
return JsonResponse({'status':False,'data':'方法不允许'})
|
||||
@ -374,6 +395,8 @@ def modify_doc(request,doc_id):
|
||||
else:
|
||||
return HttpResponse("非法请求")
|
||||
except Exception as e:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return HttpResponse('请求出错')
|
||||
elif request.method == 'POST':
|
||||
try:
|
||||
@ -400,6 +423,8 @@ def modify_doc(request,doc_id):
|
||||
else:
|
||||
return JsonResponse({'status': False,'data':'参数错误'})
|
||||
except Exception as e:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return JsonResponse({'status':False,'data':'请求出错'})
|
||||
|
||||
|
||||
@ -426,6 +451,8 @@ def del_doc(request):
|
||||
else:
|
||||
return JsonResponse({'status':False,'data':'参数错误'})
|
||||
except Exception as e:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return JsonResponse({'status':False,'data':'请求出错'})
|
||||
|
||||
|
||||
@ -544,6 +571,8 @@ def create_doctemp(request):
|
||||
else:
|
||||
return JsonResponse({'status':False,'data':'模板标题不能为空'})
|
||||
except Exception as e:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return JsonResponse({'status':False,'data':'请求出错'})
|
||||
else:
|
||||
return JsonResponse({'status':False,'data':'方法不允许'})
|
||||
@ -560,6 +589,8 @@ def modify_doctemp(request,doctemp_id):
|
||||
else:
|
||||
return HttpResponse('非法请求')
|
||||
except Exception as e:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return HttpResponse('请求出错')
|
||||
elif request.method == 'POST':
|
||||
try:
|
||||
@ -578,6 +609,8 @@ def modify_doctemp(request,doctemp_id):
|
||||
else:
|
||||
return JsonResponse({'status':False,'data':'参数错误'})
|
||||
except Exception as e:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return JsonResponse({'status':False,'data':'请求出错'})
|
||||
else:
|
||||
return HttpResponse('方法不允许')
|
||||
@ -598,6 +631,8 @@ def del_doctemp(request):
|
||||
else:
|
||||
return JsonResponse({'status': False, 'data': '参数错误'})
|
||||
except Exception as e:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return JsonResponse({'status':False,'data':'请求出错'})
|
||||
|
||||
|
||||
@ -630,6 +665,8 @@ def manage_doctemp(request):
|
||||
doctemps = paginator.page(paginator.num_pages)
|
||||
return render(request, 'app_doc/manage_doctemp.html', locals())
|
||||
except Exception as e:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return HttpResponse('请求出错')
|
||||
else:
|
||||
return HttpResponse('方法不允许')
|
||||
@ -647,6 +684,8 @@ def get_doctemp(request):
|
||||
else:
|
||||
return JsonResponse({'status':False,'data':'参数错误'})
|
||||
except Exception as e:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return JsonResponse({'status':False,'data':'请求出错'})
|
||||
else:
|
||||
return JsonResponse({'status':False,'data':'方法错误'})
|
||||
@ -758,4 +797,152 @@ def report_file(request):
|
||||
else:
|
||||
return JsonResponse({'status':False,'data':'不支持的类型'})
|
||||
else:
|
||||
return Http404
|
||||
return Http404
|
||||
|
||||
|
||||
# 图片素材管理
|
||||
@login_required()
|
||||
def manage_image(request):
|
||||
# 获取图片
|
||||
if request.method == 'GET':
|
||||
try:
|
||||
groups = ImageGroup.objects.filter(user=request.user) # 获取所有分组
|
||||
all_img_cnt = Image.objects.filter(user=request.user).count()
|
||||
no_group_cnt = Image.objects.filter(user=request.user,group_id=None).count() # 获取所有未分组的图片数量
|
||||
g_id = int(request.GET.get('group', 0)) # 图片分组id
|
||||
if int(g_id) == 0:
|
||||
image_list = Image.objects.filter(user=request.user) # 查询所有图片
|
||||
elif int(g_id) == -1:
|
||||
image_list = Image.objects.filter(user=request.user,group_id=None) # 查询指定分组的图片
|
||||
else:
|
||||
image_list = Image.objects.filter(user=request.user,group_id=g_id) # 查询指定分组的图片
|
||||
paginator = Paginator(image_list, 20)
|
||||
page = request.GET.get('page', 1)
|
||||
try:
|
||||
images = paginator.page(page)
|
||||
except PageNotAnInteger:
|
||||
images = paginator.page(1)
|
||||
except EmptyPage:
|
||||
images = paginator.page(paginator.num_pages)
|
||||
images.group = g_id
|
||||
return render(request,'app_doc/manage_image.html',locals())
|
||||
except:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return render(request,'404.html')
|
||||
elif request.method == 'POST':
|
||||
try:
|
||||
img_id = request.POST.get('img_id','')
|
||||
types = request.POST.get('types','') # 操作类型:0表示删除,1表示修改,2表示获取
|
||||
# 删除图片
|
||||
if int(types) == 0:
|
||||
img = Image.objects.get(id=img_id)
|
||||
if img.user != request.user:
|
||||
return JsonResponse({'status': False, 'data': '未授权请求'})
|
||||
file_path = settings.BASE_DIR+img.file_path
|
||||
is_exist = os.path.exists(file_path)
|
||||
if is_exist:
|
||||
os.remove(file_path)
|
||||
img.delete() # 删除记录
|
||||
return JsonResponse({'status':True,'data':'删除完成'})
|
||||
# 移动图片分组
|
||||
elif int(types) == 1:
|
||||
group_id = request.POST.get('group_id',None)
|
||||
if group_id is None:
|
||||
Image.objects.filter(id=img_id).update(group_id=None)
|
||||
else:
|
||||
group = ImageGroup.objects.get(id=group_id,user=request.user)
|
||||
Image.objects.filter(id=img_id).update(group_id=group)
|
||||
return JsonResponse({'status':True,'data':'移动完成'})
|
||||
# 获取图片
|
||||
elif int(types) == 2:
|
||||
group_id = request.POST.get('group_id', None) # 接受分组ID参数
|
||||
if group_id is None: #
|
||||
return JsonResponse({'status':False,'data':'参数错误'})
|
||||
elif int(group_id) == 0:
|
||||
imgs = Image.objects.filter(user=request.user)
|
||||
elif int(group_id) == -1:
|
||||
imgs = Image.objects.filter(user=request.user,group_id=None)
|
||||
else:
|
||||
imgs = Image.objects.filter(user=request.user,group_id=group_id)
|
||||
img_list = []
|
||||
for img in imgs:
|
||||
item = {
|
||||
'path':img.file_path,
|
||||
'name':img.file_name,
|
||||
}
|
||||
img_list.append(item)
|
||||
return JsonResponse({'status':True,'data':img_list})
|
||||
else:
|
||||
return JsonResponse({'status':False,'data':'非法参数'})
|
||||
except ObjectDoesNotExist:
|
||||
return JsonResponse({'status':False,'data':'图片不存在'})
|
||||
except:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return JsonResponse({'status':False,'data':'程序异常'})
|
||||
|
||||
# 图片分组管理
|
||||
@login_required()
|
||||
def manage_img_group(request):
|
||||
if request.method == 'GET':
|
||||
groups = ImageGroup.objects.filter(user=request.user)
|
||||
return render(request,'app_doc/manage_image_group.html',locals())
|
||||
# 操作分组
|
||||
elif request.method == 'POST':
|
||||
types = request.POST.get('types',None) # 请求类型,0表示创建分组,1表示修改分组,2表示删除分组,3表示获取分组
|
||||
# 创建分组
|
||||
if int(types) == 0:
|
||||
group_name = request.POST.get('group_name', '')
|
||||
if group_name not in ['','默认分组','未分组']:
|
||||
ImageGroup.objects.create(
|
||||
user = request.user,
|
||||
group_name = group_name
|
||||
)
|
||||
return JsonResponse({'status':True,'data':'ok'})
|
||||
else:
|
||||
return JsonResponse({'status':False,'data':'名称无效'})
|
||||
# 修改分组
|
||||
elif int(types) == 1:
|
||||
group_name = request.POST.get("group_name",'')
|
||||
if group_name not in ['','默认分组','未分组']:
|
||||
group_id = request.POST.get('group_id', '')
|
||||
ImageGroup.objects.filter(id=group_id).update(group_name=group_name)
|
||||
return JsonResponse({'status':True,'data':'修改成功'})
|
||||
else:
|
||||
return JsonResponse({'status':False,'data':'名称无效'})
|
||||
|
||||
# 删除分组
|
||||
elif int(types) == 2:
|
||||
try:
|
||||
group_id = request.POST.get('group_id','')
|
||||
group = ImageGroup.objects.get(id=group_id,user=request.user) # 查询分组
|
||||
images = Image.objects.filter(group_id=group_id).update(group_id=None) # 移动图片到未分组
|
||||
group.delete() # 删除分组
|
||||
return JsonResponse({'status':True,'data':'删除完成'})
|
||||
except:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return JsonResponse({'status':False,'data':'删除错误'})
|
||||
# 获取分组
|
||||
elif int(types) == 3:
|
||||
try:
|
||||
group_list = []
|
||||
all_cnt = Image.objects.all().count()
|
||||
non_group_cnt = Image.objects.filter(group_id=None).count()
|
||||
group_list.append({'group_name':'全部图片','group_cnt':all_cnt,'group_id':0})
|
||||
group_list.append({'group_name':'未分组','group_cnt':non_group_cnt,'group_id':-1})
|
||||
groups = ImageGroup.objects.filter(user=request.user) # 查询所有分组
|
||||
for group in groups:
|
||||
group_cnt = Image.objects.filter(group_id=group).count()
|
||||
item = {
|
||||
'group_id':group.id,
|
||||
'group_name':group.group_name,
|
||||
'group_cnt':group_cnt
|
||||
}
|
||||
group_list.append(item)
|
||||
return JsonResponse({'status':True,'data':group_list})
|
||||
except:
|
||||
if settings.DEBUG:
|
||||
print(traceback.print_exc())
|
||||
return JsonResponse({'status':False,'data':'出现错误'})
|
||||
58
static/mrdoc-admin.css
Normal file
58
static/mrdoc-admin.css
Normal file
@ -0,0 +1,58 @@
|
||||
/* 用户中心 图片管理 */
|
||||
.image-list{
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
display:flex;
|
||||
float: left;
|
||||
align-items:center;
|
||||
width: 160px;
|
||||
height:180px;
|
||||
margin: 0 20px 30px 0;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.image-list:hover{
|
||||
background-color: #EAFFEA;
|
||||
}
|
||||
.image-list-i{
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
-webkit-background-size: contain;
|
||||
/*background-size: contain;*/
|
||||
/*background-position: 50% 50%;*/
|
||||
/*background-repeat: no-repeat;*/
|
||||
/*padding-bottom: 100%;*/
|
||||
border: 1px solid transparent;
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.img-file-name{
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
-o-text-overflow: ellipsis;
|
||||
white-space:nowrap;
|
||||
width:160px;
|
||||
height:24px;
|
||||
display:block;
|
||||
}
|
||||
/* 图片管理按钮 */
|
||||
.opera-img-btn{
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
width: 160px;
|
||||
height: 25px;
|
||||
display: none;
|
||||
background:#393D49;
|
||||
opacity:0.5;
|
||||
}
|
||||
.opera-img-btn i{
|
||||
font-size:20px;
|
||||
color:white;
|
||||
}
|
||||
.opera-img-btn i:hover{
|
||||
color:red;
|
||||
}
|
||||
@ -198,7 +198,7 @@ body, html {
|
||||
min-width: 0;
|
||||
background: #fff;
|
||||
flex-direction: column;
|
||||
padding-bottom: 64px;
|
||||
/*padding-bottom: 64px;*/
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
left:300px;
|
||||
|
||||
456
static/viewerjs/viewer.css
Normal file
456
static/viewerjs/viewer.css
Normal file
@ -0,0 +1,456 @@
|
||||
/*!
|
||||
* Viewer.js v1.5.0
|
||||
* https://fengyuanchen.github.io/viewerjs
|
||||
*
|
||||
* Copyright 2015-present Chen Fengyuan
|
||||
* Released under the MIT license
|
||||
*
|
||||
* Date: 2019-11-23T05:10:21.757Z
|
||||
*/
|
||||
|
||||
.viewer-zoom-in::before,
|
||||
.viewer-zoom-out::before,
|
||||
.viewer-one-to-one::before,
|
||||
.viewer-reset::before,
|
||||
.viewer-prev::before,
|
||||
.viewer-play::before,
|
||||
.viewer-next::before,
|
||||
.viewer-rotate-left::before,
|
||||
.viewer-rotate-right::before,
|
||||
.viewer-flip-horizontal::before,
|
||||
.viewer-flip-vertical::before,
|
||||
.viewer-fullscreen::before,
|
||||
.viewer-fullscreen-exit::before,
|
||||
.viewer-close::before {
|
||||
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAARgAAAAUCAYAAABWOyJDAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAAQPSURBVHic7Zs/iFxVFMa/0U2UaJGksUgnIVhYxVhpjDbZCBmLdAYECxsRFBTUamcXUiSNncgKQbSxsxH8gzAP3FU2jY0kKKJNiiiIghFlccnP4p3nPCdv3p9778vsLOcHB2bfveeb7955c3jvvNkBIMdxnD64a94GHMfZu3iBcRynN7zAOI7TG15gHCeeNUkr8zaxG2lbYDYsdgMbktBsP03jdQwljSXdtBhLOmtjowC9Mg9L+knSlcD8TNKpSA9lBpK2JF2VdDSR5n5J64m0qli399hNFMUlpshQii5jbXTbHGviB0nLNeNDSd9VO4A2UdB2fp+x0eCnaXxWXGA2X0au/3HgN9P4LFCjIANOJdrLr0zzZ+BEpNYDwKbpnQMeAw4m8HjQtM6Z9qa917zPQwFr3M5KgA6J5rTJCdFZJj9/lyvGhsDvwFNVuV2MhhjrK6b9bFiE+j1r87eBl4HDwCF7/U/k+ofAX5b/EXBv5JoLMuILzf3Ap6Z3EzgdqHMCuF7hcQf4HDgeoHnccncqdK/TvSDWffFXI/exICY/xZyqc6XLWF1UFZna4gJ7q8BsRvgd2/xXpo6P+D9dfT7PpECtA3cnWPM0GXGFZh/wgWltA+cDNC7X+AP4GzjZQe+k5dRxuYPeiuXU7e1qwLpDz7dFjXKRaSwuMLvAlG8zZlG+YmiK1HoFqT7wP2z+4Q45TfEGcMt01xLoNZEBTwRqD4BLpnMLeC1A41UmVxsXgXeBayV/Wx20rpTyrpnWRft7p6O/FdqzGrDukPNtkaMoMo3FBdBSQMOnYBCReyf05s126fU9ytfX98+mY54Kxnp7S9K3kj6U9KYdG0h6UdLbkh7poFXMfUnSOyVvL0h6VtIXHbS6nOP+s/Zm9mvyXW1uuC9ohZ72E9uDmXWLJOB1GxsH+DxPftsB8B6wlGDN02TAkxG6+4D3TWsbeC5CS8CDFce+AW500LhhOW2020TRjK3b21HEmgti9m0RonxbdMZeVzV+/4tF3cBpP7E9mKHNL5q8h5g0eYsCMQz0epq8gQrwMXAgcs0FGXGFRcB9wCemF9PkbYqM/Bas7fxLwNeJPdTdpo4itQti8lPMqTpXuozVRVXPpbHI3KkNTB1NfkL81j2mvhDp91HgV9MKuRIqrykj3WPq4rHyL+axj8/qGPmTqi6F9YDlHOvJU6oYcTsh/TYSzWmTE6JT19CtLTJt32D6CmHe0eQn1O8z5AXgT4sx4Vcu0/EQecMydB8z0hUWkTd2t4CrwNEePqMBcAR4mrBbwyXLPWJa8zrXmmLEhNBmfpkuY2102xxrih+pb+ieAb6vGhuA97UcJ5KR8gZ77K+99xxeYBzH6Q3/Z0fHcXrDC4zjOL3hBcZxnN74F+zlvXFWXF9PAAAAAElFTkSuQmCC');
|
||||
background-repeat: no-repeat;
|
||||
background-size: 280px;
|
||||
color: transparent;
|
||||
display: block;
|
||||
font-size: 0;
|
||||
height: 20px;
|
||||
line-height: 0;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.viewer-zoom-in::before {
|
||||
background-position: 0 0;
|
||||
content: 'Zoom In';
|
||||
}
|
||||
|
||||
.viewer-zoom-out::before {
|
||||
background-position: -20px 0;
|
||||
content: 'Zoom Out';
|
||||
}
|
||||
|
||||
.viewer-one-to-one::before {
|
||||
background-position: -40px 0;
|
||||
content: 'One to One';
|
||||
}
|
||||
|
||||
.viewer-reset::before {
|
||||
background-position: -60px 0;
|
||||
content: 'Reset';
|
||||
}
|
||||
|
||||
.viewer-prev::before {
|
||||
background-position: -80px 0;
|
||||
content: 'Previous';
|
||||
}
|
||||
|
||||
.viewer-play::before {
|
||||
background-position: -100px 0;
|
||||
content: 'Play';
|
||||
}
|
||||
|
||||
.viewer-next::before {
|
||||
background-position: -120px 0;
|
||||
content: 'Next';
|
||||
}
|
||||
|
||||
.viewer-rotate-left::before {
|
||||
background-position: -140px 0;
|
||||
content: 'Rotate Left';
|
||||
}
|
||||
|
||||
.viewer-rotate-right::before {
|
||||
background-position: -160px 0;
|
||||
content: 'Rotate Right';
|
||||
}
|
||||
|
||||
.viewer-flip-horizontal::before {
|
||||
background-position: -180px 0;
|
||||
content: 'Flip Horizontal';
|
||||
}
|
||||
|
||||
.viewer-flip-vertical::before {
|
||||
background-position: -200px 0;
|
||||
content: 'Flip Vertical';
|
||||
}
|
||||
|
||||
.viewer-fullscreen::before {
|
||||
background-position: -220px 0;
|
||||
content: 'Enter Full Screen';
|
||||
}
|
||||
|
||||
.viewer-fullscreen-exit::before {
|
||||
background-position: -240px 0;
|
||||
content: 'Exit Full Screen';
|
||||
}
|
||||
|
||||
.viewer-close::before {
|
||||
background-position: -260px 0;
|
||||
content: 'Close';
|
||||
}
|
||||
|
||||
.viewer-container {
|
||||
bottom: 0;
|
||||
direction: ltr;
|
||||
font-size: 0;
|
||||
left: 0;
|
||||
line-height: 0;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
top: 0;
|
||||
-ms-touch-action: none;
|
||||
touch-action: none;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.viewer-container::-moz-selection,
|
||||
.viewer-container *::-moz-selection {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.viewer-container::selection,
|
||||
.viewer-container *::selection {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.viewer-container img {
|
||||
display: block;
|
||||
height: auto;
|
||||
max-height: none !important;
|
||||
max-width: none !important;
|
||||
min-height: 0 !important;
|
||||
min-width: 0 !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.viewer-canvas {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.viewer-canvas > img {
|
||||
height: auto;
|
||||
margin: 15px auto;
|
||||
max-width: 90% !important;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.viewer-footer {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.viewer-navbar {
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.viewer-list {
|
||||
-webkit-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
height: 50px;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
padding: 1px 0;
|
||||
}
|
||||
|
||||
.viewer-list > li {
|
||||
color: transparent;
|
||||
cursor: pointer;
|
||||
float: left;
|
||||
font-size: 0;
|
||||
height: 50px;
|
||||
line-height: 0;
|
||||
opacity: 0.5;
|
||||
overflow: hidden;
|
||||
-webkit-transition: opacity 0.15s;
|
||||
transition: opacity 0.15s;
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
.viewer-list > li:hover {
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
.viewer-list > li + li {
|
||||
margin-left: 1px;
|
||||
}
|
||||
|
||||
.viewer-list > .viewer-loading {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.viewer-list > .viewer-loading::after {
|
||||
border-width: 2px;
|
||||
height: 20px;
|
||||
margin-left: -10px;
|
||||
margin-top: -10px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.viewer-list > .viewer-active,
|
||||
.viewer-list > .viewer-active:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.viewer-player {
|
||||
background-color: #000;
|
||||
bottom: 0;
|
||||
cursor: none;
|
||||
display: none;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.viewer-player > img {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.viewer-toolbar > ul {
|
||||
display: inline-block;
|
||||
margin: 0 auto 5px;
|
||||
overflow: hidden;
|
||||
padding: 3px 0;
|
||||
}
|
||||
|
||||
.viewer-toolbar > ul > li {
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
float: left;
|
||||
height: 24px;
|
||||
overflow: hidden;
|
||||
-webkit-transition: background-color 0.15s;
|
||||
transition: background-color 0.15s;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.viewer-toolbar > ul > li:hover {
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
.viewer-toolbar > ul > li::before {
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
.viewer-toolbar > ul > li + li {
|
||||
margin-left: 1px;
|
||||
}
|
||||
|
||||
.viewer-toolbar > ul > .viewer-small {
|
||||
height: 18px;
|
||||
margin-bottom: 3px;
|
||||
margin-top: 3px;
|
||||
width: 18px;
|
||||
}
|
||||
|
||||
.viewer-toolbar > ul > .viewer-small::before {
|
||||
margin: -1px;
|
||||
}
|
||||
|
||||
.viewer-toolbar > ul > .viewer-large {
|
||||
height: 30px;
|
||||
margin-bottom: -3px;
|
||||
margin-top: -3px;
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
.viewer-toolbar > ul > .viewer-large::before {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.viewer-tooltip {
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
border-radius: 10px;
|
||||
color: #fff;
|
||||
display: none;
|
||||
font-size: 12px;
|
||||
height: 20px;
|
||||
left: 50%;
|
||||
line-height: 20px;
|
||||
margin-left: -25px;
|
||||
margin-top: -10px;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
top: 50%;
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.viewer-title {
|
||||
color: #ccc;
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
margin: 0 5% 5px;
|
||||
max-width: 90%;
|
||||
opacity: 0.8;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-transition: opacity 0.15s;
|
||||
transition: opacity 0.15s;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.viewer-title:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.viewer-button {
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
height: 80px;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
right: -40px;
|
||||
top: -40px;
|
||||
-webkit-transition: background-color 0.15s;
|
||||
transition: background-color 0.15s;
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.viewer-button:focus,
|
||||
.viewer-button:hover {
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
.viewer-button::before {
|
||||
bottom: 15px;
|
||||
left: 15px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.viewer-fixed {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.viewer-open {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.viewer-show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.viewer-hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.viewer-backdrop {
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.viewer-invisible {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.viewer-move {
|
||||
cursor: move;
|
||||
cursor: -webkit-grab;
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.viewer-fade {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.viewer-in {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.viewer-transition {
|
||||
-webkit-transition: all 0.3s;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
@-webkit-keyframes viewer-spinner {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes viewer-spinner {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.viewer-loading::after {
|
||||
-webkit-animation: viewer-spinner 1s linear infinite;
|
||||
animation: viewer-spinner 1s linear infinite;
|
||||
border: 4px solid rgba(255, 255, 255, 0.1);
|
||||
border-left-color: rgba(255, 255, 255, 0.5);
|
||||
border-radius: 50%;
|
||||
content: '';
|
||||
display: inline-block;
|
||||
height: 40px;
|
||||
left: 50%;
|
||||
margin-left: -20px;
|
||||
margin-top: -20px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 40px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.viewer-hide-xs-down {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 991px) {
|
||||
.viewer-hide-sm-down {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1199px) {
|
||||
.viewer-hide-md-down {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
3117
static/viewerjs/viewer.js
Normal file
3117
static/viewerjs/viewer.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -13,9 +13,6 @@
|
||||
<!-- 页头结束 -->
|
||||
<div class="layui-main">
|
||||
<div style="text-align: center;margin-top: 40px;">
|
||||
<!--<h1>-->
|
||||
<!--<strong>页面未找到……</strong>-->
|
||||
<!--</h1>-->
|
||||
<img src="{% static '404.png' %}">
|
||||
<p><a href="{% url 'pro_list' %}" >返回首页</a></p>
|
||||
</div>
|
||||
|
||||
@ -26,6 +26,31 @@
|
||||
.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;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
</style>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
|
||||
@ -56,6 +81,8 @@
|
||||
});
|
||||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var element = layui.element;
|
||||
var laypage = layui.laypage;
|
||||
var md_changed = false; //初始化一个变量,用于判断编辑器是否修改
|
||||
//初始化editormd
|
||||
var editor = editormd("editor-md", {
|
||||
@ -68,14 +95,19 @@
|
||||
"bold", "del", "italic", "quote", "ucwords", "uppercase", "lowercase","kaiSpan", "|",
|
||||
"h1", "h2", "h3", "h4", "h5", "h6", "|",
|
||||
"list-ul", "list-ol", "hr", "|",
|
||||
"link", "reference-link", "image", "code", "preformatted-text", "code-block", "table", "datetime", "emoji", "html-entities", "pagebreak", "|",
|
||||
"link", "reference-link","imgUpload", "code", "preformatted-text", "code-block", "table", "datetime", "emoji", "html-entities", "pagebreak", "|",
|
||||
"watch", "preview", "|",
|
||||
"help"
|
||||
]
|
||||
},
|
||||
//自定义工具栏添加楷体按钮
|
||||
toolbarIconTexts : {
|
||||
kaiSpan : "楷"
|
||||
kaiSpan : "楷",
|
||||
imgUpload:'fa-image',
|
||||
},
|
||||
//自定义工具栏添加图片按钮
|
||||
toolbarIconsClass : {
|
||||
imgUpload:'fa-image',
|
||||
},
|
||||
//设置自定义工具栏按钮的事件
|
||||
toolbarHandlers : {
|
||||
@ -97,11 +129,25 @@
|
||||
// this == 当前editormd实例
|
||||
//console.log("testIcon =>", this, cm, icon, cursor, selection);
|
||||
},
|
||||
// 点击工具栏图片图标的响应函数 - 上传图片和选择图片
|
||||
imgUpload : function(cm,icon,cursor,selection){
|
||||
layer.ready(function(){
|
||||
element.init();
|
||||
});
|
||||
layer.open({
|
||||
type:'1',
|
||||
title:'添加图片',
|
||||
area:['800px','600px'],
|
||||
id:'uploadImg',//配置ID,
|
||||
content:$('#upload-img'),
|
||||
})
|
||||
}
|
||||
},
|
||||
//设置语言
|
||||
lang : {
|
||||
toolbar : {
|
||||
kaiSpan : "添加楷体span标签",
|
||||
imgUpload:"添加图片到文档",
|
||||
}
|
||||
},
|
||||
//配置项
|
||||
@ -158,45 +204,147 @@
|
||||
}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){
|
||||
console.log('选择图片')
|
||||
$("#select-img-group").empty(); //删除已有分组按钮
|
||||
//请求新的分组数据
|
||||
$.post("{% url 'manage_img_group' %}",{'types':3},function(r){
|
||||
if(r.status){
|
||||
//console.log(r.data)
|
||||
group_btn_str = ''
|
||||
for(let i in r.data){
|
||||
group_btn_str += '<button class="layui-btn layui-btn-normal" 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)
|
||||
}
|
||||
});
|
||||
//请求全部图片数据
|
||||
var loading = layer.load();
|
||||
$.post("{% url 'manage_image' %}",{'types':2,'group_id':0},function(r){
|
||||
if(r.status){
|
||||
//img_list_str = '<ul>'
|
||||
//for(let i in r.data){
|
||||
// img_list_str += '<li class="select-img-list"><img class="select-img-list-i" src="' + r.data[i].path + '" title="' + r.data[i].name + '" /></li>'
|
||||
//}
|
||||
//img_list_str += '</ul>'
|
||||
//$("#select-img").append(img_list_str);
|
||||
//调用分页显示
|
||||
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.close(loading);//关闭加载提示
|
||||
}else{
|
||||
layer.close(loading);
|
||||
layer.msg("获取图片失败")
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
//插入选择的图片到编辑器
|
||||
insertImg = function(e){
|
||||
console.log(e.src);
|
||||
editor.insertValue("\n");
|
||||
};
|
||||
//切换图片分组
|
||||
switchImgGroup = function(e){
|
||||
var switch_loading = layer.load();
|
||||
$.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.close(switch_loading); //关闭加载提示
|
||||
} else {
|
||||
layer.close(switch_loading);
|
||||
layer.msg("获取分组图片失败")
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<script src="{% static 'mrdoc.js?version={{mrdoc_version}}' %}"></script>
|
||||
<script src="{% static 'mrdoc.js' %}?version={{mrdoc_version}}"></script>
|
||||
{% block custom_script %}
|
||||
{% endblock %}
|
||||
</body>
|
||||
{% block custom_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" href="{% url 'create_doctemp' %}" target="_blank">创建新模板</a>
|
||||
<a class="layui-btn layui-btn-normal" 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);" onclick="insertTemp('{{temp.id}}');">选择模板</a>
|
||||
{# <a href="javascript:void(0);" onclick="modifyTemp();">修改</a>#}
|
||||
{# <a href="javascript:void(0);" onclick="delTemp();">删除</a>#}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
<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">
|
||||
<button class="layui-btn layui-btn-normal layui-btn-lg" id="upload_img">点击上传图片</button>
|
||||
</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>
|
||||
<script>
|
||||
//按钮选择上传图片
|
||||
var upload = layui.upload;
|
||||
upload.render({
|
||||
elem: '#upload_img',
|
||||
url: '{% url "upload_doc_img" %}',
|
||||
done: function(res, index, upload){ //上传后的回调
|
||||
//上传成功
|
||||
if(res.success == 1){
|
||||
editor.insertValue("\n");
|
||||
layer.closeAll();
|
||||
layer.msg("上传成功");
|
||||
}else{
|
||||
layer.msg("上传出错,请重试!")
|
||||
}
|
||||
},
|
||||
accept: 'images', //允许上传的文件类型
|
||||
acceptMime:'image/*',
|
||||
field:'manage_upload',
|
||||
size: 5000, //最大允许上传的文件大小
|
||||
|
||||
})
|
||||
</script>
|
||||
</html>
|
||||
@ -15,26 +15,26 @@
|
||||
<a class="btn pull-left" aria-label="" href="{% url 'create_doc' %}?pid={{project.id}}" target="_blank">
|
||||
<i class="fa fa-file"></i> 新建
|
||||
</a>
|
||||
<!-- 文档目录 -->
|
||||
<div id="toc-container" style="display:none;padding:10px;overflow:auto;"></div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content_head %}
|
||||
<h1>{{ doc.name }}</h1><hr>
|
||||
|
||||
<p style="color: #666;font-size:12px;">
|
||||
<!--<i class="fa fa-th-large"></i> 发表:{{ doc.create_time }}-->
|
||||
<i class="fa fa-user"></i> 作者:{{ doc.create_user.username }}
|
||||
<i class="fa fa-edit"></i> 最后修改于:{{ doc.modify_time }}
|
||||
<!--<i class="fa fa-user"></i> {{ doc.create_user.username }}-->
|
||||
</p>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block page_content %}
|
||||
{# {{ doc.content | safe }} #}
|
||||
<!--<style>
|
||||
div.editormd-toc-menu ul.markdown-toc-list li,ul.markdown-toc-list > li > ul li{
|
||||
<!--list-style: none;
|
||||
}
|
||||
</style>-->
|
||||
<textarea id="" style="display: none;">{{ doc.pre_content }}</textarea>
|
||||
<textarea style="display: none;">{{ doc.pre_content }}</textarea>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block doc_previous_next %}
|
||||
@ -56,4 +56,23 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block custom_script %}
|
||||
<script>
|
||||
var layer = layui.layer;
|
||||
var toc = $("#toc-container").find('li');
|
||||
if(toc.length > 0){
|
||||
layer.open({
|
||||
title: '目录',
|
||||
type:1,
|
||||
offset:'r',//坐标
|
||||
maxmin:true, //最大最小化
|
||||
area: ['200px','200px'],
|
||||
shade: 0,
|
||||
content: $("#toc-container"),
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
@ -40,7 +40,20 @@
|
||||
}
|
||||
/* 下拉目录隐藏li样式 */
|
||||
.editormd-toc-menu ul.markdown-toc-list li{
|
||||
list-style:none;
|
||||
/*list-style:none;*/
|
||||
}
|
||||
/* 弹出框文档目录样式 */
|
||||
ul.markdown-toc-list{
|
||||
list-style-position:inside;
|
||||
}
|
||||
ul.markdown-toc-list li{
|
||||
list-style: inherit!important;
|
||||
}
|
||||
ul.markdown-toc-list > li > ul > li,ul.markdown-toc-list > li > ul li{
|
||||
padding-left:10px;
|
||||
}
|
||||
ul.markdown-toc-list a{
|
||||
text-decoration: underline!important;
|
||||
}
|
||||
</style>
|
||||
<!--[if lt IE 9]>
|
||||
@ -170,10 +183,7 @@
|
||||
</div>
|
||||
<!-- 正文结束 -->
|
||||
</div>
|
||||
<!-- 文档目录 -->
|
||||
<div class="doc-cata">
|
||||
<div id="toc-container"></div>
|
||||
</div>
|
||||
|
||||
{% block doc_previous_next %}{% endblock %}
|
||||
<!-- 社交分享 -->
|
||||
<div class="share-div" style="margin-top: 10px;padding:10px;text-align: center;background-color: #fafafa">
|
||||
@ -219,7 +229,6 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% block custom_script %}
|
||||
<script>
|
||||
$.ajaxSetup({
|
||||
data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
|
||||
@ -233,8 +242,11 @@
|
||||
flowChart : true, // 流程图
|
||||
sequenceDiagram : true, // 时序图
|
||||
tocm : true, //目录
|
||||
toc :true,
|
||||
tocContainer : "#toc-container",
|
||||
tocDropdown : false,
|
||||
atLink : false,//禁用@链接
|
||||
//tocContainer : "#toc-container"
|
||||
|
||||
});
|
||||
//为当前页面的目录链接添加蓝色样式
|
||||
$("nav li a").each(function (i) {
|
||||
@ -372,6 +384,7 @@
|
||||
{{ static_code | safe }}
|
||||
{% endif %}
|
||||
<!-- 统计代码结束 -->
|
||||
{% block custom_script %}
|
||||
{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
@ -6,6 +6,8 @@
|
||||
<meta charset="UTF-8">
|
||||
<title>{% block title %}{% endblock %} - 个人中心 - MrDoc</title>
|
||||
<link href="{% static 'layui/css/layui.css' %}?version={{mrdoc_version}}" rel="stylesheet">
|
||||
<link href="{% static 'mrdoc-admin.css' %}?version={{mrdoc_version}}" rel="stylesheet">
|
||||
<link href="{% static 'viewerjs/viewer.css' %}?version={{mrdoc_version}}" rel="stylesheet">
|
||||
<link rel="icon" href="{% static 'favicon_16.png' %}"/>
|
||||
<style>
|
||||
.logo img{
|
||||
@ -14,7 +16,7 @@
|
||||
.layui-btn a{
|
||||
color:white;
|
||||
}
|
||||
/* 管理文档 文档状态条件筛选 */
|
||||
/* 管理文档文档状态条件筛选 管理图片图片分组筛选 */
|
||||
.doc_status_condition > a.current{
|
||||
color: #000!important;
|
||||
}
|
||||
@ -56,9 +58,12 @@
|
||||
<li class="layui-nav-item layui-nav-itemed">
|
||||
<a href="{% url 'manage_doc' %}"><i class="layui-icon layui-icon-file-b"></i> 文档管理</a>
|
||||
</li>
|
||||
<li class="layui-nav-item layui-nav-itemed">
|
||||
<li class="layui-nav-item layui-nav-itemed">
|
||||
<a href="{% url 'manage_doctemp' %}"><i class="layui-icon layui-icon-template"></i> 文档模板管理</a>
|
||||
</li>
|
||||
<li class="layui-nav-item layui-nav-itemed">
|
||||
<a href="{% url 'manage_image' %}"><i class="layui-icon layui-icon-picture"></i> 图片素材管理</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
221
template/app_doc/manage_image.html
Normal file
221
template/app_doc/manage_image.html
Normal file
@ -0,0 +1,221 @@
|
||||
{% extends 'app_doc/manage_base.html' %}
|
||||
{% load staticfiles %}
|
||||
{% block title %}图片素材管理{% endblock %}
|
||||
{% block content %}
|
||||
<div class="layui-card-header" style="margin-bottom: 10px;">
|
||||
<div class="layui-row">
|
||||
<span style="font-size:18px;">图片素材管理
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-row">
|
||||
<form action="" method="get">
|
||||
<div class="layui-form-item">
|
||||
<!--<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>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
<div class="layui-row">
|
||||
<!--<span style="font-size:16px;"><b>分组: </b></span>-->
|
||||
<span class="layui-breadcrumb doc_status_condition" lay-separator="|">
|
||||
{% load project_filter %}
|
||||
<a href="{% url 'manage_image' %}?group=0" class="{% if g_id == 0 %}current{% endif %}">全部图片({{all_img_cnt}})</a>
|
||||
<a href="{% url 'manage_image' %}?group=-1" class="{% if g_id == -1 %}current{% endif %}">未分组({{no_group_cnt}})</a>
|
||||
{% for group in groups %}
|
||||
<a href="{% url 'manage_image' %}?group={{group.id}}" class="{% if g_id == group.id %}current{% endif %}">{{group.group_name}}({{group.id | img_group_cnt}})</a>
|
||||
{% endfor %}
|
||||
</span>
|
||||
</div>
|
||||
<div class="layui-row" lay-skin="line">
|
||||
<ul style="padding: 20px;" id="images">
|
||||
{% for img in images %}
|
||||
<li class="image-list">
|
||||
<!--<i class="image-list-i" style="background-image: url('{{img.file_path}}');"></i>-->
|
||||
<img class="image-list-i" src="{{img.file_path}}" title="{{img.file_name}}">
|
||||
<!--<span class="img-file-name" title="{{img.file_name}}">{{img.file_name}}</span>-->
|
||||
<!--<input type="checkbox" />-->
|
||||
<div class="opera-img-btn">
|
||||
<a href="javascript:void(0);" class="move-img" title="移动分组" data-src="{{img.file_path}}" data-id="{{img.id}}"><i class="layui-icon layui-icon-transfer"></i></a>
|
||||
<a href="javascript:void(0);" class="del-img" title="删除图片" data-src="{{img.file_path}}" data-id="{{img.id}}"><i class="layui-icon layui-icon-delete"></i></a>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<hr>
|
||||
<div class="layui-row">
|
||||
<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>
|
||||
{% 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>
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block custom_script %}
|
||||
<script src="{% static 'viewerjs/viewer.js' %}"></script>
|
||||
<script>
|
||||
var form = layui.form;
|
||||
|
||||
//悬浮显示图片按钮
|
||||
$(".image-list").mouseover(function(){
|
||||
$(this).find(".opera-img-btn").show();
|
||||
});
|
||||
$(".image-list").mouseleave(function(){
|
||||
$(this).find(".opera-img-btn").hide();
|
||||
});
|
||||
//删除图片
|
||||
$(".del-img").click(function(){
|
||||
var img_id = $(this).data("id");
|
||||
var img_src = $(this).data("src");
|
||||
layer.open({
|
||||
type:1,
|
||||
title:'删除图片',
|
||||
area:'300px;',
|
||||
id:'delImg',//配置ID
|
||||
content:'<div style="margin:10px;"><img src="'+ img_src +'" style="width:50px;height:50px;margin:10px;"/><span>删除此图片后,文档中添加的该图片将不再显示!</span></div>',
|
||||
btn:['确定','取消'], //添加按钮
|
||||
btnAlign:'c', //按钮居中
|
||||
yes:function (index,layero) {
|
||||
data = {
|
||||
'img_id':img_id,
|
||||
'types':0
|
||||
}
|
||||
$.post("{% url 'manage_image' %}",data,function(r){
|
||||
if(r.status){
|
||||
//删除成功
|
||||
window.location.reload();
|
||||
//layer.close(index)
|
||||
}else{
|
||||
//删除失败,提示
|
||||
console.log(r)
|
||||
layer.msg(r.data)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
})
|
||||
});
|
||||
//移动分组
|
||||
$(".move-img").click(function(){
|
||||
var img_id = $(this).data("id");
|
||||
var img_src = $(this).data("src");
|
||||
layer.open({
|
||||
type:1,
|
||||
title:'移动图片分组',
|
||||
area:['300px','300px'],
|
||||
id:'moveImg',//配置ID
|
||||
content:$("#move-group-layer"),
|
||||
btn:['确定','取消'], //添加按钮
|
||||
btnAlign:'c', //按钮居中
|
||||
yes:function (index,layero) {
|
||||
data = {
|
||||
'types':1,
|
||||
'img_id':img_id,
|
||||
'group_id':$("#group_id").val()
|
||||
}
|
||||
console.log(data)
|
||||
$.post("{% url 'manage_image' %}",data,function(r){
|
||||
if(r.status){
|
||||
//移动成功
|
||||
window.location.reload();
|
||||
//layer.close(index)
|
||||
}else{
|
||||
//移动失败,提示
|
||||
console.log(r)
|
||||
layer.msg(r.data)
|
||||
}
|
||||
})
|
||||
},
|
||||
success:function(){
|
||||
form.render();
|
||||
}
|
||||
})
|
||||
});
|
||||
//查看图片
|
||||
var options = {
|
||||
//inline: true,
|
||||
url: 'data-original',
|
||||
fullscreen:false,//全屏
|
||||
rotatable:false,//旋转
|
||||
scalable:false,//翻转
|
||||
//zoomable:false,//缩放
|
||||
button:false,//关闭按钮
|
||||
};
|
||||
const viewer = new Viewer(document.getElementById('images'), options);
|
||||
//创建图片分组
|
||||
createImgGroup = function(){
|
||||
layer.open({
|
||||
type:1,
|
||||
title:'新建图片分组',
|
||||
area:'300px;',
|
||||
id:'createImgGroup',//配置ID
|
||||
content:'<div style="margin:10px;"><input type="text" id="img_group_name" class="layui-input" /></div>',
|
||||
btn:['确定','取消'], //添加按钮
|
||||
btnAlign:'c', //按钮居中
|
||||
yes:function (index,layero) {
|
||||
data = {
|
||||
'types':0,
|
||||
'group_name':$("#img_group_name").val(),
|
||||
}
|
||||
$.post("{% url 'manage_img_group' %}",data,function(r){
|
||||
if(r.status){
|
||||
//新建成功
|
||||
window.location.reload();
|
||||
//layer.close(index)
|
||||
}else{
|
||||
//新建失败,提示
|
||||
console.log(r)
|
||||
layer.msg(r.data)
|
||||
}
|
||||
})
|
||||
},
|
||||
})
|
||||
};
|
||||
//上传图片
|
||||
var upload = layui.upload;
|
||||
upload.render({
|
||||
elem: '#upload_img',
|
||||
url: '{% url "upload_doc_img" %}',
|
||||
done: function(res, index, upload){ //上传后的回调
|
||||
//上传成功,刷新页面
|
||||
if(res.success == 1){
|
||||
window.location.reload();
|
||||
}else{
|
||||
layer.msg("上传出错,请重试!")
|
||||
}
|
||||
},
|
||||
accept: 'images', //允许上传的文件类型
|
||||
acceptMime:'image/*',
|
||||
field:'manage_upload',
|
||||
size: 5000, //最大允许上传的文件大小
|
||||
|
||||
})
|
||||
</script>
|
||||
<!--移动图片分组DIV块-->
|
||||
<div style="margin:10px;display:none;" class="layui-form" id="move-group-layer">
|
||||
<div class="layui-form-item">
|
||||
<select id="group_id">
|
||||
{% for group in groups %}
|
||||
<option value="{{group.id}}">{{group.group_name}}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
114
template/app_doc/manage_image_group.html
Normal file
114
template/app_doc/manage_image_group.html
Normal file
@ -0,0 +1,114 @@
|
||||
{% extends 'app_doc/manage_base.html' %}
|
||||
{% load staticfiles %}
|
||||
{% block title %}图片分组管理{% endblock %}
|
||||
{% block content %}
|
||||
<div class="layui-row" style="margin-bottom: 10px;padding-left:15px;">
|
||||
<span class="layui-breadcrumb" lay-separator=">">
|
||||
<a href="{% url 'manage_image' %}">图片管理</a>
|
||||
<a><cite>图片分组管理</cite></a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="layui-card-header" style="margin-bottom: 10px;">
|
||||
<div class="layui-row">
|
||||
<span style="font-size:18px;">图片分组管理
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-row">
|
||||
<form action="{% url 'manage_doctemp' %}" method="get">
|
||||
<div class="layui-form-item">
|
||||
<!--<button class="layui-btn layui-btn-normal" type="button" onclick="createImgGroup()">新建分组</button>-->
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="layui-row" lay-skin="line">
|
||||
<table class="layui-table" id="doctemp-list" lay-skin="">
|
||||
<colgroup>
|
||||
<col width="200">
|
||||
<col width="200">
|
||||
<col>
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>分组名称</th>
|
||||
<th>图片数量</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% load project_filter %}
|
||||
{% for group in groups %}
|
||||
<tr>
|
||||
<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>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block custom_script %}
|
||||
<script>
|
||||
delGroup = function(group_id){
|
||||
layer.open({
|
||||
type:1,
|
||||
title:'删除分组',
|
||||
area:'300px;',
|
||||
id:'delGroup',//配置ID
|
||||
content:'<div style="margin-left:10px;">警告:操作将删除此图片分组,分组下所属图片将移动到【未分组】!</div>',
|
||||
btn:['确定','取消'], //添加按钮
|
||||
btnAlign:'c', //按钮居中
|
||||
yes:function (index,layero) {
|
||||
data = {
|
||||
'types':2,
|
||||
'group_id':group_id,
|
||||
}
|
||||
$.post("{% url 'manage_img_group' %}",data,function(r){
|
||||
if(r.status){
|
||||
//删除成功
|
||||
window.location.reload();
|
||||
//layer.close(index)
|
||||
}else{
|
||||
//删除失败,提示
|
||||
console.log(r)
|
||||
layer.msg(r.data)
|
||||
}
|
||||
})
|
||||
},
|
||||
});
|
||||
};
|
||||
modifyGroup = function(group_id){
|
||||
layer.open({
|
||||
type:1,
|
||||
title:'修改分组',
|
||||
area:'300px;',
|
||||
id:'modifyGroup',//配置ID
|
||||
content:'<div style="margin:10px;"><input class="layui-input" placeholder="输入图片分组的新名称" id="new-group-name"></input></div>',
|
||||
btn:['确定','取消'], //添加按钮
|
||||
btnAlign:'c', //按钮居中
|
||||
yes:function (index,layero) {
|
||||
data = {
|
||||
'types':1,
|
||||
'group_id':group_id,
|
||||
'group_name':$("#new-group-name").val()
|
||||
}
|
||||
$.post("{% url 'manage_img_group' %}",data,function(r){
|
||||
if(r.status){
|
||||
//修改成功
|
||||
window.location.reload();
|
||||
//layer.close(index)
|
||||
}else{
|
||||
//修改失败,提示
|
||||
console.log(r)
|
||||
layer.msg(r.data)
|
||||
}
|
||||
})
|
||||
},
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
Loading…
x
Reference in New Issue
Block a user