优化和添加了一些功能

This commit is contained in:
yangjian 2019-12-01 20:44:16 +08:00
parent ac8441f843
commit 999f13cf98
44 changed files with 932 additions and 169 deletions

19
CHANGES.md Normal file
View File

@ -0,0 +1,19 @@
## 版本更新记录
### 2019-12-01
- 添加MrDoc全站favicon图标
- 添加后台配置关闭注册功能、启用邮箱功能、统计代码、广告代码等功能
- 添加通过邮箱找回密码功能
- 优化管理员界面退出后403的处理
- 优化文档浏览界面文档渲染加载逻辑
### 2019-11
- 添加404页面视图
- 完善首页文集列表简介样式
- 完善后台管理员对文集的权限逻辑
### 2019-08
MrDoc第一版发布

View File

@ -66,6 +66,7 @@ TEMPLATES = [
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'app_admin.context_processors.sys_setting', # 自定义系统设置上下文渲染
],
},
},
@ -115,7 +116,7 @@ USE_I18N = True
USE_L10N = True
USE_TZ = True
USE_TZ = False
# Static files (CSS, JavaScript, Images)

View File

@ -1,4 +1,6 @@
# MrDoc
# MrDoc - 一个简单的文档写作应用
![Mrdoc首页](./docs/mrdoc_index.png)
## 介绍
一个简单的MarkDown文档写作系统。
@ -10,11 +12,14 @@ MrDoc拥有以下特点
- 提供文档模板功能,支持文档模板的创建、修改;
- 仿GitBook文档阅读页面支持文档阅读页面的字体缩放字体类型修改
- 支持三级目录层级显示;
- 使用方便、二次开发修改也方便;
在开发过程中参考和借鉴了GitBook、ShowDoc、Wordbook等应用的功能和样式。
## 软件架构
基于Python Web框架Django构建。
后端基于Python Web框架Django
编程语言Python 3
@ -50,6 +55,33 @@ Markdown科学公式Katex.js
加入MrDoc交流QQ群群号为735507293入群密码mrdoc
## 版本更新日志
版本更新日志详见:[CHANGES.md](./CHANGES.md)
## 版本更新
关注州的先生微信公众号IDzmister2016,及时获取MrDoc版本更新信息。
关注州的先生微信公众号IDzmister2016、博客 https://zmister.com,及时获取MrDoc版本更新信息。
## 更多截图
### 文档界面
![MrDoc文档页](./docs/mrdoc_docdetail.png)
### 登录界面
![MrDoc登录页](./docs/mrdoc_login.png)
### 注册界面
![MrDoc注册页](./docs/mrdoc_register.png)
### 文档写作界面
![MrDoc写作页](./docs/mrdoc_write.png)
### 文档模板界面
![MrDoc文档模板页](./docs/mrdoc_doctemp.png)
### 管理员后台界面
![MrDoc管理员后台](./docs/mrdoc_admin.png)
### 普通用户后台界面
![MrDoc普通用户后台](./docs/mrdoc_user.png)

View File

@ -0,0 +1,15 @@
# coding:utf-8
# @文件: context_processer.py
# @创建者:州的先生
# #日期2019/11/16
# 博客地址zmister.com
from app_admin.models import SysSetting
# 系统设置 - 上下文变量
def sys_setting(request):
setting_dict = dict()
# 获取系统设置状态
datas = SysSetting.objects.filter(types="basic")
for data in datas:
setting_dict[data.name] = data.value
return setting_dict

View File

@ -1,4 +1,6 @@
from django.core.exceptions import PermissionDenied # 权限拒绝异常
from django.http import Http404
from app_admin.models import SysSetting
# 超级管理员用户需求
def superuser_only(function):
@ -11,4 +13,19 @@ def superuser_only(function):
raise PermissionDenied
return function(request, *args, **kwargs)
return _inner
return _inner
# 开放注册需求
def open_register(function):
'''只有开放注册才能访问'''
def _inner(request,*args,**kwargs):
try:
status = SysSetting.objects.get(name='close_register')
except:
# 如果不存在close_register这个属性那么表示是开放注册的
return function(request, *args, **kwargs)
if status.value == 'on':
raise Http404
return function(request, *args, **kwargs)
return _inner

View File

@ -0,0 +1,26 @@
# Generated by Django 2.1 on 2019-11-16 15:46
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='SysSetting',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=50, verbose_name='项目')),
('value', models.TextField(verbose_name='内容')),
],
options={
'verbose_name': '系统设置',
'verbose_name_plural': '系统设置',
},
),
]

View File

@ -0,0 +1,22 @@
# Generated by Django 2.1 on 2019-11-17 00:08
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app_admin', '0001_initial'),
]
operations = [
migrations.RemoveField(
model_name='syssetting',
name='id',
),
migrations.AlterField(
model_name='syssetting',
name='name',
field=models.CharField(max_length=50, primary_key=True, serialize=False, verbose_name='项目'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 2.1 on 2019-11-17 00:16
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app_admin', '0002_auto_20191117_0808'),
]
operations = [
migrations.AlterField(
model_name='syssetting',
name='value',
field=models.TextField(blank=True, null=True, verbose_name='内容'),
),
]

View File

@ -0,0 +1,33 @@
# Generated by Django 2.1 on 2019-11-21 13:03
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app_admin', '0003_auto_20191117_0816'),
]
operations = [
migrations.CreateModel(
name='EmaiVerificationCode',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('email_name', models.EmailField(max_length=254, verbose_name='电子邮箱')),
('verification_type', models.CharField(max_length=50, verbose_name='验证码类型')),
('verification_code', models.CharField(max_length=10, verbose_name='验证码')),
('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('expire_time', models.DateTimeField(auto_now=True, verbose_name='过期时间')),
],
options={
'verbose_name': '电子邮件验证码',
'verbose_name_plural': '电子邮件验证码',
},
),
migrations.AddField(
model_name='syssetting',
name='types',
field=models.CharField(default='basic', max_length=10, verbose_name='类型'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 2.1 on 2019-11-25 21:55
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app_admin', '0004_auto_20191121_2103'),
]
operations = [
migrations.AlterField(
model_name='emaiverificationcode',
name='expire_time',
field=models.DateTimeField(verbose_name='过期时间'),
),
]

View File

@ -1,3 +1,30 @@
from django.db import models
# Create your models here.
# 系统设置项模型
class SysSetting(models.Model):
name = models.CharField(verbose_name="项目",max_length=50,primary_key=True)
value = models.TextField(verbose_name="内容",null=True,blank=True)
types = models.CharField(verbose_name="类型",max_length=10,default="basic")
def __str__(self):
return self.name
class Meta:
verbose_name = '系统设置'
verbose_name_plural = verbose_name
# 电子邮件验证码模型
class EmaiVerificationCode(models.Model):
email_name = models.EmailField(verbose_name="电子邮箱")
verification_type = models.CharField(verbose_name="验证码类型",max_length=50)
verification_code = models.CharField(verbose_name="验证码",max_length=10)
create_time = models.DateTimeField(verbose_name="创建时间",auto_now_add=True)
expire_time = models.DateTimeField(verbose_name="过期时间")
def __str__(self):
return "{}:{}".format(self.verification_type,self.email_name)
class Meta:
verbose_name = '电子邮件验证码'
verbose_name_plural = verbose_name

View File

@ -11,7 +11,11 @@ urlpatterns = [
path('change_pwd',views.admin_change_pwd,name="change_pwd"), # 管理员修改用户密码
path('modify_pwd',views.change_pwd,name="modify_pwd"), # 普通用户修改密码
path('project_manage/',views.admin_project,name='project_manage'), # 文集管理
path('doc_manage/',views.admin_doc,name='doc_manage'), # 文集管理
path('doctemp_manage/',views.admin_doctemp,name='doctemp_manage'), # 文集管理
path('check_code/',views.check_code,name='check_code'), # 验证码
path('doc_manage/',views.admin_doc,name='doc_manage'), # 文档管理
path('doctemp_manage/',views.admin_doctemp,name='doctemp_manage'), # 文档模板管理
path('setting/',views.admin_setting,name="sys_setting"), # 应用设置
path('check_code/',views.check_code,name='check_code'), # 注册验证码
path('forget_pwd/',views.forget_pwd,name='forget_pwd'), # 忘记密码
path('send_email_vcode/',views.send_email_vcode,name='send_email_vcode'), # 忘记密码发送邮件验证码
]

77
app_admin/utils.py Normal file
View File

@ -0,0 +1,77 @@
# coding:utf-8
# @文件: utils.py
# @创建者:州的先生
# #日期2019/11/23
# 博客地址zmister.com
import smtplib
from django.conf import settings
from email.mime.text import MIMEText
from app_admin.models import SysSetting
import random
# 生成数字验证码
def generate_vcode(n=6):
# 生成数字验证码
_num = ''.join(map(str, range(3, 10)))
vcode_str = ''.join(random.sample(_num, n))
return vcode_str
# 发送电子邮件
def send_email(to_email,vcode_str):
email_enable = SysSetting.objects.get(types="basic",name='enable_email')
if email_enable.value == 'on':
smtp_host = SysSetting.objects.get(types='email',name='smtp_host').value
send_emailer = SysSetting.objects.get(types='email', name='send_emailer').value
smtp_port = SysSetting.objects.get(types='email', name='smtp_port').value
username = SysSetting.objects.get(types='email', name='username').value
pwd = SysSetting.objects.get(types='email', name='pwd').value
ssl = SysSetting.objects.get(types='email',name='smtp_ssl').value
print(smtp_host,smtp_port,send_emailer,username,pwd)
msg_from = send_emailer # 发件人邮箱
passwd = dectry(pwd) # 发件人邮箱密码
msg_to = to_email # 收件人邮箱
if ssl:
s = smtplib.SMTP_SSL(smtp_host, int(smtp_port)) # 发件箱邮件服务器及端口号
else:
s = smtplib.SMTP(smtp_host, int(smtp_host))
subject = "MrDoc - 重置密码验证码"
content = "你的验证码为:{}验证码30分钟内有效".format(vcode_str)
msg = MIMEText(content, _subtype='html', _charset='utf-8')
msg['Subject'] = subject
msg['From'] = 'MrDoc助手[{}]'.format(msg_from)
msg['To'] = msg_to
try:
s.login(username, passwd)
s.sendmail(msg_from, msg_to, msg.as_string())
return True
except smtplib.SMTPException as e:
print(repr(e))
return False
finally:
s.quit()
else:
return False
# 加密
def enctry(s):
k = settings.SECRET_KEY
encry_str = ""
for i,j in zip(s,k):
# i为字符j为秘钥字符
temp = str(ord(i)+ord(j))+'_' # 加密字符 = 字符的Unicode码 + 秘钥的Unicode码
encry_str = encry_str + temp
return encry_str
# 解密
def dectry(p):
k = settings.SECRET_KEY
dec_str = ""
for i,j in zip(p.split("_")[:-1],k):
# i 为加密字符j为秘钥字符
temp = chr(int(i) - ord(j)) # 解密字符 = (加密Unicode码字符 - 秘钥字符的Unicode码)的单字节字符
dec_str = dec_str+temp
return dec_str

View File

@ -4,10 +4,12 @@ from django.contrib.auth import authenticate,login,logout # 认证相关方法
from django.contrib.auth.models import User # Django默认用户模型
from django.contrib.auth.decorators import login_required # 登录需求装饰器
from django.core.paginator import Paginator,PageNotAnInteger,EmptyPage,InvalidPage # 后端分页
from app_admin.decorators import superuser_only
import json
import datetime
from app_admin.decorators import superuser_only,open_register
import json,datetime,hashlib
from app_doc.models import *
from app_admin.models import *
from app_admin.utils import *
# 返回验证码图片
def check_code(request):
@ -53,6 +55,7 @@ def log_in(request):
# 注册视图
@open_register
def register(request):
if request.user.is_authenticated:
return redirect('/')
@ -69,10 +72,10 @@ def register(request):
email_exit = User.objects.filter(email=email)
username_exit = User.objects.filter(username=username)
if email_exit.count() > 0:
errormsg = '电子邮箱已被注册使用,请更换电子邮箱地址'
errormsg = '电子邮箱已被注册!'
return render(request, 'register.html', locals())
elif username_exit.count() > 0:
errormsg = '用户名已存在,请换一个用户名'
errormsg = '用户名已被使用'
return render(request, 'register.html', locals())
elif len(password) < 6:
errormsg = '密码必须大于等于6位'
@ -110,6 +113,62 @@ def log_out(request):
return redirect(request.META['HTTP_REFERER'])
# 忘记密码
def forget_pwd(request):
if request.method == 'GET':
return render(request,'forget_pwd.html',locals())
elif request.method == 'POST':
email = request.POST.get("email",None) # 邮箱
vcode = request.POST.get("vcode",None) # 验证码
new_pwd= request.POST.get('password',None) # 密码
new_pwd_confirm = request.POST.get('confirm_password')
# 查询验证码和邮箱是否匹配
try:
data = EmaiVerificationCode.objects.get(email_name=email,verification_code=vcode,verification_type='忘记密码')
expire_time = data.expire_time
print(expire_time)
if expire_time > datetime.datetime.now():
user = User.objects.get(email=email)
user.set_password(new_pwd)
user.save()
errormsg = "修改密码成功,请返回登录!"
return render(request, 'forget_pwd.html', locals())
else:
errormsg = "验证码已过期"
return render(request, 'forget_pwd.html', locals())
except Exception as e:
print(repr(e))
errormsg = "验证码错误"
return render(request,'forget_pwd.html',locals())
# 发送电子邮箱验证码
def send_email_vcode(request):
if request.method == 'POST':
email = request.POST.get('email',None)
is_email = User.objects.filter(email=email)
if is_email.count() != 0:
vcode_str = generate_vcode()
# 发送邮件
send_status = send_email(to_email=email, vcode_str=vcode_str)
if send_status:
# 生成过期时间
now_time = datetime.datetime.now()
expire_time = now_time + datetime.timedelta(minutes=30)
# 创建数据库记录
EmaiVerificationCode.objects.create(
email_name = email,
verification_type = '忘记密码',
verification_code = vcode_str,
expire_time = expire_time
)
return JsonResponse({'status':True,'data':'发送成功'})
else:
return JsonResponse({'status':False,'data':'发送验证码出错,请重试!'})
else:
return JsonResponse({'status':False,'data':'电子邮箱不存在!'})
# 管理员后台首页 - 用户管理
@superuser_only
def admin_user(request):
@ -317,3 +376,109 @@ def change_pwd(request):
return JsonResponse({'status':False,'data':'修改出错'})
else:
return HttpResponse('方法错误')
# 管理员后台 - 应用设置
@superuser_only
def admin_setting(request):
email_settings = SysSetting.objects.filter(types="email")
if email_settings.count() == 6:
emailer = email_settings.get(name='send_emailer')
email_host = email_settings.get(name='smtp_host')
email_port = email_settings.get(name='smtp_port')
email_username = email_settings.get(name="username")
email_ssl = email_settings.get(name="smtp_ssl")
email_pwd = email_settings.get(name="pwd")
if request.method == 'GET':
return render(request,'app_admin/admin_setting.html',locals())
elif request.method == 'POST':
types = request.POST.get('type',None)
# 基础设置
if types == 'basic':
close_register = request.POST.get('close_register',None)
static_code = request.POST.get('static_code',None)
ad_code = request.POST.get('ad_code',None)
beian_code = request.POST.get('beian_code',None)
enbale_email = request.POST.get("enable_email",None)
# 更新开放注册状态
SysSetting.objects.update_or_create(
name='close_register',
defaults={'value':close_register,'types':'basic'}
)
# 更新统计代码状态
SysSetting.objects.update_or_create(
name = 'static_code',
defaults={'value':static_code,'types':'basic'}
)
# 更新广告代码状态
SysSetting.objects.update_or_create(
name = 'ad_code',
defaults={'value':ad_code,'types':'basic'}
)
# 更新备案号
SysSetting.objects.update_or_create(
name='beian_code',
defaults={'value':beian_code,'types':'basic'}
)
# 更新邮箱启用状态
SysSetting.objects.update_or_create(
name='enable_email',
defaults={'value': enbale_email, 'types': 'basic'}
)
return render(request,'app_admin/admin_setting.html',locals())
elif types == 'email':
# 读取上传的参数
emailer = request.POST.get("send_emailer",None)
host = request.POST.get("smtp_host",None)
port = request.POST.get("smtp_port",None)
username = request.POST.get("smtp_username",None)
pwd = request.POST.get("smtp_pwd",None)
ssl = request.POST.get("smtp_ssl",None)
# 对密码进行加密
pwd = enctry(pwd)
if emailer != None:
# 更新发件箱
SysSetting.objects.update_or_create(
name = 'send_emailer',
defaults={"value":emailer,"types":'email'}
)
if host != None:
# 更新邮箱主机
SysSetting.objects.update_or_create(
name='smtp_host',
defaults={"value": host, "types": 'email'}
)
if port != None:
# 更新邮箱主机端口
SysSetting.objects.update_or_create(
name='smtp_port',
defaults={"value": port, "types": 'email'}
)
if username != None:
# 更新用户名
SysSetting.objects.update_or_create(
name='username',
defaults={"value": username, "types": 'email'}
)
if pwd != None:
# 更新密码
SysSetting.objects.update_or_create(
name='pwd',
defaults={"value": pwd, "types": 'email'}
)
if ssl != None:
# 更新SSL
SysSetting.objects.update_or_create(
name='smtp_ssl',
defaults={"value": ssl, "types": 'email'}
)
email_settings = SysSetting.objects.filter(types="email")
if email_settings.count() == 6:
emailer = email_settings.get(name='send_emailer')
email_host = email_settings.get(name='smtp_host')
email_port = email_settings.get(name='smtp_port')
email_username = email_settings.get(name="username")
email_ssl = email_settings.get(name="smtp_ssl")
email_pwd = email_settings.get(name="pwd")
return render(request, 'app_admin/admin_setting.html',locals())

BIN
docs/mrdoc_admin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

BIN
docs/mrdoc_docdetail.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

BIN
docs/mrdoc_doctemp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
docs/mrdoc_index.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
docs/mrdoc_index.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
docs/mrdoc_login.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
docs/mrdoc_register.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
docs/mrdoc_user.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

BIN
docs/mrdoc_write.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
static/404.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

BIN
static/favicon_16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 B

View File

@ -349,3 +349,8 @@ li.active > a{
.switch-font{
font-family: Serif;
}
/* 广告样式 */
.ad-code{
margin:10px;
}

28
static/mrdoc.js Normal file
View File

@ -0,0 +1,28 @@
//修改用户密码
changePwd = function(uid,username){
layer.open({
type:1,
title:'修改密码',
area:'300px;',
id:'changePwd',
content:'<div style="padding:10px 0 0 20px;">修改用户[' + username + ']的密码:</div><div style="padding: 20px;"><input class="layui-input" type="password" id="newPwd1" style="margin-bottom:10px;" placeholder="输入新密码" required lay-verify="required"><input class="layui-input" type="password" id="newPwd2" placeholder="再次确认新密码" required lay-verify="required"></div>',
btn:['确认修改','取消'],
yes:function (index,layero) {
data = {
'password':$("#newPwd1").val(),
'password2':$("#newPwd2").val(),
}
$.post("{% url 'modify_pwd' %}",data,function(r){
if(r.status){
//修改成功
window.location.reload();
//layer.close(index)
}else{
//修改失败,提示
//console.log(r)
layer.msg(r.data)
}
})
},
})
};

28
template/403.html Normal file
View File

@ -0,0 +1,28 @@
{% load staticfiles %}
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>拒绝访问 - MrDoc</title>
<link href="{% static 'layui/css/layui.css' %}" rel="stylesheet">
<link href="{% static 'mrdoc.css' %}" rel="stylesheet">
</head>
<body class="layui-layout-body">
<!-- 页头 -->
{% include 'app_doc/head_base.html' %}
<!-- 页头结束 -->
<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>
</div>
<script src="https://cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>
<script src="{% static 'layui/layui.all.js' %}"></script>
</body>
</html>

View File

@ -3,51 +3,20 @@
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>页面未找到 - MrDoc</title>
<title>404 页面未找到 - MrDoc</title>
<link href="{% static 'layui/css/layui.css' %}" rel="stylesheet">
<link href="{% static 'style.css' %}" rel="stylesheet">
<link href="{% static 'mrdoc.css' %}" rel="stylesheet">
</head>
<body class="layui-layout-body">
<div class="layui-header">
<div class="layui-main">
<a class="logo" href="{% url 'pro_list' %}">
{# <img src="/media/logo.png" />#}
<h1><strong>MrDoc</strong></h1>
</a>
<ul class="layui-nav layui-layout-right">
{% if request.user.is_authenticated %}
<li class="layui-nav-item">
<a href="javascript:void(0);">
<i class="layui-icon layui-icon-username"></i> {{request.user.username}}
</a>
<dl class="layui-nav-child">
{% if request.user.is_superuser %}
<dd><a href="{% url 'user_manage' %}">进入后台</a></dd>
{% endif %}
<dd><a href="{% url 'manage_doc' %}">管理文档</a></dd>
<dd><a href="javascript:void(0);">修改密码</a></dd>
<dd><a href="{% url 'logout' %}">退出登录</a></dd>
</dl>
</li>
{% else %}
<li class="layui-nav-item">
<a href="javascript:void(0);">
<i class="layui-icon layui-icon-username"></i> 游客
</a>
<dl class="layui-nav-child">
<dd><a href="{% url 'register' %}">注册</a></dd>
<dd><a href="{% url 'login' %}">登录</a></dd>
</dl>
</li>
{% endif %}
</ul>
</div>
</div>
<!-- 页头 -->
{% include 'app_doc/head_base.html' %}
<!-- 页头结束 -->
<div class="layui-main">
<div style="text-align: center;margin-top: 20px;">
<h1>
<strong>页面未找到……</strong>
</h1>
<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>
</div>

View File

@ -4,6 +4,7 @@
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %} - 后台管理 - MrDoc</title>
<link rel="icon" href="{% static 'favicon_16.png' %}"/>
<link href="{% static 'layui/css/layui.css' %}" rel="stylesheet">
<style>
.logo img{
@ -52,6 +53,9 @@
<li class="layui-nav-item layui-nav-itemed">
<a href="{% url 'user_manage' %}"><i class="layui-icon layui-icon-user"></i> 用户管理</a>
</li>
<li class="layui-nav-item layui-nav-itemed">
<a href="{% url 'sys_setting' %}"><i class="layui-icon layui-icon-user"></i> 应用设置</a>
</li>
{% endif %}
</ul>
</div>
@ -64,7 +68,7 @@
<div class="layui-footer" style="text-align:center;">
<!-- 底部固定区域 -->
© <a href="">MrDoc</a>
© 2019 <a href="http://mrdoc.zmister.com" target="_blank">MrDoc</a> - 一个简单的文档系统
</div>
</div>

View File

@ -43,8 +43,8 @@
<td>{{ doc.create_time }}</td>
<td>
{# <a href="javascript:void(0);" onclick="insertTemp('{{temp.id}}');">查看</a>#}
<a href="{% url 'modify_doc' doc_id=doc.id %}" target="_blank">修改</a>
<a href="javascript:void(0);" onclick="delDoc('{{doc.id}}');">删除</a>
<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>
</td>
</tr>
{% endfor %}

View File

@ -42,8 +42,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">修改</a>
<a href="javascript:void(0);" onclick="delTemp('{{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>
</td>
</tr>
{% endfor %}

View File

@ -49,9 +49,9 @@
<td>{{ pro.create_time }}</td>
<td>{{ pro.create_user }}</td>
<td>
<a href="{% url 'pro_index' pro_id=pro.id %}" target="_blank">查看</a>
<a href="javascript:void(0);" onclick="modifyProject('{{pro.id}}','{{pro.name}}','{{pro.intro}}')">修改</a>
<a href="javascript:void(0);" onclick="delProject('{{pro.id}}');">删除</a>
<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>
</td>
</tr>
{% endfor %}

View File

@ -0,0 +1,121 @@
{% extends 'app_admin/admin_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">
<div class="layui-tab">
<ul class="layui-tab-title">
<li class="layui-this">基础设置</li>
<li>邮箱设置</li>
<!--<li>广告设置</li>-->
</ul>
<div class="layui-tab-content">
<!-- 网站设置 -->
<div class="layui-tab-item layui-show">
<form class="layui-form" action="{% url 'sys_setting' %}" method="post">
{% csrf_token %}
<input type="text" name="type" hidden value="basic">
<div class="layui-form-item">
<label class="layui-form-label">禁止注册</label>
<div class="layui-input-block">
<input type="checkbox" name="close_register" lay-skin="switch" lay-text="开启|关闭" {% if close_register %}checked{% endif %}>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">启用邮箱</label>
<div class="layui-input-block">
<input type="checkbox" name="enable_email" lay-skin="switch" lay-text="开启|关闭" {% if enable_email %}checked{% endif %}>
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">统计代码</label>
<div class="layui-input-block">
<textarea name="static_code" placeholder="如果需要调用第三方的统计功能,请将第三方统计工具代码输入至此,可以包含<script>标签" class="layui-textarea"></textarea>
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">广告代码</label>
<div class="layui-input-block">
<textarea name="ad_code" placeholder="如果需要在文档正文上方添加广告,请将广告相关代码输入至此,可以包含<script>标签" class="layui-textarea">{{ad_code}}</textarea>
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="formDemo">保存</button>
</div>
</div>
</form>
</div>
<!-- 网站设置结束 -->
<!-- 邮箱设置 -->
<div class="layui-tab-item">
<form class="layui-form" action="" method="post">
{% csrf_token %}
<input type="text" name="type" hidden value="email">
<div class="layui-form-item">
<label class="layui-form-label">发件邮箱</label>
<div class="layui-input-block">
<input type="email" name="send_emailer" class="layui-input" required value="{{emailer.value}}">
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">SMTP 主机</label>
<div class="layui-input-block">
<input type="text" name="smtp_host" class="layui-input" required value="{{email_host.value}}">
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">SMTP 端口</label>
<div class="layui-input-block">
<input type="number" name="smtp_port" class="layui-input" required value="{{email_port.value}}">
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">SMTP 用户名</label>
<div class="layui-input-block">
<input type="text" name="smtp_username" class="layui-input" required value="{{email_username.value}}">
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">SMTP 密码</label>
<div class="layui-input-block">
<input type="password" name="smtp_pwd" class="layui-input" required value="{{email_pwd.value}}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">使用SSL</label>
<div class="layui-input-block">
<input type="checkbox" name="smtp_ssl" lay-skin="switch" lay-text="开启|关闭" {% if email_ssl %}checked{% endif %}>
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="formDemo">保存邮箱设置</button>
</div>
</div>
</form>
</div>
<!-- 邮箱设置结束 -->
<!-- 广告设置 -->
<div class="layui-tab-item">内容3</div>
<!-- 广告设置结束 -->
</div>
</div>
</div>
{% endblock %}

View File

@ -6,50 +6,21 @@
<title>{% block title %}{% endblock %} - MrDoc</title>
<link href="{% static 'layui/css/layui.css' %}" rel="stylesheet">
<link rel="stylesheet" href="{% static 'editor.md/css/editormd.css' %}" />
<link href="{% static 'style.css' %}" rel="stylesheet">
<link href="{% static 'mrdoc.css' %}" rel="stylesheet">
<link rel="icon" href="{% static 'favicon_16.png' %}"/>
{% block custom_style %}{% endblock %}
</head>
<body class="layui-layout-body">
<div class="layui-header">
<div class="layui-main">
<a class="logo" href="{% url 'pro_list' %}">
{# <img src="/media/logo.png" />#}
<h1>
<strong>MrDoc</strong>
<span style="font-size: 16px;">{% block subtitle %}{% endblock %}</span>
</h1>
</a>
<ul class="layui-nav layui-layout-right">
{% if request.user.is_authenticated %}
<li class="layui-nav-item">
<a href="javascript:void(0);">
<i class="layui-icon layui-icon-username"></i> {{request.user.username}}
</a>
<dl class="layui-nav-child">
<dd><a href="{% url 'manage_doc' %}">管理文档</a></dd>
{# <dd><a href="javascript:void(0);">修改密码</a></dd>#}
<dd><a href="{% url 'logout' %}">退出登录</a></dd>
</dl>
</li>
{% else %}
<li class="layui-nav-item">
<a href="javascript:void(0);">
<i class="layui-icon layui-icon-username"></i> 游客
</a>
<dl class="layui-nav-child">
<!-- <dd><a href="">基本资料</a></dd> -->
<dd><a href="javascript:void(0);">注册</a></dd>
<dd><a href="{% url 'login' %}">登录</a></dd>
</dl>
</li>
{% endif %}
</ul>
</div>
</div>
<!-- 页头 -->
{% include 'app_doc/head_base.html' %}
<!-- 页头结束 -->
<!-- 主体开始 -->
<div class="layui-main">
{% block content %}
{% endblock %}
</div>
<!-- 主体结束 -->
<script src="https://cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>
<script src="{% static 'layui/layui.all.js' %}"></script>
@ -114,7 +85,9 @@
}
}
});
</script>
<script src="{% static 'mrdoc.js' %}"></script>
{% block custom_script %}
{% endblock %}
</body>

View File

@ -0,0 +1,40 @@
<div class="layui-header">
<div class="layui-main">
<a class="logo" href="{% url 'pro_list' %}">
<h1><strong>MrDoc</strong></h1>
</a>
<ul class="layui-nav layui-layout-right">
{% if request.user.is_authenticated %}
<li class="layui-nav-item">
<a href="javascript:void(0);">
<i class="layui-icon layui-icon-username"></i> {{request.user.username}}
</a>
<dl class="layui-nav-child">
<!-- <dd><a href="">基本资料</a></dd> -->
{% if request.user.is_superuser %}
<dd><a href="{% url 'user_manage' %}">进入后台</a></dd>
{% endif %}
<dd><a href="{% url 'manage_doc' %}">管理文档</a></dd>
<dd><a href="javascript:void(0);" onclick="changePwd('{{ request.user.id }}','{{ request.user.username }}' )">修改密码</a></dd>
<dd><a href="{% url 'logout' %}">退出登录</a></dd>
</dl>
</li>
{% else %}
<li class="layui-nav-item">
<a href="javascript:void(0);">
<i class="layui-icon layui-icon-username"></i> 游客
</a>
<dl class="layui-nav-child">
<!-- <dd><a href="">基本资料</a></dd> -->
{% if close_register == 'on' %}
<dd><a href="{% url 'login' %}">登录</a></dd>
{% else %}
<dd><a href="{% url 'register' %}">注册</a></dd>
<dd><a href="{% url 'login' %}">登录</a></dd>
{% endif %}
</dl>
</li>
{% endif %}
</ul>
</div>
</div>

View File

@ -4,8 +4,9 @@
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %} - MrDoc</title>
<title>{% block title %}{% endblock %} - 个人中心 - MrDoc</title>
<link href="{% static 'layui/css/layui.css' %}" rel="stylesheet">
<link rel="icon" href="{% static 'favicon_16.png' %}"/>
<style>
.logo img{
height: 30px;

View File

@ -46,8 +46,8 @@
<td>{{ doc.create_time }}</td>
<td>
{# <a href="javascript:void(0);" onclick="insertTemp('{{temp.id}}');">查看</a>#}
<a href="{% url 'modify_doc' doc_id=doc.id %}" target="_blank">修改</a>
<a href="javascript:void(0);" onclick="delDoc('{{doc.id}}');">删除</a>
<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>
</td>
</tr>
{% endfor %}

View File

@ -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">修改</a>
<a href="javascript:void(0);" onclick="delTemp('{{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>
</td>
</tr>
{% endfor %}

View File

@ -42,9 +42,9 @@
<td>{{ pro.intro }}</td>
<td>{{ pro.create_time }}</td>
<td>
<a href="{% url 'pro_index' pro_id=pro.id %}" target="_blank">查看</a>
<a href="javascript:void(0);" onclick="modifyProject('{{pro.id}}','{{pro.name}}','{{pro.intro}}')">修改</a>
<a href="javascript:void(0);" onclick="delProject('{{pro.id}}');">删除</a>
<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>
</td>
</tr>
{% endfor %}

View File

@ -5,51 +5,15 @@
<meta charset="UTF-8">
<title>MrDoc - 一个简单的文档写作系统</title>
<link href="{% static 'layui/css/layui.css' %}" rel="stylesheet">
<link href="{% static 'style.css' %}" rel="stylesheet">
<link href="{% static 'mrdoc.css' %}" rel="stylesheet">
<link rel="icon" href="{% static 'favicon_16.png' %}"/>
</head>
<body class="layui-layout-body">
<div class="layui-header">
<div class="layui-main">
<a class="logo" href="{% url 'pro_list' %}">
{# <img src="/media/logo.png" />#}
<h1><strong>MrDoc</strong></h1>
</a>
{# <div class="component">#}
{# <div class="layui-input-inline">#}
{# <input class="layui-input" placeholder="搜索文集"/>#}
{# </div>#}
{# </div>#}
<ul class="layui-nav layui-layout-right">
{% if request.user.is_authenticated %}
<li class="layui-nav-item">
<a href="javascript:void(0);">
<i class="layui-icon layui-icon-username"></i> {{request.user.username}}
</a>
<dl class="layui-nav-child">
<!-- <dd><a href="">基本资料</a></dd> -->
{% if request.user.is_superuser %}
<dd><a href="{% url 'user_manage' %}">进入后台</a></dd>
{% endif %}
<dd><a href="{% url 'manage_doc' %}">管理文档</a></dd>
<dd><a href="javascript:void(0);" onclick="changePwd('{{ request.user.id }}','{{ request.user.username }}' )">修改密码</a></dd>
<dd><a href="{% url 'logout' %}">退出登录</a></dd>
</dl>
</li>
{% else %}
<li class="layui-nav-item">
<a href="javascript:void(0);">
<i class="layui-icon layui-icon-username"></i> 游客
</a>
<dl class="layui-nav-child">
<!-- <dd><a href="">基本资料</a></dd> -->
<dd><a href="{% url 'register' %}">注册</a></dd>
<dd><a href="{% url 'login' %}">登录</a></dd>
</dl>
</li>
{% endif %}
</ul>
</div>
</div>
<!-- 页头 -->
{% include 'app_doc/head_base.html' %}
<!-- 页头结束 -->
<!-- 主体 -->
<div class="layui-main">
{% for p in project_list %}
<div class="project-item">
@ -94,7 +58,7 @@
</a>
</div>
</div>
<!-- 主体结束 -->
<script src="https://cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>
<script src="{% static 'layui/layui.all.js' %}"></script>
{% block custom_script %}
@ -187,8 +151,10 @@
},
})
};
</script>
<!-- 统计代码开始 -->
{{ static | safe }}
<!-- 统计代码结束 -->
{% endblock %}
</body>
</html>

View File

@ -9,7 +9,8 @@
<link rel="stylesheet" href="{% static 'prism/prism.css' %}" />
<link rel="stylesheet" href="{% static 'katex/katex.min.css' %}" />
<link rel="stylesheet" href="{% static 'share.js/css/share.min.css' %}" />
<link href="{% static 'style.css' %}" rel="stylesheet">
<link rel="icon" href="{% static 'favicon_16.png' %}"/>
<link href="{% static 'mrdoc.css' %}" rel="stylesheet">
<style>
.doc-content ul li{
list-style:disc;
@ -69,6 +70,7 @@
</div>
</div>
<!-- 左侧目录栏结束 -->
<!-- 右侧文档栏 -->
<div class="doc-body">
<!-- 文档导航 -->
@ -105,11 +107,12 @@
<div class="doc-body-content-div">
<!-- 文档内容 -->
<div class="doc-content">
<!-- 标题 -->
<div class="doc-info">
{% if doc %}
<h1>{{ doc.name }}</h1>
<hr>
<p style="color: #cccccc;">
<p style="color: #666;">
<i class="layui-icon layui-icon-date"></i> {{ doc.create_time }}&nbsp;&nbsp;&nbsp;&nbsp;
<i class="layui-icon layui-icon-user"></i> {{ doc.create_user.username }}
</p>
@ -117,7 +120,16 @@
<h1>共有{{ search_result.count }}个搜索结果</h1>
<hr>
{% endif %}
<!-- 广告代码开始 -->
{% if ad_code %}
<div class="ad-code">
{{ ad_code | safe }}
</div>
{% endif %}
<!-- 广告代码结束 -->
</div>
<!-- 标题结束 -->
<!-- 正文开始 -->
<div class="markdown-body" id="content">
{% if doc %}
{# {{ doc.content | safe }}#}
@ -136,6 +148,7 @@
{% endfor %}
{% endif %}
</div>
<!-- 正文结束 -->
</div>
<!-- 文档目录 -->
<div class="doc-cata">
@ -170,6 +183,17 @@
$.ajaxSetup({
data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
});
//解析Markdown为HTML
editormd.markdownToHTML("content", {
htmlDecode : "style,script,iframe",
emoji : true,
taskList : true,
tex : true, // 科学公式
flowChart : true, // 流程图
sequenceDiagram : true, // 默认不解析
tocm : true, //目录
//tocContainer : "#toc-container"
});
//为当前页面的目录链接添加样式
$("nav li a").each(function (i) {
var $me = $(this);
@ -183,17 +207,6 @@
$me.parent().removeClass("active");
}
});
//解析Markdown为HTML
editormd.markdownToHTML("content", {
htmlDecode : "style,script,iframe",
emoji : true,
taskList : true,
tex : true, // 科学公式
flowChart : true, // 流程图
sequenceDiagram : true, // 默认不解析
tocm : true, //目录
//tocContainer : "#toc-container"
});
</script>
<!-- 页面初始化字体设置 -->
<script>
@ -294,6 +307,9 @@
}
};
</script>
<!-- 统计代码开始 -->
{{ static | safe }}
<!-- 统计代码结束 -->
{% endblock %}
</body>
</html>

129
template/forget_pwd.html Normal file
View File

@ -0,0 +1,129 @@
{% load staticfiles %}
<!DOCTYPE html>
<html lang='zh-CN'>
<head>
<title>忘记密码 - MrDoc</title>
<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">
<style>
body{
background-color: #fafafa;
text-align: center;
}
.container{
display: flex;
display: -webkit-flex;
justify-content: center;
align-items: center;
}
.login-form{
margin-top: 15%;
{#width: 400px;#}
padding: 20px 50px 20px 60px;
background-color: #fff;
-webkit-box-shadow: #666 0px 0px 10px;
-moz-box-shadow: #666 0px 0px 10px;
box-shadow: #666 0px 0px 10px;
}
.register-link{
font-size: 12px;
}
</style>
</head>
<body>
<div class="container">
<div></div>
<div></div>
<div class="login-form">
<form class="layui-form" action="{% url 'forget_pwd' %}" method='POST'>
{% csrf_token %}
<div class="layui-form-item">
<h2><strong>忘记密码 - MrDoc</strong></h2>
</div>
<span style='color:red;margin-bottom: 10px;'>{{ errormsg }}</span>
<div class="layui-form-item">
<div class="layui-input-inline">
<input type="text" name="email" id="email" required lay-verify="required" placeholder="请输入注册邮箱" class="layui-input">
</div>
<button class="layui-btn layui-btn-normal" type="button" id="send_email_vcode" onclick="getCode(this)">发送验证码</button>
</div>
<div class="layui-form-item">
<input type="text" name="vcode" required lay-verify="required" placeholder="请输入验证码" autocomplete="off" class="layui-input">
</div>
<div class="layui-form-item">
<input type="password" name="password" required lay-verify="required" placeholder="请输入新密码" autocomplete="off" class="layui-input">
</div>
<div class="layui-form-item">
<input type="password" name="confirm_password" required lay-verify="required" placeholder="请确认新密码" autocomplete="off" class="layui-input">
</div>
<div class="layui-form-item">
<button class="layui-btn layui-btn-fluid layui-btn-radius layui-btn-normal" lay-submit type="submit">修改密码</button>
</div>
<a href="{% url 'login' %}" class="register-link">返回登录</a>&nbsp;
</form>
</div>
</div>
</body>
<script src="https://cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>
<script src="{% static 'layui/layui.all.js' %}"></script>
<script>
$.ajaxSetup({
data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
});
layer = layui.layer;
btn = $("#send_email_vcode");
// 发送验证码倒计时60s
function getCode(e) {
email = document.getElementById("email");
if(email.value.length == 0){
layer.msg("请输入电子邮箱");
}else{
if(!(/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/.test(email.value))){
layer.msg("电子邮箱有误,请重填")
}else{
//调用获取验证码的接口
$.post("{% url 'send_email_vcode' %}",{'email':email.value},function(r){
if(r.status){
layer.msg("验证码发送成功,请查收!");
}else{
layer.msg(r.data)
}
});
//按照指定的周期(以毫秒计)来调用函数或计算表达式。
//在ajax请求之后再调用函数
t = setInterval(function () {
countdown(e)
}, 1000)
//获取验证码成功后调用倒计时函数
countdown(e);
}
}
}
var time = 60;
function countdown(e){
if (time == 0) {
//这里时设置当时间到0的时候重新设置点击事件并且默认time修改为60
//e.setAttribute("onclick","getcode(this)");
btn.attr("disabled", false);
btn.html("获取验证码");
btn.removeClass("disabled");
btn.removeClass("layui-btn-disabled")
time = 60;
clearInterval(t);
}else{
//这里是显示时间倒计时的时候点击不生效
//e.setAttribute("onclick", '');
btn.addClass("disabled");
btn.addClass("layui-btn-disabled")
btn.attr("disabled", true);
btn.html("重新发送(" + time + ")");
//document.getElementById("getcode").innerHTML="重新发送"+time;
time--;
}
}
</script>
</html>

View File

@ -39,12 +39,12 @@
<form class="layui-form" action="{% url 'login' %}" method='POST'>
{% csrf_token %}
<div class="layui-form-item">
<h2><strong>登录 - MrDoc</strong></h2>
<h2><strong>登录 - <a href="/">MrDoc</a></strong></h2>
</div>
<span style='color:red;margin-bottom: 10px;'>{{ errormsg }}</span>
<div class="layui-form-item">
<div class="layui-input-inline">
<input type="text" name="username" required lay-verify="required" placeholder="请输入用户名" autocomplete="off" class="layui-input">
<input type="text" name="username" required lay-verify="required" placeholder="请输入用户名" autocomplete="off" class="layui-input" >
</div>
</div>
<div class="layui-form-item">
@ -57,7 +57,16 @@
<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 'register' %}" class="register-link">注册新账号</a>
{% if close_register == 'on' %}
本站暂不开放注册
{% else %}
<a href="{% url 'register' %}" class="register-link">注册账号</a>&nbsp;
{% endif %}
{% if enable_email == 'on' %}
<a href="{% url 'forget_pwd' %}" class="register-link">忘记密码</a>
{% endif %}
</form>
</div>
</div>