功能变化(全局):拉取其他分支代码;
						commit
						70588e3d5b
					
				
							
								
								
									
										48
									
								
								README.md
								
								
								
								
							
							
						
						
									
										48
									
								
								README.md
								
								
								
								
							| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
# Django-Vue-Admin
 | 
			
		||||
 | 
			
		||||
[](https://gitee.com/liqianglog/django-vue-admin/blob/master/LICENSE) [](https://pypi.org/project/django-simpleui/#history) [](https://python.org/)  [](https://nodejs.org/zh-cn/download/releases/)[](https://pypi.org/project/django-simpleui/)
 | 
			
		||||
[](https://gitee.com/liqianglog/django-vue-admin/blob/master/LICENSE) [](https://pypi.org/project/django-simpleui/#history) [](https://python.org/)  
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -12,26 +12,25 @@ Django-Vue-Admin 是一套全部开源的快速开发平台,毫无保留给个
 | 
			
		|||
* 后端采用Python语言Django框架。
 | 
			
		||||
* 权限认证使用Jwt,支持多终端认证系统。
 | 
			
		||||
* 支持加载动态权限菜单,多方式轻松权限控制。
 | 
			
		||||
* ~~高效率开发,使用代码生成器可以一键生成前后端代码。~~
 | 
			
		||||
* 特别鸣谢:[RuoYi](https://gitee.com/y_project/RuoYi-Vue) ,[Vue-Element-Admin](https://github.com/PanJiaChen/vue-element-admin),[eladmin-web](https://gitee.com/elunez/eladmin-web?_from=gitee_search),[Gin-Vue-Admin](https://www.gin-vue-admin.com/)。
 | 
			
		||||
* 特别鸣谢:<u>[Gin-Vue-Admin](https://www.gin-vue-admin.com/)</u>,[RuoYi](https://gitee.com/y_project/RuoYi-Vue) ,[Vue-Element-Admin](https://github.com/PanJiaChen/vue-element-admin),[eladmin-web](https://gitee.com/elunez/eladmin-web?_from=gitee_search)。
 | 
			
		||||
 | 
			
		||||
## QQ群
 | 
			
		||||
 | 
			
		||||
- QQ群号:812482043
 | 
			
		||||
 | 
			
		||||
- 由于项目正在启步阶段,第一版预计3月底发,后序会慢慢维护其他版本,有什么不到位的请大家担待~
 | 
			
		||||
- 二维码
 | 
			
		||||
 | 
			
		||||
  <img src='https://gitee.com/liqianglog/django-vue-admin/raw/master/dvadmin-ui/src/assets/images/qq.jpg' width='200'>
 | 
			
		||||
 | 
			
		||||
## 源码地址
 | 
			
		||||
 | 
			
		||||
gitee地址:[https://gitee.com/liqianglog/django-vue-admin](https://gitee.com/liqianglog/django-vue-admin)
 | 
			
		||||
gitee地址(主推):[https://gitee.com/liqianglog/django-vue-admin](https://gitee.com/liqianglog/django-vue-admin)
 | 
			
		||||
 | 
			
		||||
github地址:[https://github.com/liqianglog/django-vue-admin](https://github.com/liqianglog/django-vue-admin)
 | 
			
		||||
 | 
			
		||||
## 内置功能
 | 
			
		||||
 | 
			
		||||
##### 预计3月底发布v1.0正式版本,个别功能开发中 [版本功能说明](https://gitee.com/liqianglog/django-vue-admin/wikis/releaseNote?sort_id=3615540)
 | 
			
		||||
##### 后期版本 [版本功能说明](https://gitee.com/liqianglog/django-vue-admin/wikis/releaseNote?sort_id=3615540)
 | 
			
		||||
 | 
			
		||||
1.  用户管理:用户是系统操作者,该功能主要完成系统用户配置。
 | 
			
		||||
2.  部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。
 | 
			
		||||
| 
						 | 
				
			
			@ -44,11 +43,10 @@ github地址:[https://github.com/liqianglog/django-vue-admin](https://github.c
 | 
			
		|||
9.  通知公告:发布通知公告给所有人,进行消息的通知。
 | 
			
		||||
10.  操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
 | 
			
		||||
11.  登录日志:系统登录日志记录查询包含登录异常。
 | 
			
		||||
12.  在线用户:当前系统中活跃用户状态监控、用户强退功能。
 | 
			
		||||
13.  定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。
 | 
			
		||||
14.  用户注册:新用户注册页面。
 | 
			
		||||
15.  服务监控:监视当前系统CPU、内存、磁盘、堆栈、celery 当前状态等相关信息。
 | 
			
		||||
16.  在线构建器:拖动表单元素生成相应的HTML代码。
 | 
			
		||||
12.  定时日志:celery定时任务执行日志记录。
 | 
			
		||||
13.  在线用户:当前系统中活跃用户状态监控、用户强退功能。
 | 
			
		||||
14.  定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。
 | 
			
		||||
15.  在线构建器:拖动表单元素生成相应的HTML代码。
 | 
			
		||||
 | 
			
		||||
## 在线体验
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -68,9 +66,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 +90,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,16 +104,34 @@ 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
 | 
			
		||||
 | 
			
		||||
后端接口文档地址:http://127.0.0.1:8000/docs/
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
### docker-compose 运行
 | 
			
		||||
 | 
			
		||||
~~~shell
 | 
			
		||||
# 先安装docker-compose (自行百度安装),执行此命令等待安装
 | 
			
		||||
docker-compose up
 | 
			
		||||
# 初始化后端数据(第一次执行即可)
 | 
			
		||||
docker exec -ti dvadmin-django bash
 | 
			
		||||
python manage.py init -y
 | 
			
		||||
exit
 | 
			
		||||
 | 
			
		||||
前端地址:http://127.0.0.1:8080
 | 
			
		||||
后端地址:http://127.0.0.1:8000
 | 
			
		||||
账号:admin 密码:123456
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## 演示图
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,25 +23,7 @@ services:
 | 
			
		|||
        npm install --registry=https://registry.npm.taobao.org
 | 
			
		||||
        rm -rf /dvadmin-ui/dist
 | 
			
		||||
        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
 | 
			
		||||
        npm run dev
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  dvadmin-redis:
 | 
			
		||||
| 
						 | 
				
			
			@ -104,6 +86,8 @@ services:
 | 
			
		|||
    volumes:
 | 
			
		||||
      - ./dvadmin-backend:/dvadmin-backend
 | 
			
		||||
      - ./logs/log:/var/log
 | 
			
		||||
    env_file:
 | 
			
		||||
      - ./.env
 | 
			
		||||
    ports:
 | 
			
		||||
      - "8000:8000"
 | 
			
		||||
    expose:
 | 
			
		||||
| 
						 | 
				
			
			@ -135,31 +119,6 @@ services:
 | 
			
		|||
    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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +0,0 @@
 | 
			
		|||
FROM nginx:latest
 | 
			
		||||
 | 
			
		||||
COPY nginx.conf /etc/nginx/nginx.conf
 | 
			
		||||
 | 
			
		||||
CMD ["nginx", "-g", "daemon off;"]
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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-----
 | 
			
		||||
| 
						 | 
				
			
			@ -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-----
 | 
			
		||||
| 
						 | 
				
			
			@ -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-----
 | 
			
		||||
| 
						 | 
				
			
			@ -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-----
 | 
			
		||||
| 
						 | 
				
			
			@ -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-----
 | 
			
		||||
| 
						 | 
				
			
			@ -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-----
 | 
			
		||||
| 
						 | 
				
			
			@ -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-----
 | 
			
		||||
| 
						 | 
				
			
			@ -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-----
 | 
			
		||||
| 
						 | 
				
			
			@ -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-----
 | 
			
		||||
| 
						 | 
				
			
			@ -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-----
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -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"]
 | 
			
		||||
| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
 | 
			
		||||
| 
						 | 
				
			
			@ -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/
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -63,6 +63,7 @@ MIDDLEWARE = [
 | 
			
		|||
    'django.contrib.messages.middleware.MessageMiddleware',
 | 
			
		||||
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
 | 
			
		||||
    'vadmin.op_drf.middleware.ApiLoggingMiddleware',  # 用于记录API访问日志
 | 
			
		||||
    'vadmin.op_drf.middleware.PermissionModeMiddleware',  # 权限中间件
 | 
			
		||||
]
 | 
			
		||||
# 允许跨域源
 | 
			
		||||
CORS_ORIGIN_ALLOW_ALL = CORS_ORIGIN_ALLOW_ALL
 | 
			
		||||
| 
						 | 
				
			
			@ -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)}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)))
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,14 +1,21 @@
 | 
			
		|||
"""
 | 
			
		||||
django中间件
 | 
			
		||||
"""
 | 
			
		||||
import json
 | 
			
		||||
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, get_verbose_name
 | 
			
		||||
from ..utils.response import ErrorJsonResponse
 | 
			
		||||
 | 
			
		||||
logger = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ApiLoggingMiddleware(MiddlewareMixin):
 | 
			
		||||
| 
						 | 
				
			
			@ -36,9 +43,16 @@ class ApiLoggingMiddleware(MiddlewareMixin):
 | 
			
		|||
            body['password'] = '*' * len(body['password'])
 | 
			
		||||
        if not hasattr(response, 'data') or not isinstance(response.data, dict):
 | 
			
		||||
            response.data = {}
 | 
			
		||||
        if not response.data and response.content:
 | 
			
		||||
            try:
 | 
			
		||||
                content = json.loads(response.content.decode())
 | 
			
		||||
                response.data = content if isinstance(content, dict) else {}
 | 
			
		||||
            except:
 | 
			
		||||
                pass
 | 
			
		||||
        user = get_request_user(request)
 | 
			
		||||
        info = {
 | 
			
		||||
            'request_ip': getattr(request, 'request_ip', 'unknown'),
 | 
			
		||||
            'creator': request.user,
 | 
			
		||||
            'creator': user if not isinstance(user, AnonymousUser) else None,
 | 
			
		||||
            'dept_belong_id': getattr(request.user, 'dept_id', None),
 | 
			
		||||
            'request_method': request.method,
 | 
			
		||||
            'request_path': request.request_path,
 | 
			
		||||
| 
						 | 
				
			
			@ -52,11 +66,14 @@ class ApiLoggingMiddleware(MiddlewareMixin):
 | 
			
		|||
            'json_result': {"code": response.data.get('code'), "msg": response.data.get('msg')},
 | 
			
		||||
            'request_modular': request.session.get('model_name'),
 | 
			
		||||
        }
 | 
			
		||||
        if isinstance(request.user, AnonymousUser):
 | 
			
		||||
            info['creator'] = None
 | 
			
		||||
        log = OperationLog(**info)
 | 
			
		||||
        log.save()
 | 
			
		||||
 | 
			
		||||
    def process_view(self, request, view_func, view_args, view_kwargs):
 | 
			
		||||
        if hasattr(view_func, 'cls') and hasattr(view_func.cls, 'queryset'):
 | 
			
		||||
            request.session['model_name'] = get_verbose_name(view_func.cls.queryset)
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    def process_request(self, request):
 | 
			
		||||
        self.__handle_request(request)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -77,3 +94,76 @@ class PermissionModeMiddleware(MiddlewareMixin):
 | 
			
		|||
    """
 | 
			
		||||
    权限模式拦截判断
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def process_request(self, request):
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    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.get(method, []):
 | 
			
		||||
            return 30
 | 
			
		||||
        return -10
 | 
			
		||||
 | 
			
		||||
    def process_view(self, request, view_func, view_args, view_kwargs):
 | 
			
		||||
        # 判断环境变量中,是否为演示模式(正常可忽略此判断)
 | 
			
		||||
        white_list = ['/admin/logout/', '/admin/login/']
 | 
			
		||||
        if os.getenv('DEMO_ENV') and not request.method in ['GET', 'OPTIONS'] and request.path not in white_list:
 | 
			
		||||
            return ErrorJsonResponse(data={}, msg=f'演示模式,不允许操作!')
 | 
			
		||||
 | 
			
		||||
        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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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'))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,13 @@
 | 
			
		|||
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
 | 
			
		||||
from ...op_drf.models import CoreModel
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class UserProfile(AbstractUser):
 | 
			
		||||
class UserProfile(AbstractUser, CoreModel):
 | 
			
		||||
    USER_TYPE_CHOICES = (
 | 
			
		||||
        (0, "后台用户"),
 | 
			
		||||
        (1, "前台用户"),
 | 
			
		||||
| 
						 | 
				
			
			@ -24,9 +25,30 @@ class UserProfile(AbstractUser):
 | 
			
		|||
    post = ManyToManyField(to='Post', verbose_name='关联岗位', db_constraint=False)
 | 
			
		||||
    role = ManyToManyField(to='Role', verbose_name='关联角色', db_constraint=False)
 | 
			
		||||
    dept = ForeignKey(to='Dept', verbose_name='归属部门', on_delete=CASCADE, db_constraint=False, null=True, blank=True)
 | 
			
		||||
    dept_belong_id = CharField(max_length=64, verbose_name="数据归属部门", null=True, blank=True)
 | 
			
		||||
    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 = '用户管理'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,115 @@
 | 
			
		|||
"""
 | 
			
		||||
常用的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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DeptDestroyPermission(CustomPermission):
 | 
			
		||||
    """
 | 
			
		||||
    部门删除权限校验:判断部门下是否有用户存在,存在不可删除
 | 
			
		||||
    """
 | 
			
		||||
    message = '没有有操作权限'
 | 
			
		||||
 | 
			
		||||
    def has_permission(self, request: Request, view: APIView):
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def check_queryset(self, request, instance):
 | 
			
		||||
        if instance.values_list('userprofile', flat=True):
 | 
			
		||||
            self.message = "该部门下有关联用户,无法删除!"
 | 
			
		||||
            return False
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def has_object_permission(self, request: Request, view: APIView, instance):
 | 
			
		||||
        res = self.check_queryset(request, instance)
 | 
			
		||||
        return res
 | 
			
		||||
| 
						 | 
				
			
			@ -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,14 +220,14 @@ 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
 | 
			
		||||
 | 
			
		||||
    def get_unread_msg_count(self, obj: UserProfile):
 | 
			
		||||
        return MessagePush.objects.filter(status='2').exclude(user=obj,
 | 
			
		||||
                                                              messagepushuser_message_push__is_read=True).count()
 | 
			
		||||
        return MessagePush.objects.filter(status='2').exclude(messagepushuser_message_push__is_read=True,
 | 
			
		||||
                                                              messagepushuser_message_push__user=obj).count()
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = UserProfile
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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, DeptDestroyPermission
 | 
			
		||||
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),
 | 
			
		||||
| 
						 | 
				
			
			@ -47,7 +48,10 @@ class GetRouters(APIView):
 | 
			
		|||
        return dict
 | 
			
		||||
 | 
			
		||||
    def get(self, request, format=None):
 | 
			
		||||
        menus = Menu.objects.filter(role__userprofile=request.user) \
 | 
			
		||||
        kwargs = {}
 | 
			
		||||
        if not request.user.is_superuser:
 | 
			
		||||
            kwargs['role__userprofile'] = request.user
 | 
			
		||||
        menus = Menu.objects.filter(**kwargs) \
 | 
			
		||||
            .exclude(menuType='2').values('id', 'name', 'web_path', 'visible', 'status', 'isFrame', 'component_path',
 | 
			
		||||
                                          'icon', 'parentId', 'orderNum', 'isCache').distinct()
 | 
			
		||||
        data = []
 | 
			
		||||
| 
						 | 
				
			
			@ -78,9 +82,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 +131,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, DeptDestroyPermission)
 | 
			
		||||
    create_extra_permission_classes = (CommonPermission,)
 | 
			
		||||
    search_fields = ('deptName',)
 | 
			
		||||
    ordering = 'create_datetime'  # 默认排序
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -192,23 +196,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 +215,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 +243,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 +275,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)
 | 
			
		||||
