Merge remote-tracking branch 'origin/v2.x' into v2.x

pull/63/head
猿小天 2022-05-31 17:16:23 +08:00
commit d20ae4d133
33 changed files with 191 additions and 104 deletions

View File

@ -45,12 +45,12 @@
- 插件市场:[戳我](https://bbs.django-vue-admin.com/plugMarket.html)👩‍👦‍👦 - 插件市场:[戳我](https://bbs.django-vue-admin.com/plugMarket.html)👩‍👦‍👦
- django-vue-admin交流01群812482043 [点击链接加入群聊](https://qm.qq.com/cgi-bin/qm/qr?k=aJVwjDvH-Es4MPJQuoO32N0SucK22TE5&jump_from=webapi) - django-vue-admin交流01群(已满)812482043 [点击链接加入群聊](https://qm.qq.com/cgi-bin/qm/qr?k=aJVwjDvH-Es4MPJQuoO32N0SucK22TE5&jump_from=webapi)
- django-vue-admin交流02群687252418 [点击链接加入群聊](https://qm.qq.com/cgi-bin/qm/qr?k=4jJN4IjWGfxJ8YJXbb_gTsuWjR34WLdc&jump_from=webapi) - django-vue-admin交流02群687252418 [点击链接加入群聊](https://qm.qq.com/cgi-bin/qm/qr?k=4jJN4IjWGfxJ8YJXbb_gTsuWjR34WLdc&jump_from=webapi)
- 二维码 - 二维码
<img src='https://gitee.com/liqianglog/django-vue-admin/raw/master/dvadmin-ui/src/assets/images/qq.jpg' width='200'> <img src='https://images.gitee.com/uploads/images/2022/0530/233203_5fb11883_5074988.jpeg' width='200'>
## 源码地址 ## 源码地址
@ -82,7 +82,7 @@ github地址[https://github.com/liqianglog/django-vue-admin](https://github.c
## 准备工作 ## 准备工作
~~~ ~~~
Python >= 3.6.0 (推荐3.8+版本) Python >= 3.8.0 (推荐3.8+版本)
nodejs >= 14.0 (推荐最新) nodejs >= 14.0 (推荐最新)
Mysql >= 5.7.0 (可选默认数据库sqlite3推荐8.0版本) Mysql >= 5.7.0 (可选默认数据库sqlite3推荐8.0版本)
Redis(可选,最新版) Redis(可选,最新版)
@ -148,14 +148,15 @@ npm run dev
# 先安装docker-compose (自行百度安装),执行此命令等待安装如有使用celery插件请打开docker-compose.yml中celery 部分注释 # 先安装docker-compose (自行百度安装),执行此命令等待安装如有使用celery插件请打开docker-compose.yml中celery 部分注释
docker-compose up -d docker-compose up -d
# 初始化后端数据(第一次执行即可) # 初始化后端数据(第一次执行即可)
docker exec -ti DVAdmin-django bash docker exec -ti dvadmin-django bash
python manage.py makemigrations python manage.py makemigrations
python manage.py migrate python manage.py migrate
python manage.py init -y python manage.py init_area
python manage.py init
exit exit
前端地址http://127.0.0.1:8080 前端地址http://127.0.0.1:8080
后端地址http://127.0.0.1:8000 后端地址http://127.0.0.1:8080/api
# 在服务器上请把127.0.0.1 换成自己公网ip # 在服务器上请把127.0.0.1 换成自己公网ip
账号superadmin 密码admin123456 账号superadmin 密码admin123456
@ -171,21 +172,25 @@ docker-compose up -d --build
## 演示图✅ ## 演示图✅
![image-01](https://gitee.com/liqianglog/pic/raw/master/master/01.png) ![image-01](https://images.gitee.com/uploads/images/2022/0530/234137_b58c8f98_5074988.png)
![image-02](https://gitee.com/liqianglog/pic/raw/master/master/02.png) ![image-02](https://images.gitee.com/uploads/images/2022/0530/234240_39834603_5074988.png)
![image-03](https://gitee.com/liqianglog/pic/raw/master/master/03.png) ![image-03](https://images.gitee.com/uploads/images/2022/0530/234339_35e728a0_5074988.png)
![image-04](https://gitee.com/liqianglog/pic/raw/master/master/04.png) ![image-04](https://images.gitee.com/uploads/images/2022/0530/234426_957036b0_5074988.png)
![image-05](https://gitee.com/liqianglog/pic/raw/master/master/05.png) ![image-05](https://images.gitee.com/uploads/images/2022/0530/234458_898be492_5074988.png)
![image-06](https://gitee.com/liqianglog/pic/raw/master/master/06.png) ![image-06](https://images.gitee.com/uploads/images/2022/0530/234521_35b40076_5074988.png)
![image-07](https://gitee.com/liqianglog/pic/raw/master/master/06.png) ![image-07](https://images.gitee.com/uploads/images/2022/0530/234615_c2325639_5074988.png)
![image-08](https://gitee.com/liqianglog/pic/raw/master/master/08.png) ![image-08](https://images.gitee.com/uploads/images/2022/0530/234639_1ed6cc93_5074988.png)
![image-09](https://images.gitee.com/uploads/images/2022/0530/234815_cea2c53f_5074988.png)
![image-10](https://images.gitee.com/uploads/images/2022/0530/234840_5f3e5f53_5074988.png)

View File

@ -12,5 +12,6 @@ import os
from django.core.asgi import get_asgi_application from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings') os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true"
application = get_asgi_application() application = get_asgi_application()

View File

@ -1,9 +1,9 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django.conf import settings from django.conf import settings
from django.db import ProgrammingError
from django.db import connection from django.db import connection
def is_tenants_mode(): def is_tenants_mode():
""" """
判断是否为租户模式 判断是否为租户模式
@ -35,7 +35,7 @@ def _get_all_system_config():
system_config_obj = SystemConfig.objects.filter(status=True, parent_id__isnull=False).values( system_config_obj = SystemConfig.objects.filter(status=True, parent_id__isnull=False).values(
'parent__key', 'key', 'value', 'form_item_type').order_by('sort') 'parent__key', 'key', 'value', 'form_item_type').order_by('sort')
for system_config in system_config_obj: for system_config in system_config_obj:
value = system_config.get('value') or '' value = system_config.get('value', '')
if value and system_config.get('form_item_type') == 7: if value and system_config.get('form_item_type') == 7:
value = value[0].get('url') value = value[0].get('url')
data[f"{system_config.get('parent__key')}.{system_config.get('key')}"] = value data[f"{system_config.get('parent__key')}.{system_config.get('key')}"] = value

View File

@ -12,5 +12,6 @@ import os
from django.core.wsgi import get_wsgi_application from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings') os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true"
application = get_wsgi_application() application = get_wsgi_application()

View File

@ -24,7 +24,7 @@ DATABASE_USER = "root"
DATABASE_PASSWORD = "123456" DATABASE_PASSWORD = "123456"
# 表前缀 # 表前缀
TABLE_PREFIX = "sys_" TABLE_PREFIX = "dvadmin_"
# ================================================= # # ================================================= #
# ******** redis配置无redis 可不进行配置 ******** # # ******** redis配置无redis 可不进行配置 ******** #
# ================================================= # # ================================================= #

View File

@ -255,13 +255,13 @@
{ {
"name": "重设密码", "name": "重设密码",
"value": "ResetPassword", "value": "ResetPassword",
"api": "/api/system/user/reset_password/{id}/", "api": "/api/system/user/{id}/reset_password/",
"method": 2 "method": 2
}, },
{ {
"name": "重置密码", "name": "重置密码",
"value": "DefaultPassword", "value": "DefaultPassword",
"api": "/api/system/user/reset_to_default_password/{id}/", "api": "/api/system/user/{id}/reset_to_default_password/",
"method": 2 "method": 2
}, },
{ {

View File

@ -188,6 +188,11 @@ class Dictionary(CoreModel):
super().save(force_insert, force_update, using, update_fields) super().save(force_insert, force_update, using, update_fields)
dispatch.refresh_dictionary() # 有更新则刷新字典配置 dispatch.refresh_dictionary() # 有更新则刷新字典配置
def delete(self, using=None, keep_parents=False):
res = super().delete(using, keep_parents)
dispatch.refresh_dictionary()
return res
class OperationLog(CoreModel): class OperationLog(CoreModel):
request_modular = models.CharField(max_length=64, verbose_name="请求模块", null=True, blank=True, help_text="请求模块") request_modular = models.CharField(max_length=64, verbose_name="请求模块", null=True, blank=True, help_text="请求模块")
@ -321,6 +326,11 @@ class SystemConfig(CoreModel):
super().save(force_insert, force_update, using, update_fields) super().save(force_insert, force_update, using, update_fields)
dispatch.refresh_system_config() # 有更新则刷新系统配置 dispatch.refresh_system_config() # 有更新则刷新系统配置
def delete(self, using=None, keep_parents=False):
res = super().delete(using, keep_parents)
dispatch.refresh_system_config()
return res
class LoginLog(CoreModel): class LoginLog(CoreModel):
LOGIN_TYPE_CHOICES = ( LOGIN_TYPE_CHOICES = (

View File

@ -28,12 +28,6 @@ system_url.register(r'api_white_list', ApiWhiteListViewSet)
system_url.register(r'system_config', SystemConfigViewSet) system_url.register(r'system_config', SystemConfigViewSet)
urlpatterns = [ urlpatterns = [
path('role/roleId_get_menu/<int:pk>/', RoleViewSet.as_view({'get': 'roleId_get_menu'})),
path('menu/web_router/', MenuViewSet.as_view({'get': 'web_router'})),
path('user/user_info/', UserViewSet.as_view({'get': 'user_info', 'put': 'update_user_info'})),
path('user/change_password/<int:pk>/', UserViewSet.as_view({'put': 'change_password'})),
path('user/reset_to_default_password/<int:pk>/', UserViewSet.as_view({'put': 'reset_to_default_password'})),
path('user/reset_password/<int:pk>/', UserViewSet.as_view({'put': 'reset_password'})),
path('user/export/', UserViewSet.as_view({'post': 'export_data', })), path('user/export/', UserViewSet.as_view({'post': 'export_data', })),
path('user/import/', UserViewSet.as_view({'get': 'import_data', 'post': 'import_data'})), path('user/import/', UserViewSet.as_view({'get': 'import_data', 'post': 'import_data'})),
path('system_config/save_content/', SystemConfigViewSet.as_view({'put': 'save_content'})), path('system_config/save_content/', SystemConfigViewSet.as_view({'put': 'save_content'})),

View File

@ -157,7 +157,7 @@ class MenuViewSet(CustomModelViewSet):
filter_fields = ['parent', 'name', 'status', 'is_link', 'visible', 'cache', 'is_catalog'] filter_fields = ['parent', 'name', 'status', 'is_link', 'visible', 'cache', 'is_catalog']
extra_filter_backends = [] extra_filter_backends = []
@action(methods=['GET'], detail=True, permission_classes=[]) @action(methods=['GET'], detail=False, permission_classes=[])
def web_router(self, request): def web_router(self, request):
"""用于前端获取当前角色的路由""" """用于前端获取当前角色的路由"""
user = request.user user = request.user

View File

@ -101,6 +101,7 @@ class UserUpdateSerializer(CustomModelSerializer):
validators=[ validators=[
CustomUniqueValidator(queryset=Users.objects.all(), message="手机号必须唯一") CustomUniqueValidator(queryset=Users.objects.all(), message="手机号必须唯一")
], ],
allow_blank=True
) )
def save(self, **kwargs): def save(self, **kwargs):
@ -228,7 +229,7 @@ class UserViewSet(CustomModelViewSet):
"role": "角色ID", "role": "角色ID",
} }
@action(methods=["GET"], detail=True, permission_classes=[IsAuthenticated]) @action(methods=["GET"], detail=False, permission_classes=[IsAuthenticated])
def user_info(self, request): def user_info(self, request):
"""获取当前用户信息""" """获取当前用户信息"""
user = request.user user = request.user
@ -241,7 +242,7 @@ class UserViewSet(CustomModelViewSet):
} }
return DetailResponse(data=result, msg="获取成功") return DetailResponse(data=result, msg="获取成功")
@action(methods=["PUT"], detail=True, permission_classes=[IsAuthenticated]) @action(methods=["PUT"], detail=False, permission_classes=[IsAuthenticated])
def update_user_info(self, request): def update_user_info(self, request):
"""修改当前用户信息""" """修改当前用户信息"""
user = request.user user = request.user

View File

@ -165,8 +165,9 @@ class CustomDjangoFilterBackend(DjangoFilterBackend):
def find_filter_lookups(self, orm_lookups, search_term_key): def find_filter_lookups(self, orm_lookups, search_term_key):
for lookup in orm_lookups: for lookup in orm_lookups:
# if lookup.find(search_term_key) >= 0: # if lookup.find(search_term_key) >= 0:
new_lookup = lookup.split("__")[0]
# 修复条件搜索错误 bug # 修复条件搜索错误 bug
if lookup == search_term_key: if new_lookup == search_term_key:
return lookup return lookup
return None return None

View File

@ -65,9 +65,7 @@ class ImportSerializerMixin:
for ele in data: for ele in data:
# 获取 unique 字段 # 获取 unique 字段
filter_dic = {i: ele.get(i) for i in list(set(self.import_field_dict.keys()) & set(unique_list))} filter_dic = {i: ele.get(i) for i in list(set(self.import_field_dict.keys()) & set(unique_list))}
print(11, ele)
instance = filter_dic and queryset.filter(**filter_dic).first() instance = filter_dic and queryset.filter(**filter_dic).first()
print(22, instance)
if instance and not updateSupport: if instance and not updateSupport:
continue continue
if not filter_dic: if not filter_dic:

View File

@ -65,37 +65,27 @@ class CustomPermission(BasePermission):
def has_permission(self, request, view): def has_permission(self, request, view):
if isinstance(request.user, AnonymousUser): if isinstance(request.user, AnonymousUser):
return False return False
# 对ViewSet下的def方法进行权限判断
# 当权限为空时,则可以访问
is_head = getattr(view, 'head', None)
if is_head:
head_kwargs = getattr(view.head, 'kwargs', None)
if head_kwargs:
_permission_classes = getattr(head_kwargs, 'permission_classes', None)
if _permission_classes is None:
return True
# 判断是否是超级管理员 # 判断是否是超级管理员
if request.user.is_superuser: if request.user.is_superuser:
return True return True
else: else:
api = request.path # 当前请求接口 api = request.path # 当前请求接口
method = request.method # 当前请求方法 method = request.method # 当前请求方法
methodList = ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'] methodList = ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'PATCH']
method = methodList.index(method) method = methodList.index(method)
# ***接口白名单*** # ***接口白名单***
api_white_list = ApiWhiteList.objects.values(permission__api=F('url'), permission__method=F('method')) api_white_list = ApiWhiteList.objects.values(permission__api=F('url'), permission__method=F('method'))
api_white_list = [ api_white_list = [
str(item.get('permission__api').replace('{id}', '.*?')) + ":" + str(item.get('permission__method')) for str(item.get('permission__api').replace('{id}', '([a-zA-Z0-9-]+)')) + ":" + str(
item in api_white_list if item.get('permission__api')] item.get('permission__method')) + '$' for item in api_white_list if item.get('permission__api')]
# ********# # ********#
if not hasattr(request.user, "role"): if not hasattr(request.user, "role"):
return False return False
userApiList = request.user.role.values('permission__api', 'permission__method') # 获取当前用户的角色拥有的所有接口 userApiList = request.user.role.values('permission__api', 'permission__method') # 获取当前用户的角色拥有的所有接口
ApiList = [ ApiList = [
str(item.get('permission__api').replace('{id}', '.*?')) + ":" + str(item.get('permission__method')) for str(item.get('permission__api').replace('{id}', '([a-zA-Z0-9-]+)')) + ":" + str(
item in item.get('permission__method')) + '$' for item in userApiList if item.get('permission__api')]
userApiList if item.get('permission__api')] new_api_ist = api_white_list + ApiList
new_api_ist = api_white_list + ApiList
new_api = api + ":" + str(method) new_api = api + ":" + str(method)
for item in new_api_ist: for item in new_api_ist:
matchObj = re.match(item, new_api, re.M | re.I) matchObj = re.match(item, new_api, re.M | re.I)

View File

@ -4,7 +4,7 @@ chardet==4.0.0
coreapi==2.3.3 coreapi==2.3.3
coreschema==0.0.4 coreschema==0.0.4
Django==3.2.3 Django==3.2.3
django-comment-migrate==0.1.1 django-comment-migrate==0.1.5
django-cors-headers==3.10.1 django-cors-headers==3.10.1
django-filter==21.1 django-filter==21.1
django-ranged-response==0.2.0 django-ranged-response==0.2.0

View File

@ -2,6 +2,6 @@ FROM registry.cn-zhangjiakou.aliyuncs.com/dvadmin-pro/python38-base-backend:late
WORKDIR /backend WORKDIR /backend
COPY ./backend/ . COPY ./backend/ .
RUN awk 'BEGIN { cmd="cp -i ./conf/env.example.py ./conf/env.py "; print "n" |cmd; }' RUN awk 'BEGIN { cmd="cp -i ./conf/env.example.py ./conf/env.py "; print "n" |cmd; }'
RUN python3 -m pip install -i https://mirrors.aliyun.com/pypi/simple/ -r requirements.txt RUN python3 -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ -r requirements.txt
CMD ["celery", "-A", "application", "worker", "-B", "--loglevel=info"] CMD ["celery", "-A", "application", "worker", "-B", "--loglevel=info"]

View File

@ -2,5 +2,5 @@ FROM registry.cn-zhangjiakou.aliyuncs.com/dvadmin-pro/python38-base-backend:late
WORKDIR /backend WORKDIR /backend
COPY ./backend/ . COPY ./backend/ .
RUN awk 'BEGIN { cmd="cp -i ./conf/env.example.py ./conf/env.py "; print "n" |cmd; }' RUN awk 'BEGIN { cmd="cp -i ./conf/env.example.py ./conf/env.py "; print "n" |cmd; }'
RUN python3 -m pip install -i https://mirrors.aliyun.com/pypi/simple/ -r requirements.txt RUN python3 -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ -r requirements.txt
CMD ["daphne","-b","0.0.0.0","-p","8000","application.asgi:application"] CMD ["daphne","-b","0.0.0.0","-p","8000","application.asgi:application"]

View File

@ -7,7 +7,7 @@ server {
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https; proxy_set_header X-Forwarded-Proto https;
set_real_ip_from 177.7.0.0/16; set_real_ip_from 0.0.0.0/0;
real_ip_header X-Forwarded-For; real_ip_header X-Forwarded-For;
root /usr/share/nginx/html; root /usr/share/nginx/html;
index index.html index.php index.htm; index index.html index.php index.htm;
@ -18,9 +18,9 @@ server {
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Proto $scheme;
set_real_ip_from 177.7.0.0/16; set_real_ip_from 0.0.0.0/0;
real_ip_header X-Forwarded-For; real_ip_header X-Forwarded-For;
rewrite ^/api/(.*)$ /$1 break; #重写 rewrite ^/api/(.*)$ /$1 break; #重写
proxy_pass http://177.7.0.12:8000/; # 设置代理服务器的协议和地址 proxy_pass http://177.8.0.12:8000/; # 设置代理服务器的协议和地址
} }
} }

View File

@ -42,7 +42,7 @@ export function getErrorMessage (msg) {
function createService () { function createService () {
// 创建一个 axios 实例 // 创建一个 axios 实例
const service = axios.create({ const service = axios.create({
baseURL: process.env.VUE_APP_API_URL, baseURL: util.baseURL(),
timeout: 20000, timeout: 20000,
paramsSerializer: (params) => qs.stringify(params, { indices: false }) paramsSerializer: (params) => qs.stringify(params, { indices: false })
}) })

View File

@ -59,7 +59,7 @@ export default {
// //
headers: { Authorization: 'JWT ' + util.cookies.get('token') }, headers: { Authorization: 'JWT ' + util.cookies.get('token') },
// //
url: process.env.VUE_APP_API + '/api/system/file/' url: util.baseURL() + 'api/system/file/'
} }
} }
}, },
@ -78,7 +78,7 @@ export default {
/** 下载模板操作 */ /** 下载模板操作 */
importTemplate () { importTemplate () {
downloadFile({ downloadFile({
url: process.env.VUE_APP_API + this.importApi, url: util.baseURL() + this.importApi,
params: {}, params: {},
method: 'get' method: 'get'
}) })

View File

@ -242,7 +242,7 @@ export default {
...defaultElProps.columns ...defaultElProps.columns
] ]
} else { } else {
defaultElProps.radioConfig = this.elProps.radioConfig defaultElProps.radioConfig = this.elProps
? this.elProps.radioConfig ? this.elProps.radioConfig
: {} : {}
defaultElProps.columns = [ defaultElProps.columns = [

View File

@ -1,3 +1,4 @@
import util from '@/libs/util.js'
export default { export default {
'image-uploader': { 'image-uploader': {
form: { component: { name: 'd2p-file-uploader', props: { elProps: { listType: 'picture-card', accept: '.png,.jpeg,.jpg,.ico,.bmp,.gif' } } } }, form: { component: { name: 'd2p-file-uploader', props: { elProps: { listType: 'picture-card', accept: '.png,.jpeg,.jpg,.ico,.bmp,.gif' } } } },
@ -26,6 +27,14 @@ export default {
const value = row[col.key] const value = row[col.key]
if (value != null && value) { if (value != null && value) {
row[col.key] = value.split(',') row[col.key] = value.split(',')
// 进行组装地址纠正地址
row[col.key].map((val, index) => {
if (val.startsWith('/')) {
row[col.key][index] = util.baseURL() + val.slice(1)
} else {
row[col.key][index] = !val.startsWith('http') ? util.baseURL() + val : val
}
})
} }
} }
}, },
@ -56,6 +65,14 @@ export default {
const value = row[col.key] const value = row[col.key]
if (value != null && value) { if (value != null && value) {
row[col.key] = value.split(',') row[col.key] = value.split(',')
// 进行组装地址纠正地址
row[col.key].map((val, index) => {
if (val.startsWith('/')) {
row[col.key][index] = util.baseURL() + val.slice(1)
} else {
row[col.key][index] = !val.startsWith('http') ? util.baseURL() + val : val
}
})
} }
} }
}, },
@ -82,6 +99,14 @@ export default {
const value = row[col.key] const value = row[col.key]
if (value != null && value) { if (value != null && value) {
row[col.key] = value.split(',') row[col.key] = value.split(',')
// 进行组装地址纠正地址
row[col.key].map((val, index) => {
if (val.startsWith('/')) {
row[col.key][index] = util.baseURL() + val.slice(1)
} else {
row[col.key][index] = !val.startsWith('http') ? util.baseURL() + val : val
}
})
} }
} }
}, },
@ -112,6 +137,14 @@ export default {
const value = row[col.key] const value = row[col.key]
if (value != null && value) { if (value != null && value) {
row[col.key] = value.split(',') row[col.key] = value.split(',')
// 进行组装地址纠正地址
row[col.key].map((val, index) => {
if (val.startsWith('/')) {
row[col.key][index] = util.baseURL() + val.slice(1)
} else {
row[col.key][index] = !val.startsWith('http') ? util.baseURL() + val : val
}
})
} }
} }
} }

View File

@ -18,8 +18,7 @@ import XEUtils from 'xe-utils'
import store from '@/store/index' import store from '@/store/index'
import { urlPrefix as deptPrefix } from '@/views/system/dept/api' import { urlPrefix as deptPrefix } from '@/views/system/dept/api'
import types from '@/config/d2p-extends/types' import types from '@/config/d2p-extends/types'
import { checkPlugins } from '@/views/plugins' import { checkPlugins, plugins } from '@/views/plugins'
const uploadUrl = util.baseURL() + 'api/system/file/'
/** /**
// vxe0 // vxe0
@ -32,7 +31,8 @@ const uploadUrl = util.baseURL() + 'api/system/file/'
// 按如下重命名引入可与官方版共存index.vue中标签用<d2-crud-x />使用加强版 // 按如下重命名引入可与官方版共存index.vue中标签用<d2-crud-x />使用加强版
// 不传name则d2CrudX的标签仍为<d2-crud>,不可与官方版共存 // 不传name则d2CrudX的标签仍为<d2-crud>,不可与官方版共存
Vue.use(d2CrudX, { name: 'd2-crud-x' }) Vue.use(d2CrudX, { name: 'd2-crud-x' })
// 注册dvadmin插件
Vue.use(plugins)
// // 官方版此处为演示与官方版共存而引入全新项目中可以用d2-crud-x完全替代官方版 // // 官方版此处为演示与官方版共存而引入全新项目中可以用d2-crud-x完全替代官方版
// Vue.use(d2Crud) // Vue.use(d2Crud)
/** /**
@ -167,7 +167,7 @@ Vue.use(D2pUploader, {
domain: 'http://d2p.file.veryreader.com' domain: 'http://d2p.file.veryreader.com'
}, },
form: { form: {
action: uploadUrl, action: util.baseURL() + 'api/system/file/',
name: 'file', name: 'file',
data: {}, // 上传附加参数 data: {}, // 上传附加参数
headers () { headers () {
@ -180,7 +180,7 @@ Vue.use(D2pUploader, {
if (ret.data === null || ret.data === '') { if (ret.data === null || ret.data === '') {
throw new Error('上传失败') throw new Error('上传失败')
} }
return { url: util.baseURL() + ret.data.url, key: option.data.key } return { url: util.baseURL() + ret.data.url, key: option.data.key, id: ret.data.id }
}, },
withCredentials: false // 是否带cookie withCredentials: false // 是否带cookie
} }
@ -368,6 +368,20 @@ Vue.prototype.commonEndColumns = function (param = {}) {
title: '创建时间', title: '创建时间',
key: 'create_datetime', key: 'create_datetime',
width: 160, width: 160,
search: {
disabled: !showData.create_datetime.showForm,
width: 240,
component: { // 查询框组件配置默认根据form配置生成
name: 'el-date-picker',
props: {
type: 'daterange',
'range-separator': '',
'start-placeholder': '开始',
'end-placeholder': '结束',
valueFormat: 'yyyy-MM-dd'
}
}
},
show: showData.create_datetime.showTable, show: showData.create_datetime.showTable,
type: 'datetime', type: 'datetime',
sortable: true, sortable: true,

View File

@ -218,7 +218,7 @@ export default {
_self.$refs.userInfoForm.validate((valid) => { _self.$refs.userInfoForm.validate((valid) => {
if (valid) { if (valid) {
request({ request({
url: '/api/system/user/user_info/', url: '/api/system/user/update_user_info/',
method: 'put', method: 'put',
data: _self.userInfo data: _self.userInfo
}).then((res) => { }).then((res) => {
@ -266,7 +266,7 @@ export default {
params.newPassword = _self.$md5(params.newPassword) params.newPassword = _self.$md5(params.newPassword)
params.newPassword2 = _self.$md5(params.newPassword2) params.newPassword2 = _self.$md5(params.newPassword2)
request({ request({
url: '/api/system/user/change_password/' + userId + '/', url: '/api/system/user/' + userId + '/change_password/',
method: 'put', method: 'put',
data: params data: params
}).then((res) => { }).then((res) => {

View File

@ -76,7 +76,7 @@ export const handleRouter = function (menuData) {
meta: { meta: {
title: item.name, title: item.name,
auth: true, auth: true,
cache: item.cache === 1 cache: item.cache
} }
} }
result.push(obj) result.push(obj)

View File

@ -16,7 +16,6 @@ import pluginError from '@/plugin/error'
import pluginLog from '@/plugin/log' import pluginLog from '@/plugin/log'
import pluginOpen from '@/plugin/open' import pluginOpen from '@/plugin/open'
import tableSelector from '@/components/table-selector/index' import tableSelector from '@/components/table-selector/index'
import { plugins } from '@/views/plugins/index.js'
export default { export default {
async install (Vue, options) { async install (Vue, options) {
// 设置为 false 以阻止 vue 在启动时生成生产提示 // 设置为 false 以阻止 vue 在启动时生成生产提示
@ -40,6 +39,5 @@ export default {
Vue.use(pluginLog) Vue.use(pluginLog)
Vue.use(pluginOpen) Vue.use(pluginOpen)
Vue.use(tableSelector) Vue.use(tableSelector)
Vue.use(plugins)
} }
} }

View File

@ -35,12 +35,13 @@ export default {
*/ */
async load ({ state, dispatch, commit }) { async load ({ state, dispatch, commit }) {
// store 赋值 // store 赋值
state.data = await dispatch('d2admin/db/get', { const data = await dispatch('d2admin/db/get', {
dbName: 'sys', dbName: 'sys',
path: 'settings.init', path: 'settings.init',
defaultValue: {}, defaultValue: {},
user: true user: true
}, { root: true }) }, { root: true })
commit('set', data)
} }
}, },
mutations: { mutations: {
@ -52,6 +53,16 @@ export default {
*/ */
async get (state, key, value) { async get (state, key, value) {
return state[key] return state[key]
},
/**
* @description 赋值系统配置
* @param {Object} state state
* @param {Object} value active
*/
async set (state, value) {
state.data = value
state.keepRecord = value['login.keep_record']
return state.data
} }
} }
} }

View File

@ -7,6 +7,7 @@ export const crudOptions = (vm) => {
}, },
options: { options: {
tableType: 'vxe-table', tableType: 'vxe-table',
stripe: false,
rowKey: true, // 必须设置true or false rowKey: true, // 必须设置true or false
rowId: 'id', rowId: 'id',
height: '100%', // 表格高度100%, 使用toolbar必须设置 height: '100%', // 表格高度100%, 使用toolbar必须设置

View File

@ -1,15 +1,12 @@
<!--
* @创建文件时间: 2021-06-01 22:41:21
* @Auther: 猿小天
* @最后修改人: 猿小天
* @最后修改时间: 2021-08-09 20:27:09
* 联系Qq:1638245306
* @文件介绍: 字典管理
-->
<template> <template>
<d2-container :class="{ 'page-compact': crud.pageOptions.compact }"> <d2-container :class="{ 'page-compact': crud.pageOptions.compact }">
<!-- <template slot="header">测试页面1</template>--> <!-- <template slot="header">测试页面1</template>-->
<d2-crud-x ref="d2Crud" v-bind="_crudProps" v-on="_crudListeners" @dictionaryConfigure="dictionaryConfigure"> <d2-crud-x
ref="d2Crud"
v-bind="_crudProps"
v-on="_crudListeners"
@dictionaryConfigure="dictionaryConfigure"
>
<div slot="header"> <div slot="header">
<crud-search <crud-search
ref="search" ref="search"
@ -30,14 +27,18 @@
/> />
</div> </div>
</d2-crud-x> </d2-crud-x>
<el-drawer <el-drawer :visible.sync="drawer" :size="700">
:visible.sync="drawer" <div slot="title">
:size="700"> <span>字典列表</span>
<div slot="title"> <el-tag size="small" style="margin-left: 10px">{{
<span>字典列表</span> dictionaryRow.label
<el-tag size="small" style="margin-left: 10px">{{dictionaryRow.label}}</el-tag> }}</el-tag>
</div> </div>
<sub-dictionary style="margin-top: 80px;margin-left: 10px" :dictionaryRow="dictionaryRow"></sub-dictionary> <sub-dictionary
style="margin-top: 80px; margin-left: 10px"
:dictionaryRow="dictionaryRow"
>
</sub-dictionary>
</el-drawer> </el-drawer>
</d2-container> </d2-container>
</template> </template>
@ -80,6 +81,10 @@ export default {
dictionaryConfigure (scope) { dictionaryConfigure (scope) {
this.drawer = true this.drawer = true
this.dictionaryRow = scope.row this.dictionaryRow = scope.row
},
doAfterRowChange (row) {
this.doRefresh({ from: 'afterRowChange' })
this.$store.dispatch('d2admin/dictionary/load')
} }
} }
} }

View File

@ -44,8 +44,7 @@ export default {
} }
}, },
data () { data () {
return { return {}
}
}, },
methods: { methods: {
getCrudOptions () { getCrudOptions () {
@ -70,6 +69,10 @@ export default {
}, },
delRequest (row) { delRequest (row) {
return api.DelObj(row.id) return api.DelObj(row.id)
},
doAfterRowChange (row) {
this.doRefresh({ from: 'afterRowChange' })
this.$store.dispatch('d2admin/dictionary/load')
} }
} }
} }

