forked from mirror/MrDoc
新增收藏管理功能
This commit is contained in:
parent
68bd783c33
commit
8a98473753
@ -12,6 +12,8 @@
|
||||
- [优化]文档编辑器界面样式和交互;
|
||||
- [修复]仅有私密文集的站点游客可搜索到私密文集的问题;
|
||||
- [新增]文集水印配置;
|
||||
- [新增]文集文档收藏功能;
|
||||
- [优化]首页样式;
|
||||
|
||||
|
||||
### v0.6.2 2020-12
|
||||
|
@ -40,7 +40,7 @@ SECRET_KEY = '5&71mt9@^58zdg*_!t(x6g14q*@84d%ptr%%s6e0l50zs0we3d'
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = CONFIG.getboolean('site','debug')
|
||||
|
||||
VERSIONS = '0.6.2'
|
||||
VERSIONS = '0.6.3'
|
||||
|
||||
ALLOWED_HOSTS = ['*']
|
||||
|
||||
|
@ -65,4 +65,5 @@ urlpatterns = [
|
||||
path('manage_overview/',views.manage_overview,name="manage_overview"), # 个人中心概览
|
||||
path('manage_self/',views.manage_self,name="manage_self"), # 个人设置
|
||||
path('my_collect/',views.my_collect,name="my_collect"), # 我的收藏
|
||||
path('manage_collect/',views.manage_collect,name="manage_collect"), # 收藏管理
|
||||
]
|
117
app_doc/views.py
117
app_doc/views.py
@ -1,6 +1,7 @@
|
||||
# coding:utf-8
|
||||
from django.shortcuts import render,redirect
|
||||
from django.http.response import JsonResponse,Http404,HttpResponseNotAllowed,HttpResponse
|
||||
from django.http import QueryDict
|
||||
from django.http import HttpResponseForbidden
|
||||
from django.contrib.auth.decorators import login_required # 登录需求装饰器
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
@ -2982,4 +2983,118 @@ def my_collect(request):
|
||||
return JsonResponse({'status':True,'data':'收藏成功'})
|
||||
|
||||
elif request.method == 'DELETE':
|
||||
pass
|
||||
pass
|
||||
|
||||
# 收藏管理
|
||||
@login_required()
|
||||
@require_http_methods(['GET','POST','DELETE'])
|
||||
@csrf_exempt
|
||||
def manage_collect(request):
|
||||
if request.method == 'GET':
|
||||
# 收藏文集数量
|
||||
collect_project_cnt = MyCollect.objects.filter(create_user=request.user, collect_type=2).count()
|
||||
# 收藏文档数量
|
||||
collect_doc_cnt = MyCollect.objects.filter(create_user=request.user, collect_type=1).count()
|
||||
# 所有收藏数量
|
||||
all_cnt = collect_project_cnt + collect_doc_cnt
|
||||
|
||||
return render(request,'app_doc/manage/manage_collect.html',locals())
|
||||
elif request.method == 'POST':
|
||||
kw = request.POST.get('kw', '') # 搜索词
|
||||
collect_type = request.POST.get('type', '') # 收藏类型
|
||||
if collect_type in ['1', '2']:
|
||||
q_type = [int(collect_type)]
|
||||
else:
|
||||
q_type = [1, 2]
|
||||
|
||||
page = request.POST.get('page', 1)
|
||||
limit = request.POST.get('limit', 10)
|
||||
# 没有搜索
|
||||
if kw == '':
|
||||
collect_list = MyCollect.objects.filter(
|
||||
create_user=request.user,
|
||||
collect_type__in=q_type,
|
||||
).order_by('-create_time')
|
||||
# 有搜索
|
||||
else:
|
||||
collect_list = MyCollect.objects.filter(
|
||||
Q(content__icontains=kw) | Q(name__icontains=kw),
|
||||
create_user=request.user, collect_type__in=q_type
|
||||
).order_by('-create_time')
|
||||
|
||||
# 分页处理
|
||||
paginator = Paginator(collect_list, limit)
|
||||
page = request.GET.get('page', page)
|
||||
try:
|
||||
collects = paginator.page(page)
|
||||
except PageNotAnInteger:
|
||||
collects = paginator.page(1)
|
||||
except EmptyPage:
|
||||
collects = paginator.page(paginator.num_pages)
|
||||
|
||||
table_data = []
|
||||
for collect in collects:
|
||||
if collect.collect_type == 1:
|
||||
item_doc = Doc.objects.get(id=collect.collect_id)
|
||||
item_id = item_doc.id
|
||||
item_name = item_doc.name
|
||||
item_project = Project.objects.get(id=item_doc.top_doc)
|
||||
item_project_name = item_project.name
|
||||
item_project_id = item_project.id
|
||||
else:
|
||||
item_project = Project.objects.get(id=collect.collect_id)
|
||||
item_id = item_project.id
|
||||
item_name = item_project.name
|
||||
item_project_name = ''
|
||||
item_project_id = ''
|
||||
item = {
|
||||
'id': collect.id,
|
||||
'item_id':item_id,
|
||||
'item_name': item_name,
|
||||
'type': collect.collect_type,
|
||||
'item_project_id':item_project_id,
|
||||
'item_project_name':item_project_name,
|
||||
'create_time': collect.create_time,
|
||||
}
|
||||
table_data.append(item)
|
||||
resp_data = {
|
||||
"code": 0,
|
||||
"msg": "ok",
|
||||
"count": collect_list.count(),
|
||||
"data": table_data
|
||||
}
|
||||
return JsonResponse(resp_data)
|
||||
elif request.method == 'DELETE':
|
||||
try:
|
||||
# 获取收藏ID
|
||||
DELETE = QueryDict(request.body)
|
||||
collect_id = DELETE.get('collect_id', None)
|
||||
range = DELETE.get('range', 'single')
|
||||
if collect_id:
|
||||
if range == 'single':
|
||||
# 查询收藏
|
||||
try:
|
||||
collect = MyCollect.objects.get(id=collect_id)
|
||||
except ObjectDoesNotExist:
|
||||
return JsonResponse({'status': False, 'data': '收藏不存在'})
|
||||
# 如果请求用户为站点管理员、收藏的创建者,可以删除
|
||||
if (request.user == collect.create_user) or (request.user.is_superuser):
|
||||
MyCollect.objects.filter(id=collect_id).delete()
|
||||
return JsonResponse({'status': True, 'data': '删除完成'})
|
||||
else:
|
||||
return JsonResponse({'status': False, 'data': '非法请求'})
|
||||
elif range == 'multi':
|
||||
collects = collect_id.split(",")
|
||||
try:
|
||||
MyCollect.objects.filter(id__in=collects, create_user=request.user).delete()
|
||||
return JsonResponse({'status': True, 'data': '删除完成'})
|
||||
except:
|
||||
return JsonResponse({'status': False, 'data': '非法请求'})
|
||||
else:
|
||||
return JsonResponse({'status': False, 'data': '类型错误'})
|
||||
|
||||
else:
|
||||
return JsonResponse({'status': False, 'data': '参数错误'})
|
||||
except Exception as e:
|
||||
logger.exception("取消收藏出错")
|
||||
return JsonResponse({'status': False, 'data': '请求出错'})
|
||||
|
@ -152,6 +152,14 @@ def user_center_menu(request):
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "my_collect",
|
||||
"title": "我的收藏",
|
||||
"icon": "layui-icon layui-icon-star",
|
||||
"type": 1,
|
||||
"openType": "_iframe",
|
||||
"href": reverse("manage_collect")
|
||||
},
|
||||
{
|
||||
"id": "self_settings",
|
||||
"title": "个人管理",
|
||||
|
Binary file not shown.
1
static/icon_img/simi.svg
Normal file
1
static/icon_img/simi.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1609668475194" class="icon" viewBox="0 0 1194 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6789" xmlns:xlink="http://www.w3.org/1999/xlink" width="23.3203125" height="20"><defs><style type="text/css"></style></defs><path d="M1187.2 329.941333c12.8-20.650667 8.533333-48.213333-8.533333-64.298666-19.2-16.042667-44.885333-11.477333-59.818667 9.216-2.133333 2.261333-239.274667 303.018667-521.301333 303.018666-273.493333 0-521.301333-303.018667-523.434667-305.322666-14.933333-18.346667-42.752-20.650667-59.818667-4.608-17.109333 16.085333-19.242667 45.909333-4.266666 64.298666 4.266667 6.869333 55.509333 68.864 136.704 137.728L37.76 591.616c-17.066667 18.346667-14.933333 48.213333 2.133333 64.298667 4.266667 9.173333 14.933333 13.781333 25.642667 13.781333 10.666667 0 21.376-4.608 29.909333-13.781333l117.504-130.858667c55.552 41.344 121.813333 80.341333 194.432 107.904l-44.842666 162.986667c-6.4 25.258667 6.4 50.517333 29.866666 57.386666h12.842667c19.2 0 36.309333-13.781333 40.576-34.432l44.885333-162.986666c34.176 6.869333 70.485333 11.477333 106.837334 11.477333 36.309333 0 72.618667-4.608 106.794666-11.52l44.885334 160.725333c4.266667 20.650667 23.466667 34.432 40.576 34.432 4.266667 0 8.533333 0 10.666666-2.304 23.552-6.869333 36.352-32.128 29.952-57.386666l-44.885333-160.682667c72.661333-27.562667 138.88-66.56 194.432-107.904l115.370667 128.554667c8.533333 9.216 19.2 13.781333 29.909333 13.781333 10.666667 0 21.333333-4.565333 29.909333-13.781333 17.066667-18.346667 17.066667-45.909333 2.133334-64.256l-108.970667-121.685334c87.594667-68.864 138.88-135.424 138.88-135.424z" p-id="6790" fill="#e6e6e6"></path></svg>
|
After Width: | Height: | Size: 1.8 KiB |
@ -291,15 +291,16 @@
|
||||
//修改成功
|
||||
window.localStorage.removeItem('mrdoc_doc_cache') // 清空文档缓存
|
||||
if(status === 1){
|
||||
layer.msg('发布成功,即将跳转',function(){
|
||||
layer.msg('发布成功',function(){
|
||||
md_changed = false;
|
||||
window.location.href = "{% url 'doc' pro_id=doc.top_doc doc_id=doc.id %}";
|
||||
// window.location.href = "{% url 'doc' pro_id=doc.top_doc doc_id=doc.id %}";
|
||||
window.location.href = "/modify_doc/{{doc.id}}/";
|
||||
});
|
||||
}else{
|
||||
layer.msg('保存成功',{time:1000},function(){
|
||||
md_changed = false;
|
||||
//跳转到文档修改
|
||||
window.location.href = "/modify_doc/"+r.data.doc+"/";
|
||||
window.location.href = "/modify_doc/{{doc.id}}/";
|
||||
});
|
||||
}
|
||||
}else{
|
||||
|
223
template/app_doc/manage/manage_collect.html
Normal file
223
template/app_doc/manage/manage_collect.html
Normal file
@ -0,0 +1,223 @@
|
||||
{% extends 'app_doc/user/user_base.html' %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "收藏管理" %}{% endblock %}
|
||||
{% block content %}
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">{% trans "高级筛选" %}</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-form">
|
||||
<!-- <div class="layui-form-item">
|
||||
<label class="layui-form-label">{% trans "关键词" %}</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" name="kw" placeholder="请输入标题" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
<button class="layui-btn layui-btn-normal layui-btn-sm" id="search">{% trans "搜索" %}</button>
|
||||
</div> -->
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">{% trans "收藏类型" %}</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="status" title="全部({{all_cnt}})" value="-1" lay-skin="primary" checked lay-filter="collect_type">
|
||||
<input type="radio" name="status" title="文集({{collect_project_cnt}})" value="2" lay-skin="primary" lay-filter="collect_type">
|
||||
<input type="radio" name="status" title="文档({{collect_doc_cnt}})" value="1" lay-skin="primary" lay-filter="collect_type">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<table id="collect-table" lay-filter="collect-table"></table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 表格工具栏 -->
|
||||
<script type="text/html" id="doc-toolbar">
|
||||
<button class="layui-btn layui-btn-warm pear-btn-sm" lay-event="batchRemove">
|
||||
<i class="layui-icon layui-icon-delete"></i>取消收藏
|
||||
</button>
|
||||
</script>
|
||||
|
||||
<!-- 文档名称 -->
|
||||
<script type="text/html" id="collect-name">
|
||||
{% verbatim %}
|
||||
{{#if (d.type == 1) { }}
|
||||
<img src="/static/icon_img/manage-doc-icon.svg" height="14px" width="14px"></img>
|
||||
<a href="/project-{{d.item_project_id}}/doc-{{d.item_id}}" target="_blank">{{d.item_name}}</a>
|
||||
{{# }else if(d.type == 2){ }}
|
||||
<!-- <span class="layui-badge-dot layui-bg-orange"></span> -->
|
||||
<img src="/static/icon_img/manage-pro-icon.svg" height="14px" width="14px"></img>
|
||||
<a href="/project-{{d.item_id}}/" target="_blank">{{ d.item_name }} </a>
|
||||
{{# } }}
|
||||
{% endverbatim %}
|
||||
</script>
|
||||
|
||||
<!-- 修改时间 -->
|
||||
<script type="text/html" id="collect-create-time">
|
||||
{% verbatim %}
|
||||
{{layui.util.toDateString(d.create_time, "yyyy-MM-dd HH:mm:ss")}}
|
||||
{% endverbatim %}
|
||||
</script>
|
||||
|
||||
<!-- 单个收藏操作 -->
|
||||
<script type="text/html" id="doc-bar">
|
||||
{% verbatim %}
|
||||
<button class="layui-btn layui-btn-warm pear-btn-sm" lay-event="remove"><i class="layui-icon layui-icon-delete"></i></button>
|
||||
{% endverbatim %}
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
{% block custom_script %}
|
||||
<script>
|
||||
layui.use(['table', 'form', 'jquery', 'dtree','layer'], function() {
|
||||
let table = layui.table;
|
||||
let form = layui.form;
|
||||
let $ = layui.jquery;
|
||||
let dtree = layui.dtree;
|
||||
var layer = layui.layer;
|
||||
$.ajaxSetup({
|
||||
data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
|
||||
});
|
||||
let cols = [
|
||||
[
|
||||
{type: 'checkbox',width:20},
|
||||
{title: '名称',field: 'name',align: 'left',templet:"#collect-name",minWidth:280},
|
||||
{title: '归属',field: 'item_project_name',align: 'left',templet:"#project-role"},
|
||||
{title: '收藏时间',field: 'create_time',align: 'left',templet:"#collect-create-time"},
|
||||
{title: '操作',toolbar: '#doc-bar',align: 'left',} ]
|
||||
]
|
||||
// 渲染表格
|
||||
table.render({
|
||||
elem: '#collect-table',
|
||||
method:'post',
|
||||
where:{
|
||||
'type':-1,
|
||||
},
|
||||
url: "{% url 'manage_collect' %}",
|
||||
page: true,
|
||||
cols: cols,
|
||||
skin: 'line',
|
||||
toolbar: '#doc-toolbar',
|
||||
defaultToolbar: ['filter']
|
||||
});
|
||||
// 取消收藏
|
||||
delCollect = function(collect_id){
|
||||
layer.open({
|
||||
type:1,
|
||||
title:'删除收藏',
|
||||
area:'300px;',
|
||||
id:'delPro',//配置ID
|
||||
content:'<div style="margin-left:10px;">警告:此操作将删除此收藏!</div>',
|
||||
btn:['确定','取消'], //添加按钮
|
||||
btnAlign:'c', //按钮居中
|
||||
yes:function (index,layero) {
|
||||
let loading = layer.load();
|
||||
$.ajax({
|
||||
url: "{% url 'manage_collect' %}",
|
||||
dataType: 'json',
|
||||
type: 'delete',
|
||||
data:{'collect_id':collect_id,'range':'single',},
|
||||
success: function(r) {
|
||||
layer.closeAll();
|
||||
if (r.status) {
|
||||
layer.msg("取消成功", {
|
||||
icon: 1,
|
||||
time: 1000
|
||||
}, function() {
|
||||
table.reload('collect-table');
|
||||
});
|
||||
} else {
|
||||
layer.msg(r.data, {
|
||||
icon: 2,
|
||||
time: 1000
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 批量取消收藏
|
||||
batchRemoveCollect = function(obj) {
|
||||
let data = table.checkStatus(obj.config.id).data;
|
||||
if (data.length === 0) {
|
||||
layer.msg("未选中任何收藏", {
|
||||
icon: 3,
|
||||
time: 1000
|
||||
});
|
||||
return false;
|
||||
}
|
||||
let collect_id = "";
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
collect_id += data[i].id + ",";
|
||||
}
|
||||
collect_id = collect_id.substr(0, collect_id.length - 1);
|
||||
// console.log(pro_id)
|
||||
layer.confirm('确定要取消这些收藏?', {
|
||||
icon: 3,
|
||||
title: '提示'
|
||||
}, function(index) {
|
||||
layer.close(index);
|
||||
let loading = layer.load();
|
||||
$.ajax({
|
||||
url: "{% url 'manage_collect' %}",
|
||||
dataType: 'json',
|
||||
type: 'delete',
|
||||
data:{'collect_id':collect_id,'range':'multi'},
|
||||
success: function(r) {
|
||||
layer.close(loading);
|
||||
if (r.status) {
|
||||
layer.msg("取消成功", {
|
||||
icon: 1,
|
||||
time: 1000
|
||||
}, function() {
|
||||
table.reload('collect-table');
|
||||
});
|
||||
} else {
|
||||
layer.msg(r.data, {
|
||||
icon: 2,
|
||||
time: 1000
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
// 监听类型筛选
|
||||
form.on('radio(collect_type)', function(data){
|
||||
console.log(data.value); //被点击的radio的value值
|
||||
table.reload('collect-table',{
|
||||
where:{
|
||||
'type':data.value,
|
||||
},
|
||||
})
|
||||
});
|
||||
// 监听搜索按钮
|
||||
$("#search").click(function(){
|
||||
table.reload('collect-table',{
|
||||
where:{
|
||||
'type':1,'kw':$("input[name=kw]").val(),
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
// 侦听取消收藏按钮
|
||||
table.on("tool(collect-table)",function(obj){
|
||||
if (obj.event === 'remove') {
|
||||
// console.log(obj)
|
||||
delCollect(obj.data.id)
|
||||
}
|
||||
});
|
||||
// 侦听表格工具栏
|
||||
table.on("toolbar(collect-table)",function(obj){
|
||||
if (obj.event === 'add') { // 新增文集
|
||||
createProject();
|
||||
}else if(obj.event === 'batchRemove'){ // 批量删除文集
|
||||
batchRemoveCollect(obj)
|
||||
}
|
||||
});
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
@ -15,7 +15,6 @@
|
||||
<link href="{% static 'layui/css/layui.css' %}" rel="stylesheet">
|
||||
<link href="{% static 'mrdoc/mrdoc.css' %}?version={{mrdoc_version}}" rel="stylesheet">
|
||||
<link rel="icon" href="{% static 'search/mrdoc_logo_300.png' %}" sizes="192x192" />
|
||||
<!-- <link href="//at.alicdn.com/t/font_2281207_xtauo52jlgk.css" rel="stylesheet"> -->
|
||||
<style>
|
||||
.layui-nav .layui-this:after, .layui-nav-bar, .layui-nav-tree, .layui-nav-itemed:after {
|
||||
background-color: #333 !important;
|
||||
@ -129,7 +128,11 @@
|
||||
<div class="layui-col-md3 layui-col-xs12 project-item">
|
||||
<a href="{% url 'pro_index' p.id %}" target="_blank">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header" >
|
||||
<div class="layui-card-header"
|
||||
{% if p.role == 1 %}
|
||||
style="background: url({% static 'icon_img/simi.svg' %}) no-repeat right bottom;"
|
||||
{% endif %}
|
||||
>
|
||||
{% if p.icon %}
|
||||
<p class="layui-elip" style="font-weight: 700;"><svg class="icon" aria-hidden="true"><use xlink:href="#{{p.icon}}"></use></svg> {{ p.name }} <span class="layui-badge-rim">{{p.id|get_doc_count}}</span></p>
|
||||
{% else %}
|
||||
@ -137,7 +140,6 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="layui-card-body" style="font-size: 12px;">
|
||||
<!-- <p class="layui-word-aux layui-elip"><i class="layui-icon layui-icon-user"></i> {% if p.create_user.first_name != '' %} {{p.create_user.first_name}} {% else %} {{p.create_user}}{% endif %}</p> -->
|
||||
<p class="tooltip layui-word-aux">
|
||||
<i class="layui-icon layui-icon-speaker"></i>
|
||||
{% if p.intro == "" %}
|
||||
|
Loading…
Reference in New Issue
Block a user