| 
						 | 
				
			
			@ -378,7 +362,7 @@ class UserProfileModelViewSet(CustomModelViewSet):
 | 
			
		|||
        :return:
 | 
			
		||||
        """
 | 
			
		||||
        instance = self.queryset.get(id=request.user.id)
 | 
			
		||||
        instance.mobile = request.data.get('newPassword', None)
 | 
			
		||||
        instance.password = request.data.get('newPassword', None)
 | 
			
		||||
        if not authenticate(username=request.user.username, password=request.data.get('oldPassword', None)):
 | 
			
		||||
            return ErrorResponse(msg='旧密码不正确!')
 | 
			
		||||
        instance.set_password(request.data.get('newPassword'))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,8 +33,8 @@
 | 
			
		|||
-- ----------------------------
 | 
			
		||||
-- Records of permission_userprofile
 | 
			
		||||
-- ----------------------------
 | 
			
		||||
INSERT INTO `permission_userprofile` (id, password, last_login, is_superuser, first_name, last_name, is_staff, is_active, date_joined, username, secret, email, mobile, avatar, name, gender, remark, user_type, create_datetime, update_datetime, dept_id, dept_belong_id) VALUES (1, 'pbkdf2_sha256$150000$OjTMSXJgkzrE$jEQCjWbIbXwpN4k2z0o8Yvou1UQGuoJALyL/kGDZFd4=', '2021-02-27 06:20:28.214775', 1, '', '', 1, 1, '2021-02-27 06:20:09.188689', 'admin', '3704adf3-380f-4c27-a8da-60420e8cb4ab', 'admin@qq.com', NULL, NULL, '管理员', '2', '1', 2, '2021-02-27 06:20:09.263192', '2021-02-27 09:14:30.009998', 8, 1);
 | 
			
		||||
INSERT INTO `permission_userprofile` (id, password, last_login, is_superuser, first_name, last_name, is_staff, is_active, date_joined, username, secret, email, mobile, avatar, name, gender, remark, user_type, create_datetime, update_datetime, dept_id, dept_belong_id) VALUES (2, 'pbkdf2_sha256$150000$5Z9LSi7LpNms$xVguE/dOEpI4D95LjSaKm0xzG7vNSopUolANr8f/6/E=', NULL, 0, '', '', 0, 1, '2021-03-03 15:38:27.009893', 'dvadmin', 'b4c5d79a-f01c-4244-92f8-b5288eca1d50', NULL, NULL, NULL, '普通用户', '2', NULL, 0, '2021-03-03 15:38:27.010771', '2021-03-03 15:38:27.086069', 8, 1);
 | 
			
		||||
INSERT INTO `permission_userprofile` (id, password, last_login, is_superuser, first_name, last_name, is_staff, is_active, date_joined, username, secret, email, mobile, avatar, name, gender, remark, user_type, create_datetime, update_datetime, dept_id, dept_belong_id, creator_id) VALUES (1, 'pbkdf2_sha256$150000$OjTMSXJgkzrE$jEQCjWbIbXwpN4k2z0o8Yvou1UQGuoJALyL/kGDZFd4=', '2021-02-27 06:20:28.214775', 1, '', '', 1, 1, '2021-02-27 06:20:09.188689', 'admin', '3704adf3-380f-4c27-a8da-60420e8cb4ab', 'admin@qq.com', NULL, NULL, '管理员', '2', '1', 2, '2021-02-27 06:20:09.263192', '2021-02-27 09:14:30.009998', 1, 1, 1);
 | 
			
		||||
INSERT INTO `permission_userprofile` (id, password, last_login, is_superuser, first_name, last_name, is_staff, is_active, date_joined, username, secret, email, mobile, avatar, name, gender, remark, user_type, create_datetime, update_datetime, dept_id, dept_belong_id, creator_id) VALUES (2, 'pbkdf2_sha256$150000$5Z9LSi7LpNms$xVguE/dOEpI4D95LjSaKm0xzG7vNSopUolANr8f/6/E=', NULL, 0, '', '', 0, 1, '2021-03-03 15:38:27.009893', 'dvadmin', 'b4c5d79a-f01c-4244-92f8-b5288eca1d50', NULL, NULL, NULL, '普通用户', '2', NULL, 0, '2021-03-03 15:38:27.010771', '2021-03-03 15:38:27.086069', 1, 1, 1);
 | 
			
		||||
-- ----------------------------
 | 
			
		||||
-- Table structure for permission_userprofile_post
 | 
			
		||||
-- ----------------------------
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,9 +13,10 @@ def files_path(instance, filename):
 | 
			
		|||
 | 
			
		||||
class SaveFile(CoreModel):
 | 
			
		||||
    name = CharField(max_length=128, verbose_name="文件名称", null=True, blank=True)
 | 
			
		||||
    type = CharField(max_length=32, verbose_name="文件类型", null=True, blank=True)
 | 
			
		||||
    type = CharField(max_length=200, 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, )
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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}"
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,7 @@ from rest_framework.routers import DefaultRouter
 | 
			
		|||
 | 
			
		||||
from ..system.views import DictDataModelViewSet, DictDetailsModelViewSet, \
 | 
			
		||||
    ConfigSettingsModelViewSet, SaveFileModelViewSet, MessagePushModelViewSet, LoginInforModelViewSet, \
 | 
			
		||||
    OperationLogModelViewSet, CeleryLogModelViewSet
 | 
			
		||||
    OperationLogModelViewSet, CeleryLogModelViewSet, SystemInfoApiView
 | 
			
		||||
 | 
			
		||||
router = DefaultRouter()
 | 
			
		||||
router.register(r'dict/type', DictDataModelViewSet)
 | 
			
		||||
| 
						 | 
				
			
			@ -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,9 @@ 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', })),
 | 
			
		||||
    # 获取系统信息cpu、内存、硬盘
 | 
			
		||||
    re_path('sys/info/', SystemInfoApiView.as_view())
 | 
			
		||||
]
 | 
			
		||||
urlpatterns += router.urls
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,22 +1,30 @@
 | 
			
		|||
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 rest_framework.views import APIView
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
from ..utils.system_info_utils import get_memory_used_percent, get_cpu_used_percent, get_disk_used_percent
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DictDataModelViewSet(CustomModelViewSet):
 | 
			
		||||
| 
						 | 
				
			
			@ -31,23 +39,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 +58,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 +72,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 +120,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 +137,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 +167,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):
 | 
			
		||||
    """
 | 
			
		||||