View File

@ -3,7 +3,7 @@
</template> </template>
<script> <script>
import { mapActions } from 'vuex' import { mapActions, mapState } from 'vuex'
import localeMixin from '@/locales/mixin.js' import localeMixin from '@/locales/mixin.js'
import * as api from '@/views/system/login/api' import * as api from '@/views/system/login/api'
@ -15,15 +15,6 @@ export default {
}, },
data () { data () {
return { return {
siteName: this.systemConfig('login.site_name'), //
siteLogo: this.systemConfig('login.site_logo') || require('./image/dvadmin.png'), // logo
loginBackground: this.systemConfig('login.login_background') || require('./image/bg.jpg'), //
copyright: this.systemConfig('login.copyright'), //
keepRecord: this.systemConfig('login.keep_record'), //
helpUrl: this.systemConfig('login.help_url'), //
privacyUrl: this.systemConfig('login.privacy_url'), //
clauseUrl: this.systemConfig('login.clause_url'), //
captchaState: this.systemConfig('base.captcha_state') || true, //
processTitle: process.env.VUE_APP_TITLE || 'D2Admin', processTitle: process.env.VUE_APP_TITLE || 'D2Admin',
backgroundImage: 'url(' + this.loginBackground + ')', backgroundImage: 'url(' + this.loginBackground + ')',
// //
@ -67,6 +58,19 @@ export default {
] ]
} }
}, },
computed: {
...mapState('d2admin', {
siteLogo: state => state.settings.data['login.site_logo'] || require('./image/dvadmin.png'), // logo
keepRecord: state => state.settings.data['login.keep_record'],
siteName: state => state.settings.data['login.site_name'], //
copyright: state => state.settings.data['login.copyright'],
loginBackground: state => state.settings.data['login.login_background'] || require('./image/bg.jpg'), //
helpUrl: state => state.settings.data['login.help_url'], //
privacyUrl: state => state.settings.data['login.privacy_url'], //
clauseUrl: state => state.settings.data['login.clause_url'], //
captchaState: state => state.settings.data['base.captcha_state'] !== undefined ? state.settings.data['base.captcha_state'] : true //
})
},
mounted () { mounted () {
}, },
beforeDestroy () { beforeDestroy () {

View File

@ -170,7 +170,7 @@ export const crudOptions = (vm) => {
} }
} }
}, },
width: 180, minWidth: 180,
type: 'input', type: 'input',
form: { form: {
rules: [ // 表单校验规则 rules: [ // 表单校验规则
@ -225,7 +225,16 @@ export const crudOptions = (vm) => {
form: { form: {
value: false, value: false,
component: { component: {
placeholder: '请选择是否外链接' placeholder: '请选择是否目录'
},
valueChange (key, value, form, { getColumn, mode, component, immediate, getComponent }) {
if (!value) {
form.web_path = undefined
form.component = undefined
form.component_name = undefined
form.cache = false
form.is_link = false
}
} }
} }
}, },
@ -247,7 +256,9 @@ export const crudOptions = (vm) => {
placeholder: '请选择是否外链接' placeholder: '请选择是否外链接'
}, },
valueChange (key, value, form, { getColumn, mode, component, immediate, getComponent }) { valueChange (key, value, form, { getColumn, mode, component, immediate, getComponent }) {
form.web_path = null form.web_path = undefined
form.component = undefined
form.component_name = undefined
if (value) { if (value) {
getColumn('web_path').title = '外链接地址' getColumn('web_path').title = '外链接地址'
getColumn('web_path').component.placeholder = '请输入外链接地址' getColumn('web_path').component.placeholder = '请输入外链接地址'
@ -378,7 +389,7 @@ export const crudOptions = (vm) => {
search: { search: {
disabled: false disabled: false
}, },
width: 50, width: 60,
type: 'radio', type: 'radio',
dict: { dict: {
data: vm.dictionary('button_whether_bool') data: vm.dictionary('button_whether_bool')
@ -416,6 +427,9 @@ export const crudOptions = (vm) => {
component: { component: {
placeholder: '请选择侧边可见' placeholder: '请选择侧边可见'
}, },
rules: [ // 表单校验规则
{ required: true, message: '侧边可见必填项' }
],
helper: { helper: {
render (h) { render (h) {
return (< el-alert title="是否显示在侧边菜单中" type="warning" /> return (< el-alert title="是否显示在侧边菜单中" type="warning" />
@ -440,7 +454,10 @@ export const crudOptions = (vm) => {
value: true, value: true,
component: { component: {
placeholder: '请选择状态' placeholder: '请选择状态'
} },
rules: [ // 表单校验规则
{ required: true, message: '状态必填项' }
]
} }
} }
].concat(vm.commonEndColumns({ ].concat(vm.commonEndColumns({

View File

@ -47,7 +47,7 @@ export function DelObj (id) {
// 通过角色id,获取菜单数据 // 通过角色id,获取菜单数据
export function GetMenuData (obj) { export function GetMenuData (obj) {
return request({ return request({
url: '/api/system/role/roleId_get_menu/' + obj.id + '/', url: '/api/system/role/' + obj.id + '/roleId_get_menu/',
method: 'get', method: 'get',
params: {} params: {}
}).then(res => { }).then(res => {

View File

@ -50,7 +50,7 @@ export function DelObj (id) {
*/ */
export function ResetPwd (obj) { export function ResetPwd (obj) {
return request({ return request({
url: urlPrefix + 'reset_password/' + obj.id + '/', url: urlPrefix + obj.id + '/reset_password/',
method: 'put', method: 'put',
data: obj data: obj
}) })