!4 system消息通知:修复已读消息bug;permission:接口权限完成

* system消息通知:修复已读消息bug;permission:接口权限完成。
* system消息通知:修复已读消息bug
* docker_env:删除docker中的nginx、dvadmin-doc;权限管理:对数据的增删改查的权限控制
* 删除mongodb配置
* Merge branch 'dvadmin-dev' of https://gitee.com/liqianglog/django-vue-admin
* -文件管理——清理废弃文件功能
* -文件管理——清理废弃文件功能
pull/4/MERGE
李强 2021-03-29 01:54:41 +08:00
parent 0384353ad9
commit 0c3a73b647
80 changed files with 629 additions and 1674 deletions

View File

@ -1,6 +1,6 @@
# Django-Vue-Admin
[![img](https://img.shields.io/badge/license-MIT-blue.svg)](https://gitee.com/liqianglog/django-vue-admin/blob/master/LICENSE) [![img](https://img.shields.io/pypi/v/django-simpleui.svg)](https://pypi.org/project/django-simpleui/#history) [![img](https://img.shields.io/badge/python-%3E=3.6.x-green.svg)](https://python.org/) ![PyPI - Django Version badge](https://img.shields.io/badge/django%20versions-2.2-blue)[![img](https://img.shields.io/badge/node-%3E%3D%2012.0.0-brightgreen)](https://nodejs.org/zh-cn/download/releases/)[![img](https://img.shields.io/pypi/dm/django-simpleui.svg)](https://pypi.org/project/django-simpleui/)
[![img](https://img.shields.io/badge/license-MIT-blue.svg)](https://gitee.com/liqianglog/django-vue-admin/blob/master/LICENSE) [![img](https://img.shields.io/pypi/v/django-simpleui.svg)](https://pypi.org/project/django-simpleui/#history) [![img](https://img.shields.io/badge/python-%3E=3.6.x-green.svg)](https://python.org/) ![PyPI - Django Version badge](https://img.shields.io/badge/django%20versions-2.2-blue)![img](https://img.shields.io/badge/node-%3E%3D%2012.0.0-brightgreen)
@ -68,9 +68,6 @@ git clone https://gitee.com/liqianglog/django-vue-admin.git
cd dvadmin-ui
# 安装依赖
npm install
# 建议不要直接使用cnpm安装依赖会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题。
npm install --registry=https://registry.npm.taobao.org
# 启动服务
@ -95,7 +92,12 @@ npm run build:prod
~~~bash
1. 进入项目目录 cd dvadmin-backend
2. 在项目根目录中,复制 ./conf/env.example.py 文件为一份新的到 ./conf 文件夹下,并重命名为 env.py
3. 在 env.py 中配置数据库信息
mysql数据库版本建议:5.7以上
mysql数据库字符集utf8mb4
mysql数据库排序规则utf8mb4_0900_ai_ci
4. 安装依赖环境
pip3 install -r requirements.txt
5. 执行迁移命令:
@ -104,10 +106,13 @@ npm run build:prod
6. 初始化数据
python3 manage.py init
7. 启动项目
python3 manage.py runserver 0.0.0.0:8000
python3 manage.py runserver 127.0.0.1:8000
定时任务启动命令:
celery -A application worker -B --loglevel=info
注:
Windows 运行celery 需要安装 pip install eventlet
celery -A application worker -P eventlet --loglevel=info
初始账号admin 密码123456

View File

@ -25,25 +25,6 @@ services:
npm run build:prod
dvadmin-doc:
container_name: dvadmin-doc
build:
context: ./
dockerfile: ./docker_env/vue-doc/Dockerfile
environment:
TZ: Asia/Shanghai
volumes:
- "./dvadmin-doc:/dvadmin-doc"
command:
- /bin/bash
- -c
- |
cd /dvadmin-doc
npm install --registry=https://registry.npm.taobao.org
rm -rf /dvadmin-doc/dist
npm run docs:build
dvadmin-redis:
image: redis:latest
container_name: dvadmin-redis
@ -134,32 +115,3 @@ services:
restart: always
networks:
- dvadmin_net
dvadmin-nginx:
image: nginx:latest
container_name: dvadmin-nginx
# build: ./docker_env/nginx
restart: always
ports:
- "80:80"
- "443:443"
expose:
- "80"
- "443"
volumes:
- ./docker_env/nginx/nginx.conf:/etc/nginx/nginx.conf
- ./docker_env/nginx/sites-enabled:/etc/nginx/sites-enabled
- ./docker_env/nginx/keys:/nginx/keys
- ./dvadmin-backend:/dvadmin-backend
- ./dvadmin-doc:/dvadmin-doc
- ./dvadmin-ui:/dvadmin-ui
- ./logs/nginx:/var/log/nginx
depends_on:
- dvadmin-django
networks:
- dvadmin_net
networks:
dvadmin_net:
driver: bridge

View File

@ -1,6 +0,0 @@
FROM nginx:latest
COPY nginx.conf /etc/nginx/nginx.conf
CMD ["nginx", "-g", "daemon off;"]

View File

@ -1,61 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFoTCCBImgAwIBAgIQA4TN09XlucVnL4BLCuvHijANBgkqhkiG9w0BAQsFADBy
MQswCQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywg
SW5jLjEdMBsGA1UECxMURG9tYWluIFZhbGlkYXRlZCBTU0wxHTAbBgNVBAMTFFRy
dXN0QXNpYSBUTFMgUlNBIENBMB4XDTIxMDMwMzAwMDAwMFoXDTIyMDMwMjIzNTk1
OVowIzEhMB8GA1UEAxMYYXBpLmRqYW5nby12dWUtYWRtaW4uY29tMIIBIjANBgkq
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu5QSBTQbToLUu4wCYy/BNoinqFkXiTZE
aV6/5PJIeNsz75fnAEuBpIATEHqRsY6L9HdYAvBiAEv6ufCZhzwWF7ph1ZMhg6ul
foaQwoVCkbKi/zgwi3tvteda5vXQs4e8GvgZ6zkabQ4cZFjVpb3dA6huBbs20jLf
YYXsXWsJEGF3JK5okQ08+u/h/q0lFDFa70S9hpQXMtSfCCW/AuEc/+tG7rnUul1o
MXjpVnDOmg+CZfIYgi9D30/zd1DYFJOEwawl5FKLFQY7TOn3RlZ3SR4mNbbhIgHP
L9S1xHGcm8UC7PKuOgh8+5Nl0aeeUB1liuzM/w5JbF4L4FoZW6ciNQIDAQABo4IC
gDCCAnwwHwYDVR0jBBgwFoAUf9OZ86BHDjEAVlYijrfMnt3KAYowHQYDVR0OBBYE
FHvXBhsuPta7SwvCVVgv9e/bZ9AeMCMGA1UdEQQcMBqCGGFwaS5kamFuZ28tdnVl
LWFkbWluLmNvbTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEG
CCsGAQUFBwMCMD4GA1UdIAQ3MDUwMwYGZ4EMAQIBMCkwJwYIKwYBBQUHAgEWG2h0
dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzCBkgYIKwYBBQUHAQEEgYUwgYIwNAYI
KwYBBQUHMAGGKGh0dHA6Ly9zdGF0dXNlLmRpZ2l0YWxjZXJ0dmFsaWRhdGlvbi5j
b20wSgYIKwYBBQUHMAKGPmh0dHA6Ly9jYWNlcnRzLmRpZ2l0YWxjZXJ0dmFsaWRh
dGlvbi5jb20vVHJ1c3RBc2lhVExTUlNBQ0EuY3J0MAkGA1UdEwQCMAAwggEEBgor
BgEEAdZ5AgQCBIH1BIHyAPAAdgApeb7wnjk5IfBWc59jpXflvld9nGAK+PlNXSZc
JV3HhAAAAXf48Te1AAAEAwBHMEUCIDjqPKTNX4EcFxayaLirTT1y98X9X1HP97bM
IV0HpJmYAiEAjMdYYUqFuHLkSl4/bq5F/FPtt25AbKGhyolIVDWvsNoAdgAiRUUH
WVUkVpY/oS/x922G4CMmY63AS39dxoNcbuIPAgAAAXf48TgFAAAEAwBHMEUCIBQM
bXvVtAOXQfBjp+7HzsyWH51BZ2vyH1VyLpuGSs7dAiEAiyt4h7P7oRheoZKmn8wp
CptaYocY509Dr8aFbCicWWAwDQYJKoZIhvcNAQELBQADggEBAJG3Ne57IlaucGjH
y6j/zJsRnCsIrVNoPUROma+2FD7SauHT6U7iDLtNT5BIrBmDcEnYdqMAjJQoRJC1
VvXSkABEngUajpdpB0m8k9UVB5W+6Extt8TYyRLu1/Xpq0JHiOg+rPYK3UljYybG
2V9KWNhYd2G5yg0+1ZzvaC3zEFIfQJpuESio6hEbilT6FLeVC8TabL0/2tqE12n/
uWYU3Pr9AokD0OQkzN4BUswwIpYBfAXa6HLvj+V6tLOthxY0PLuOm7WiwU2MP0bz
dq6LIFu0z8fkwBkkqXXtgSfCigqvRhybaKKF0FT4cdJUb0cfMhUshlzWpJ5EEskO
46xDUok=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIErjCCA5agAwIBAgIQBYAmfwbylVM0jhwYWl7uLjANBgkqhkiG9w0BAQsFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0xNzEyMDgxMjI4MjZaFw0yNzEyMDgxMjI4MjZaMHIxCzAJBgNVBAYTAkNO
MSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMR0wGwYDVQQL
ExREb21haW4gVmFsaWRhdGVkIFNTTDEdMBsGA1UEAxMUVHJ1c3RBc2lhIFRMUyBS
U0EgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgWa9X+ph+wAm8
Yh1Fk1MjKbQ5QwBOOKVaZR/OfCh+F6f93u7vZHGcUU/lvVGgUQnbzJhR1UV2epJa
e+m7cxnXIKdD0/VS9btAgwJszGFvwoqXeaCqFoP71wPmXjjUwLT70+qvX4hdyYfO
JcjeTz5QKtg8zQwxaK9x4JT9CoOmoVdVhEBAiD3DwR5fFgOHDwwGxdJWVBvktnoA
zjdTLXDdbSVC5jZ0u8oq9BiTDv7jAlsB5F8aZgvSZDOQeFrwaOTbKWSEInEhnchK
ZTD1dz6aBlk1xGEI5PZWAnVAba/ofH33ktymaTDsE6xRDnW97pDkimCRak6CEbfe
3dXw6OV5AgMBAAGjggFPMIIBSzAdBgNVHQ4EFgQUf9OZ86BHDjEAVlYijrfMnt3K
AYowHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQD
AgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAG
AQH/AgEAMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au
ZGlnaWNlcnQuY29tMEIGA1UdHwQ7MDkwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2lj
ZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwTAYDVR0gBEUwQzA3Bglg
hkgBhv1sAQIwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29t
L0NQUzAIBgZngQwBAgEwDQYJKoZIhvcNAQELBQADggEBAK3dVOj5dlv4MzK2i233
lDYvyJ3slFY2X2HKTYGte8nbK6i5/fsDImMYihAkp6VaNY/en8WZ5qcrQPVLuJrJ
DSXT04NnMeZOQDUoj/NHAmdfCBB/h1bZ5OGK6Sf1h5Yx/5wR4f3TUoPgGlnU7EuP
ISLNdMRiDrXntcImDAiRvkh5GJuH4YCVE6XEntqaNIgGkRwxKSgnU3Id3iuFbW9F
UQ9Qqtb1GX91AJ7i4153TikGgYCdwYkBURD8gSVe8OAco6IfZOYt/TEwii1Ivi1C
qnuUlWpsF1LdQNIdfbW3TSe0BhQa7ifbVIfvPWHYOu3rkg1ZeMo6XRU9B4n5VyJY
RmE=
-----END CERTIFICATE-----

View File

@ -1,27 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAu5QSBTQbToLUu4wCYy/BNoinqFkXiTZEaV6/5PJIeNsz75fn
AEuBpIATEHqRsY6L9HdYAvBiAEv6ufCZhzwWF7ph1ZMhg6ulfoaQwoVCkbKi/zgw
i3tvteda5vXQs4e8GvgZ6zkabQ4cZFjVpb3dA6huBbs20jLfYYXsXWsJEGF3JK5o
kQ08+u/h/q0lFDFa70S9hpQXMtSfCCW/AuEc/+tG7rnUul1oMXjpVnDOmg+CZfIY
gi9D30/zd1DYFJOEwawl5FKLFQY7TOn3RlZ3SR4mNbbhIgHPL9S1xHGcm8UC7PKu
Ogh8+5Nl0aeeUB1liuzM/w5JbF4L4FoZW6ciNQIDAQABAoIBAAEnd9Xq3GknAm6V
/bTFCDQQ8rElPTEVsaWRVO5wdDQ0KxVkEqKMlGNh+1wMWQWl6iQKsPKxrnSwgv4u
Zg9wNfWW6r+w7FGeVoIZC157Ce4SEpEt9BSDoawVnJhTtmFIakajNKufGhPGNLQE
XOosaSX63RRxcrSn5fp4Y7wuaqucXzPV3MuRABrDTHugW1O37570HLwvY9Hmf2+N
WIqEasCjeZ575EwTcqqVwB/j3BNqyrbkxP6aFszxYdMvlK/mpPhrShV6+QmuP02j
OvRt9HM8knUVzsGJzuDk5V5VUGejih3VZO1BuqP1LFb1j4siWBoKpVQrP0wSJzaa
5Vru/wECgYEA9SygrrkPESbjSLYIJU4mRmC4zSqbUoWpvTgpK29nNmif7BSJ9bRr
2QSCIho58a0bl3a7GLwY0dnEyDYKF9nTQ8HqlkvwRwxdMql+0hU0o5hOBnljYoyM
BBptFvoihCe2se+1FEQkunAFCDph00S5utz+8uTlHSFiSy/fQ4GOZwECgYEAw9xl
kZOPSGNEd69F9gtkOAT0kWuazvePSoeYNldZ/MZyE0zE4Wyh5Dk8y5cBt3Pw0ZTr
NN1dc24EkjcFIBop4Me5n5zKr4rH1XKsUQ2jaTurp/fVQwGo820n+ChO8cIEobHY
p6wmKopnnDKOATMjZd8hg+Gck7qWoeTxk3XizzUCgYAFGGJWfz4S6y36Ct5seA1P
lR8CFIqZ0nFOn2YrousQNGhubZbYZmF/ZxqVPtpJbYGPSkZlIzOY2N/AEW9wQ3Si
idsoOHfL4jPlo6QhFZO8eqPUep1YJPeb9jiiK5ygBntDg2nN/ASPY1iXbS8vRtRd
T850mdExI8p5KYuISZ7+AQKBgHF/ENhoErqW04ErbzYh6cRQksyF92KBsGY25uxu
d/XzpP0sGlaq1bFjvagYbGU7aUx5qEatFE8kbL+x5GVy49uewSEOAaHxoNU+qz4Y
0h3T9yfRhKJcnuPY2DWEXiLYFEkCvxKCvmceZuXrocBuOs/4mfpLTamJkWplOdwC
jxkVAoGBALU/996M9frxtjvzQdF3ncbKrDcptZN6s1hIBVk1t2PzcT0XgiOUZRqj
jvUqZWg7MV6kovdjg7N2KSE0u9p2nysL4ejvZRKMNNBdaFJvOUcaYCMTHok1KfXp
Bq75mMgfFLrY+huWzKdRWkEjqD6A05Us48iuikW5Ec32sI6mUzg9
-----END RSA PRIVATE KEY-----

View File

@ -1,61 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFrDCCBJSgAwIBAgIQDw9E1qRxoRsSagKtIUbGJzANBgkqhkiG9w0BAQsFADBy
MQswCQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywg
SW5jLjEdMBsGA1UECxMURG9tYWluIFZhbGlkYXRlZCBTU0wxHTAbBgNVBAMTFFRy
dXN0QXNpYSBUTFMgUlNBIENBMB4XDTIxMDMyMDAwMDAwMFoXDTIyMDMxOTIzNTk1
OVowKTEnMCUGA1UEAxMeZGFpbHkuYXBpLmRqYW5nby12dWUtYWRtaW4uY29tMIIB
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyijP5M9nLFbIimHuhYl4cK7C
e4SewgiERRThx+4/iLzFKMVHpSQ0GgcSN7e6tLlfgMzRcUbAnUsia4bzcp0UG+w0
Ny6OrFF7XuU71YQ3B+35NpfAvJGr7pw71aFpl1l+jz9iym4iw6yN5F8poq6TR7Gl
PNhX1YWZ+Wy0MCDnvQ00MBsQ/42CGEPzE6ZdKJ3l19NY/9/djnxZE+OgMVR3cdCI
I/Et0mahIWYaPGP14/nIzNfOcEZtJMHmgSGF/l9NyUdsrRRK7ltV87YWeU86e2Da
hqW9v0oSOLepOzg4PB4wU2IJfykRMXfJNUG6iWjOMVPdqIFTXjJZvtvZg5J4GQID
AQABo4IChTCCAoEwHwYDVR0jBBgwFoAUf9OZ86BHDjEAVlYijrfMnt3KAYowHQYD
VR0OBBYEFOqwsoYN4FxXPwL2my2kdh/PuVB4MCkGA1UdEQQiMCCCHmRhaWx5LmFw
aS5kamFuZ28tdnVlLWFkbWluLmNvbTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYw
FAYIKwYBBQUHAwEGCCsGAQUFBwMCMD4GA1UdIAQ3MDUwMwYGZ4EMAQIBMCkwJwYI
KwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzCBkgYIKwYBBQUH
AQEEgYUwgYIwNAYIKwYBBQUHMAGGKGh0dHA6Ly9zdGF0dXNlLmRpZ2l0YWxjZXJ0
dmFsaWRhdGlvbi5jb20wSgYIKwYBBQUHMAKGPmh0dHA6Ly9jYWNlcnRzLmRpZ2l0
YWxjZXJ0dmFsaWRhdGlvbi5jb20vVHJ1c3RBc2lhVExTUlNBQ0EuY3J0MAkGA1Ud
EwQCMAAwggEDBgorBgEEAdZ5AgQCBIH0BIHxAO8AdQBGpVXrdfqRIDC1oolp9PN9
ESxBdL79SbiFq/L8cP5tRwAAAXhNdRxuAAAEAwBGMEQCICntYjFg4csRL4bxiJvr
ma95JmMzYRrLx84UgLbd1iWhAiB64xH69vjCf4JfVB+3G1UN6G4pphW4m/nYBA2E
ElFuIgB2ACJFRQdZVSRWlj+hL/H3bYbgIyZjrcBLf13Gg1xu4g8CAAABeE11HF4A
AAQDAEcwRQIhANsjDO2cASF5sGZCyjS8jz9qA+5N4WWFxG+tO4VyELjtAiAIqurr
QbHF9fkBFDg995q5eR16ncpS1d75a0Nhis62PjANBgkqhkiG9w0BAQsFAAOCAQEA
DADo2zekDxm3zbuHGAlQR17h4BtD3tRDy58J58L5CnL+VhNLAN2Fp4AQF1w4a4+z
89ZFOKn+RcwSwyYDFHqsKYa7QYL97z7GJ1ASPG79faO5osbo1SOrSdwzIjjUnSD5
V4Fr0Fw6NYkq72pJPZkPEeivGEG3MvhzTaFSTwkylDVx6wxzaPY/p9WJpbopKN/8
+2WSM0b6UB1cuOgfJlhcqYYFqAPO/2XLY60uPpKgboPFAznT8T2QSaYd7JXHndYJ
IgTtXPr7hPOeXP9kDdUycCf3WOjp00gSk/guSujW4ZEaqCrJOkiMCbOrgyCIF7AK
pzwp4H5aJpzHXqObsb5n3Q==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIErjCCA5agAwIBAgIQBYAmfwbylVM0jhwYWl7uLjANBgkqhkiG9w0BAQsFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0xNzEyMDgxMjI4MjZaFw0yNzEyMDgxMjI4MjZaMHIxCzAJBgNVBAYTAkNO
MSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMR0wGwYDVQQL
ExREb21haW4gVmFsaWRhdGVkIFNTTDEdMBsGA1UEAxMUVHJ1c3RBc2lhIFRMUyBS
U0EgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgWa9X+ph+wAm8
Yh1Fk1MjKbQ5QwBOOKVaZR/OfCh+F6f93u7vZHGcUU/lvVGgUQnbzJhR1UV2epJa
e+m7cxnXIKdD0/VS9btAgwJszGFvwoqXeaCqFoP71wPmXjjUwLT70+qvX4hdyYfO
JcjeTz5QKtg8zQwxaK9x4JT9CoOmoVdVhEBAiD3DwR5fFgOHDwwGxdJWVBvktnoA
zjdTLXDdbSVC5jZ0u8oq9BiTDv7jAlsB5F8aZgvSZDOQeFrwaOTbKWSEInEhnchK
ZTD1dz6aBlk1xGEI5PZWAnVAba/ofH33ktymaTDsE6xRDnW97pDkimCRak6CEbfe
3dXw6OV5AgMBAAGjggFPMIIBSzAdBgNVHQ4EFgQUf9OZ86BHDjEAVlYijrfMnt3K
AYowHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQD
AgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAG
AQH/AgEAMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au
ZGlnaWNlcnQuY29tMEIGA1UdHwQ7MDkwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2lj
ZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwTAYDVR0gBEUwQzA3Bglg
hkgBhv1sAQIwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29t
L0NQUzAIBgZngQwBAgEwDQYJKoZIhvcNAQELBQADggEBAK3dVOj5dlv4MzK2i233
lDYvyJ3slFY2X2HKTYGte8nbK6i5/fsDImMYihAkp6VaNY/en8WZ5qcrQPVLuJrJ
DSXT04NnMeZOQDUoj/NHAmdfCBB/h1bZ5OGK6Sf1h5Yx/5wR4f3TUoPgGlnU7EuP
ISLNdMRiDrXntcImDAiRvkh5GJuH4YCVE6XEntqaNIgGkRwxKSgnU3Id3iuFbW9F
UQ9Qqtb1GX91AJ7i4153TikGgYCdwYkBURD8gSVe8OAco6IfZOYt/TEwii1Ivi1C
qnuUlWpsF1LdQNIdfbW3TSe0BhQa7ifbVIfvPWHYOu3rkg1ZeMo6XRU9B4n5VyJY
RmE=
-----END CERTIFICATE-----

View File

@ -1,27 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAyijP5M9nLFbIimHuhYl4cK7Ce4SewgiERRThx+4/iLzFKMVH
pSQ0GgcSN7e6tLlfgMzRcUbAnUsia4bzcp0UG+w0Ny6OrFF7XuU71YQ3B+35NpfA
vJGr7pw71aFpl1l+jz9iym4iw6yN5F8poq6TR7GlPNhX1YWZ+Wy0MCDnvQ00MBsQ
/42CGEPzE6ZdKJ3l19NY/9/djnxZE+OgMVR3cdCII/Et0mahIWYaPGP14/nIzNfO
cEZtJMHmgSGF/l9NyUdsrRRK7ltV87YWeU86e2DahqW9v0oSOLepOzg4PB4wU2IJ
fykRMXfJNUG6iWjOMVPdqIFTXjJZvtvZg5J4GQIDAQABAoIBAFYjOqXXe7IoTi2s
mbnbf+6fgC2qLg0mHNnkkmmiif7E1EtRd/wVJ4AZmDkWd57ux5M1cl6OU58R9xoS
9+NTq9BT/lGu7ErfMy6VhT+upNYjn4cT9SND/Jrghhw6OSgskWEPFJSFhhmTCiiP
Jcn0EbxAJNR+qDpKQXfGSiahtqxV01kNRU/j6YmVrQEoVif/9+LJmcs5Uy+gqA4a
fQou8/QQjrmPHPOSSWZ8aZlPNt89+E4P+XIkf4rPxD8lrWd2ufDeCdm1As4qYQQD
c/eeBh6qkrKijZZ8NRgonTaCYPXkkkHME4BgdP2gVCW/KMVfdM5pVVk7dctSs+6w
VFfF5CsCgYEA/pXLQXt6PUlJAVSFodK8CndZY1pAbzLNVTsDAVuEAepwmEL7Tw0O
nV4igsANdRxZxEdYWsY8CClNTNLNY92zaAbpsQXHxHqnXnl2ZGQi1Jb2eFR6zw+m
8Qyb6aca58Q95flHQY75/+IFWemj76p1aT7aIvpElMdkBUh1Ak92cv8CgYEAy0hu
MqJga0/3UoMLhjhUVWGXI6NBpvWNv7FqSeQ2SDj0iBib7nyrlP41bCcyHFXryrXf
YsbG4fq0mmyhQUz4++OP57lxXXBu3UvBd6qQUorWX9HVHy6ljun8PsJdNUGj9Q2v
arH6Rv/emIx86IAOGjgIgK+YiNwiw/uEYgNzTOcCgYBryjh4zTMAZ9sFOSgrT/JV
7Bpounm1myjdAVNQa9MEjKKHlTSaT8j0UDsEaRRJlWtcc2ixZmVcf0A/WrGjquaf
EO45CV1/jv72PS8nak5k/FX2tK4apWHlhZUt5Ja7spcSm+zTkRnAgY4Kd6X1f5Ke
sQHi9Vu8Mn/izL7d748TOQKBgH75txuZoXBmeq3nfQNRnBvY4Xc5OoD3UJs0Tpfp
HJ7wNI3uETheVy6xutzbfsmEQcxU3jvsvb3Zw4XR5MfNNJjiA7lSdCVRXW6NK0N8
HrnwTwd7IgxgLrmeHhl1fpMNdURUUAXtNc+zc28GEd+IXUazSVxYUobqOi0Apigy
z4pxAoGBAPKd+WMUS94Ne7WMHDzcCcQKl2dJmBVj036qCtPgUL4yDyRDc/H1fQxI
jr/+JueqktrJgJsOL4uygn0zzKIJyQIToufxOodUdmviRLaH2UskNUBUjIBqyDc0
pjPebC7sxg6HZQmVpgX4klj1IWDpudD+cCRGF9SIzKRvNEadLgOl
-----END RSA PRIVATE KEY-----

View File

@ -1,61 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFsDCCBJigAwIBAgIQBbQIKLDxaNeKW6HjUJCFNjANBgkqhkiG9w0BAQsFADBy
MQswCQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywg
SW5jLjEdMBsGA1UECxMURG9tYWluIFZhbGlkYXRlZCBTU0wxHTAbBgNVBAMTFFRy
dXN0QXNpYSBUTFMgUlNBIENBMB4XDTIxMDMyMDAwMDAwMFoXDTIyMDMxOTIzNTk1
OVowKjEoMCYGA1UEAxMfZGFpbHkuZGVtby5kamFuZ28tdnVlLWFkbWluLmNvbTCC
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKAOwxsoKm4vH/gv8h7OHYHI
5dQAAKm3tk1ZsyY9cMlSq/GIMSY15BZSwdSiwyI3vcCpmz2YCVRXpH8r0LNm/Ygu
fjVeK1H+F6fQkGj7065ye1Z15PtgI6Dx9dhLlFlR3lZYm0MVwSIW2xgVqbL+WNKl
198afnP+/B/Klzjyud4wqAlzDcD8lIh8iL0LMY3HSHzSzr8xtYZLxUvEzcl+vRF9
a9GjTOgg01Ukk04zHXan7VInK1/lurQ+WuntfPFDe/jmlEid4/wvB/lCMi0KUSWd
0C9CCB+2q/Lsa0hr8v4DF1TS1/YGg/y0Ye1+DzpKLKv/mfe6py18Ca7FcnFoKVsC
AwEAAaOCAogwggKEMB8GA1UdIwQYMBaAFH/TmfOgRw4xAFZWIo63zJ7dygGKMB0G
A1UdDgQWBBQ14z4HfGEjC4tAPVnN/AvsXmgHYDAqBgNVHREEIzAhgh9kYWlseS5k
ZW1vLmRqYW5nby12dWUtYWRtaW4uY29tMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUE
FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwPgYDVR0gBDcwNTAzBgZngQwBAgEwKTAn
BggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIGSBggrBgEF
BQcBAQSBhTCBgjA0BggrBgEFBQcwAYYoaHR0cDovL3N0YXR1c2UuZGlnaXRhbGNl
cnR2YWxpZGF0aW9uLmNvbTBKBggrBgEFBQcwAoY+aHR0cDovL2NhY2VydHMuZGln
aXRhbGNlcnR2YWxpZGF0aW9uLmNvbS9UcnVzdEFzaWFUTFNSU0FDQS5jcnQwCQYD
VR0TBAIwADCCAQUGCisGAQQB1nkCBAIEgfYEgfMA8QB3AEalVet1+pEgMLWiiWn0
830RLEF0vv1JuIWr8vxw/m1HAAABeE1yhJEAAAQDAEgwRgIhAIdZiX5qq+KJjdtl
2Z9ejh5o9VHKyVVUgkJb0+S8aQGlAiEA5nEVffySiTcUogz+b7n34hmG2aW3YO02
UhMzyv7hoGcAdgAiRUUHWVUkVpY/oS/x922G4CMmY63AS39dxoNcbuIPAgAAAXhN
coRmAAAEAwBHMEUCIDFWIi3mkGmkB/uuTCqJyPTz8/WS4vqvdAUWO+MuxuaoAiEA
yP80fJCLnfso7VoJcWQT1l6bN6XL/jxip1OjXU0+dQMwDQYJKoZIhvcNAQELBQAD
ggEBAB0vH0OMrwGOQHdRdaN9t+2Yc1xnBNcksHcCmVD09gO2clA06OqTiu77g8lw
KwO2M5DmNFAA2onDxRVIL6auyLNdyK4X2m9i1eGnyAKro7d4owIlG30JdJ7uHzLG
ROL9SR0ibNZwOhoKSfpy3a+fWngMjCdW8pAFJHfPbOf6lP/CpGwoBnLvm9a9ZG3K
m2NmFN1/GPje25tXy0S/NaVFDVcJyfMeuVKqdwY9sbN7nOYGUury5NC5LWbgJ0T2
KWLcZc3LCa791kHLWVt/KI+9UgpM6Xiie0jUUIU92NaxBD/wY/jybPiogJkAz/sl
TncbnwO2+WpN6jIy9ccs8ogUMTQ=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIErjCCA5agAwIBAgIQBYAmfwbylVM0jhwYWl7uLjANBgkqhkiG9w0BAQsFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0xNzEyMDgxMjI4MjZaFw0yNzEyMDgxMjI4MjZaMHIxCzAJBgNVBAYTAkNO
MSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMR0wGwYDVQQL
ExREb21haW4gVmFsaWRhdGVkIFNTTDEdMBsGA1UEAxMUVHJ1c3RBc2lhIFRMUyBS
U0EgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgWa9X+ph+wAm8
Yh1Fk1MjKbQ5QwBOOKVaZR/OfCh+F6f93u7vZHGcUU/lvVGgUQnbzJhR1UV2epJa
e+m7cxnXIKdD0/VS9btAgwJszGFvwoqXeaCqFoP71wPmXjjUwLT70+qvX4hdyYfO
JcjeTz5QKtg8zQwxaK9x4JT9CoOmoVdVhEBAiD3DwR5fFgOHDwwGxdJWVBvktnoA
zjdTLXDdbSVC5jZ0u8oq9BiTDv7jAlsB5F8aZgvSZDOQeFrwaOTbKWSEInEhnchK
ZTD1dz6aBlk1xGEI5PZWAnVAba/ofH33ktymaTDsE6xRDnW97pDkimCRak6CEbfe
3dXw6OV5AgMBAAGjggFPMIIBSzAdBgNVHQ4EFgQUf9OZ86BHDjEAVlYijrfMnt3K
AYowHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQD
AgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAG
AQH/AgEAMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au
ZGlnaWNlcnQuY29tMEIGA1UdHwQ7MDkwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2lj
ZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwTAYDVR0gBEUwQzA3Bglg
hkgBhv1sAQIwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29t
L0NQUzAIBgZngQwBAgEwDQYJKoZIhvcNAQELBQADggEBAK3dVOj5dlv4MzK2i233
lDYvyJ3slFY2X2HKTYGte8nbK6i5/fsDImMYihAkp6VaNY/en8WZ5qcrQPVLuJrJ
DSXT04NnMeZOQDUoj/NHAmdfCBB/h1bZ5OGK6Sf1h5Yx/5wR4f3TUoPgGlnU7EuP
ISLNdMRiDrXntcImDAiRvkh5GJuH4YCVE6XEntqaNIgGkRwxKSgnU3Id3iuFbW9F
UQ9Qqtb1GX91AJ7i4153TikGgYCdwYkBURD8gSVe8OAco6IfZOYt/TEwii1Ivi1C
qnuUlWpsF1LdQNIdfbW3TSe0BhQa7ifbVIfvPWHYOu3rkg1ZeMo6XRU9B4n5VyJY
RmE=
-----END CERTIFICATE-----

View File

@ -1,27 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAoA7DGygqbi8f+C/yHs4dgcjl1AAAqbe2TVmzJj1wyVKr8Ygx
JjXkFlLB1KLDIje9wKmbPZgJVFekfyvQs2b9iC5+NV4rUf4Xp9CQaPvTrnJ7VnXk
+2AjoPH12EuUWVHeVlibQxXBIhbbGBWpsv5Y0qXX3xp+c/78H8qXOPK53jCoCXMN
wPyUiHyIvQsxjcdIfNLOvzG1hkvFS8TNyX69EX1r0aNM6CDTVSSTTjMddqftUicr
X+W6tD5a6e188UN7+OaUSJ3j/C8H+UIyLQpRJZ3QL0IIH7ar8uxrSGvy/gMXVNLX
9gaD/LRh7X4POkosq/+Z97qnLXwJrsVycWgpWwIDAQABAoIBABaP2NHdrhQnwWu/
T8km3dhFz5vm6jECVrN9nE1yJhFtqBOH0qx5C+9Xor9iDXv9JoWKLaTCPI0ZPkoM
4kI/wietrMMXb1IuAqX4YOWORgRrr9YmupdIBzhbPdVLsMbhzaPB9r+UnqEQXrmn
ksB1WQ5MgWsPdYQit+XqrWQXgbrU9kAP5+aO2GKrlnWZqBgshUkd2Sq5rdgrK5nv
kcmVBGClPsgOG2HgA+aJoFGLccoF8NMrBWaSc+zlHjiT8fP2YnMcDsX8Fw1tETbK
P9jf9wd4b/2ezKL3TWJMkbTRnxBwDgARWFVrD9jZqLtw342YuGQnEhPJFFdepKpQ
3GtbyiECgYEA0KlSF3K+coEjCjBGSFD5ACmB5ipl/NFPXVjCG1vHGHRh/0WnXBPI
zY3pRHFr9cJKLxQPe+4085yFXGTV7GHhH4nd1tEVxrH8ouNok0/WL4HHtvfGOq/H
sKQsZKVaUXd+NTZmzoXXJsb9Jgnu6r4AS4QazP1FRxSbSToxbut1ezsCgYEAxF6f
mAFz9p5ptNStJLXV53nTgNHK0Hk2cISu5aAUGQKA26VwnZTEo09Wt+WOGjzjTkSi
+TCoFfG77aqFQ1AyuAYWWErcS4/1/p0SeINXdztx34CJM/OqJ/AtjdL+09xwUZe6
JeUWWPMJukkrFkjNkCjkdQlVxG+a3jMlmM016GECgYEAoJJ8QuEhH7qyvUdy/nmZ
dH98oCPmggyM15fTH/yblP0S4L+4T8pFz7EyXmIuI1xVfC8iz0r7YrEDi5tpaFPW
S0/r8EDMUjBr6um3cw2QFNT5XJsF5+mXcR6Vrwn0HBcpf0eTC8DBVezxqFEik3CN
h49slG0e39lCurJWkjYOHTsCgYBeA/Oi4ic0DvoLErvm1IwZ7BDgHxFcKHxw+IWH
+NFGfBVXk+jL+Vr/2U9qciRL2ZT2dxQT/ECtaPQRwM9WwAHYa0mtcgHwx3b+NROP
0UpCEprdZ/vIfMOdpXcZ7MgGhQbdeags1naRlaK1pqxTWf3ZJErk4dhHWSurcI9y
jeVeYQKBgQCsIaGmX/xigoLaEucXOM4V34QU1gepJkDLDNEw4r9EoNHoBCwIaGxX
CWCsyuOwnCWM2OJJth5a+1xPYul0jsh7HCShICpkMsktoq4UdYbBfVNQiqenI7L7
l6/mzU5Ds6KXKVh2FZ7O8zcup1BYs0pAHTZqF+P/1FjSu1jbGfezFg==
-----END RSA PRIVATE KEY-----

View File

@ -1,61 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFoTCCBImgAwIBAgIQBL1afhbyouKA0yBDgDhq/zANBgkqhkiG9w0BAQsFADBy
MQswCQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywg
SW5jLjEdMBsGA1UECxMURG9tYWluIFZhbGlkYXRlZCBTU0wxHTAbBgNVBAMTFFRy
dXN0QXNpYSBUTFMgUlNBIENBMB4XDTIxMDMyMDAwMDAwMFoXDTIyMDMxOTIzNTk1
OVowJDEiMCAGA1UEAxMZZGVtby5kamFuZ28tdnVlLWFkbWluLmNvbTCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMk2tqLVSJyC/VTuWlZ+a+bjthUotJ/o
yQcXMC6eu/KyHbWqh5Ccj2kLh/zf9uhcs/GcYl/H1hyIVuiC+SHGmGfCqQB96vLl
uwwJDlM+y910xKmKV2S6DEFbXDZP76pShrpPs1nDkU5gftuGhX1S77pmMqjbOsG+
gZJAlAZKzT5xnGwpo4rkHc8xPY0ac29+9HXYDawpmySSdbfG+W0kape/wBexFmO+
KLt/oRk+QJbtPguLNLLlvZznf+fFp5UcmsVks/scg9fM1pnj3QQaCB8RXQQKkskm
Hi67PGFJOeepNFkApzHO4sUM3ya2Rskzfs9DtTlCODn3XFSVJz7DyTsCAwEAAaOC
An8wggJ7MB8GA1UdIwQYMBaAFH/TmfOgRw4xAFZWIo63zJ7dygGKMB0GA1UdDgQW
BBSRBeJj2dUcPqhi3km5tbW5lZP3aTAkBgNVHREEHTAbghlkZW1vLmRqYW5nby12
dWUtYWRtaW4uY29tMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcD
AQYIKwYBBQUHAwIwPgYDVR0gBDcwNTAzBgZngQwBAgEwKTAnBggrBgEFBQcCARYb
aHR0cDovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIGSBggrBgEFBQcBAQSBhTCBgjA0
BggrBgEFBQcwAYYoaHR0cDovL3N0YXR1c2UuZGlnaXRhbGNlcnR2YWxpZGF0aW9u
LmNvbTBKBggrBgEFBQcwAoY+aHR0cDovL2NhY2VydHMuZGlnaXRhbGNlcnR2YWxp
ZGF0aW9uLmNvbS9UcnVzdEFzaWFUTFNSU0FDQS5jcnQwCQYDVR0TBAIwADCCAQIG
CisGAQQB1nkCBAIEgfMEgfAA7gB1AEalVet1+pEgMLWiiWn0830RLEF0vv1JuIWr
8vxw/m1HAAABeE1whV0AAAQDAEYwRAIgPFX8oV29XVZMDi2tbEuBo2AuS4udT2I/
tMHo9EPNPOYCIGFeOpkGfPcG4szSvKEmUIYimb3vejH0QJ6qB3+T6E5kAHUAIkVF
B1lVJFaWP6Ev8fdthuAjJmOtwEt/XcaDXG7iDwIAAAF4TXCFeAAABAMARjBEAiBC
HxlN8ItLz/FW/gYrmGGXTVvxxnVKv9t5bsj2AsdmOQIgJVu8zYZVNjt7AHFusZWg
ZYSY0Qd+11v1oXBHAi0OUAowDQYJKoZIhvcNAQELBQADggEBAEKj+pGihWMbm/Bm
d+7Ra6gngG5N/c7S1cPzmOAlX3bWOFLqZRVPiC8Xa5uzLuqkYMiRIuIFUjZj2CwS
gKVwEk3xIL76sMVURV17mhjV7jbhzCSIqnEVLpiGRsuEoHKW8UUAzBdAZjjk4D+Y
LZKOQKcWojGTCyRJA5dRHy+sWtnZcHGaD36UHeVh0ctFhoVcc9Oxsh9T6W4NnMd/
CthO8fDic3643232J+6VF1vH5fkz1Q6UGbH+GbmkZ70Rv9YCl78zU77juBfTy9ht
HJmcwLWF6Hef7Z+K2QnvT6H+cIb6OxSErshy9TlKgTRjVD7A3wTrri/dCJqfINVk
FoBVzmQ=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIErjCCA5agAwIBAgIQBYAmfwbylVM0jhwYWl7uLjANBgkqhkiG9w0BAQsFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0xNzEyMDgxMjI4MjZaFw0yNzEyMDgxMjI4MjZaMHIxCzAJBgNVBAYTAkNO
MSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMR0wGwYDVQQL
ExREb21haW4gVmFsaWRhdGVkIFNTTDEdMBsGA1UEAxMUVHJ1c3RBc2lhIFRMUyBS
U0EgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgWa9X+ph+wAm8
Yh1Fk1MjKbQ5QwBOOKVaZR/OfCh+F6f93u7vZHGcUU/lvVGgUQnbzJhR1UV2epJa
e+m7cxnXIKdD0/VS9btAgwJszGFvwoqXeaCqFoP71wPmXjjUwLT70+qvX4hdyYfO
JcjeTz5QKtg8zQwxaK9x4JT9CoOmoVdVhEBAiD3DwR5fFgOHDwwGxdJWVBvktnoA
zjdTLXDdbSVC5jZ0u8oq9BiTDv7jAlsB5F8aZgvSZDOQeFrwaOTbKWSEInEhnchK
ZTD1dz6aBlk1xGEI5PZWAnVAba/ofH33ktymaTDsE6xRDnW97pDkimCRak6CEbfe
3dXw6OV5AgMBAAGjggFPMIIBSzAdBgNVHQ4EFgQUf9OZ86BHDjEAVlYijrfMnt3K
AYowHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQD
AgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAG
AQH/AgEAMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au
ZGlnaWNlcnQuY29tMEIGA1UdHwQ7MDkwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2lj
ZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwTAYDVR0gBEUwQzA3Bglg
hkgBhv1sAQIwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29t
L0NQUzAIBgZngQwBAgEwDQYJKoZIhvcNAQELBQADggEBAK3dVOj5dlv4MzK2i233
lDYvyJ3slFY2X2HKTYGte8nbK6i5/fsDImMYihAkp6VaNY/en8WZ5qcrQPVLuJrJ
DSXT04NnMeZOQDUoj/NHAmdfCBB/h1bZ5OGK6Sf1h5Yx/5wR4f3TUoPgGlnU7EuP
ISLNdMRiDrXntcImDAiRvkh5GJuH4YCVE6XEntqaNIgGkRwxKSgnU3Id3iuFbW9F
UQ9Qqtb1GX91AJ7i4153TikGgYCdwYkBURD8gSVe8OAco6IfZOYt/TEwii1Ivi1C
qnuUlWpsF1LdQNIdfbW3TSe0BhQa7ifbVIfvPWHYOu3rkg1ZeMo6XRU9B4n5VyJY
RmE=
-----END CERTIFICATE-----

View File

@ -1,27 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAyTa2otVInIL9VO5aVn5r5uO2FSi0n+jJBxcwLp678rIdtaqH
kJyPaQuH/N/26Fyz8ZxiX8fWHIhW6IL5IcaYZ8KpAH3q8uW7DAkOUz7L3XTEqYpX
ZLoMQVtcNk/vqlKGuk+zWcORTmB+24aFfVLvumYyqNs6wb6BkkCUBkrNPnGcbCmj
iuQdzzE9jRpzb370ddgNrCmbJJJ1t8b5bSRql7/AF7EWY74ou3+hGT5Alu0+C4s0
suW9nOd/58WnlRyaxWSz+xyD18zWmePdBBoIHxFdBAqSySYeLrs8YUk556k0WQCn
Mc7ixQzfJrZGyTN+z0O1OUI4OfdcVJUnPsPJOwIDAQABAoIBAA8baQX7vnplyVBt
nuG8lyxcL2kSR9FzwFgkcQ0nBNR5dAqWNZxxbMEFyR1+0UJr52S+CZLIZbZ5tBC7
+KmFCB9OObMcQR4ginUiXu14GwVTBYr3JI2e/FmR2vAG+2cN0Ci/4CberJO2Yf/o
bzBUIESd9LLB1v0B6SeKarK4PgWwjrr/twowABRBhkkKFErfYZjfNh1mALXPNEUA
7z3a8abw+JWympIFKWxi3YXyLOJZaGawOPDhq+ZVv+7rXvIyAzUzpmwCprjZFL4Q
hgN7IY7KjYK772Ffe0nwMbd3wbwYeAelM9fndH9dTMrQ1n6EcDBzla8Cwl6OVEk3
GpQqOfECgYEA+7qFHw75AOI3FFke/2VOJ58m0rrYJwDrLazlrzashi7qgJOBY6jp
yjLgGCOcR9v8pRWkOw2VLy+dhdr16Xp/XYhuSa6O5EC7igtnUVx9xu+XAksZiB97
f4lm7F3uirEh7ewuqiRETI9o6V5iGTCSMSc21zlJ1zoxnLMSuMyCKTECgYEAzKDD
PNJVZAiZJ25JKinkZlTyQ9VmQkfrvsIBWheN844uoSmmLR4PNwriZQtlURI58WA2
pe20aHJaleOJvzgW/OvcB+7mf/Ukn1mw6Ciusj6jXLXmmq8i80W0RMr1Rdbq8+dp
DNZt0iDXEZXHEGqdkpkn/gsvYL+jeIiKyuJ9PisCgYAoZGF//lMORT45UaObr5G+
4dbE8Z5Fg+w4xAmG9+rvDRAr2X9lknERNOCofu5QyYfcpYBYyXEqxSUtmVjkQfe1
9nJb+FqNXaW6HOJTN9gm18MPZyWNph+W82FEhD4Gmy2qk79ZJcCf2FMpPy/Wguiy
Ymx2VIb4tinHzyQt6wLnwQKBgAURSiR8dP7oM5rFYWx44x4hpmpFo6WqkE0GEvB/
OtW4RLFbDbF6WBgd3eNwt86dK/AtWM0dKOWZR2ME4olowzD6SlWr9etfT8vedcIa
F9F0Oal3G8Hi6nOp20AE4rQbEXB+35wgx1F33LujwO1IJqTVxCbHciHsPQkkIIPL
vhxHAoGAdwbRiK2OCmycedsD+L5qdxOYiL8JIAXLP+H7ZD0Jyx21UxQAmvza6fIx
HygnDGzrTJoOPEWu5WmGs4i6mr1bChHpo85LVNfytsxbE59y3I0va1IlSUC6wjXP
Yy3caUiBgxmzz4vhqCFdpLhT2SyyB4m13ggLmeyqLy88WnYCgiE=
-----END RSA PRIVATE KEY-----

View File

@ -1,61 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFszCCBJugAwIBAgIQCGwikUrRfEUk8GbxRWLVIDANBgkqhkiG9w0BAQsFADBy
MQswCQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywg
SW5jLjEdMBsGA1UECxMURG9tYWluIFZhbGlkYXRlZCBTU0wxHTAbBgNVBAMTFFRy
dXN0QXNpYSBUTFMgUlNBIENBMB4XDTIxMDMwMzAwMDAwMFoXDTIyMDMwMjIzNTk1
OVowHzEdMBsGA1UEAxMUZGphbmdvLXZ1ZS1hZG1pbi5jb20wggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQC0iitqUeTxkq5qabbVcB+7a+YArfKAJBRvcj+T
VVdRkvEjcfGLvXIJUTvcUqJkRRYFbimdjB5q7CWCld8bgz/UOpIEmbdqn+WgzrNn
WWZrRiN5ylHAsIaKlgYKh6gcftEco6OgkrM8oyq1gORRBIcSj95VcqpIeAUMVyCX
R0h3dXnLCVe70ejr8w2cyHrSeS68mXw7LlAdfC0JAZTB/wxwcitSnnIVEbV6wMzG
BD5Ka/WprnJgJa7Prb5KHiZh4UG4Es2JpIHALMYLIeKQCUCIP1NmW8Ale+nhY9kD
tJeSEIY+/dRoDjpPkkIZalMp+5p0yDQ1LIO4pDZxnoI2vFLFAgMBAAGjggKWMIIC
kjAfBgNVHSMEGDAWgBR/05nzoEcOMQBWViKOt8ye3coBijAdBgNVHQ4EFgQUru5P
/0LuJj6hxqHWVYUN690wFNEwOQYDVR0RBDIwMIIUZGphbmdvLXZ1ZS1hZG1pbi5j
b22CGHd3dy5kamFuZ28tdnVlLWFkbWluLmNvbTAOBgNVHQ8BAf8EBAMCBaAwHQYD
VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMD4GA1UdIAQ3MDUwMwYGZ4EMAQIB
MCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzCBkgYI
KwYBBQUHAQEEgYUwgYIwNAYIKwYBBQUHMAGGKGh0dHA6Ly9zdGF0dXNlLmRpZ2l0
YWxjZXJ0dmFsaWRhdGlvbi5jb20wSgYIKwYBBQUHMAKGPmh0dHA6Ly9jYWNlcnRz
LmRpZ2l0YWxjZXJ0dmFsaWRhdGlvbi5jb20vVHJ1c3RBc2lhVExTUlNBQ0EuY3J0
MAkGA1UdEwQCMAAwggEEBgorBgEEAdZ5AgQCBIH1BIHyAPAAdgBGpVXrdfqRIDC1
oolp9PN9ESxBdL79SbiFq/L8cP5tRwAAAXf475pDAAAEAwBHMEUCIHTgL1+oRWE+
REuWNRa5J1cflPKW63jk6/3ibF+Sm5peAiEAt74SK9Ka9QyMJfP57eDl3xA1Ctnb
Bz6zTLIQFFicPGsAdgAiRUUHWVUkVpY/oS/x922G4CMmY63AS39dxoNcbuIPAgAA
AXf475pNAAAEAwBHMEUCIQDOE36oL7MAxmHdEoI338jLW0xnBN8VeW9XyuTzIcq7
eQIgLwJTNfLqgw7TofY3dKqof5rkcuJWMmSI4aapUUBjFfIwDQYJKoZIhvcNAQEL
BQADggEBAC9lYBZuCzle1tSaJ4nVfogwHf0B4lKjDI8ixEnrDaY0tAuYst4S7zoU
76dZcpdwQjVLtlLk5jyaNdN5ohsu9WpErq6N7bXKhbSPBavCPxP4sMWMvmeQQUtB
UKqqRofXbx3WcWtsf1/Wlg3pyb0oyJ7kKt3iDG9OYEihQzEyG5Y72IE+HsbhTAWR
zqxGnmMumQ+JTnxCCudPoVPk25i2BfndMbcY4N6YyJYuLwMojtMkAeWtRdMmqtiy
lMb7EbWLYCHDyv892WTzie1BqZ7YcOaE59OChhmoYxiSXNHPCToIFECTz6BhPxlI
T3LbIM4+81HNDebdR17NUE3zN44OjsA=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIErjCCA5agAwIBAgIQBYAmfwbylVM0jhwYWl7uLjANBgkqhkiG9w0BAQsFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0xNzEyMDgxMjI4MjZaFw0yNzEyMDgxMjI4MjZaMHIxCzAJBgNVBAYTAkNO
MSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMR0wGwYDVQQL
ExREb21haW4gVmFsaWRhdGVkIFNTTDEdMBsGA1UEAxMUVHJ1c3RBc2lhIFRMUyBS
U0EgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgWa9X+ph+wAm8
Yh1Fk1MjKbQ5QwBOOKVaZR/OfCh+F6f93u7vZHGcUU/lvVGgUQnbzJhR1UV2epJa
e+m7cxnXIKdD0/VS9btAgwJszGFvwoqXeaCqFoP71wPmXjjUwLT70+qvX4hdyYfO
JcjeTz5QKtg8zQwxaK9x4JT9CoOmoVdVhEBAiD3DwR5fFgOHDwwGxdJWVBvktnoA
zjdTLXDdbSVC5jZ0u8oq9BiTDv7jAlsB5F8aZgvSZDOQeFrwaOTbKWSEInEhnchK
ZTD1dz6aBlk1xGEI5PZWAnVAba/ofH33ktymaTDsE6xRDnW97pDkimCRak6CEbfe
3dXw6OV5AgMBAAGjggFPMIIBSzAdBgNVHQ4EFgQUf9OZ86BHDjEAVlYijrfMnt3K
AYowHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQD
AgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAG
AQH/AgEAMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au
ZGlnaWNlcnQuY29tMEIGA1UdHwQ7MDkwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2lj
ZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwTAYDVR0gBEUwQzA3Bglg
hkgBhv1sAQIwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29t
L0NQUzAIBgZngQwBAgEwDQYJKoZIhvcNAQELBQADggEBAK3dVOj5dlv4MzK2i233
lDYvyJ3slFY2X2HKTYGte8nbK6i5/fsDImMYihAkp6VaNY/en8WZ5qcrQPVLuJrJ
DSXT04NnMeZOQDUoj/NHAmdfCBB/h1bZ5OGK6Sf1h5Yx/5wR4f3TUoPgGlnU7EuP
ISLNdMRiDrXntcImDAiRvkh5GJuH4YCVE6XEntqaNIgGkRwxKSgnU3Id3iuFbW9F
UQ9Qqtb1GX91AJ7i4153TikGgYCdwYkBURD8gSVe8OAco6IfZOYt/TEwii1Ivi1C
qnuUlWpsF1LdQNIdfbW3TSe0BhQa7ifbVIfvPWHYOu3rkg1ZeMo6XRU9B4n5VyJY
RmE=
-----END CERTIFICATE-----

View File

@ -1,27 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAtIoralHk8ZKuamm21XAfu2vmAK3ygCQUb3I/k1VXUZLxI3Hx
i71yCVE73FKiZEUWBW4pnYweauwlgpXfG4M/1DqSBJm3ap/loM6zZ1lma0YjecpR
wLCGipYGCoeoHH7RHKOjoJKzPKMqtYDkUQSHEo/eVXKqSHgFDFcgl0dId3V5ywlX
u9Ho6/MNnMh60nkuvJl8Oy5QHXwtCQGUwf8McHIrUp5yFRG1esDMxgQ+Smv1qa5y
YCWuz62+Sh4mYeFBuBLNiaSBwCzGCyHikAlAiD9TZlvAJXvp4WPZA7SXkhCGPv3U
aA46T5JCGWpTKfuadMg0NSyDuKQ2cZ6CNrxSxQIDAQABAoIBAA5RZOcOLp9/+Agl
cSQVO9cD1B5arUA/XEWIZIVdP8sO4cPjXfosoJYflKVBAnL8TaZJmdBOU/071C+6
jhKjApVkvb7SqAqzOqVZrz2zh91bFyYqBvjGpyznf/wmzQzRe+kPC0OJTuCwugrh
+Xl5Z/LvaP0S1nFf31qesE1/ED609pvWtdUWj2oop9zORBzjaGcXeOKNqX8XnQCp
rJ487wcnuL8Nnuu+vuh8dC9o7zwjGrKwXhM3sijLp4q9VOF9fW2bYLyfLUR3FCFq
JPrQXe1mY28w+uIlnEdPkwgGIJbzur601BuzU9ZH5MSl7iYV319MPz+rtizFJxLm
OCg5hcMCgYEA7RrgQsrSj4fhi0VVkQ3fFeLJPQlvVcMK0OOYxP3cKQYSgXo79bQK
i9yRCRVS2UTGh8B3MGbPr+sRINokeYtjWxGDOwAlkye9kRiCKzzZOrlwDAY/SEDZ
HH5mVnv9UHtxCFSUub67IVWH7wCmoprKEK/loyvJFiE5jsxVmNZl3o8CgYEAwu1R
nBsETJLuN5/fB9rW3NvjaHGT1B6LQ1uIBmsU6V71gBasawX/X3ENOoX1dQa2japp
x58pjLJuP/t4WgZ41PBagij2G83VdFBdvrcVSk7B1yt8rudxmcvo1K6FR2FG7DMU
9kkb9JKFT3/FM7LT+z4xXxJ0AoNg6QD1IIT5Y2sCgYEAyQUvOxGQISY334bh+8AB
8iE7MidsoA5jfiRoIiOEY7eFOwbyDOcexeMzh7rvacs4cmGH655O2Lv34p1vrSiz
DMO1OfFu6esYegqIWbYWCgar61XkkxJ/v/ueMhae9nwhoclr6mq9Zo6IV+Z6YIPR
awJmM8fsjXmPvfSZYaHr7hsCgYAPzW99SU9q6cp4JfTNzTb4BreD4xlJ7AP8PPJl
Gs9CMBmU/cGSl5ThZufco7mHeDjaeUNEFKooptp7Q2a5Xab0FFwyCyIQlPpGCLHg
4TTPplzelb7w6wBxqG9CtrdFVySJx4ZehQTIKgy2qjQRgeDfkGYuP++5uG7l1NcK
gN066wKBgDg2F4yMx4SBWL3aBjIVd+Zilm+pkU1ZGC1XcuLnqSSMcoDy/JMszQC1
SEdDxgnCGlkWjtaxNPwfZTPU0SIoX5dcAx1EaHDJ+ibiIKGtM8forSCiP8fNz0oR
SYNZaYVuDJb1SFk9vKJMuIIFWS+AM6rlcOpNu6A0+1MbstM4BvwS
-----END RSA PRIVATE KEY-----

View File

@ -1,15 +0,0 @@
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
client_max_body_size 100m;
include /etc/nginx/sites-enabled/*;#主要是这个地方,把新建的两配置文件包含进来
server {
listen 80 default_server;
server_name _;
return 404;
}
}

View File

@ -1,46 +0,0 @@
## 将HTTP请求全部重定向至HTTPS
server {
listen 80;
server_name api.django-vue-admin.com;
charset utf-8;
access_log /var/log/nginx/api-80.access.log;
error_log /var/log/nginx/api-80.error.log;
rewrite ^(.*)$ https://${server_name}$1 permanent;
}
server {
listen 443 ssl;
server_name api.django-vue-admin.com;
root /dvadmin-backend/;#项目路径
charset utf-8;
ssl_certificate /nginx/keys/api.django-vue-admin.com.crt;#.pem证书路径
ssl_certificate_key /nginx/keys/api.django-vue-admin.com.key;#.key证书路径
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
error_page 497 https://$host$request_uri;
proxy_set_header Host $proxy_host;
proxy_set_header X-DTS-SCHEMA api;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
location / {
root html/www;
include uwsgi_params;
uwsgi_pass dvadmin-django:8000;
uwsgi_param UWSGI_SCRIPT home.wsgi;
uwsgi_param UWSGI_CHDIR /dvadmin-backend/;#项目路径
}
# Django media
location /media {
alias /dvadmin-backend/media; # your Django project's media files - amend as required
}
# Django static
location /static {
alias /dvadmin-backend/static; # your Django project's static files - amend as required
}
access_log /var/log/nginx/api-443.access.log;
error_log /var/log/nginx/api-443.error.log;
}

View File

@ -1,46 +0,0 @@
## 将HTTP请求全部重定向至HTTPS
server {
listen 80;
server_name daily.api.django-vue-admin.com;
charset utf-8;
access_log /var/log/nginx/api-80.access.log;
error_log /var/log/nginx/api-80.error.log;
rewrite ^(.*)$ https://${server_name}$1 permanent;
}
server {
listen 443 ssl;
server_name daily.api.django-vue-admin.com;
root /dvadmin-backend/;#项目路径
charset utf-8;
ssl_certificate /nginx/keys/daily.api.django-vue-admin.com.crt;#.pem证书路径
ssl_certificate_key /nginx/keys/daily.api.django-vue-admin.com.key;#.key证书路径
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
error_page 497 https://$host$request_uri;
proxy_set_header Host $proxy_host;
proxy_set_header X-DTS-SCHEMA daily.api;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
location / {
root html/www;
include uwsgi_params;
uwsgi_pass dvadmin-django:8000;
uwsgi_param UWSGI_SCRIPT home.wsgi;
uwsgi_param UWSGI_CHDIR /dvadmin-backend/;#项目路径
}
# Django media
location /media {
alias /dvadmin-backend/media; # your Django project's media files - amend as required
}
# Django static
location /static {
alias /dvadmin-backend/static; # your Django project's static files - amend as required
}
access_log /var/log/nginx/daily.api-443.access.log;
error_log /var/log/nginx/daily.api-443.error.log;
}

View File

@ -1,44 +0,0 @@
## 将HTTP请求全部重定向至HTTPS
server {
listen 80;
server_name daily.demo.django-vue-admin.com;
charset utf-8;
access_log /var/log/nginx/daily.demo-80.access.log;
error_log /var/log/nginx/daily.demo-80.error.log;
rewrite ^(.*)$ https://${server_name}$1 permanent;
}
server {
listen 443 ssl;
server_name daily.demo.django-vue-admin.com;
root /vadmin-doc/;#项目路径
charset utf-8;
ssl_certificate /nginx/keys/daily.demo.django-vue-admin.com.crt;#.pem证书路径
ssl_certificate_key /nginx/keys/daily.demo.django-vue-admin.com.key;#.key证书路径
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
error_page 497 https://$host$request_uri;
proxy_set_header Host $proxy_host;
proxy_set_header X-DTS-SCHEMA daily.demo;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
location / {
try_files $uri $uri/ @router;#需要指向下面的@router否则会出现vue的路由在nginx中刷新出现404
root /dvadmin-ui/dist/;
add_header Cache-Control max-age=no-cache;
index index.html index.php index.htm;
}
location ~* \.(css|js|png|jpg|jpeg|gif|gz|svg|mp4|ogg|ogv|webm|htc|xml|woff)$ {
access_log off;
add_header Cache-Control max-age=604800;
root /dvadmin-ui/dist/;
index index.html index.php index.htm;
}
location @router {
rewrite ^.*$ /index.html last;
}
access_log /var/log/nginx/daily.demo-443.access.log;
error_log /var/log/nginx/daily.demo-443.error.log;
}

View File

@ -1,44 +0,0 @@
## 将HTTP请求全部重定向至HTTPS
server {
listen 80;
server_name demo.django-vue-admin.com;
charset utf-8;
access_log /var/log/nginx/demo-80.access.log;
error_log /var/log/nginx/demo-80.error.log;
rewrite ^(.*)$ https://${server_name}$1 permanent;
}
server {
listen 443 ssl;
server_name demo.django-vue-admin.com;
root /vadmin-doc/;#项目路径
charset utf-8;
ssl_certificate /nginx/keys/demo.django-vue-admin.com.crt;#.pem证书路径
ssl_certificate_key /nginx/keys/demo.django-vue-admin.com.key;#.key证书路径
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
error_page 497 https://$host$request_uri;
proxy_set_header Host $proxy_host;
proxy_set_header X-DTS-SCHEMA demo;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
location / {
try_files $uri $uri/ @router;#需要指向下面的@router否则会出现vue的路由在nginx中刷新出现404
root /dvadmin-ui/dist/;
add_header Cache-Control max-age=no-cache;
index index.html index.php index.htm;
}
location ~* \.(css|js|png|jpg|jpeg|gif|gz|svg|mp4|ogg|ogv|webm|htc|xml|woff)$ {
access_log off;
add_header Cache-Control max-age=604800;
root /dvadmin-ui/dist/;
index index.html index.php index.htm;
}
location @router {
rewrite ^.*$ /index.html last;
}
access_log /var/log/nginx/demo-443.access.log;
error_log /var/log/nginx/demo-443.error.log;
}

View File

@ -1,37 +0,0 @@
## 将HTTP请求全部重定向至HTTPS
server {
listen 80;
server_name django-vue-admin.com;
charset utf-8;
access_log /var/log/nginx/www-80.access.log;
error_log /var/log/nginx/www-80.error.log;
rewrite ^(.*)$ https://${server_name}$1 permanent;
}
server {
listen 443 ssl;
server_name django-vue-admin.com;
root /vadmin-doc/;#项目路径
charset utf-8;
ssl_certificate /nginx/keys/www.django-vue-admin.com.crt;#.pem证书路径
ssl_certificate_key /nginx/keys/www.django-vue-admin.com.key;#.key证书路径
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
error_page 497 https://$host$request_uri;
proxy_set_header Host $proxy_host;
proxy_set_header X-DTS-SCHEMA www;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
location / {
try_files $uri $uri/ @router;#需要指向下面的@router否则会出现vue的路由在nginx中刷新出现404
root /dvadmin-doc/docs/.vuepress/dist/;
index index.html index.php index.htm;
}
location @router {
rewrite ^.*$ /index.html last;
}
access_log /var/log/nginx/www-443.access.log;
error_log /var/log/nginx/www-443.error.log;
}

View File

@ -1,37 +0,0 @@
## 将HTTP请求全部重定向至HTTPS
server {
listen 80;
server_name www.django-vue-admin.com;
charset utf-8;
access_log /var/log/nginx/www-80.access.log;
error_log /var/log/nginx/www-80.error.log;
rewrite ^(.*)$ https://${server_name}$1 permanent;
}
server {
listen 443 ssl;
server_name www.django-vue-admin.com;
root /vadmin-doc/;#项目路径
charset utf-8;
ssl_certificate /nginx/keys/www.django-vue-admin.com.crt;#.pem证书路径
ssl_certificate_key /nginx/keys/www.django-vue-admin.com.key;#.key证书路径
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
error_page 497 https://$host$request_uri;
proxy_set_header Host $proxy_host;
proxy_set_header X-DTS-SCHEMA www;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
location / {
try_files $uri $uri/ @router;#需要指向下面的@router否则会出现vue的路由在nginx中刷新出现404
root /dvadmin-doc/docs/.vuepress/dist/;
index index.html index.php index.htm;
}
location @router {
rewrite ^.*$ /index.html last;
}
access_log /var/log/nginx/www-443.access.log;
error_log /var/log/nginx/www-443.error.log;
}

View File

@ -1,5 +0,0 @@
FROM node:12
COPY ./dvadmin-ui/package.json /
RUN npm install --registry=https://registry.npm.taobao.org
#RUN npm run build:prod
#CMD ["npm","run","dev"]

View File

@ -21,7 +21,7 @@ from conf.env import *
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0,os.path.join(BASE_DIR,'apps'))
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
@ -54,6 +54,7 @@ INSTALLED_APPS = [
]
MIDDLEWARE = [
'vadmin.op_drf.middleware.PermissionModeMiddleware', # 权限中间件
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
@ -202,7 +203,7 @@ LOGGING = {
'loggers': {
# default日志
'': {
'handlers': ['console','error','file'],
'handlers': ['console', 'error', 'file'],
'level': 'INFO',
},
# 数据库相关日志
@ -239,7 +240,6 @@ else:
}
}
connect(MONGO_DATABASE_NAME, host=os.getenv('MONGO_HOST') or MONGO_HOST, port=MONGO_PORT, serverSelectionTimeoutMS=1000, connect=False)
# redis 缓存
REDIS_URL = f'redis://:{REDIS_PASSWORD if REDIS_PASSWORD else ""}@{os.getenv("REDIS_HOST") or REDIS_HOST}:{REDIS_PORT}/{REDIS_DB}'
CACHES = {
@ -301,24 +301,30 @@ USERNAME_FIELD = 'username'
# ************** 登录验证码配置 ************** #
# ================================================= #
CAPTCHA_STATE = CAPTCHA_STATE
#字母验证码
CAPTCHA_IMAGE_SIZE = (160, 60) # 设置 captcha 图片大小
CAPTCHA_LENGTH = 4 # 字符个数
CAPTCHA_TIMEOUT = 1 # 超时(minutes)
#加减乘除验证码
# 字母验证码
CAPTCHA_IMAGE_SIZE = (160, 60) # 设置 captcha 图片大小
CAPTCHA_LENGTH = 4 # 字符个数
CAPTCHA_TIMEOUT = 1 # 超时(minutes)
# 加减乘除验证码
CAPTCHA_OUTPUT_FORMAT = '%(image)s %(text_field)s %(hidden_field)s '
CAPTCHA_FONT_SIZE = 40 # 字体大小
CAPTCHA_FONT_SIZE = 40 # 字体大小
CAPTCHA_FOREGROUND_COLOR = '#0033FF' # 前景色
CAPTCHA_BACKGROUND_COLOR = '#F5F7F4' # 背景色
CAPTCHA_NOISE_FUNCTIONS = (
# 'captcha.helpers.noise_arcs', # 线
# 'captcha.helpers.noise_dots', # 点
)
# 'captcha.helpers.noise_arcs', # 线
# 'captcha.helpers.noise_dots', # 点
)
# CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.random_char_challenge'
CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.math_challenge'
API_LOG_ENABLE = True
# API_LOG_METHODS = 'ALL' # ['POST', 'DELETE']
# API_LOG_METHODS = ['POST', 'DELETE'] # ['POST', 'DELETE']
BROKER_URL = f'redis://:{REDIS_PASSWORD if REDIS_PASSWORD else ""}@{os.getenv("REDIS_HOST") or REDIS_HOST}:{REDIS_PORT}/2' #Broker使用Redis, 使用0数据库(暂时不是很清楚原理)
CELERYBEAT_SCHEDULER = 'django_celery_beat.schedulers.DatabaseScheduler' #Backend数据库
BROKER_URL = f'redis://:{REDIS_PASSWORD if REDIS_PASSWORD else ""}@{os.getenv("REDIS_HOST") or REDIS_HOST}:' \
f'{REDIS_PORT}/{locals().get("CELERY_DB", 2)}' # Broker使用Redis
CELERYBEAT_SCHEDULER = 'django_celery_beat.schedulers.DatabaseScheduler' # Backend数据库
# ================================================= #
# ************** 其他配置 ************** #
# ================================================= #
# 接口权限
INTERFACE_PERMISSION = {locals().get("INTERFACE_PERMISSION", False)}

View File

@ -22,7 +22,7 @@ from django.urls import re_path, include
from django.views.static import serve
from rest_framework.views import APIView
from apps.vadmin.op_drf.response import SuccessResponse
from vadmin.utils.response import SuccessResponse
class CaptchaRefresh(APIView):

View File

@ -10,7 +10,6 @@ from django.utils import six
from mongoengine.queryset import visitor
from rest_framework.filters import BaseFilterBackend, SearchFilter, OrderingFilter
from ..permission.models import Dept
from ..utils.model_util import get_dept
logger = logging.getLogger(__name__)
@ -119,7 +118,7 @@ class DataLevelPermissionsFilter(BaseFilterBackend):
return queryset.none()
# 1. 判断过滤的数据是否有创建人所在部门 "dept_belong_id" 字段
if not hasattr(queryset.model, 'dept_belong_id'):
if not getattr(queryset.model, 'dept_belong_id', None):
return queryset
# 2. 如果用户没有关联角色则返回本部门数据
@ -127,7 +126,7 @@ class DataLevelPermissionsFilter(BaseFilterBackend):
return queryset.filter(dept_belong_id=user_dept_id)
# 3. 根据所有角色 获取所有权限范围
role_list = request.user.role.all().values('admin', 'dataScope')
role_list = request.user.role.filter(status='1').values('admin', 'dataScope')
dataScope_list = []
for ele in role_list:
# 3.1 判断用户是否为超级管理员角色/如果有1(所有数据) 则返回所有数据
@ -138,16 +137,15 @@ class DataLevelPermissionsFilter(BaseFilterBackend):
# 4. 只为仅本人数据权限时只返回过滤本人数据,并且部门为自己本部门(考虑到用户会变部门,只能看当前用户所在的部门数据)
if dataScope_list == ['5']:
return queryset.filter(creator=request.user, dept_belong_id=request.user.dept_id)
return queryset.filter(creator=request.user, dept_belong_id=user_dept_id)
# 5. 自定数据权限 获取部门,根据部门过滤
dept_list = []
for ele in dataScope_list:
if ele == '2':
dept_list.extend(request.user.role.all().values_list('dept__id', flat=True))
dept_list.extend(request.user.role.filter(status='1').values_list('dept__id', flat=True))
elif ele == '3':
dept_list.append(user_dept_id)
elif ele == '4':
dept_list.extend(get_dept(user_dept_id,))
dept_list.extend(get_dept(user_dept_id, ))
return queryset.filter(dept_belong_id__in=list(set(dept_list)))

View File

@ -1,14 +1,20 @@
"""
django中间件
"""
import logging
import os
from django.conf import settings
from django.contrib.auth.models import AnonymousUser
from django.utils.deprecation import MiddlewareMixin
from apps.vadmin.permission.models import Menu
from apps.vadmin.system.models import OperationLog
from ..utils.request_util import get_request_ip, get_request_data, get_request_path, get_browser, get_os, \
get_login_location
get_login_location, get_request_canonical_path, get_request_user
from ..utils.response import ErrorJsonResponse
logger = logging.getLogger(__name__)
class ApiLoggingMiddleware(MiddlewareMixin):
@ -77,3 +83,78 @@ class PermissionModeMiddleware(MiddlewareMixin):
"""
权限模式拦截判断
"""
def process_request(self, request):
"""
判断环境变量中是否为演示模式(正常可忽略此判断)
:param request:
:return:
"""
white_list = ['/admin/logout/', '/admin/login/']
if os.getenv('DEMO_ENV') and not request.method == 'GET' and request.path not in white_list:
return ErrorJsonResponse(data={}, msg=f'演示模式,不允许操作!')
def has_interface_permission(self, request, method, view_path, user=None):
"""
接口权限验证,优先级:
(1)接口是否接入权限管理, :继续; :通过
(2)认证的user是否superuser, :通过; :继续
(3)user的角色有该接口权限, :通过, :不通过
auth_code含义: auth_code >=0, 表示接口认证通过; auth_code < 0, 表示无接口访问权限, 具体含义如下
-1:
-10: 该请求已认证的用户没有这个接口的访问权限
0:
1: 白名单
10: 该接口没有录入权限系统, 放行 请求中认证的用户为超级管理员, 直接放行
20: 请求中认证的用户是superuser放行
30: 请求中认证的用户对应的角色中,某个角色包含了该接口的访问权限, 放行
1. 先获取所有录入系统的接口
2 判断此用户是否为 superuser
3. 获取此用户所请求的接口
4. 获取此用户关联角色所有有权限的接口
:param interface: 接口模型
:param path: 接口路径
:param method: 请求方法
:param project: 接口所属项目
:param args:
:param kwargs:
:return:
"""
interface_dict = Menu.get_interface_dict()
# (1) 接口是否接入权限管理, 是:继续; 否:通过
if not view_path in interface_dict.get(method, []):
return 10
# (2)认证的user是否superuser, 是:通过; 否:继续
if user.is_superuser or (hasattr(user, 'role') and user.role.filter(status='1', admin=True).count()):
return 20
# (3)user的角色有该接口权限, 是:通过, 否:不通过
if view_path in user.get_user_interface_dict:
return 30
return -10
def process_view(self, request, view_func, view_args, view_kwargs):
if not settings.INTERFACE_PERMISSION:
return
user = get_request_user(request)
if user and not isinstance(user, AnonymousUser):
method = request.method.upper()
if method == 'GET': # GET 不设置接口权限
return
view_path = get_request_canonical_path(request, *view_args, **view_kwargs)
auth_code = self.has_interface_permission(request, method, view_path, user)
logger.info(f"[{user.username}] {method}:{view_path}, 权限认证:{auth_code}")
if auth_code >= 0:
return
return ErrorJsonResponse(data={}, msg=f'无接口访问权限!')
def process_response(self, request, response):
"""
主要请求处理完之后记录
:param request:
:param response:
:return:
"""
return response

View File

@ -320,12 +320,13 @@ class ImportSerializerMixin:
updateSupport = request.data.get('updateSupport')
# 从excel中组织对应的数据结构然后使用序列化器保存
data = excel_to_data(request.data.get('file_url'), self.import_field_data)
unique_list = [ele.attname for ele in self.get_queryset().model._meta.get_fields() if
queryset = self.filter_queryset(self.get_queryset())
unique_list = [ele.attname for ele in queryset.model._meta.get_fields() if
hasattr(ele, 'unique') and ele.unique == True]
for ele in data:
# 获取 unique 字段
filter_dic = {i: ele.get(i) for i in list(set(self.import_field_data.keys()) & set(unique_list))}
instance = self.get_queryset().filter(**filter_dic).first()
instance = queryset.filter(**filter_dic).first()
if instance and not updateSupport:
continue
if not filter_dic:
@ -357,6 +358,7 @@ class ExportSerializerMixin:
"'%s' 请配置对应的导出模板字段。"
% self.__class__.__name__
)
data = self.export_serializer_class(self.get_queryset(), many=True).data
queryset = self.filter_queryset(self.get_queryset())
data = self.export_serializer_class(queryset, many=True).data
return SuccessResponse(export_excel_save_model(request, self.export_field_data, data,
f'导出{get_verbose_name(self.get_queryset())}.xls'))
f'导出{get_verbose_name(queryset)}.xls'))

View File

@ -20,6 +20,7 @@ class CustomModelSerializer(ModelSerializer):
# 添加默认时间返回格式
create_datetime = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False, read_only=True)
update_datetime = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False, read_only=True)
creator_name = serializers.SlugRelatedField(slug_field="username", source="creator", read_only=True)
def __init__(self, instance=None, data=empty, request=None, **kwargs):
super().__init__(instance, data, **kwargs)

View File

@ -1,4 +1,5 @@
from django.db.models import IntegerField, ForeignKey, CharField, CASCADE
from django.core.cache import cache
from django.db.models import IntegerField, ForeignKey, CharField, CASCADE, Q
from ...op_drf.models import CoreModel
@ -34,6 +35,31 @@ class Menu(CoreModel):
visible = CharField(max_length=8, verbose_name="显示状态")
isCache = CharField(max_length=8, verbose_name="是否缓存")
@classmethod
def get_interface_dict(cls):
"""
获取所有接口列表
:return:
"""
interface_dict = cache.get('permission_interface_dict', {})
if not interface_dict:
for ele in Menu.objects.filter(~Q(interface_path=''), ~Q(interface_path=None), status='1', ).values(
'interface_path', 'interface_method'):
if ele.get('interface_method') in interface_dict:
interface_dict[ele.get('interface_method', '')].append(ele.get('interface_path'))
else:
interface_dict[ele.get('interface_method', '')] = [ele.get('interface_path')]
cache.set('permission_interface_dict', interface_dict, 84600)
return interface_dict
@classmethod
def delete_cache(cls):
"""
清空缓存中的接口列表
:return:
"""
cache.delete('permission_interface_dict')
class Meta:
verbose_name = '菜单管理'
verbose_name_plural = verbose_name

View File

@ -1,6 +1,7 @@
from uuid import uuid4
from django.contrib.auth.models import UserManager, AbstractUser
from django.core.cache import cache
from django.db.models import IntegerField, ForeignKey, CharField, TextField, ManyToManyField, CASCADE
from ...op_drf.fields import CreateDateTimeField, UpdateDateTimeField
@ -28,6 +29,29 @@ class UserProfile(AbstractUser):
create_datetime = CreateDateTimeField()
update_datetime = UpdateDateTimeField()
@property
def get_user_interface_dict(self):
interface_dict = cache.get(f'permission_interface_dict{self.username}', {})
if not interface_dict:
for ele in self.role.filter(status='1', menu__status='1').values('menu__interface_path',
'menu__interface_method').distinct():
interface_path = ele.get('menu__interface_path')
if interface_path is None or interface_path == '':
continue
if ele.get('menu__interface_method') in interface_dict:
interface_dict[ele.get('menu__interface_method', '')].append(interface_path)
else:
interface_dict[ele.get('menu__interface_method', '')] = [interface_path]
cache.set(f'permission_interface_dict_{self.username}', interface_dict, 84600)
return interface_dict
@property
def delete_cache(self):
"""
清空缓存中的接口列表
:return:
"""
return cache.delete(f'permission_interface_dict_{self.username}')
class Meta:
verbose_name = '用户管理'
verbose_name_plural = verbose_name

View File

@ -0,0 +1,95 @@
"""
常用的Permission以及DRF的Permission
@author: ruoxing
"""
import logging
from django.contrib.auth import get_user_model
from rest_framework.permissions import (BasePermission,
)
from rest_framework.request import Request
from rest_framework.views import APIView
from ..utils.model_util import get_dept
logger = logging.getLogger(__name__)
User = get_user_model()
class CustomPermission(BasePermission):
def __init__(self, message=None) -> None:
super().__init__()
self.message = getattr(self.__class__, 'message', '无权限')
self.user: User = None
def init_permission(self, request: Request, view: APIView):
self.user = request.user
def has_permission(self, request: Request, view: APIView):
return True
def has_object_permission(self, request: Request, view: APIView, obj):
return True
class CommonPermission(CustomPermission):
"""
通用权限类判断用户是否有这条数据的查询权限如没有则直接没有操作权限
0. 获取用户的部门id没有部门则返回 False
1. 判断过滤的数据是否有创建人所在部门 "dept_belong_id" 字段没有则返回 True
2. 如果用户没有关联角色则校验该数据是否属于本部门
3. 根据所有角色 获取所有权限范围
3.1 判断用户是否为超级管理员角色/如果有1(所有数据) 则有权限操作
4. 只为仅本人数据权限时只有操作本人数据权限并且部门为自己本部门(考虑到用户会变部门只能看当前用户所在的部门数据)
5. 自定数据权限 获取部门根据部门判断是否有权限操作
"""
message = '没有有操作权限'
def check_queryset(self, request, instance):
# 0. 获取用户的部门id没有部门则返回 False
user_dept_id = getattr(request.user, 'dept_id')
if not user_dept_id:
self.message = "该用户无部门,无权限操作!"
return False
# 1. 判断过滤的数据是否有创建人所在部门 "dept_belong_id" 字段,没有则返回 True
if not getattr(instance, 'dept_belong_id', None):
return True
# 2. 如果用户没有关联角色则校验该数据是否属于本部门
if not hasattr(request.user, 'role'):
self.message = "该用户无角色,无权限操作!"
return False
# 3. 根据所有角色 获取所有权限范围
role_list = request.user.role.filter(status='1').values('admin', 'dataScope')
dataScope_list = []
for ele in role_list:
# 3.1 判断用户是否为超级管理员角色/如果有1(所有数据) 则有权限操作
if '1' == ele.get('dataScope') or ele.get('admin') == True:
return True
dataScope_list.append(ele.get('dataScope'))
dataScope_list = list(set(dataScope_list))
# 4. 只为仅本人数据权限时只有操作本人数据权限,并且部门为自己本部门(考虑到用户会变部门,只能看当前用户所在的部门数据)
if dataScope_list == ['5']:
return int(instance.dept_belong_id) == user_dept_id and request.user == instance.creator
# 5. 自定数据权限 获取部门,根据部门判断,是否有权限操作
dept_list = []
for ele in dataScope_list:
if ele == '2':
dept_list.extend(request.user.role.filter(status='1').values_list('dept__id', flat=True))
elif ele == '3':
dept_list.append(user_dept_id)
elif ele == '4':
dept_list.extend(get_dept(user_dept_id, ))
return int(instance.dept_belong_id) in list(set(dept_list))
def has_permission(self, request: Request, view: APIView):
return True
def has_object_permission(self, request: Request, view: APIView, instance):
self.message = f"没有此数据操作权限!"
res = self.check_queryset(request, instance)
return res

View File

@ -37,6 +37,10 @@ class MenuCreateUpdateSerializer(CustomModelSerializer):
# raise APIException(message=f'仅Manger能创建/更新角色为公共角色')
return super().validate(attrs)
def save(self, **kwargs):
Menu.delete_cache()
return super().save(**kwargs)
class Meta:
model = Menu
fields = '__all__'
@ -91,7 +95,7 @@ class DeptTreeSerializer(serializers.ModelSerializer):
class Meta:
model = Dept
fields = ('id', 'label', 'parentId')
fields = ('id', 'label', 'parentId', 'status')
# ================================================= #
@ -216,7 +220,7 @@ class UserProfileSerializer(CustomModelSerializer):
unread_msg_count = serializers.SerializerMethodField(read_only=True)
def get_admin(self, obj: UserProfile):
role_list = obj.role.all().values_list('admin', flat=True)
role_list = obj.role.filter(status='1').values_list('admin', flat=True)
if True in list(set(role_list)):
return True
return False
@ -261,7 +265,7 @@ class UserProfileCreateUpdateSerializer(CustomModelSerializer):
})
def get_admin(self, obj: UserProfile):
role_list = obj.role.all().values_list('admin', flat=True)
role_list = obj.role.filter(status='1').values_list('admin', flat=True)
if True in list(set(role_list)):
return True
return False

View File

@ -2,6 +2,7 @@ from django.contrib.auth import authenticate
from rest_framework.request import Request
from rest_framework.views import APIView
from .permissions import CommonPermission
from ..op_drf.filters import DataLevelPermissionsFilter
from ..op_drf.viewsets import CustomModelViewSet
from ..permission.filters import MenuFilter, DeptFilter, PostFilter, RoleFilter, UserProfileFilter
@ -12,7 +13,6 @@ from ..permission.serializers import UserProfileSerializer, MenuSerializer, Role
PostSimpleSerializer, RoleSimpleSerializer, ExportUserProfileSerializer, ExportRoleSerializer, ExportPostSerializer, \
UserProfileImportSerializer
from ..system.models import DictDetails
from ..utils.export_excel import export_excel_save_model
from ..utils.response import SuccessResponse, ErrorResponse
@ -25,6 +25,7 @@ class GetUserProfileView(APIView):
user_dict = UserProfileSerializer(request.user).data
permissions_list = ['*:*:*'] if user_dict.get('admin') else Menu.objects.filter(
role__userprofile=request.user).values_list('perms', flat=True)
delete_cache = request.user.delete_cache
return SuccessResponse({
'permissions': [ele for ele in permissions_list if ele],
'roles': Role.objects.filter(userprofile=request.user).values_list('roleKey', flat=True),
@ -78,9 +79,9 @@ class MenuModelViewSet(CustomModelViewSet):
update_serializer_class = MenuCreateUpdateSerializer
filter_class = MenuFilter
extra_filter_backends = [DataLevelPermissionsFilter]
# update_extra_permission_classes = (IsManagerPermission,)
# destroy_extra_permission_classes = (IsManagerPermission,)
# create_extra_permission_classes = (IsManagerPermission,)
update_extra_permission_classes = (CommonPermission,)
destroy_extra_permission_classes = (CommonPermission,)
create_extra_permission_classes = (CommonPermission,)
search_fields = ('name',)
ordering = 'create_datetime' # 默认排序
@ -127,9 +128,9 @@ class DeptModelViewSet(CustomModelViewSet):
update_serializer_class = DeptCreateUpdateSerializer
filter_class = DeptFilter
extra_filter_backends = [DataLevelPermissionsFilter]
# update_extra_permission_classes = (IsManagerPermission,)
# destroy_extra_permission_classes = (IsManagerPermission,)
# create_extra_permission_classes = (IsManagerPermission,)
update_extra_permission_classes = (CommonPermission,)
destroy_extra_permission_classes = (CommonPermission,)
create_extra_permission_classes = (CommonPermission,)
search_fields = ('deptName',)
ordering = 'create_datetime' # 默认排序
@ -192,23 +193,13 @@ class PostModelViewSet(CustomModelViewSet):
update_serializer_class = PostCreateUpdateSerializer
filter_class = PostFilter
extra_filter_backends = [DataLevelPermissionsFilter]
# update_extra_permission_classes = (IsManagerPermission,)
# destroy_extra_permission_classes = (IsManagerPermission,)
# create_extra_permission_classes = (IsManagerPermission,)
update_extra_permission_classes = (CommonPermission,)
destroy_extra_permission_classes = (CommonPermission,)
create_extra_permission_classes = (CommonPermission,)
search_fields = ('postName',)
ordering = ['postSort', 'create_datetime'] # 默认排序
def export(self, request: Request, *args, **kwargs):
"""
导出岗位
:param request:
:param args:
:param kwargs:
:return:
"""
field_data = ['岗位序号', '岗位编码', '岗位名称', '岗位排序', '状态', '创建者', '修改者', '备注']
data = ExportPostSerializer(Post.objects.all(), many=True).data
return SuccessResponse(export_excel_save_model(request, field_data, data, '导出岗位数据.xls'))
export_field_data = ['岗位序号', '岗位编码', '岗位名称', '岗位排序', '状态', '创建者', '修改者', '备注']
export_serializer_class = ExportPostSerializer
class RoleModelViewSet(CustomModelViewSet):
@ -221,23 +212,13 @@ class RoleModelViewSet(CustomModelViewSet):
update_serializer_class = RoleCreateUpdateSerializer
filter_class = RoleFilter
extra_filter_backends = [DataLevelPermissionsFilter]
# update_extra_permission_classes = (IsManagerPermission,)
# destroy_extra_permission_classes = (IsManagerPermission,)
# create_extra_permission_classes = (IsManagerPermission,)
update_extra_permission_classes = (CommonPermission,)
destroy_extra_permission_classes = (CommonPermission,)
create_extra_permission_classes = (CommonPermission,)
search_fields = ('roleName',)
ordering = 'create_datetime' # 默认排序
def export(self, request: Request, *args, **kwargs):
"""
导出角色
:param request:
:param args:
:param kwargs:
:return:
"""
field_data = ['角色序号', '角色名称', '角色权限', '角色排序', '数据范围', '角色状态', '创建者', '修改者', '备注']
data = ExportRoleSerializer(Role.objects.all(), many=True).data
return SuccessResponse(export_excel_save_model(request, field_data, data, '导出角色数据.xls'))
export_field_data = ['角色序号', '角色名称', '角色权限', '角色排序', '数据范围', '角色状态', '创建者', '修改者', '备注']
export_serializer_class = ExportRoleSerializer
class UserProfileModelViewSet(CustomModelViewSet):
@ -259,9 +240,9 @@ class UserProfileModelViewSet(CustomModelViewSet):
'gender': '用户性别(男/女/未知)',
'is_active': '帐号状态(启用/禁用)', 'password': '登录密码', 'dept': '部门ID', 'role': '角色ID',
'post': '岗位ID'}
# update_extra_permission_classes = (IsManagerPermission,)
# destroy_extra_permission_classes = (IsManagerPermission,)
# create_extra_permission_classes = (IsManagerPermission,)
update_extra_permission_classes = (CommonPermission,)
destroy_extra_permission_classes = (CommonPermission,)
create_extra_permission_classes = (CommonPermission,)
search_fields = ('username',)
ordering = 'create_datetime' # 默认排序
@ -291,8 +272,8 @@ class UserProfileModelViewSet(CustomModelViewSet):
"""
userId = request.query_params.get('userId')
data = {
'posts': PostSimpleSerializer(Post.objects.all().order_by('postSort'), many=True).data,
'roles': RoleSimpleSerializer(Role.objects.all().order_by('roleSort'), many=True).data
'posts': PostSimpleSerializer(Post.objects.filter(status='1').order_by('postSort'), many=True).data,
'roles': RoleSimpleSerializer(Role.objects.filter(status='1').order_by('roleSort'), many=True).data
}
if userId:
instance = self.queryset.get(id=userId)

View File

@ -43,6 +43,7 @@ class SaveFileFilter(django_filters.rest_framework.FilterSet):
文件管理 简单过滤器
"""
name = django_filters.CharFilter(lookup_expr='icontains')
type = django_filters.CharFilter(lookup_expr='icontains')
class Meta:
model = SaveFile

View File

@ -1,7 +1,6 @@
from ..models.config_settings import ConfigSettings
from ..models.dict_data import DictData
from ..models.dict_details import DictDetails
from ..models.web_set import WebSet
from ..models.save_file import SaveFile
from ..models.message_push import MessagePush
from ..models.message_push import MessagePushUser

View File

@ -16,6 +16,7 @@ class SaveFile(CoreModel):
type = CharField(max_length=32, verbose_name="文件类型", null=True, blank=True)
size = CharField(max_length=64, verbose_name="文件大小", null=True, blank=True)
address = CharField(max_length=16, verbose_name="存储位置", null=True, blank=True) # 本地、阿里云、腾讯云..
source = CharField(max_length=16, verbose_name="文件来源", null=True, blank=True) # 导出、用户上传.
oss_url = CharField(max_length=200, verbose_name="OSS地址", null=True, blank=True)
status = BooleanField(default=True, verbose_name="文件是否存在")
file = FileField(verbose_name="文件URL", upload_to=files_path, )

View File

@ -1,19 +0,0 @@
from django.db.models import TextField, CharField
from ...op_drf.models import CoreModel
class WebSet(CoreModel):
name = CharField(max_length=64, verbose_name="站点名称")
web_site = CharField(max_length=256, verbose_name="站点网址", null=True, blank=True)
logo = CharField(max_length=256, verbose_name="网站Logo", null=True, blank=True)
record_info = TextField(verbose_name="备案信息", null=True, blank=True)
statistics_code = TextField(verbose_name="统计代码", null=True, blank=True)
copyright_info = TextField(verbose_name="版权信息", null=True, blank=True)
class Meta:
verbose_name = '站点设置'
verbose_name_plural = verbose_name
def __str__(self):
return f"{self.name}"

View File

@ -1,3 +1,4 @@
from django.core.cache import cache
from rest_framework import serializers
from .models import LoginInfor, OperationLog, CeleryLog
@ -79,6 +80,10 @@ class DictDetailsCreateUpdateSerializer(CustomModelSerializer):
字典详情 创建/更新时的列化器
"""
def save(self, **kwargs):
cache.delete('system_dict_details')
return super().save(**kwargs)
class Meta:
model = DictDetails
fields = '__all__'
@ -114,13 +119,17 @@ class ConfigSettingsCreateUpdateSerializer(CustomModelSerializer):
参数设置 创建/更新时的列化器
"""
def save(self, **kwargs):
cache.delete('system_configKey')
return super().save(**kwargs)
class Meta:
model = ConfigSettings
fields = '__all__'
# ================================================= #
# ************** 参数设置 序列化器 ************** #
# ************** 文件管理 序列化器 ************** #
# ================================================= #
class SaveFileSerializer(CustomModelSerializer):
@ -136,7 +145,7 @@ class SaveFileSerializer(CustomModelSerializer):
class SaveFileCreateUpdateSerializer(CustomModelSerializer):
"""
字典详情 创建/更新时的列化器
文件管理 创建/更新时的列化器
"""
file_url = serializers.CharField(source='file.url', read_only=True)
@ -146,6 +155,7 @@ class SaveFileCreateUpdateSerializer(CustomModelSerializer):
self.validated_data['size'] = files.size
self.validated_data['type'] = files.content_type
self.validated_data['address'] = '本地存储'
self.validated_data['source'] = '用户上传'
instance = super().save(**kwargs)
# 进行判断是否需要OSS上传
return instance
@ -228,7 +238,6 @@ class LoginInforSerializer(CustomModelSerializer):
"""
登录日志 简单序列化器
"""
creator_name = serializers.SlugRelatedField(slug_field="username", source="creator", read_only=True)
class Meta:
model = LoginInfor
@ -239,7 +248,6 @@ class ExportLoginInforSerializer(CustomModelSerializer):
"""
导出 登录日志 简单序列化器
"""
creator_name = serializers.SlugRelatedField(slug_field="username", source="creator", read_only=True)
class Meta:
model = LoginInfor
@ -255,7 +263,6 @@ class OperationLogSerializer(CustomModelSerializer):
"""
操作日志 简单序列化器
"""
creator_name = serializers.SlugRelatedField(slug_field="username", source="creator", read_only=True)
class Meta:
model = OperationLog
@ -266,7 +273,6 @@ class ExportOperationLogSerializer(CustomModelSerializer):
"""
导出 操作日志 简单序列化器
"""
creator_name = serializers.SlugRelatedField(slug_field="username", source="creator", read_only=True)
class Meta:
model = OperationLog

View File

@ -20,10 +20,14 @@ urlpatterns = [
re_path('config/configKey/(?P<pk>.*)/', ConfigSettingsModelViewSet.as_view({'get': 'get_config_key'})),
# 参数管理导出
re_path('config/export/', ConfigSettingsModelViewSet.as_view({'get': 'export'})),
# 清理参数缓存
re_path('config/clearCache/', ConfigSettingsModelViewSet.as_view({'delete': 'clearCache', })),
# 导出字典管理数据
re_path('dict/type/export/', DictDataModelViewSet.as_view({'get': 'export'})),
# 导出字典详情数据
re_path('dict/data/export/', DictDetailsModelViewSet.as_view({'get': 'export'})),
# 清理字典缓存
re_path('dict/type/clearCache/', DictDetailsModelViewSet.as_view({'delete': 'clearCache', })),
# 消息通知导出
re_path('message/export/', MessagePushModelViewSet.as_view({'get': 'export', })),
# 用户个人消息列表
@ -42,5 +46,8 @@ urlpatterns = [
re_path('celery_log/clean/', CeleryLogModelViewSet.as_view({'delete': 'clean_all', })),
# 导出定时日志
re_path('celery_log/export/', CeleryLogModelViewSet.as_view({'get': 'export', })),
# 清除废弃文件
re_path('clearsavefile/', SaveFileModelViewSet.as_view({'post': 'clearsavefile', })),
]
urlpatterns += router.urls

View File

@ -1,21 +1,27 @@
import os
from django.conf import settings
from django.core.cache import cache
from django.db.models import Q
from rest_framework.request import Request
from .models import LoginInfor, OperationLog, CeleryLog
from ..op_drf.filters import DataLevelPermissionsFilter
from ..op_drf.viewsets import CustomModelViewSet
from ..permission.permissions import CommonPermission
from ..system.filters import DictDetailsFilter, DictDataFilter, ConfigSettingsFilter, MessagePushFilter, \
SaveFileFilter, LoginInforFilter, OperationLogFilter, CeleryLogFilter
from ..system.models import DictData, DictDetails, ConfigSettings, SaveFile, MessagePush
from ..system.models import MessagePushUser
from ..system.serializers import DictDataSerializer, DictDataCreateUpdateSerializer, DictDetailsSerializer, \
DictDetailsCreateUpdateSerializer, DictDetailsListSerializer, ConfigSettingsSerializer, \
DictDetailsCreateUpdateSerializer, ConfigSettingsSerializer, \
ConfigSettingsCreateUpdateSerializer, SaveFileSerializer, SaveFileCreateUpdateSerializer, \
ExportConfigSettingsSerializer, ExportDictDataSerializer, ExportDictDetailsSerializer, \
MessagePushSerializer, MessagePushCreateUpdateSerializer, ExportMessagePushSerializer, LoginInforSerializer, \
OperationLogSerializer, ExportOperationLogSerializer, ExportLoginInforSerializer, CeleryLogSerializer, \
ExportCeleryLogSerializer
from ..utils.export_excel import export_excel_save_model
from ..utils.file_util import get_all_files, remove_empty_dir, delete_files
from ..utils.response import SuccessResponse
@ -31,23 +37,13 @@ class DictDataModelViewSet(CustomModelViewSet):
# retrieve_serializer_class = DetailRoleSerializer
extra_filter_backends = [DataLevelPermissionsFilter]
filter_class = DictDataFilter
# update_extra_permission_classes = (IsManagerPermission,)
# destroy_extra_permission_classes = (IsManagerPermission,)
# create_extra_permission_classes = (IsManagerPermission,)
update_extra_permission_classes = (CommonPermission,)
destroy_extra_permission_classes = (CommonPermission,)
create_extra_permission_classes = (CommonPermission,)
search_fields = ('dictName',)
ordering = 'id' # 默认排序
def export(self, request: Request, *args, **kwargs):
"""
导出字典管理数据
:param request:
:param args:
:param kwargs:
:return:
"""
field_data = ['字典主键', '字典名称', '字典类型', '字典状态', '创建者', '修改者', '备注']
data = ExportDictDataSerializer(DictData.objects.all(), many=True).data
return SuccessResponse(export_excel_save_model(request, field_data, data, '导出参数管理数据.xls'))
export_field_data = ['字典主键', '字典名称', '字典类型', '字典状态', '创建者', '修改者', '备注']
export_serializer_class = ExportDictDataSerializer
class DictDetailsModelViewSet(CustomModelViewSet):
@ -60,9 +56,9 @@ class DictDetailsModelViewSet(CustomModelViewSet):
update_serializer_class = DictDetailsCreateUpdateSerializer
filter_class = DictDetailsFilter
extra_filter_backends = [DataLevelPermissionsFilter]
# update_extra_permission_classes = (IsManagerPermission,)
# destroy_extra_permission_classes = (IsManagerPermission,)
# create_extra_permission_classes = (IsManagerPermission,)
update_extra_permission_classes = (CommonPermission,)
destroy_extra_permission_classes = (CommonPermission,)
create_extra_permission_classes = (CommonPermission,)
search_fields = ('dictLabel',)
ordering = 'sort' # 默认排序
@ -74,11 +70,30 @@ class DictDetailsModelViewSet(CustomModelViewSet):
:param kwargs:
:return:
"""
queryset = self.queryset.filter(dict_data__dictType=kwargs.get('pk')).order_by('sort')
if hasattr(self, 'handle_logging'):
self.handle_logging(request, *args, **kwargs)
serializer = DictDetailsListSerializer(queryset, many=True)
return SuccessResponse(serializer.data)
dict_details_dic = cache.get('system_dict_details', {})
if not dict_details_dic:
queryset = self.filter_queryset(self.get_queryset())
queryset_dic = queryset.order_by('sort').values('dict_data__dictType', 'dictLabel', 'dictValue',
'is_default')
for ele in queryset_dic:
dictType = ele.pop('dict_data__dictType')
if dictType in dict_details_dic:
dict_details_dic[dictType].append(ele)
else:
dict_details_dic[dictType] = [ele]
cache.set('system_dict_details', dict_details_dic, 84600)
return SuccessResponse(dict_details_dic.get(kwargs.get('pk'), []))
def clearCache(self, request: Request, *args, **kwargs):
"""
清理键值缓存
:param request:
:param args:
:param kwargs:
:return:
"""
cache.delete('system_dict_details')
return SuccessResponse(msg='清理成功!')
def export(self, request: Request, *args, **kwargs):
"""
@ -103,12 +118,14 @@ class ConfigSettingsModelViewSet(CustomModelViewSet):
create_serializer_class = ConfigSettingsCreateUpdateSerializer
update_serializer_class = ConfigSettingsCreateUpdateSerializer
filter_class = ConfigSettingsFilter
extra_filter_backends = [DataLevelPermissionsFilter]
# update_extra_permission_classes = (IsManagerPermission,)
# destroy_extra_permission_classes = (IsManagerPermission,)
# create_extra_permission_classes = (IsManagerPermission,)
search_fields = ('configName',)
ordering = 'id' # 默认排序
extra_filter_backends = [DataLevelPermissionsFilter]
update_extra_permission_classes = (CommonPermission,)
destroy_extra_permission_classes = (CommonPermission,)
create_extra_permission_classes = (CommonPermission,)
export_field_data = ['参数主键', '参数名称', '参数键名', '参数键值', '系统内置', '参数状态', '创建者', '修改者', '备注']
export_serializer_class = ExportConfigSettingsSerializer
def get_config_key(self, request: Request, *args, **kwargs):
"""
@ -118,22 +135,24 @@ class ConfigSettingsModelViewSet(CustomModelViewSet):
:param kwargs:
:return:
"""
queryset = self.queryset.filter(configKey=kwargs.get('pk')).first()
# if hasattr(self, 'handle_logging'):
# self.handle_logging(request, *args, **kwargs)
return SuccessResponse(msg=queryset.configValue if queryset else '')
config_key_dic = cache.get('system_configKey')
if not config_key_dic:
queryset = self.filter_queryset(self.get_queryset())
config_key_dic = {ele.get('configKey'): ele.get('configValue') for ele in
queryset.values('configValue', 'configKey')}
cache.set('system_configKey', config_key_dic, 84600)
return SuccessResponse(msg=config_key_dic.get(kwargs.get('pk'), ''))
def export(self, request: Request, *args, **kwargs):
def clearCache(self, request: Request, *args, **kwargs):
"""
导出参数管理数据
清理键值缓存
:param request:
:param args:
:param kwargs:
:return:
"""
field_data = ['参数主键', '参数名称', '参数键名', '参数键值', '系统内置', '参数状态', '创建者', '修改者', '备注']
data = ExportConfigSettingsSerializer(ConfigSettings.objects.all(), many=True).data
return SuccessResponse(export_excel_save_model(request, field_data, data, '导出参数管理数据.xls'))
cache.delete('system_configKey')
return SuccessResponse(msg='清理成功!')
class SaveFileModelViewSet(CustomModelViewSet):
@ -146,9 +165,32 @@ class SaveFileModelViewSet(CustomModelViewSet):
update_serializer_class = SaveFileCreateUpdateSerializer
filter_class = SaveFileFilter
extra_filter_backends = [DataLevelPermissionsFilter]
update_extra_permission_classes = (CommonPermission,)
destroy_extra_permission_classes = (CommonPermission,)
create_extra_permission_classes = (CommonPermission,)
search_fields = ('configName',)
ordering = '-create_datetime' # 默认排序
def clearsavefile(self, request: Request, *args, **kwargs):
"""
清理废弃文件
:param request:
:param args:
:param kwargs:
:return:
"""
# 获取废弃文件列表
file_list = get_all_files(os.path.join(settings.MEDIA_ROOT, 'system'))
queryset_files = [os.path.join(os.path.join(settings.MEDIA_ROOT) + os.sep, ele) for ele in
list(self.get_queryset().values_list('file', flat=True))]
delete_list = list(set(file_list) - set(queryset_files))
# 进行文件删除操作
delete_files(delete_list)
# 递归删除空文件
remove_empty_dir(os.path.join(settings.MEDIA_ROOT, 'system'))
return SuccessResponse(msg=f"成功清理废弃文件{len(delete_list)}")
class MessagePushModelViewSet(CustomModelViewSet):
"""
@ -159,8 +201,14 @@ class MessagePushModelViewSet(CustomModelViewSet):
create_serializer_class = MessagePushCreateUpdateSerializer
update_serializer_class = MessagePushCreateUpdateSerializer
extra_filter_backends = [DataLevelPermissionsFilter]
update_extra_permission_classes = (CommonPermission,)
destroy_extra_permission_classes = (CommonPermission,)
create_extra_permission_classes = (CommonPermission,)
filter_class = MessagePushFilter
ordering = "-update_datetime" # 默认排序
export_field_data = ['消息序号', '标题', '内容', '消息类型', '是否审核', '消息状态', '通知接收消息用户',
'创建者', '修改者', '修改时间', '创建时间']
export_serializer_class = ExportMessagePushSerializer
def get_user_messages(self, request: Request, *args, **kwargs):
"""
@ -170,11 +218,12 @@ class MessagePushModelViewSet(CustomModelViewSet):
is_read = request.query_params.get('is_read', None)
if is_read:
if is_read == 'False':
queryset = queryset.filter(Q(messagepushuser_message_push__is_read=is_read) | Q(user=None))
else:
queryset = queryset.filter(messagepushuser_message_push__is_read=is_read)
queryset = queryset.filter(is_reviewed=True)
queryset = queryset.exclude(Q(messagepushuser_message_push__is_read=True),
Q(messagepushuser_message_push__user=request.user))
elif is_read == 'True':
queryset = queryset.filter(messagepushuser_message_push__is_read=True,
messagepushuser_message_push__user=request.user)
queryset = queryset.filter(is_reviewed=True).distinct()
page = self.paginate_queryset(queryset)
if hasattr(self, 'handle_logging'):
self.handle_logging(request, *args, **kwargs)
@ -197,18 +246,6 @@ class MessagePushModelViewSet(CustomModelViewSet):
instance.save()
return SuccessResponse()
def export(self, request: Request, *args, **kwargs):
"""
导出岗位
:param request:
:param args:
:param kwargs:
:return:
"""
field_data = ['消息序号', '标题', '内容', '消息类型', '是否审核', '消息状态', '通知接收消息用户', '创建者', '修改者', '修改时间', '创建时间']
data = ExportMessagePushSerializer(MessagePush.objects.all(), many=True).data
return SuccessResponse(export_excel_save_model(request, field_data, data, '导出岗位数据.xls'))
class LoginInforModelViewSet(CustomModelViewSet):
"""
@ -218,6 +255,9 @@ class LoginInforModelViewSet(CustomModelViewSet):
serializer_class = LoginInforSerializer
filter_class = LoginInforFilter
extra_filter_backends = [DataLevelPermissionsFilter]
update_extra_permission_classes = (CommonPermission,)
destroy_extra_permission_classes = (CommonPermission,)
create_extra_permission_classes = (CommonPermission,)
ordering = '-create_datetime' # 默认排序
export_field_data = ['访问编号', '用户名称', '登录地址', '登录地点', '浏览器', '操作系统',
'登录状态', '操作信息', '登录日期']
@ -243,6 +283,9 @@ class OperationLogModelViewSet(CustomModelViewSet):
serializer_class = OperationLogSerializer
filter_class = OperationLogFilter
extra_filter_backends = [DataLevelPermissionsFilter]
update_extra_permission_classes = (CommonPermission,)
destroy_extra_permission_classes = (CommonPermission,)
create_extra_permission_classes = (CommonPermission,)
ordering = '-create_datetime' # 默认排序
export_field_data = ['请求模块', '请求地址', '请求参数', '请求方式', '操作说明', '请求ip地址',
'请求浏览器', '响应状态码', '操作地点', '操作系统', '返回信息', '响应状态', '操作用户名']
@ -266,6 +309,10 @@ class CeleryLogModelViewSet(CustomModelViewSet):
"""
queryset = CeleryLog.objects.all()
serializer_class = CeleryLogSerializer
extra_filter_backends = [DataLevelPermissionsFilter]
update_extra_permission_classes = (CommonPermission,)
destroy_extra_permission_classes = (CommonPermission,)
create_extra_permission_classes = (CommonPermission,)
filter_class = CeleryLogFilter
ordering = '-create_datetime' # 默认排序
export_field_data = ['任务名称', '执行参数', '执行时间', '运行状态', '任务结果', '创建时间']

View File

@ -22,9 +22,9 @@ from django.urls import re_path, include
from rest_framework.documentation import include_docs_urls
from rest_framework.views import APIView
from .op_drf.response import SuccessResponse
from .permission.views import GetUserProfileView, GetRouters
from .utils.login import LoginView, LogoutView
from .utils.response import SuccessResponse
class CaptchaRefresh(APIView):

View File

@ -134,7 +134,9 @@ def export_excel_save_model(request, field_data, data, FilName):
savefile.type = 'application/vnd.ms-excel'
savefile.size = os.path.getsize(os.path.join(settings.MEDIA_ROOT, file_rul))
savefile.address = '本地存储'
savefile.source = '导出'
savefile.creator = request.user
savefile.dept_belong_id = getattr(request.user, 'dept_id', None)
savefile.modifier = request.user.username
savefile.save()
return SaveFileSerializer(savefile).data

View File

@ -0,0 +1,48 @@
"""
封装文件操作:
递归读取所有文件目录形成列表
递归删除空目录
批量删除文件
"""
import os
def get_all_files(targetDir):
"""
递归读取所有文件目录形成列表
:param targetDir:
:return:
"""
files = []
listFiles = os.listdir(targetDir)
for i in range(0, len(listFiles)):
path = os.path.join(targetDir, listFiles[i])
if os.path.isdir(path):
files.extend(get_all_files(path))
elif os.path.isfile(path):
files.append(path)
return files
def remove_empty_dir(path):
"""
递归删除空目录
:param path:
:return:
"""
for root, dirs, files in os.walk(path, topdown=False):
if not files and not dirs:
os.rmdir(root)
def delete_files(delete_list: list):
"""
批量删除文件
:param delete_list:
:return:
"""
for file_path in delete_list:
try:
os.remove(file_path)
except(FileNotFoundError):
pass

View File

@ -8,10 +8,10 @@ from django.contrib.auth.models import AbstractBaseUser
from django.contrib.auth.models import AnonymousUser
from django.core.cache import cache
from django.urls.resolvers import ResolverMatch
from rest_framework.authentication import BaseAuthentication
from rest_framework.settings import api_settings as drf_settings
from user_agents import parse
from apps.vadmin.utils.authentication import OpAuthJwtAuthentication
logger = logging.getLogger(__name__)
@ -26,18 +26,8 @@ def get_request_user(request, authenticate=True):
user: AbstractBaseUser = getattr(request, 'user', None)
if user and user.is_authenticated:
return user
authentication: BaseAuthentication = None
for authentication_class in drf_settings.DEFAULT_AUTHENTICATION_CLASSES:
try:
authentication = authentication_class()
user_auth_tuple = authentication.authenticate(request)
if user_auth_tuple is not None:
user, token = user_auth_tuple
if authenticate:
request.user = user
return user
except Exception:
pass
user, tokrn = OpAuthJwtAuthentication().authenticate(request)
print(22, user)
return user or AnonymousUser()
@ -127,9 +117,11 @@ def get_request_canonical_path(request, *args, **kwargs):
for value in resolver_match.args:
path = path.replace(f"/{value}", "/{id}")
for key, value in resolver_match.kwargs.items():
path = path.replace(f"/{value}", f"/{{{key}}}")
if key == 'pk':
pass
path = path.replace(f"/{value}", f"/{{id}}")
continue
path = path.replace(f"/{value}", f"/{{{key}}}")
return path
@ -182,7 +174,7 @@ def get_login_location(request, *args, **kwargs):
r = requests.get(apiurl)
content = r.content.decode('GBK')
location = str(content).replace('\r', '').replace('\n', '')[:64]
cache.set(request_ip, location, 8640)
cache.set(request_ip, location, 86400)
return location
except Exception as e:
pass

View File

@ -1,7 +1,7 @@
"""
常用的Response以及Django的ResponseDRF的Response
"""
from django.http.response import DjangoJSONEncoder
from django.http.response import DjangoJSONEncoder, JsonResponse
from rest_framework.response import Response
@ -56,3 +56,36 @@ class ErrorResponse(Response):
def __str__(self):
return str(self.std_data)
class SuccessJsonResponse(JsonResponse):
"""
标准JsonResponse, SuccessJsonResponse(data)SuccessJsonResponse(data=data)
(1)仅SuccessResponse无法使用时才能推荐使用SuccessJsonResponse
"""
def __init__(self, data, msg='success', encoder=DjangoJSONEncoder, safe=True, json_dumps_params=None, **kwargs):
std_data = {
"code": 200,
"data": data,
"msg": msg,
"status": 'success'
}
super().__init__(std_data, encoder, safe, json_dumps_params, **kwargs)
class ErrorJsonResponse(JsonResponse):
"""
标准JsonResponse, 仅ErrorResponse无法使用时才能使用ErrorJsonResponse
(1)默认错误码返回2001, 也可以指定其他返回码:ErrorJsonResponse(code=xxx)
"""
def __init__(self, data, msg='error', code=201, encoder=OpDRFJSONEncoder, safe=True, json_dumps_params=None,
**kwargs):
std_data = {
"code": code,
"data": data,
"msg": msg,
"status": 'error'
}
super().__init__(std_data, encoder, safe, json_dumps_params, **kwargs)

View File

@ -15,13 +15,6 @@ DATABASE_PASSWORD = "q1w2e3r4T%Y^U&MYSQL"
# 数据库名
DATABASE_NAME = "django-vue-admin"
# ================================================= #
# ************** mongodb 数据库配置 ************** #
# ================================================= #
MONGO_DATABASE_NAME = 'django-vue-admin'
MONGO_HOST = 'localhost'
MONGO_PORT = 27017
# ================================================= #
# ************** redis 数据库配置 ************** #
# ================================================= #
@ -29,6 +22,8 @@ REDIS_DB = 1
REDIS_HOST = '127.0.0.1'
REDIS_PORT = 6379
REDIS_PASSWORD = 'q1w2e3r4T%Y^U&'
# celery 定时任务redis 库号
CELERY_DB = 2
# ================================================= #
# ************** 默认配置 ************** #
@ -44,3 +39,5 @@ CAPTCHA_STATE = True
# 操作日志配置
API_LOG_ENABLE = True
API_LOG_METHODS = ['POST', 'DELETE', 'PUT'] # 'ALL' or ['POST', 'DELETE']
# 接口权限
INTERFACE_PERMISSION = True

View File

@ -1,4 +1,5 @@
asgiref==3.3.1
celery==5.0.5
Django==2.2.16
django-cors-headers==3.7.0
django_celery_beat==2.2.0

View File

@ -1,47 +0,0 @@
module.exports = {
title: 'Django-Vue-Admin',
base: '/',
head: [
[
'link', // 设置 favicon.ico注意图片放在 public 文件夹下
{ rel: 'icon', href: '/logo.png' }
]
],
description: '',
themeConfig: {
logo: '/logo.png',
nav: [
{ text: '在线文档', link: '/document/' },
{ text: '关于我们', link: '/about/' },
{ text: '在线体验', link: 'https://demo.django-vue-admin.com/' },
{ text: 'Gitee', link: 'https://gitee.com/liqianglog/django-vue-admin' },
{ text: 'Github', link: 'https://github.com/liqianglog/django-vue-admin' },
],
sidebar: [
{
title: '文档', // 必要的
// path: '/document/', // 可选的, 标题的跳转链接应为绝对路径且必须存在
collapsable: false, // 可选的, 默认值是 true,
sidebarDepth: 1, // 可选的, 默认值是 1
children: [
'/document/',
'/document/kslj',
'/document/hjbs',
'/document/web',
'/document/server',
'/document/gxrz',
]
},
{
title: '其他',
children: [
'/other/cjwt',
'/other/jzzc',
],
collapsable: false,
sidebarDepth: 1,
initialOpenGroupIndex: -1 // 可选的, 默认值是 0
}
]
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

View File

@ -1,22 +0,0 @@
---
home: true
heroImage: /logo.png
heroText: Django-Vue-Admin
tagline: 使用django+vue进行极速开发的全栈管理系统
actionText: 快速开始 →
actionLink: /document/
features:
- title: 简单易用
details: 大幅度降低应用层代码难度,让每一个刚开始学习 django 和vue的新手都能快速上手。这将会是你上手学习 django+vue的最佳代码。
- title: 自由拓展
details: 系统底层代码和业务逻辑代码分层清晰,不会发生相互干扰,便于根据自己业务方向进行拓展。
- title: 标准化目录
details: 项目目录分层清晰,项目模式结构清晰,包名语义化,让你更加容易理解目录结构,读懂代码更加方便!
- title: 功能完善
details: 内置完整的权限架构,包括:菜单、角色、用户、字典、参数、监控、代码生成等一系列系统常规模块。
- title: 代码生成器
details: 在线配置表信息生成对应的代码,一键生成模块,包含增删改查/排序/导出/权限控制等操作,编译即可使用。
- title: 完全响应式布局
details: 提供多终端适配:电脑、平板、手机等所有主流设备,提供多种不同风格的皮肤。页面美观,高端大气上档次。
footer: MIT Licensed | Copyright © 2021-2021 django-vue-admin All Rights Reserved
---

View File

@ -1 +0,0 @@
# 关于我们

View File

@ -1 +0,0 @@
# 项目介绍

View File

@ -1 +0,0 @@
# 更新日志

View File

@ -1,98 +0,0 @@
# 环境部署
## 1.前端搭建环境
### 1.1 安装node
## 1. 后端搭建环境
### 1.1 安装Python3.8
### 1.2 安装Reids
sudo apt-get install -y redis-server
### 1.3 安装nginx
sudo apt-get install -y nginx
### 1.1 安装其它软件
sudo apt-get install -y python3-venv pcre pcre-devel pcre-static zlib* gcc openssl openssl-devel libffi-devel
## 2. 创建虚拟环境
### 2.1 进入项目目录 cd gh-baohua-backend
在项目根目录中,复制./conf/env.example.py文件为一份新的到./conf文件夹下并重命名为env.py在env.py中配置数据库信息。
### 2.2 激活虚拟环境
#### 2.2.1 python(python3) -m venv xxxx-venv, (xxxx根据情况定义)
#### 2.2.2 \xxxx-venv\Scripts\activate (window OS)
#### 2.2.3 sudo chmod -R 777 xxxx-venv/* (Linux OS)
#### 2.2.4 source ./gh-baohua-venv/bin/activate (Linux OS)
## 3. 升级pip
sudo python(python3) -m pip install --upgrade pip
## 4. 安装依赖环境
pip install -r requirements.txt
## 5. 执行迁移命令:
python manage.py makemigrations
python manage.py migrate
## 6. 初始化数据
python manage.py init
## 7. 启动项目
python manage.py runserver 8888
## 8. 初始账号:admin 密码:123456
## 9. 搭建正式环境完成上述步骤1-6
### 9.1 配置uwsgi.ini(主要配置项)
[uwsgi]
chdir = /mnt/dvadmin-backend
wsgi-file = /mnt/dvadmin-backend/application/wsgi.py
home = /mnt/dvadmin-backend/leo-baohua-venv
pidfile = /mnt/dvadmin-backend/uwsgi.pid
daemonize = /mnt/dvadmin-backend/uwsgi.log
master = true
processes = 8
socket = 0.0.0.0:7777
module = application.wsgi:application
vacuum = true
### 9.2 Nginx 配置
#### 9.2.1 配置uwsgi
server {
listen 7077;
server_name 192.168.xx.xxx;
location / {
include uwsgi_params;
uwsgi_pass 127.0.0.1:7777;
}
}
#### 9.2.2 配置前端
server {
listen 7078;
server_name 192.168.xx.xxx;
root /mnt/dvadmin-ui/dist;
index index.html index.htm index.nginx-debian.html;
location / {
try_files $uri $uri/ /index.html;
}
}
#### 9.2.3 配置前端接口-env.production
VUE_APP_BASE_API = 'http://192.168.xx.xxx:7077'

View File

@ -1 +0,0 @@
# 快速了解

View File

@ -1 +0,0 @@
# 后台手册

View File

@ -1,29 +0,0 @@
# 前端手册
## 添加菜单页面
- 在views中添加页面如下
![image-20210228004427903](http://pic.pgroom.cn/image-20210228004427903.png)
- 在前端系统中,权限管理——菜单管理——新增
- 例如:一级菜单(目录)
![image-20210228004905398](http://pic.pgroom.cn/image-20210228004905398.png)
- 添加末级菜单
![image-20210228010700514](http://pic.pgroom.cn/image-20210228010700514.png)
- 添加外链跳转菜单(菜单类型目录菜单均可)
![image-20210228005521735](http://pic.pgroom.cn/image-20210228005521735.png)
- 按钮同理
- 给角色添加按钮权限
- 权限管理——角色管理——修改——添加对应按钮——刷新页面即可。
<img src="http://pic.pgroom.cn/image-20210228010835275.png" alt="image-20210228010835275" style="zoom: 33%;" />

View File

@ -1 +0,0 @@
# 常见问题

View File

@ -1 +0,0 @@
# 捐赠支持

View File

@ -1,15 +0,0 @@
{
"name": "django-vue-admin-doc",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"docs:dev": "vuepress dev docs",
"docs:build": "vuepress build docs"
},
"author": "",
"license": "ISC",
"devDependencies": {
"vuepress": "^1.8.2"
}
}

View File

@ -79,8 +79,8 @@
"vue-template-compiler": "2.6.12"
},
"engines": {
"node": ">=8.9",
"npm": ">= 3.0.0"
"node": ">=12.0",
"npm": ">= 6.0.0"
},
"browserslist": [
"> 1%",

View File

@ -28,7 +28,7 @@ export function getDept(deptId) {
// 查询部门下拉树结构
export function treeselect() {
return request({
url: '/admin/permission/dept/treeselect/',
url: '/admin/permission/dept/treeselect/?status=1',
method: 'get'
})
}
@ -36,7 +36,7 @@ export function treeselect() {
// 根据角色ID查询部门树结构
export function roleDeptTreeselect(roleId) {
return request({
url: '/admin/permission/dept/roleDeptTreeselect/' + roleId + '/',
url: '/admin/permission/dept/roleDeptTreeselect/' + roleId + '/?status=1',
method: 'get'
})
}

View File

@ -20,7 +20,7 @@ export function getMenu(menuId) {
// 查询菜单下拉树结构
export function treeselect() {
return request({
url: '/admin/permission/menus/treeselect/',
url: '/admin/permission/menus/treeselect/?status=1',
method: 'get'
})
}
@ -28,7 +28,7 @@ export function treeselect() {
// 根据角色ID查询菜单下拉树结构
export function roleMenuTreeselect(roleId) {
return request({
url: '/admin/permission/menus/roleMenuTreeselect/' + roleId + '/',
url: '/admin/permission/menus/roleMenuTreeselect/' + roleId + '/?status=1',
method: 'get'
})
}

View File

@ -20,7 +20,7 @@ export function getConfig(configId) {
// 根据参数键名查询参数值
export function getConfigKey(configKey) {
return request({
url: '/admin/system/config/configKey/' + configKey + '/',
url: '/admin/system/config/configKey/' + configKey + '/?status=1',
method: 'get'
})
}

View File

@ -20,7 +20,7 @@ export function getData(dictCode) {
// 根据字典类型查询字典数据信息
export function getDicts(dictType) {
return request({
url: '/admin/system/dict/get/type/' + dictType + '/',
url: '/admin/system/dict/get/type/' + dictType + '/?status=1',
method: 'get'
})
}

View File

@ -1,465 +0,0 @@
<!--
@description: 封装组件
-->
<template>
<div style="padding-left: 10px;">
<el-row v-if="topLayout" style="margin-bottom: 20px">
<el-col v-if="topLayoutLeft" :span="18">
<div class="grid-content bg-purple">
<el-input
v-model="searchForm.search"
:disabled="tableLoading"
:size="$ELEMENT.size"
:placeholder="filterPlaceholder"
clearable
style="width: 200px;"
@keyup.enter.native="handleSearchFormSubmit"/>
<el-button
:size="$ELEMENT.size"
type="primary"
title="过滤"
@click="handleSearchFormSubmit">
<common-icon value="svg:icon-filter"/>
</el-button>
<el-button
v-show="isFilter"
:size="$ELEMENT.size"
type="info"
title="取消过滤"
style="margin-left: 0;"
@click="handleCancelFilter">
<common-icon value="svg:icon-unfilter"/>
</el-button>
<slot name="button"/>
</div>
</el-col>
<el-col v-if="topLayoutRight" :span="6">
<div class="grid-content bg-purple-light" style="text-align: right">
<slot name="tools"/>
<el-button
:size="$ELEMENT.size"
name="refresh"
type="info"
title="导出数据"
@click="handleExportTableData">
<svg-icon icon-class="icon-excel" style="font-size: 1em"/>
</el-button>
<el-popover
placement="bottom"
width="200"
trigger="click">
<div style="width: 50px;">
<el-checkbox-group v-model="showFields">
<el-checkbox
v-for="(field, index) in fields"
:key="index"
:label="field"
:checked="field.show"
style="width: 100%"
@change="handleSelectField($event, field)">{{ field.label }}</el-checkbox>
</el-checkbox-group>
</div>
<el-button
slot="reference"
:size="$ELEMENT.size"
name="refresh"
type="info"
icon="el-icon-s-fold"
title="设置显示的字段"/>
</el-popover>
</div>
</el-col>
</el-row>
<el-table
v-loading="tableLoading"
ref="table"
:data="filterData"
:span-method="spanMethod"
:max-height="maxHeight"
:row-key="getRowKeys"
:stripe="stripe"
:fit="fit"
:border="border"
:empty-text="emptyText"
:highlight-current-row="highlightCurrentRow"
:show-overflow-tooltip="showOverflowTooltip"
@cell-click="handleCellClick"
@cell-dblclick="handleCellDbClick"
@header-click="handleHeaderClick"
@row-click="handleRowClick"
@row-dblclick="handleRowDblClick"
@selection-change="handleSelectionChange">
<el-table-column
v-if="selection"
:reserve-selection="true"
type="selection"
width="50"/>
<template v-for="field in fields">
<el-table-column
v-if="field.show"
:key="field.prop"
:prop="field.prop"
:label="field.label"
:sortable="field.sortable"
:width="field.width || ''"
show-overflow-tooltip>
<template slot-scope="scope">
<slot :name="field.prop" :values="scope.row" :prop="field.prop" :field="field">
<span v-html="formatColumnData(scope.row, field)"/>
</slot>
</template>
</el-table-column>
</template>
<slot name="column"/>
</el-table>
<el-row>
<el-col :span="6" style="margin-top: 20px">
<span>已选择:<span style="color: #ff00ff;font-weight: bold;">{{ multipleSelection.length }}</span></span>
<el-button
v-show="multipleSelection.length"
type="info"
size="mini"
title="清空多选"
@click="clearMultipleSelection">清空</el-button>
</el-col>
<el-col :span="18" style="margin-top: 20px; text-align: right">
<span>总计:<span style="color: #ff00ff;font-weight: bold;">{{ filterData.length }}</span></span>
</el-col>
</el-row>
</div>
</template>
<script>
import moment from 'moment';
import * as Utils from '@/utils';
export default {
name: 'CommonStaticTable',
props: {
value: {
type: Array,
default: () => []
},
spanMethod: {
type: Function,
default: null
},
data: {
type: Array,
default: () => []
},
initSelected: {
type: Array,
default: () => []
},
// eslint-disable-next-line vue/require-prop-types
maxHeight: {
default: 700
},
stripe: {
type: Boolean,
default: true
},
fit: {
type: Boolean,
default: true
},
highlightCurrentRow: {
type: Boolean,
default: true
},
showOverflowTooltip: {
type: Boolean,
default: true
},
border: {
type: Boolean,
default: false
},
emptyText: {
type: String,
default: '暂无数据'
},
topLayout: {
type: Array,
default: () => {
return ['left', 'right'];
}
},
bottomLayout: {
type: Array,
default: () => {
return ['left', 'right'];
}
},
fields: {
//
type: Array,
default: () => {
return [];
}
},
selection: {
// (, false)
type: Boolean,
default: false
},
// api
api: {
type: Function,
default: null
},
params: {
type: Object,
default: () => {
return {};
}
}
},
data() {
return {
tableEditable: true,
showFields: [], //
filterFields: [], //
filterPlaceholder: '过滤', //
buttonTagList: [], //
excelDialogVisible: false,
tableLoading: false,
advancedSearchForm: {},
advancedSearchFields: [],
rowKey: null,
multipleSelection: [],
excelHeader: [],
excelData: [],
searchForm: {
search: ''
},
getRowKeys: row => {
if (this.rowKey) {
return row[this.rowKey];
}
return row.id || row.uuid;
},
exportFields: [],
tableData: [],
filterData: [],
isFilter: false
};
},
computed: {
topLayoutLeft() {
return this.topLayout.indexOf('left') >= 0;
},
topLayoutRight() {
return this.topLayout.indexOf('right') >= 0;
}
},
watch: {
data: {
handler: function(newData, oldData) {
this.handleChangeTableData(newData);
},
immediate: true
}
},
mounted() {
},
created() {
this.initComponentData();
this.initData();
this.initSelect();
},
methods: {
initData() {
if (Utils.isFunction(this.api)) {
this.listInterfaceData();
}
},
initSelect() {
for (const row of this.initSelected) {
this.$refs['table'].toggleRowSelection(row, true);
}
},
initComponentData() {
this.fields.forEach(field => {
field.show = (!!field.show);
field.type = (field.type || 'string').toLocaleLowerCase();
field.label = field.label || field.prop;
field.search = (!!field.search);
field.sortable = (!!field.sortable);
field.unique = (!!field.unique);
field.width = field.width || '';
if (field.type === 'choices') {
if (Utils.isArray(field.choices) && field.choices.length > 0) {
if (!Utils.isObj(field.choices[0])) {
field.choices = field.choices.map(value => {
return {
label: value,
value: value
};
});
}
}
}
field.unique = (!!field.unique);
if (field.unique) {
this.rowKey = field.prop;
}
});
this.filterFields = this.fields.filter(field => field.search).map(field => field.prop);
if (this.filterFields.length) {
const text = this.fields.filter(field => field.search).map(field => field.label).join('、');
this.filterPlaceholder = `${text} 过滤`;
}
},
listInterfaceData() {
this.tableLoading = true;
this.api(this.params).then(response => {
this.tableLoading = false;
this.handleChangeTableData(response.data);
}).catch(() => {
this.tableLoading = false;
});
},
formatColumnData(row, field) {
const type = field.type || 'string';
const prop = field.prop;
if (field.formatter && typeof field.formatter === 'function') {
return field.formatter(row, prop, type);
}
if (type === 'string') {
return row[prop];
} else if (type === 'datetime') {
return this.formatDatetime(row[prop]);
} else if (type === 'date') {
return this.formatDate(row[prop]);
} else if (type === 'time') {
return this.formatTime(row[prop]);
} else if (type.startsWith('bool')) {
return row[prop] ? '是' : '否';
} else if (type === 'choices') {
const choices = field.choices;
return this.formatChoices(choices, row[prop]);
} else {
return row[prop];
}
},
formatChoices(choices, value) {
for (const choice of choices) {
if (choice.value === value) {
return choice.label;
}
}
return value;
},
formatDatetime(datetime) {
return moment(datetime).format('YYYY-MM-DD HH:mm:ss');
},
formatDate(date) {
return moment(date).format('YYYY-MM-DD');
},
formatTime(time) {
return moment(time).format('HH:mm:ss');
},
getMultipleSelection() {
return this.multipleSelection || [];
},
clearMultipleSelection() {
this.$refs.table.clearSelection();
},
clearSelection() {
this.$refs.table.clearSelection();
},
clearFilter() {
//
this.searchForm.search = '';
this.filterData = Array.from(this.tableData);
},
handleSelectField(e, field) {
field.show = e;
},
handleChangeTableData(data) {
this.tableData = Array.from(data);
this.filterData = Array.from(this.filterHandler(this.tableData));
},
// ,
handleExportTableData() {
this.excelDialogVisible = true;
this.exportFields = this.fields.map(field => {
return { prop: field.prop, label: field.label, show: field.show };
});
this.excelHeader = this.showFields.map(field => field['prop']);
},
//
handleSelectionChange(val) {
this.$emit('selection-change', val);
this.multipleSelection = val;
},
handleSortChange(val) {
this.sort.prop = val.prop;
this.sort.order = val.order;
this.getTableData();
},
filterHandler(data) {
if (!data) {
data = this.tableData || [];
}
const search = this.searchForm.search.trim();
if (!search.length || !this.filterFields.length) {
this.isFilter = false;
return data;
}
const filterData = data.filter(row => {
for (const field of this.filterFields) {
if (row[field] && row[field].indexOf(search) >= 0) {
return true;
}
}
return false;
});
this.isFilter = true;
return filterData;
},
handleCellClick(row, column, cell, event) {
this.$emit('cell-click', row, column, cell, event);
},
handleCellDbClick(row, column, cell, event) {
this.$emit('cell-dblclick', row, column, cell, event);
},
handleRowClick(row, column, event) {
this.$emit('row-click', row, column, event);
},
handleRowDblClick(row, column, event) {
this.$emit('row-dblclick', row, column, event);
},
handleHeaderClick(column, event) {
this.$emit('header-click', column, event);
},
toggleRowSelection(row, selected = true) {
this.$refs.table.toggleRowSelection(row, selected);
},
toggleFilter() {
//
this.filterData = Array.from(this.filterHandler());
},
handleSearchFormSubmit() {
this.toggleFilter();
},
handleCancelFilter() {
this.isFilter = false;
this.clearFilter();
}
}
};
</script>
<style scoped>
.picker {
width: 240px;
}
.el-pagination {
padding: 5px;
}
.right_pagination {
text-align: right;
padding-top: 20px;
}
</style>

View File

@ -39,9 +39,9 @@
</template>
<script>
import { getToken } from "@/utils/auth";
import {getToken} from "@/utils/auth";
export default {
export default {
props: {
//
value: [String, Object, Array],
@ -135,8 +135,12 @@ export default {
},
//
handleUploadSuccess(res, file) {
this.$message.success("上传成功");
this.$emit("input", res.url);
if (res.code === 200) {
this.$message.success("上传成功");
this.$emit("input", res.data.file);
} else {
this.$message.error(res.msg);
}
},
//
handleDelete(index) {

View File

@ -23,6 +23,7 @@ import {
parseTime,
resetForm,
selectDictLabel,
selectDictDefault,
selectDictLabels
} from "@/utils/ruoyi";
import Pagination from "@/components/Pagination";
@ -40,6 +41,7 @@ Vue.prototype.parseTime = parseTime
Vue.prototype.resetForm = resetForm
Vue.prototype.addDateRange = addDateRange
Vue.prototype.selectDictLabel = selectDictLabel
Vue.prototype.selectDictDefault = selectDictDefault
Vue.prototype.selectDictLabels = selectDictLabels
Vue.prototype.getCrontabData = getCrontabData
Vue.prototype.getIntervalData = getIntervalData

View File

@ -73,6 +73,20 @@ export function selectDictLabel(datas, value) {
})
return actions.join('');
}
// 获取字典默认值
export function selectDictDefault(datas) {
var actions = [];
Object.keys(datas).some((key) => {
if (datas[key].is_default === true) {
actions.push(datas[key].dictValue);
return true;
}
})
if (!actions[0] && datas[0]) {
actions.push(datas[0].dictValue)
}
return actions.join('');
}
// 回显数据字典字符串数组
export function selectDictLabels(datas, value, separator) {

View File

@ -253,7 +253,7 @@ export default {
leader: undefined,
phone: undefined,
email: undefined,
status: "0"
status: this.selectDictDefault(this.statusOptions),
};
this.resetForm("form");
},

View File

@ -401,16 +401,16 @@
name: undefined,
icon: undefined,
web_path: undefined,
menuType: "0",
menuType: this.selectDictDefault(this.menuTypeOptions),
orderNum: undefined,
component_path: undefined,
interface_path: undefined,
perms: undefined,
interface_method: 'GET',
interface_method: this.selectDictDefault(this.interfaceMethodOptions),
isFrame: "1",
isCache: "1",
visible: "1",
status: "1"
visible: this.selectDictDefault(this.visibleOptions),
status: this.selectDictDefault(this.statusOptions)
};
this.resetForm("form");
},

View File

@ -242,7 +242,7 @@ export default {
postCode: undefined,
postName: undefined,
postSort: 0,
status: "0",
status: this.selectDictDefault(this.statusOptions),
remark: undefined
};
this.resetForm("form");

View File

@ -440,7 +440,7 @@ export default {
roleName: undefined,
roleKey: undefined,
roleSort: 0,
status: "0",
status: this.selectDictDefault(this.statusOptions),
menu: [],
dept: [],
menuCheckStrictly: true,

View File

@ -576,7 +576,7 @@
password: undefined,
mobile: undefined,
email: undefined,
gender: undefined,
gender: this.selectDictDefault(this.sexOptions),
is_active: false,
remark: undefined,
postIds: [],

View File

@ -275,8 +275,8 @@ export default {
configName: undefined,
configKey: undefined,
configValue: undefined,
configType: "Y",
status: '0',
configType: this.selectDictDefault(this.typeOptions),
status: this.selectDictDefault(this.statusOptions),
remark: undefined
};
this.resetForm("form");

View File

@ -79,6 +79,16 @@
v-hasPermi="['system:dict:type:export:get']"
>导出</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-refresh"
size="mini"
@click="handleClearCache"
v-hasPermi="['system:dict:type:clearcache:delete']"
>清理缓存</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
@ -181,7 +191,7 @@
<script>
import {addData, delData, exportData, getData, listData, updateData} from "@/api/vadmin/system/dict/data";
import {getType, listType} from "@/api/vadmin/system/dict/type";
import {getType, listType, clearCache} from "@/api/vadmin/system/dict/type";
export default {
name: "Data",
@ -237,7 +247,6 @@
},
created() {
const dictId = this.$route.params && this.$route.params.dictId;
console.log(11111,this.$route.params)
this.getType(dictId);
this.getTypeList();
this.getDicts("sys_normal_disable").then(response => {
@ -263,7 +272,6 @@
getList() {
this.loading = true;
listData(this.queryParams).then(response => {
console.log(1212,response.data.count)
this.dataList = response.data.results;
this.total = response.data.count;
this.loading = false;
@ -285,7 +293,7 @@
dictLabel: undefined,
dictValue: undefined,
sort: 0,
status: "0",
status: this.selectDictDefault(this.typeOptions),
remark: undefined
};
this.resetForm("form");
@ -379,6 +387,12 @@
}).then(response => {
this.download(response.data.file_url,response.data.name);
})
},
/** 清理缓存按钮操作 */
handleClearCache() {
clearCache().then(response => {
this.msgSuccess("清理成功");
});
}
}
};

View File

@ -274,7 +274,7 @@ export default {
id: undefined,
dictName: undefined,
dictType: undefined,
status: "0",
status: this.selectDictDefault(this.statusOptions),
remark: undefined
};
this.resetForm("form");

View File

@ -232,9 +232,7 @@
open: false,
//
MessagePushTypeOptions: [],
//
StatusOptions: [],
//
//
MessagePushStatusOptions: [],
//
queryParams: {
@ -307,8 +305,8 @@
content: undefined,
to_path: undefined,
is_reviewed: true,
message_type: "1",
status: '1',
message_type: this.selectDictDefault(this.MessagePushStatusOptions),
status: this.selectDictDefault(this.MessagePushStatusOptions),
};
this.resetForm("form");
},

View File

@ -266,9 +266,9 @@ export default {
this.form = {
noticeId: undefined,
noticeTitle: undefined,
noticeType: undefined,
noticeType: this.selectDictDefault(this.typeOptions),
noticeContent: undefined,
status: "0"
status: this.selectDictDefault(this.statusOptions)
};
this.resetForm("form");
},

View File

@ -14,7 +14,7 @@
<el-form-item label="文件类型" prop="type">
<el-input
v-model="queryParams.type"
placeholder="请输入文件类型(待完善)"
placeholder="请输入文件类型"
clearable
size="small"
style="width: 240px"
@ -72,8 +72,33 @@
<el-table-column label="文件类型" width="150" align="center" prop="type"/>
<el-table-column label="文件大小" width="90" align="center" prop="size"/>
<el-table-column label="存储位置" align="center" prop="address"/>
<el-table-column label="文件本地地址" align="center" prop="file" :show-overflow-tooltip="true"/>
<el-table-column label="OSS地址" align="center" prop="oss_url" :show-overflow-tooltip="true"/>
<el-table-column label="文件来源" align="center" prop="source"/>
<el-table-column label="文件本地地址" align="center" prop="file" :show-overflow-tooltip="true">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-document-copy"
@click="CopyFileUrl(scope.row.file)"
v-if="scope.row.file"
></el-button>
&nbsp;
<span>{{ scope.row.file }}</span>
</template>
</el-table-column>
<el-table-column label="OSS地址" align="center" prop="oss_url" :show-overflow-tooltip="true">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-document-copy"
@click="CopyFileUrl(scope.row.oss_url)"
v-if="scope.row.oss_url"
></el-button>
&nbsp;
<span>{{ scope.row.oss_url }}</span>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="create_datetime" width="160">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.create_datetime) }}</span>
@ -218,9 +243,9 @@
type: "warning"
}).then(function () {
return clearSaveFile();
}).then(() => {
}).then((values) => {
this.getList();
this.msgSuccess("删除成功");
this.msgSuccess(values.msg);
})
},
/** 完成按钮 */
@ -229,6 +254,17 @@
this.open = false;
this.$refs.saveFile.fileList = []
},
CopyFileUrl(values){
const input = document.createElement('input');
document.body.appendChild(input);
input.setAttribute('value', values);
input.select();
if (document.execCommand('copy')) {
document.execCommand('copy');
this.msgSuccess("复制成功");
}
document.body.removeChild(input);
}
}
}