| 
						 | 
				
			
			@ -158,23 +202,31 @@ class MessagePushModelViewSet(CustomModelViewSet):
 | 
			
		|||
    serializer_class = MessagePushSerializer
 | 
			
		||||
    create_serializer_class = MessagePushCreateUpdateSerializer
 | 
			
		||||
    update_serializer_class = MessagePushCreateUpdateSerializer
 | 
			
		||||
    extra_filter_backends = [DataLevelPermissionsFilter]
 | 
			
		||||
    # 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):
 | 
			
		||||
        """
 | 
			
		||||
        获取用户自己消息列表
 | 
			
		||||
        """
 | 
			
		||||
        queryset = self.filter_queryset(self.get_queryset())
 | 
			
		||||
        queryset = queryset.filter(status=2)
 | 
			
		||||
        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 +249,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 +258,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 +286,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 +312,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 = ['任务名称', '执行参数', '执行时间', '运行状态', '任务结果', '创建时间']
 | 
			
		||||
| 
						 | 
				
			
			@ -281,3 +331,21 @@ class CeleryLogModelViewSet(CustomModelViewSet):
 | 
			
		|||
        """
 | 
			
		||||
        self.get_queryset().delete()
 | 
			
		||||
        return SuccessResponse(msg="清空成功")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SystemInfoApiView(APIView):
 | 
			
		||||
    """
 | 
			
		||||
    系统服务监控视图
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def get(self, request, *args, **kwargs):
 | 
			
		||||
        # 获取内存使用率
 | 
			
		||||
        memory_used_percent = get_memory_used_percent()
 | 
			
		||||
        # 获取cpu使用率
 | 
			
		||||
        cpu_used_percent = get_cpu_used_percent()
 | 
			
		||||
        # 获取硬盘使用率
 | 
			
		||||
        disk_used_percent = get_disk_used_percent()
 | 
			
		||||
        return SuccessResponse(data={"memory_used_percent": memory_used_percent,
 | 
			
		||||
                                     "cpu_used_percent": cpu_used_percent,
 | 
			
		||||
                                     "disk_used_percent": disk_used_percent
 | 
			
		||||
                                     })
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,8 +12,8 @@ from django.utils.translation import ugettext as _
 | 
			
		|||
from rest_framework import exceptions
 | 
			
		||||
from rest_framework_jwt.utils import jwt_decode_handler
 | 
			
		||||
 | 
			
		||||
from .decorators import exceptionHandler
 | 
			
		||||
from .jwt_util import jwt_get_session_id
 | 
			
		||||
from ..permission.models.users import UserProfile
 | 
			
		||||
 | 
			
		||||
logger = logging.getLogger(__name__)
 | 
			
		||||
User = get_user_model()
 | 
			
		||||
| 
						 | 
				
			
			@ -38,6 +38,8 @@ class OpAuthJwtAuthentication(object):
 | 
			
		|||
            raise exceptions.AuthenticationFailed(msg)
 | 
			
		||||
        except jwt.InvalidTokenError:
 | 
			
		||||
            raise exceptions.AuthenticationFailed()
 | 
			
		||||
        except UserProfile.DoesNotExist:
 | 
			
		||||
            raise exceptions.AuthenticationFailed()
 | 
			
		||||
 | 
			
		||||
        username = payload.get('username', None)
 | 
			
		||||
        if not username:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -65,8 +65,6 @@ def op_exception_handler(ex, context):
 | 
			
		|||
    """
 | 
			
		||||
    msg = ''
 | 
			
		||||
    code = '201'
 | 
			
		||||
    request = context.get('request')
 | 
			
		||||
    request.session['model_name'] = str(get_verbose_name(view=context.get('view')))
 | 
			
		||||
 | 
			
		||||
    if isinstance(ex, AuthenticationFailed):
 | 
			
		||||
        code = 401
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -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,10 @@ 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
 | 
			
		||||
    try:
 | 
			
		||||
        user, tokrn = OpAuthJwtAuthentication().authenticate(request)
 | 
			
		||||
    except Exception as e:
 | 
			
		||||
        pass
 | 
			
		||||
    return user or AnonymousUser()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -127,9 +119,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 +176,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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
"""
 | 
			
		||||
常用的Response以及Django的Response、DRF的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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,27 @@
 | 
			
		|||
import psutil as psutil
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_cpu_info():
 | 
			
		||||
    """
 | 
			
		||||
    获取cpu所有信息
 | 
			
		||||
    """
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_memory_info():
 | 
			
		||||
    """
 | 
			
		||||
    获取内存所有信息
 | 
			
		||||
    """
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_disk_info():
 | 
			
		||||
    """
 | 
			
		||||
    获取硬盘所有信息
 | 
			
		||||
    """
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_cpu_used_percent():
 | 
			
		||||
    """
 | 
			
		||||
    获取CPU运行情况
 | 
			
		||||
| 
						 | 
				
			
			@ -31,7 +52,5 @@ def get_disk_used_percent():
 | 
			
		|||
        pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    get_cpu_used_percent()
 | 
			
		||||
    get_disk_used_percent()
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -25,3 +26,4 @@ xlrd==2.0.1
 | 
			
		|||
coreapi==2.3.3
 | 
			
		||||
user-agents==2.2.0
 | 
			
		||||
eventlet==0.30.2
 | 
			
		||||
psutil==5.8.0
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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  | 
| 
						 | 
				
			
			@ -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
 | 
			
		||||
---
 | 
			
		||||
| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
# 关于我们
 | 
			
		||||
| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
# 项目介绍
 | 
			
		||||
| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
# 更新日志
 | 
			
		||||
| 
						 | 
				
			
			@ -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'
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
# 快速了解
 | 
			
		||||
| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
# 后台手册
 | 
			
		||||
| 
						 | 
				
			
			@ -1,29 +0,0 @@
 | 
			
		|||
# 前端手册
 | 
			
		||||
## 添加菜单页面
 | 
			
		||||
 | 
			
		||||
- 在views中添加页面,如下
 | 
			
		||||
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
- 在前端系统中,权限管理——菜单管理——新增
 | 
			
		||||
 | 
			
		||||
  - 例如:一级菜单(目录)
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
  - 添加末级菜单
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
  - 添加外链跳转菜单(菜单类型目录菜单均可)
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
  - 按钮同理
 | 
			
		||||
 | 
			
		||||
- 给角色添加按钮权限
 | 
			
		||||
  
 | 
			
		||||
  - 权限管理——角色管理——修改——添加对应按钮——刷新页面即可。
 | 
			
		||||
  
 | 
			
		||||
    <img src="http://pic.pgroom.cn/image-20210228010835275.png" alt="image-20210228010835275" style="zoom: 33%;" />
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
# 常见问题
 | 
			
		||||
| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
# 捐赠支持
 | 
			
		||||
| 
						 | 
				
			
			@ -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"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -3,7 +3,7 @@ ENV = 'development'
 | 
			
		|||
 | 
			
		||||
# 若依管理系统/开发环境
 | 
			
		||||
# VUE_APP_BASE_API = 'https://api.django-vue-admin.com'
 | 
			
		||||
VUE_APP_BASE_API = 'http://127.0.0.1:8000'
 | 
			
		||||
VUE_APP_BASE_API = 'http://127.0.0.1:8888'
 | 
			
		||||
 | 
			
		||||
# 路由懒加载
 | 
			
		||||
VUE_CLI_BABEL_TRANSPILE_MODULES = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,22 +2,22 @@
 | 
			
		|||
 | 
			
		||||
```bash
 | 
			
		||||
# 克隆项目
 | 
			
		||||
git clone https://gitee.com/y_project/RuoYi-Vue
 | 
			
		||||
git clone https://gitee.com/liqianglog/django-vue-admin.git
 | 
			
		||||
 | 
			
		||||
# 进入项目目录
 | 
			
		||||
cd ruoyi-ui
 | 
			
		||||
cd dvadmin-ui
 | 
			
		||||
 | 
			
		||||
# 安装依赖
 | 
			
		||||
npm install
 | 
			
		||||
 | 
			
		||||
# 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题
 | 
			
		||||
npm install --registry=https://registry.npm.taobao.org
 | 
			
		||||
 | 
			
		||||
# 启动服务
 | 
			
		||||
npm run dev
 | 
			
		||||
 | 
			
		||||
# 浏览器访问 http://localhost:8080
 | 
			
		||||
# .env.development 文件中可配置启动端口等参数
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
浏览器访问 http://localhost:80
 | 
			
		||||
浏览器访问 http://localhost:8080
 | 
			
		||||
 | 
			
		||||
## 发布
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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%",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,7 @@ import request from '@/utils/request'
 | 
			
		|||
// 查询在线用户列表
 | 
			
		||||
export function list(query) {
 | 
			
		||||
  return request({
 | 
			
		||||
    url: '/monitor/online/list',
 | 
			
		||||
    url: '/admin/monitor/online/list',
 | 
			
		||||
    method: 'get',
 | 
			
		||||
    params: query
 | 
			
		||||
  })
 | 
			
		||||
| 
						 | 
				
			
			@ -12,7 +12,7 @@ export function list(query) {
 | 
			
		|||
// 强退用户
 | 
			
		||||
export function forceLogout(tokenId) {
 | 
			
		||||
  return request({
 | 
			
		||||
    url: '/monitor/online/' + tokenId,
 | 
			
		||||
    url: '/admin/monitor/online/' + tokenId,
 | 
			
		||||
    method: 'delete'
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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'
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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'
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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'
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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'
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
        <div class="right-menu-item hover-effect">
 | 
			
		||||
          <router-link to="/user/msg">
 | 
			
		||||
            <i class="el-icon-message-solid badge-item-icon"></i>
 | 
			
		||||
            <el-badge :value="count" :max="99" style="margin-left: -4px;" v-if="count">
 | 
			
		||||
            <el-badge :value="unread_msg_count" :max="99" style="margin-left: -4px;" v-if="unread_msg_count">
 | 
			
		||||
          </el-badge>
 | 
			
		||||
          </router-link>
 | 
			
		||||
        </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -81,11 +81,11 @@ export default {
 | 
			
		|||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      count: store.getters.unread_msg_count,
 | 
			
		||||
      count: store.unread_msg_count,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapGetters(["sidebar", "avatar", "device"]),
 | 
			
		||||
    ...mapGetters(["sidebar", "avatar", "device", "unread_msg_count"]),
 | 
			
		||||
    setting: {
 | 
			
		||||
      get() {
 | 
			
		||||
        return this.$store.state.settings.showSettings;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,8 @@ const user = {
 | 
			
		|||
    name: '',
 | 
			
		||||
    avatar: '',
 | 
			
		||||
    roles: [],
 | 
			
		||||
    permissions: []
 | 
			
		||||
    permissions: [],
 | 
			
		||||
    unread_msg_count: 0
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  mutations: {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -253,7 +253,7 @@ export default {
 | 
			
		|||
        leader: undefined,
 | 
			
		||||
        phone: undefined,
 | 
			
		||||
        email: undefined,
 | 
			
		||||
        status: "0"
 | 
			
		||||
        status:  this.selectDictDefault(this.statusOptions),
 | 
			
		||||
      };
 | 
			
		||||
      this.resetForm("form");
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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");
 | 
			
		||||
      },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -242,7 +242,7 @@ export default {
 | 
			
		|||
        postCode: undefined,
 | 
			
		||||
        postName: undefined,
 | 
			
		||||
        postSort: 0,
 | 
			
		||||
        status: "0",
 | 
			
		||||
        status: this.selectDictDefault(this.statusOptions),
 | 
			
		||||
        remark: undefined
 | 
			
		||||
      };
 | 
			
		||||
      this.resetForm("form");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -440,7 +440,7 @@ export default {
 | 
			
		|||
        roleName: undefined,
 | 
			
		||||
        roleKey: undefined,
 | 
			
		||||
        roleSort: 0,
 | 
			
		||||
        status: "0",
 | 
			
		||||
        status: this.selectDictDefault(this.statusOptions),
 | 
			
		||||
        menu: [],
 | 
			
		||||
        dept: [],
 | 
			
		||||
        menuCheckStrictly: true,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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("清理成功");
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -274,7 +274,7 @@ export default {
 | 
			
		|||
        id: undefined,
 | 
			
		||||
        dictName: undefined,
 | 
			
		||||
        dictType: undefined,
 | 
			
		||||
        status: "0",
 | 
			
		||||
        status: this.selectDictDefault(this.statusOptions),
 | 
			
		||||
        remark: undefined
 | 
			
		||||
      };
 | 
			
		||||
      this.resetForm("form");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -103,9 +103,11 @@
 | 
			
		|||
        // 修改通知查询状态
 | 
			
		||||
        if (this.badgeType === "danger") {
 | 
			
		||||
          updateIsRead(this.showingMsgItem).then(response => {
 | 
			
		||||
            store.getters.unread_msg_count
 | 
			
		||||
            this.open = false;
 | 
			
		||||
            this.getList();
 | 
			
		||||
            if(response.code === 200){
 | 
			
		||||
              store.commit('SET_UNREAD_MSG_COUNT', store.getters.unread_msg_count - 1);
 | 
			
		||||
              this.open = false;
 | 
			
		||||
              this.getList();
 | 
			
		||||
            }
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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");
 | 
			
		||||
      },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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");
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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>
 | 
			
		||||
           
 | 
			
		||||
          <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>
 | 
			
		||||
           
 | 
			
		||||
          <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);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue