!58 正式发布v2.0.2版本
1. 新增:新版登录页 2. 新增:用户管理中用户类型 3. 新增:系统配置功能 4. 新增:字典管理功能 5. 新增:登录页获取初始化配置 6. 新增:初始化配置验证码是否开启 7. 新增:一键删除迁移文件的脚本 8. 优化: 文件及图片上传全局配置优化 9. 优化: 配置用户头像为剪切图片方式 10. 优化:docker-compose.yml 无法启动配置 11. 优化:后台数据初始化功能 12. 优化:用户管理中性别类型(添加未知类型) 13. 优化:创建用户时的初始化密码 14. 优化:角色权限点击子级半勾选父级 15. 优化:系统数据库table表名 16. 优化:前端部门选择,支持懒加载 17. 优化:获取ip详细地址时,添加请求超时时间及请求方式更改为get方式 18. 修复:CharFilter字段精确查询无效 19. 修复:find_filter_lookups条件搜索错误 bug 20. 修复:import_export 导入bug 21. 修复:切换[是否目录]时,没有清除组件名称、组件路由信息bugpull/59/MERGE v2.0.2
|
|
@ -1,3 +1,6 @@
|
|||
/backend/venv
|
||||
/backend/.idea
|
||||
.idea
|
||||
|
||||
.history/
|
||||
.vscode/
|
||||
|
|
@ -88,11 +88,12 @@ ENV/
|
|||
.idea/
|
||||
*.db
|
||||
.DS_Store
|
||||
__pycache__
|
||||
**/migrations
|
||||
**/migrations/*.py
|
||||
!**/migrations/__init__.py
|
||||
*.pyc
|
||||
conf/
|
||||
!conf/env.example.py
|
||||
db.sqlite3
|
||||
media/
|
||||
__pypackages__/
|
||||
package-lock.json
|
||||
|
|
|
|||
|
|
@ -12,5 +12,6 @@ import os
|
|||
from django.core.asgi import get_asgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
|
||||
os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true"
|
||||
|
||||
application = get_asgi_application()
|
||||
|
|
|
|||
|
|
@ -4,9 +4,10 @@ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
|
|||
|
||||
from django.conf import settings
|
||||
from celery import platforms
|
||||
|
||||
if getattr(settings, 'REGISTER_PLUGINS', {}).get('dvadmin_tenant', None):
|
||||
# 租户模式
|
||||
if "django_tenants" in settings.INSTALLED_APPS:
|
||||
from tenant_schemas_celery.app import CeleryApp as TenantAwareCeleryApp
|
||||
|
||||
app = TenantAwareCeleryApp()
|
||||
else:
|
||||
from celery import Celery
|
||||
|
|
|
|||
|
|
@ -0,0 +1,196 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from django.conf import settings
|
||||
from django.db import ProgrammingError
|
||||
from django.db import connection
|
||||
|
||||
def is_tenants_mode():
|
||||
"""
|
||||
判断是否为租户模式
|
||||
:return:
|
||||
"""
|
||||
return hasattr(connection, 'tenant') and connection.tenant.schema_name
|
||||
|
||||
|
||||
# ================================================= #
|
||||
# ******************** 初始化 ******************** #
|
||||
# ================================================= #
|
||||
def _get_all_dictionary():
|
||||
from dvadmin.system.models import Dictionary
|
||||
queryset = Dictionary.objects.filter(status=True, is_value=False)
|
||||
data = []
|
||||
for instance in queryset:
|
||||
data.append({
|
||||
"id": instance.id,
|
||||
"value": instance.value,
|
||||
"children": list(Dictionary.objects.filter(parent=instance.id).filter(status=1).
|
||||
values('label', 'value', 'type', 'color'))
|
||||
})
|
||||
return {ele.get("value"): ele for ele in data}
|
||||
|
||||
|
||||
def _get_all_system_config():
|
||||
data = {}
|
||||
from dvadmin.system.models import SystemConfig
|
||||
system_config_obj = SystemConfig.objects.filter(status=True, parent_id__isnull=False).values(
|
||||
'parent__key', 'key', 'value', 'form_item_type').order_by('sort')
|
||||
for system_config in system_config_obj:
|
||||
value = system_config.get('value') or ''
|
||||
if value and system_config.get('form_item_type') == 7:
|
||||
value = value[0].get('url')
|
||||
data[f"{system_config.get('parent__key')}.{system_config.get('key')}"] = value
|
||||
return data
|
||||
|
||||
|
||||
def init_dictionary():
|
||||
"""
|
||||
初始化字典配置
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
if is_tenants_mode():
|
||||
from django_tenants.utils import tenant_context, get_tenant_model
|
||||
for tenant in get_tenant_model().objects.filter():
|
||||
with tenant_context(tenant):
|
||||
settings.DICTIONARY_CONFIG[connection.tenant.schema_name] = _get_all_dictionary()
|
||||
else:
|
||||
settings.DICTIONARY_CONFIG = _get_all_dictionary()
|
||||
print("初始化字典配置完成")
|
||||
except Exception as e:
|
||||
print("请先进行数据库迁移!")
|
||||
return
|
||||
|
||||
|
||||
def init_system_config():
|
||||
"""
|
||||
初始化系统配置
|
||||
:param name:
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
|
||||
if is_tenants_mode():
|
||||
from django_tenants.utils import tenant_context, get_tenant_model
|
||||
for tenant in get_tenant_model().objects.filter():
|
||||
with tenant_context(tenant):
|
||||
settings.SYSTEM_CONFIG[connection.tenant.schema_name] = _get_all_system_config()
|
||||
else:
|
||||
settings.SYSTEM_CONFIG = _get_all_system_config()
|
||||
print("初始化系统配置完成")
|
||||
except Exception as e:
|
||||
print("请先进行数据库迁移!")
|
||||
return
|
||||
|
||||
|
||||
def refresh_dictionary():
|
||||
"""
|
||||
刷新字典配置
|
||||
:return:
|
||||
"""
|
||||
if is_tenants_mode():
|
||||
from django_tenants.utils import tenant_context, get_tenant_model
|
||||
for tenant in get_tenant_model().objects.filter():
|
||||
with tenant_context(tenant):
|
||||
settings.DICTIONARY_CONFIG[connection.tenant.schema_name] = _get_all_dictionary()
|
||||
else:
|
||||
settings.DICTIONARY_CONFIG = _get_all_dictionary()
|
||||
|
||||
|
||||
def refresh_system_config():
|
||||
"""
|
||||
刷新系统配置
|
||||
:return:
|
||||
"""
|
||||
if is_tenants_mode():
|
||||
from django_tenants.utils import tenant_context, get_tenant_model
|
||||
for tenant in get_tenant_model().objects.filter():
|
||||
with tenant_context(tenant):
|
||||
settings.SYSTEM_CONFIG[connection.tenant.schema_name] = _get_all_system_config()
|
||||
else:
|
||||
settings.SYSTEM_CONFIG = _get_all_system_config()
|
||||
|
||||
|
||||
# ================================================= #
|
||||
# ******************** 字典管理 ******************** #
|
||||
# ================================================= #
|
||||
def get_dictionary_config(schema_name=None):
|
||||
"""
|
||||
获取字典所有配置
|
||||
:param schema_name: 对应字典配置的租户schema_name值
|
||||
:return:
|
||||
"""
|
||||
if is_tenants_mode():
|
||||
dictionary_config = settings.DICTIONARY_CONFIG[schema_name or connection.tenant.schema_name]
|
||||
else:
|
||||
dictionary_config = settings.DICTIONARY_CONFIG
|
||||
return dictionary_config or {}
|
||||
|
||||
|
||||
def get_dictionary_values(key, schema_name=None):
|
||||
"""
|
||||
获取字典数据数组
|
||||
:param key: 对应字典配置的key值(字典编号)
|
||||
:param schema_name: 对应字典配置的租户schema_name值
|
||||
:return:
|
||||
"""
|
||||
dictionary_config = get_dictionary_config(schema_name)
|
||||
return dictionary_config.get(key)
|
||||
|
||||
|
||||
def get_dictionary_label(key, name, schema_name=None):
|
||||
"""
|
||||
获取获取字典label值
|
||||
:param key: 字典管理中的key值(字典编号)
|
||||
:param name: 对应字典配置的value值
|
||||
:param schema_name: 对应字典配置的租户schema_name值
|
||||
:return:
|
||||
"""
|
||||
children = get_dictionary_values(key, schema_name) or []
|
||||
for ele in children:
|
||||
if ele.get("value") == str(name):
|
||||
return ele.get("label")
|
||||
return ""
|
||||
|
||||
|
||||
# ================================================= #
|
||||
# ******************** 系统配置 ******************** #
|
||||
# ================================================= #
|
||||
def get_system_config(schema_name=None):
|
||||
"""
|
||||
获取系统配置中所有配置
|
||||
1.只传父级的key,返回全部子级,{ "父级key.子级key" : "值" }
|
||||
2."父级key.子级key",返回子级值
|
||||
:param schema_name: 对应字典配置的租户schema_name值
|
||||
:return:
|
||||
"""
|
||||
if is_tenants_mode():
|
||||
dictionary_config = settings.SYSTEM_CONFIG[schema_name or connection.tenant.schema_name]
|
||||
else:
|
||||
dictionary_config = settings.SYSTEM_CONFIG
|
||||
return dictionary_config or {}
|
||||
|
||||
|
||||
def get_system_config_values(key, schema_name=None):
|
||||
"""
|
||||
获取系统配置数据数组
|
||||
:param key: 对应系统配置的key值(字典编号)
|
||||
:param schema_name: 对应系统配置的租户schema_name值
|
||||
:return:
|
||||
"""
|
||||
system_config = get_system_config(schema_name)
|
||||
return system_config.get(key)
|
||||
|
||||
|
||||
def get_system_config_label(key, name, schema_name=None):
|
||||
"""
|
||||
获取获取系统配置label值
|
||||
:param key: 系统配置中的key值(字典编号)
|
||||
:param name: 对应系统配置的value值
|
||||
:param schema_name: 对应系统配置的租户schema_name值
|
||||
:return:
|
||||
"""
|
||||
children = get_system_config_values(key, schema_name) or []
|
||||
for ele in children:
|
||||
if ele.get("value") == str(name):
|
||||
return ele.get("label")
|
||||
return ""
|
||||
|
|
@ -27,106 +27,111 @@ from conf.env import *
|
|||
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = 'django-insecure--z8%exyzt7e_%i@1+#1mm=%lb5=^fx_57=1@a+_y7bg5-w%)sm'
|
||||
SECRET_KEY = "django-insecure--z8%exyzt7e_%i@1+#1mm=%lb5=^fx_57=1@a+_y7bg5-w%)sm"
|
||||
# 初始化plugins插件路径到环境变量中
|
||||
PLUGINS_PATH = os.path.join(BASE_DIR, 'plugins')
|
||||
[sys.path.insert(0, os.path.join(PLUGINS_PATH, ele)) for ele in os.listdir(PLUGINS_PATH) if
|
||||
os.path.isdir(os.path.join(PLUGINS_PATH, ele)) and not ele.startswith('__')]
|
||||
PLUGINS_PATH = os.path.join(BASE_DIR, "plugins")
|
||||
sys.path.insert(0, os.path.join(PLUGINS_PATH))
|
||||
|
||||
[
|
||||
sys.path.insert(0, os.path.join(PLUGINS_PATH, ele))
|
||||
for ele in os.listdir(PLUGINS_PATH)
|
||||
if os.path.isdir(os.path.join(PLUGINS_PATH, ele)) and not ele.startswith("__")
|
||||
]
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = locals().get('DEBUG', True)
|
||||
ALLOWED_HOSTS = locals().get('ALLOWED_HOSTS', ['*'])
|
||||
DEBUG = locals().get("DEBUG", True)
|
||||
ALLOWED_HOSTS = locals().get("ALLOWED_HOSTS", ["*"])
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'django_comment_migrate',
|
||||
'rest_framework',
|
||||
'django_filters',
|
||||
'corsheaders', # 注册跨域app
|
||||
'dvadmin.system',
|
||||
'drf_yasg',
|
||||
'captcha',
|
||||
"django.contrib.auth",
|
||||
"django.contrib.contenttypes",
|
||||
"django.contrib.sessions",
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
"django_comment_migrate",
|
||||
"rest_framework",
|
||||
"django_filters",
|
||||
"corsheaders", # 注册跨域app
|
||||
"dvadmin.system",
|
||||
"drf_yasg",
|
||||
"captcha",
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'whitenoise.middleware.WhiteNoiseMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'corsheaders.middleware.CorsMiddleware', # 跨域中间件
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
'dvadmin.utils.middleware.ApiLoggingMiddleware',
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
"whitenoise.middleware.WhiteNoiseMiddleware",
|
||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||
"corsheaders.middleware.CorsMiddleware", # 跨域中间件
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.middleware.csrf.CsrfViewMiddleware",
|
||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||
"django.contrib.messages.middleware.MessageMiddleware",
|
||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||
"dvadmin.utils.middleware.ApiLoggingMiddleware",
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'application.urls'
|
||||
ROOT_URLCONF = "application.urls"
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [os.path.join(BASE_DIR, 'templates')],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||
"DIRS": [os.path.join(BASE_DIR, "templates")],
|
||||
"APP_DIRS": True,
|
||||
"OPTIONS": {
|
||||
"context_processors": [
|
||||
"django.template.context_processors.debug",
|
||||
"django.template.context_processors.request",
|
||||
"django.contrib.auth.context_processors.auth",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'application.wsgi.application'
|
||||
WSGI_APPLICATION = "application.wsgi.application"
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': DATABASE_ENGINE,
|
||||
'NAME': DATABASE_NAME,
|
||||
'USER': DATABASE_USER,
|
||||
'PASSWORD': DATABASE_PASSWORD,
|
||||
'HOST': DATABASE_HOST,
|
||||
'PORT': DATABASE_PORT,
|
||||
"default": {
|
||||
"ENGINE": DATABASE_ENGINE,
|
||||
"NAME": DATABASE_NAME,
|
||||
"USER": DATABASE_USER,
|
||||
"PASSWORD": DATABASE_PASSWORD,
|
||||
"HOST": DATABASE_HOST,
|
||||
"PORT": DATABASE_PORT,
|
||||
}
|
||||
}
|
||||
AUTH_USER_MODEL = 'system.Users'
|
||||
USERNAME_FIELD = 'username'
|
||||
AUTH_USER_MODEL = "system.Users"
|
||||
USERNAME_FIELD = "username"
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
|
||||
},
|
||||
]
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/3.2/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'zh-hans'
|
||||
LANGUAGE_CODE = "zh-hans"
|
||||
|
||||
TIME_ZONE = 'Asia/Shanghai'
|
||||
TIME_ZONE = "Asia/Shanghai"
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
|
|
@ -137,13 +142,13 @@ USE_TZ = False
|
|||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/3.2/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
STATIC_URL = "/static/"
|
||||
# # 设置django的静态文件目录
|
||||
STATICFILES_DIRS = [
|
||||
os.path.join(BASE_DIR, "static"),
|
||||
]
|
||||
|
||||
MEDIA_ROOT = 'media' # 项目下的目录
|
||||
MEDIA_ROOT = "media" # 项目下的目录
|
||||
MEDIA_URL = "/media/" # 跟STATIC_URL类似,指定用户可以通过这个url找到文件
|
||||
|
||||
# 收集静态文件,必须将 MEDIA_ROOT,STATICFILES_DIRS先注释
|
||||
|
|
@ -164,78 +169,82 @@ CORS_ALLOW_CREDENTIALS = True # 指明在跨域访问中,后端是否支持
|
|||
# ================================================= #
|
||||
|
||||
# log 配置部分BEGIN #
|
||||
SERVER_LOGS_FILE = os.path.join(BASE_DIR, 'logs', 'server.log')
|
||||
ERROR_LOGS_FILE = os.path.join(BASE_DIR, 'logs', 'error.log')
|
||||
if not os.path.exists(os.path.join(BASE_DIR, 'logs')):
|
||||
os.makedirs(os.path.join(BASE_DIR, 'logs'))
|
||||
SERVER_LOGS_FILE = os.path.join(BASE_DIR, "logs", "server.log")
|
||||
ERROR_LOGS_FILE = os.path.join(BASE_DIR, "logs", "error.log")
|
||||
if not os.path.exists(os.path.join(BASE_DIR, "logs")):
|
||||
os.makedirs(os.path.join(BASE_DIR, "logs"))
|
||||
|
||||
# 格式:[2020-04-22 23:33:01][micoservice.apps.ready():16] [INFO] 这是一条日志:
|
||||
# 格式:[日期][模块.函数名称():行号] [级别] 信息
|
||||
STANDARD_LOG_FORMAT = '[%(asctime)s][%(name)s.%(funcName)s():%(lineno)d] [%(levelname)s] %(message)s'
|
||||
CONSOLE_LOG_FORMAT = '[%(asctime)s][%(name)s.%(funcName)s():%(lineno)d] [%(levelname)s] %(message)s'
|
||||
STANDARD_LOG_FORMAT = (
|
||||
"[%(asctime)s][%(name)s.%(funcName)s():%(lineno)d] [%(levelname)s] %(message)s"
|
||||
)
|
||||
CONSOLE_LOG_FORMAT = (
|
||||
"[%(asctime)s][%(name)s.%(funcName)s():%(lineno)d] [%(levelname)s] %(message)s"
|
||||
)
|
||||
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
'formatters': {
|
||||
'standard': {
|
||||
'format': STANDARD_LOG_FORMAT
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"formatters": {
|
||||
"standard": {"format": STANDARD_LOG_FORMAT},
|
||||
"console": {
|
||||
"format": CONSOLE_LOG_FORMAT,
|
||||
"datefmt": "%Y-%m-%d %H:%M:%S",
|
||||
},
|
||||
'console': {
|
||||
'format': CONSOLE_LOG_FORMAT,
|
||||
'datefmt': '%Y-%m-%d %H:%M:%S',
|
||||
},
|
||||
'file': {
|
||||
'format': CONSOLE_LOG_FORMAT,
|
||||
'datefmt': '%Y-%m-%d %H:%M:%S',
|
||||
"file": {
|
||||
"format": CONSOLE_LOG_FORMAT,
|
||||
"datefmt": "%Y-%m-%d %H:%M:%S",
|
||||
},
|
||||
},
|
||||
'handlers': {
|
||||
'file': {
|
||||
'level': 'INFO',
|
||||
'class': 'logging.handlers.RotatingFileHandler',
|
||||
'filename': SERVER_LOGS_FILE,
|
||||
'maxBytes': 1024 * 1024 * 100, # 100 MB
|
||||
'backupCount': 5, # 最多备份5个
|
||||
'formatter': 'standard',
|
||||
'encoding': 'utf-8',
|
||||
"handlers": {
|
||||
"file": {
|
||||
"level": "INFO",
|
||||
"class": "logging.handlers.RotatingFileHandler",
|
||||
"filename": SERVER_LOGS_FILE,
|
||||
"maxBytes": 1024 * 1024 * 100, # 100 MB
|
||||
"backupCount": 5, # 最多备份5个
|
||||
"formatter": "standard",
|
||||
"encoding": "utf-8",
|
||||
},
|
||||
'error': {
|
||||
'level': 'ERROR',
|
||||
'class': 'logging.handlers.RotatingFileHandler',
|
||||
'filename': ERROR_LOGS_FILE,
|
||||
'maxBytes': 1024 * 1024 * 100, # 100 MB
|
||||
'backupCount': 3, # 最多备份3个
|
||||
'formatter': 'standard',
|
||||
'encoding': 'utf-8',
|
||||
"error": {
|
||||
"level": "ERROR",
|
||||
"class": "logging.handlers.RotatingFileHandler",
|
||||
"filename": ERROR_LOGS_FILE,
|
||||
"maxBytes": 1024 * 1024 * 100, # 100 MB
|
||||
"backupCount": 3, # 最多备份3个
|
||||
"formatter": "standard",
|
||||
"encoding": "utf-8",
|
||||
},
|
||||
"console": {
|
||||
"level": "INFO",
|
||||
"class": "logging.StreamHandler",
|
||||
"formatter": "console",
|
||||
},
|
||||
'console': {
|
||||
'level': 'INFO',
|
||||
'class': 'logging.StreamHandler',
|
||||
'formatter': 'console',
|
||||
}
|
||||
},
|
||||
'loggers': {
|
||||
"loggers": {
|
||||
# default日志
|
||||
'': {
|
||||
'handlers': ['console', 'error', 'file'],
|
||||
'level': 'INFO',
|
||||
"": {
|
||||
"handlers": ["console", "error", "file"],
|
||||
"level": "INFO",
|
||||
},
|
||||
'django': {
|
||||
'handlers': ['console', 'error', 'file'],
|
||||
'level': 'INFO',
|
||||
"django": {
|
||||
"handlers": ["console", "error", "file"],
|
||||
"level": "INFO",
|
||||
"propagate": False,
|
||||
},
|
||||
'scripts': {
|
||||
'handlers': ['console', 'error', 'file'],
|
||||
'level': 'INFO',
|
||||
"scripts": {
|
||||
"handlers": ["console", "error", "file"],
|
||||
"level": "INFO",
|
||||
"propagate": False,
|
||||
},
|
||||
# 数据库相关日志
|
||||
'django.db.backends': {
|
||||
'handlers': [],
|
||||
'propagate': True,
|
||||
'level': 'INFO',
|
||||
"django.db.backends": {
|
||||
"handlers": [],
|
||||
"propagate": True,
|
||||
"level": "INFO",
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
# ================================================= #
|
||||
|
|
@ -243,34 +252,32 @@ LOGGING = {
|
|||
# ================================================= #
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
'DATETIME_FORMAT': "%Y-%m-%d %H:%M:%S", # 日期时间格式配置
|
||||
'DATE_FORMAT': "%Y-%m-%d",
|
||||
'DEFAULT_FILTER_BACKENDS': (
|
||||
"DATETIME_FORMAT": "%Y-%m-%d %H:%M:%S", # 日期时间格式配置
|
||||
"DATE_FORMAT": "%Y-%m-%d",
|
||||
"DEFAULT_FILTER_BACKENDS": (
|
||||
# 'django_filters.rest_framework.DjangoFilterBackend',
|
||||
'dvadmin.utils.filters.CustomDjangoFilterBackend',
|
||||
'rest_framework.filters.SearchFilter',
|
||||
'rest_framework.filters.OrderingFilter',
|
||||
"dvadmin.utils.filters.CustomDjangoFilterBackend",
|
||||
"rest_framework.filters.SearchFilter",
|
||||
"rest_framework.filters.OrderingFilter",
|
||||
),
|
||||
'DEFAULT_PAGINATION_CLASS': 'dvadmin.utils.pagination.CustomPagination', # 自定义分页
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': (
|
||||
'rest_framework_simplejwt.authentication.JWTAuthentication',
|
||||
'rest_framework.authentication.SessionAuthentication',
|
||||
"DEFAULT_PAGINATION_CLASS": "dvadmin.utils.pagination.CustomPagination", # 自定义分页
|
||||
"DEFAULT_AUTHENTICATION_CLASSES": (
|
||||
"rest_framework_simplejwt.authentication.JWTAuthentication",
|
||||
"rest_framework.authentication.SessionAuthentication",
|
||||
),
|
||||
'DEFAULT_PERMISSION_CLASSES': [
|
||||
'rest_framework.permissions.IsAuthenticated', # 只有经过身份认证确定用户身份才能访问
|
||||
"DEFAULT_PERMISSION_CLASSES": [
|
||||
"rest_framework.permissions.IsAuthenticated", # 只有经过身份认证确定用户身份才能访问
|
||||
# 'rest_framework.permissions.IsAdminUser', # is_staff=True才能访问 —— 管理员(员工)权限
|
||||
# 'rest_framework.permissions.AllowAny', # 允许所有
|
||||
# 'rest_framework.permissions.IsAuthenticatedOrReadOnly', # 有身份 或者 只读访问(self.list,self.retrieve)
|
||||
],
|
||||
'EXCEPTION_HANDLER': 'dvadmin.utils.exception.CustomExceptionHandler', # 自定义的异常处理
|
||||
"EXCEPTION_HANDLER": "dvadmin.utils.exception.CustomExceptionHandler", # 自定义的异常处理
|
||||
}
|
||||
# ================================================= #
|
||||
# ******************** 登录方式配置 ******************** #
|
||||
# ================================================= #
|
||||
|
||||
AUTHENTICATION_BACKENDS = [
|
||||
'dvadmin.utils.backends.CustomBackend'
|
||||
]
|
||||
AUTHENTICATION_BACKENDS = ["dvadmin.utils.backends.CustomBackend"]
|
||||
# ================================================= #
|
||||
# ****************** simplejwt配置 ***************** #
|
||||
# ================================================= #
|
||||
|
|
@ -278,12 +285,12 @@ from datetime import timedelta
|
|||
|
||||
SIMPLE_JWT = {
|
||||
# token有效时长
|
||||
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=120),
|
||||
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=120),
|
||||
# token刷新后的有效时间
|
||||
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
|
||||
"REFRESH_TOKEN_LIFETIME": timedelta(days=1),
|
||||
# 设置前缀
|
||||
'AUTH_HEADER_TYPES': ('JWT',),
|
||||
'ROTATE_REFRESH_TOKENS': True,
|
||||
"AUTH_HEADER_TYPES": ("JWT",),
|
||||
"ROTATE_REFRESH_TOKENS": True,
|
||||
}
|
||||
|
||||
# ====================================#
|
||||
|
|
@ -291,72 +298,84 @@ SIMPLE_JWT = {
|
|||
# ====================================#
|
||||
SWAGGER_SETTINGS = {
|
||||
# 基础样式
|
||||
'SECURITY_DEFINITIONS': {
|
||||
"basic": {
|
||||
'type': 'basic'
|
||||
}
|
||||
},
|
||||
"SECURITY_DEFINITIONS": {"basic": {"type": "basic"}},
|
||||
# 如果需要登录才能够查看接口文档, 登录的链接使用restframework自带的.
|
||||
|
||||
'LOGIN_URL': 'apiLogin/',
|
||||
"LOGIN_URL": "apiLogin/",
|
||||
# 'LOGIN_URL': 'rest_framework:login',
|
||||
'LOGOUT_URL': 'rest_framework:logout',
|
||||
"LOGOUT_URL": "rest_framework:logout",
|
||||
# 'DOC_EXPANSION': None,
|
||||
# 'SHOW_REQUEST_HEADERS':True,
|
||||
# 'USE_SESSION_AUTH': True,
|
||||
# 'DOC_EXPANSION': 'list',
|
||||
# 接口文档中方法列表以首字母升序排列
|
||||
'APIS_SORTER': 'alpha',
|
||||
"APIS_SORTER": "alpha",
|
||||
# 如果支持json提交, 则接口文档中包含json输入框
|
||||
'JSON_EDITOR': True,
|
||||
"JSON_EDITOR": True,
|
||||
# 方法列表字母排序
|
||||
'OPERATIONS_SORTER': 'alpha',
|
||||
'VALIDATOR_URL': None,
|
||||
'AUTO_SCHEMA_TYPE': 2, # 分组根据url层级分,0、1 或 2 层
|
||||
'DEFAULT_AUTO_SCHEMA_CLASS': 'dvadmin.utils.swagger.CustomSwaggerAutoSchema',
|
||||
"OPERATIONS_SORTER": "alpha",
|
||||
"VALIDATOR_URL": None,
|
||||
"AUTO_SCHEMA_TYPE": 2, # 分组根据url层级分,0、1 或 2 层
|
||||
"DEFAULT_AUTO_SCHEMA_CLASS": "dvadmin.utils.swagger.CustomSwaggerAutoSchema",
|
||||
}
|
||||
|
||||
# ================================================= #
|
||||
# **************** 验证码配置 ******************* #
|
||||
# ================================================= #
|
||||
CAPTCHA_STATE = True
|
||||
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_OUTPUT_FORMAT = "%(image)s %(text_field)s %(hidden_field)s "
|
||||
CAPTCHA_FONT_SIZE = 40 # 字体大小
|
||||
CAPTCHA_FOREGROUND_COLOR = '#0033FF' # 前景色
|
||||
CAPTCHA_BACKGROUND_COLOR = '#F5F7F4' # 背景色
|
||||
CAPTCHA_FOREGROUND_COLOR = "#64DAAA" # 前景色
|
||||
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' # 加减乘除验证码
|
||||
CAPTCHA_CHALLENGE_FUNCT = "captcha.helpers.math_challenge" # 加减乘除验证码
|
||||
|
||||
# ================================================= #
|
||||
# ******************** 其他配置 ******************** #
|
||||
# ================================================= #
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
|
||||
API_LOG_ENABLE = True
|
||||
# API_LOG_METHODS = 'ALL' # ['POST', 'DELETE']
|
||||
API_LOG_METHODS = ['POST', 'UPDATE', 'DELETE', 'PUT'] # ['POST', 'DELETE']
|
||||
API_LOG_METHODS = ["POST", "UPDATE", "DELETE", "PUT"] # ['POST', 'DELETE']
|
||||
API_MODEL_MAP = {
|
||||
"/token/": "登录模块",
|
||||
"/api/login/": "登录模块",
|
||||
"/api/plugins_market/plugins/": "插件市场",
|
||||
}
|
||||
# 表前缀
|
||||
TABLE_PREFIX = "dvadmin_"
|
||||
|
||||
DJANGO_CELERY_BEAT_TZ_AWARE = False
|
||||
CELERY_TIMEZONE = 'Asia/Shanghai' # celery 时区问题
|
||||
CELERY_TIMEZONE = "Asia/Shanghai" # celery 时区问题
|
||||
# 静态页面压缩
|
||||
STATICFILES_STORAGE = 'whitenoise.storage.CompressedStaticFilesStorage'
|
||||
# 初始化需要执行的列表,用来初始化后执行
|
||||
INITIALIZE_RESET_LIST = []
|
||||
STATICFILES_STORAGE = "whitenoise.storage.CompressedStaticFilesStorage"
|
||||
|
||||
ALL_MODELS_OBJECTS = [] # 所有app models 对象
|
||||
# dvadmin 插件
|
||||
REGISTER_PLUGINS = (
|
||||
# ""
|
||||
)
|
||||
|
||||
# 初始化需要执行的列表,用来初始化后执行
|
||||
INITIALIZE_LIST = []
|
||||
INITIALIZE_RESET_LIST = []
|
||||
# 表前缀
|
||||
TABLE_PREFIX = locals().get('TABLE_PREFIX', "")
|
||||
# 系统配置
|
||||
SYSTEM_CONFIG = {}
|
||||
# 字典配置
|
||||
DICTIONARY_CONFIG = {}
|
||||
|
||||
# ================================================= #
|
||||
# ******************** 插件配置 ******************** #
|
||||
# ================================================= #
|
||||
# 租户共享app
|
||||
TENANT_SHARED_APPS = []
|
||||
# 插件 urlpatterns
|
||||
PLUGINS_URL_PATTERNS = []
|
||||
# ********** 一键导入插件配置开始 **********
|
||||
# 例如:
|
||||
# from dvadmin_upgrade_center.settings import * # 升级中心
|
||||
# from dvadmin_celery.settings import * # celery 异步任务
|
||||
# ...
|
||||
# ********** 一键导入插件配置结束 **********
|
||||
|
|
|
|||
|
|
@ -22,14 +22,27 @@ from rest_framework_simplejwt.views import (
|
|||
TokenRefreshView,
|
||||
)
|
||||
|
||||
from application import dispatch
|
||||
from application import settings
|
||||
from dvadmin.system.views.login import LoginView, CaptchaView, ApiLogin, LogoutView
|
||||
from dvadmin.system.views.dictionary import InitDictionaryViewSet
|
||||
from dvadmin.system.views.login import (
|
||||
LoginView,
|
||||
CaptchaView,
|
||||
ApiLogin,
|
||||
LogoutView,
|
||||
)
|
||||
from dvadmin.system.views.system_config import InitSettingsViewSet
|
||||
from dvadmin.utils.swagger import CustomOpenAPISchemaGenerator
|
||||
|
||||
# =========== 初始化系统配置 =================
|
||||
dispatch.init_system_config()
|
||||
dispatch.init_dictionary()
|
||||
# =========== 初始化系统配置 =================
|
||||
|
||||
schema_view = get_schema_view(
|
||||
openapi.Info(
|
||||
title="Snippets API",
|
||||
default_version='v1',
|
||||
default_version="v1",
|
||||
description="Test description",
|
||||
terms_of_service="https://www.google.com/policies/terms/",
|
||||
contact=openapi.Contact(email="contact@snippets.local"),
|
||||
|
|
@ -38,20 +51,38 @@ schema_view = get_schema_view(
|
|||
public=True,
|
||||
permission_classes=(permissions.AllowAny,),
|
||||
generator_class=CustomOpenAPISchemaGenerator,
|
||||
|
||||
)
|
||||
|
||||
urlpatterns = [
|
||||
re_path(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0),
|
||||
name='schema-json'),
|
||||
path('', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
|
||||
path(r'redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
|
||||
path('api/system/', include('dvadmin.system.urls')),
|
||||
path('api/login/', LoginView.as_view(), name='token_obtain_pair'),
|
||||
path('api/logout/', LogoutView.as_view(), name='token_obtain_pair'),
|
||||
path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
|
||||
re_path(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
|
||||
path('api/captcha/', CaptchaView.as_view()),
|
||||
path('apiLogin/', ApiLogin.as_view()),
|
||||
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + static(settings.STATIC_URL,
|
||||
document_root=settings.STATIC_URL)
|
||||
urlpatterns = (
|
||||
[
|
||||
re_path(
|
||||
r"^swagger(?P<format>\.json|\.yaml)$",
|
||||
schema_view.without_ui(cache_timeout=0),
|
||||
name="schema-json",
|
||||
),
|
||||
path(
|
||||
"",
|
||||
schema_view.with_ui("swagger", cache_timeout=0),
|
||||
name="schema-swagger-ui",
|
||||
),
|
||||
path(
|
||||
r"redoc/",
|
||||
schema_view.with_ui("redoc", cache_timeout=0),
|
||||
name="schema-redoc",
|
||||
),
|
||||
path("api/system/", include("dvadmin.system.urls")),
|
||||
path("api/login/", LoginView.as_view(), name="token_obtain_pair"),
|
||||
path("api/logout/", LogoutView.as_view(), name="token_obtain_pair"),
|
||||
path("token/refresh/", TokenRefreshView.as_view(), name="token_refresh"),
|
||||
re_path(
|
||||
r"^api-auth/", include("rest_framework.urls", namespace="rest_framework")
|
||||
),
|
||||
path("api/captcha/", CaptchaView.as_view()),
|
||||
path("api/init/dictionary/", InitDictionaryViewSet.as_view()),
|
||||
path("api/init/settings/", InitSettingsViewSet.as_view()),
|
||||
path("apiLogin/", ApiLogin.as_view()),
|
||||
]
|
||||
+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
+ static(settings.STATIC_URL, document_root=settings.STATIC_URL)
|
||||
+ [re_path(ele.get('re_path'), include(ele.get('include'))) for ele in settings.PLUGINS_URL_PATTERNS]
|
||||
)
|
||||
|
|
|
|||
|
|
@ -12,5 +12,6 @@ import os
|
|||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
|
||||
os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true"
|
||||
|
||||
application = get_wsgi_application()
|
||||
|
|
|
|||
|
|
@ -3,17 +3,17 @@ import os
|
|||
from application.settings import BASE_DIR
|
||||
|
||||
# ================================================= #
|
||||
# ************** 数据库 配置 ************** #
|
||||
# *************** mysql数据库 配置 *************** #
|
||||
# ================================================= #
|
||||
|
||||
# 数据库 ENGINE ,默认演示使用 sqlite3 数据库,正式环境建议使用 mysql 数据库
|
||||
# sqlite3 设置
|
||||
DATABASE_ENGINE = "django.db.backends.sqlite3"
|
||||
DATABASE_NAME = os.path.join(BASE_DIR, 'db.sqlite3')
|
||||
DATABASE_NAME = os.path.join(BASE_DIR, "db.sqlite3")
|
||||
|
||||
# 使用mysql时,改为此配置
|
||||
# DATABASE_ENGINE = "django.db.backends.mysql"
|
||||
# DATABASE_NAME = 'django-vue-admin' # mysql 时使用
|
||||
|
||||
# 数据库地址 改为自己数据库地址
|
||||
DATABASE_HOST = "127.0.0.1"
|
||||
# # 数据库端口
|
||||
|
|
@ -23,16 +23,24 @@ DATABASE_USER = "root"
|
|||
# # 数据库密码
|
||||
DATABASE_PASSWORD = "123456"
|
||||
|
||||
# 表前缀
|
||||
TABLE_PREFIX = "dvadmin_"
|
||||
# ================================================= #
|
||||
# ************** redis配置,无redis 可不进行配置 ************** #
|
||||
# ******** redis配置,无redis 可不进行配置 ******** #
|
||||
# ================================================= #
|
||||
# REDIS_PASSWORD = ''
|
||||
# REDIS_HOST = '127.0.0.1'
|
||||
# REDIS_URL = f'redis://:{REDIS_PASSWORD or ""}@{REDIS_HOST}:6380'
|
||||
# ================================================= #
|
||||
# ************** 其他 配置 ************** #
|
||||
# ****************** 功能 启停 ******************* #
|
||||
# ================================================= #
|
||||
DEBUG = True # 线上环境请设置为True
|
||||
DEBUG = True
|
||||
# 启动登录详细概略获取(通过调用api获取ip详细地址。如果是内网,关闭即可)
|
||||
ENABLE_LOGIN_ANALYSIS_LOG = True
|
||||
# 登录接口 /api/token/ 是否需要验证码认证,用于测试,正式环境建议取消
|
||||
LOGIN_NO_CAPTCHA_AUTH = True
|
||||
# ================================================= #
|
||||
# ****************** 其他 配置 ******************* #
|
||||
# ================================================= #
|
||||
|
||||
ALLOWED_HOSTS = ["*"]
|
||||
LOGIN_NO_CAPTCHA_AUTH = True # 登录接口 /api/token/ 是否需要验证码认证,用于测试,正式环境建议取消
|
||||
ENABLE_LOGIN_ANALYSIS_LOG = True # 启动登录详细概略获取(通过调用api获取ip详细地址)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
|
||||
exclude = ["venv"] # 需要排除的文件目录
|
||||
for root, dirs, files in os.walk('.'):
|
||||
dirs[:] = [d for d in set(dirs) - set(exclude)]
|
||||
if 'migrations' in dirs:
|
||||
dir = dirs[dirs.index('migrations')]
|
||||
for root_j, dirs_j, files_j in os.walk(os.path.join(root, dir)):
|
||||
for file_k in files_j:
|
||||
if file_k != '__init__.py':
|
||||
dst_file = os.path.join(root_j, file_k)
|
||||
print('删除文件>>> ', dst_file)
|
||||
os.remove(dst_file)
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
[
|
||||
{
|
||||
"url": "/api/system/dept_lazy_tree/",
|
||||
"method": 0,
|
||||
"enable_datasource": true
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
[
|
||||
{
|
||||
"name": "DVAdmin团队",
|
||||
"sort": 1,
|
||||
"owner": "",
|
||||
"phone": "",
|
||||
"email": "",
|
||||
"status": true,
|
||||
"parent": null,
|
||||
"children": [
|
||||
{
|
||||
"name": "运营部",
|
||||
"sort": 2,
|
||||
"owner": "",
|
||||
"phone": "",
|
||||
"email": "",
|
||||
"status": true,
|
||||
"parent": 1,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"name": "技术部",
|
||||
"sort": 1,
|
||||
"owner": "",
|
||||
"phone": "",
|
||||
"email": "",
|
||||
"status": true,
|
||||
"parent": 3,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,550 @@
|
|||
[
|
||||
{
|
||||
"label": "启用/禁用-布尔值",
|
||||
"value": "button_status_bool",
|
||||
"parent": null,
|
||||
"type": 0,
|
||||
"color": null,
|
||||
"is_value": false,
|
||||
"status": true,
|
||||
"sort": 1,
|
||||
"remark": null,
|
||||
"children": [
|
||||
{
|
||||
"label": "启用",
|
||||
"value": "true",
|
||||
"parent": 1,
|
||||
"type": 6,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 1,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "禁用",
|
||||
"value": "false",
|
||||
"parent": 1,
|
||||
"type": 6,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 2,
|
||||
"remark": null,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "系统按钮",
|
||||
"value": "system_button",
|
||||
"parent": null,
|
||||
"type": 0,
|
||||
"color": null,
|
||||
"is_value": false,
|
||||
"status": true,
|
||||
"sort": 2,
|
||||
"remark": null,
|
||||
"children": [
|
||||
{
|
||||
"label": "新增",
|
||||
"value": "Create",
|
||||
"parent": 66,
|
||||
"type": 0,
|
||||
"color": "success",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 1,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "编辑",
|
||||
"value": "Update",
|
||||
"parent": 66,
|
||||
"type": 0,
|
||||
"color": "primary",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 2,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "删除",
|
||||
"value": "Delete",
|
||||
"parent": 66,
|
||||
"type": 0,
|
||||
"color": "danger",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 3,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "详情",
|
||||
"value": "Retrieve",
|
||||
"parent": 66,
|
||||
"type": 0,
|
||||
"color": "info",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 4,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "查询",
|
||||
"value": "Search",
|
||||
"parent": 66,
|
||||
"type": 0,
|
||||
"color": "warning",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 5,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "保存",
|
||||
"value": "Save",
|
||||
"parent": 66,
|
||||
"type": 0,
|
||||
"color": "success",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 6,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "导入",
|
||||
"value": "Import",
|
||||
"parent": 66,
|
||||
"type": 0,
|
||||
"color": "primary",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 7,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "导出",
|
||||
"value": "Export",
|
||||
"parent": 66,
|
||||
"type": 0,
|
||||
"color": "warning",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 8,
|
||||
"remark": null,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "启用/禁用-数字值",
|
||||
"value": "button_status_number",
|
||||
"parent": null,
|
||||
"type": 0,
|
||||
"color": null,
|
||||
"is_value": false,
|
||||
"status": true,
|
||||
"sort": 3,
|
||||
"remark": null,
|
||||
"children": [
|
||||
{
|
||||
"label": "启用",
|
||||
"value": "1",
|
||||
"parent": 7,
|
||||
"type": 1,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 1,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "禁用",
|
||||
"value": "0",
|
||||
"parent": 7,
|
||||
"type": 1,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 2,
|
||||
"remark": null,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "是/否-布尔值",
|
||||
"value": "button_whether_bool",
|
||||
"parent": null,
|
||||
"type": 0,
|
||||
"color": null,
|
||||
"is_value": false,
|
||||
"status": true,
|
||||
"sort": 4,
|
||||
"remark": null,
|
||||
"children": [
|
||||
{
|
||||
"label": "是",
|
||||
"value": "true",
|
||||
"parent": 5,
|
||||
"type": 6,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 1,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "否",
|
||||
"value": "false",
|
||||
"parent": 5,
|
||||
"type": 6,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 2,
|
||||
"remark": null,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "是/否-数字值",
|
||||
"value": "button_whether_number",
|
||||
"parent": null,
|
||||
"type": 0,
|
||||
"color": null,
|
||||
"is_value": false,
|
||||
"status": true,
|
||||
"sort": 5,
|
||||
"remark": null,
|
||||
"children": [
|
||||
{
|
||||
"label": "是",
|
||||
"value": "1",
|
||||
"parent": 10,
|
||||
"type": 1,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 1,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "否",
|
||||
"value": "2",
|
||||
"parent": 10,
|
||||
"type": 1,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 2,
|
||||
"remark": null,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "用户类型",
|
||||
"value": "user_type",
|
||||
"parent": null,
|
||||
"type": 0,
|
||||
"color": null,
|
||||
"is_value": false,
|
||||
"status": true,
|
||||
"sort": 6,
|
||||
"remark": null,
|
||||
"children": [
|
||||
{
|
||||
"label": "后台用户",
|
||||
"value": "0",
|
||||
"parent": 15,
|
||||
"type": 1,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 1,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "前台用户",
|
||||
"value": "1",
|
||||
"parent": 15,
|
||||
"type": 1,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 2,
|
||||
"remark": null,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "表单类型",
|
||||
"value": "config_form_type",
|
||||
"parent": null,
|
||||
"type": 0,
|
||||
"color": null,
|
||||
"is_value": false,
|
||||
"status": true,
|
||||
"sort": 7,
|
||||
"remark": null,
|
||||
"children": [
|
||||
{
|
||||
"label": "text",
|
||||
"value": "0",
|
||||
"parent": 49,
|
||||
"type": 1,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 0,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "textarea",
|
||||
"value": "3",
|
||||
"parent": 49,
|
||||
"type": 1,
|
||||
"color": "",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 0,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "number",
|
||||
"value": "10",
|
||||
"parent": 49,
|
||||
"type": 1,
|
||||
"color": "",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 0,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "datetime",
|
||||
"value": "1",
|
||||
"parent": 49,
|
||||
"type": 1,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 1,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "date",
|
||||
"value": "2",
|
||||
"parent": 49,
|
||||
"type": 1,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 2,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "time",
|
||||
"value": "15",
|
||||
"parent": 49,
|
||||
"type": 1,
|
||||
"color": "",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 3,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "select",
|
||||
"value": "4",
|
||||
"parent": 49,
|
||||
"type": 1,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 4,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "checkbox",
|
||||
"value": "5",
|
||||
"parent": 49,
|
||||
"type": 1,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 5,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "radio",
|
||||
"value": "6",
|
||||
"parent": 49,
|
||||
"type": 1,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 6,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "switch",
|
||||
"value": "9",
|
||||
"parent": 49,
|
||||
"type": 1,
|
||||
"color": "",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 6,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "文件附件",
|
||||
"value": "8",
|
||||
"parent": 49,
|
||||
"type": 1,
|
||||
"color": "",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 7,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "图片(单张)",
|
||||
"value": "7",
|
||||
"parent": 49,
|
||||
"type": 1,
|
||||
"color": "",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 8,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "图片(多张)",
|
||||
"value": "12",
|
||||
"parent": 49,
|
||||
"type": 1,
|
||||
"color": "",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 9,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "数组",
|
||||
"value": "11",
|
||||
"parent": 49,
|
||||
"type": 1,
|
||||
"color": "",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 11,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "关联表",
|
||||
"value": "13",
|
||||
"parent": 49,
|
||||
"type": 1,
|
||||
"color": "",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 13,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "关联表(多选)",
|
||||
"value": "14",
|
||||
"parent": 49,
|
||||
"type": 1,
|
||||
"color": "",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 14,
|
||||
"remark": null,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "性别",
|
||||
"value": "gender",
|
||||
"parent": null,
|
||||
"type": 0,
|
||||
"color": null,
|
||||
"is_value": false,
|
||||
"status": true,
|
||||
"sort": 8,
|
||||
"remark": null,
|
||||
"children": [
|
||||
{
|
||||
"label": "未知",
|
||||
"value": "0",
|
||||
"parent": 18,
|
||||
"type": 1,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 0,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "男",
|
||||
"value": "1",
|
||||
"parent": 18,
|
||||
"type": 1,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 1,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "女",
|
||||
"value": "2",
|
||||
"parent": 18,
|
||||
"type": 1,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 2,
|
||||
"remark": null,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,631 @@
|
|||
[
|
||||
{
|
||||
"name": "系统管理",
|
||||
"icon": "cog",
|
||||
"sort": 1,
|
||||
"is_link": false,
|
||||
"is_catalog": true,
|
||||
"web_path": "",
|
||||
"component": "",
|
||||
"component_name": "",
|
||||
"status": true,
|
||||
"cache": false,
|
||||
"visible": true,
|
||||
"parent": null,
|
||||
"children": [
|
||||
{
|
||||
"name": "菜单管理",
|
||||
"icon": "navicon",
|
||||
"sort": 1,
|
||||
"is_link": false,
|
||||
"is_catalog": false,
|
||||
"web_path": "/menu",
|
||||
"component": "system/menu",
|
||||
"component_name": "menu",
|
||||
"status": true,
|
||||
"cache": false,
|
||||
"visible": true,
|
||||
"parent": 277,
|
||||
"children": [],
|
||||
"menu_button": [
|
||||
{
|
||||
"name": "查询",
|
||||
"value": "Search",
|
||||
"api": "/api/system/menu/",
|
||||
"method": 0
|
||||
},
|
||||
{
|
||||
"name": "详情",
|
||||
"value": "Retrieve",
|
||||
"api": "/api/system/menu/{id}/",
|
||||
"method": 0
|
||||
},
|
||||
{
|
||||
"name": "新增",
|
||||
"value": "Create",
|
||||
"api": "/api/system/menu/",
|
||||
"method": 1
|
||||
},
|
||||
{
|
||||
"name": "编辑",
|
||||
"value": "Update",
|
||||
"api": "/api/system/menu/{id}/",
|
||||
"method": 2
|
||||
},
|
||||
{
|
||||
"name": "删除",
|
||||
"value": "Delete",
|
||||
"api": "/api/system/menu/{id}/",
|
||||
"method": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "菜单按钮",
|
||||
"icon": "dot-circle-o",
|
||||
"sort": 2,
|
||||
"is_link": false,
|
||||
"is_catalog": false,
|
||||
"web_path": "/menuButton",
|
||||
"component": "system/menuButton/index",
|
||||
"component_name": "menuButton",
|
||||
"status": true,
|
||||
"cache": false,
|
||||
"visible": false,
|
||||
"parent": 277,
|
||||
"children": [],
|
||||
"menu_button": [
|
||||
{
|
||||
"name": "查询",
|
||||
"value": "Search",
|
||||
"api": "/api/system/menu_button/",
|
||||
"method": 0
|
||||
},
|
||||
{
|
||||
"name": "新增",
|
||||
"value": "Create",
|
||||
"api": "/api/system/menu_button/",
|
||||
"method": 1
|
||||
},
|
||||
{
|
||||
"name": "编辑",
|
||||
"value": "Update",
|
||||
"api": "/api/system/menu_button/{id}/",
|
||||
"method": 2
|
||||
},
|
||||
{
|
||||
"name": "删除",
|
||||
"value": "Delete",
|
||||
"api": "/api/system/menu_button/{id}/",
|
||||
"method": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "部门管理",
|
||||
"icon": "bank",
|
||||
"sort": 3,
|
||||
"is_link": false,
|
||||
"is_catalog": false,
|
||||
"web_path": "/dept",
|
||||
"component": "system/dept/index",
|
||||
"component_name": "dept",
|
||||
"status": true,
|
||||
"cache": false,
|
||||
"visible": true,
|
||||
"parent": 277,
|
||||
"children": [],
|
||||
"menu_button": [
|
||||
{
|
||||
"name": "查询",
|
||||
"value": "Search",
|
||||
"api": "/api/system/dept/",
|
||||
"method": 0
|
||||
},
|
||||
{
|
||||
"name": "详情",
|
||||
"value": "Retrieve",
|
||||
"api": "/api/system/dept/{id}/",
|
||||
"method": 0
|
||||
},
|
||||
{
|
||||
"name": "新增",
|
||||
"value": "Create",
|
||||
"api": "/api/system/dept/",
|
||||
"method": 1
|
||||
},
|
||||
{
|
||||
"name": "编辑",
|
||||
"value": "Update",
|
||||
"api": "/api/system/dept/{id}/",
|
||||
"method": 2
|
||||
},
|
||||
{
|
||||
"name": "删除",
|
||||
"value": "Delete",
|
||||
"api": "/api/system/dept/{id}/",
|
||||
"method": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "角色管理",
|
||||
"icon": "address-book",
|
||||
"sort": 4,
|
||||
"is_link": false,
|
||||
"is_catalog": false,
|
||||
"web_path": "/role",
|
||||
"component": "system/role/index",
|
||||
"component_name": "role",
|
||||
"status": true,
|
||||
"cache": false,
|
||||
"visible": true,
|
||||
"parent": 277,
|
||||
"children": [],
|
||||
"menu_button": [
|
||||
{
|
||||
"name": "查询",
|
||||
"value": "Search",
|
||||
"api": "/api/system/role/",
|
||||
"method": 0
|
||||
},
|
||||
{
|
||||
"name": "详情",
|
||||
"value": "Retrieve",
|
||||
"api": "/api/system/role/{id}/",
|
||||
"method": 0
|
||||
},
|
||||
{
|
||||
"name": "新增",
|
||||
"value": "Create",
|
||||
"api": "/api/system/role/",
|
||||
"method": 1
|
||||
},
|
||||
{
|
||||
"name": "编辑",
|
||||
"value": "Update",
|
||||
"api": "/api/system/role/{id}/",
|
||||
"method": 2
|
||||
},
|
||||
{
|
||||
"name": "保存",
|
||||
"value": "Save",
|
||||
"api": "/api/system/role/{id}/",
|
||||
"method": 2
|
||||
},
|
||||
{
|
||||
"name": "删除",
|
||||
"value": "Delete",
|
||||
"api": "/api/system/role/{id}/",
|
||||
"method": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "用户管理",
|
||||
"icon": "users",
|
||||
"sort": 6,
|
||||
"is_link": false,
|
||||
"is_catalog": false,
|
||||
"web_path": "/user",
|
||||
"component": "system/user/index",
|
||||
"component_name": "user",
|
||||
"status": true,
|
||||
"cache": false,
|
||||
"visible": true,
|
||||
"parent": 277,
|
||||
"children": [],
|
||||
"menu_button": [
|
||||
{
|
||||
"name": "查询",
|
||||
"value": "Search",
|
||||
"api": "/api/system/user/",
|
||||
"method": 0
|
||||
},
|
||||
{
|
||||
"name": "详情",
|
||||
"value": "Retrieve",
|
||||
"api": "/api/system/user/{id}/",
|
||||
"method": 0
|
||||
},
|
||||
{
|
||||
"name": "新增",
|
||||
"value": "Create",
|
||||
"api": "/api/system/user/",
|
||||
"method": 1
|
||||
},
|
||||
{
|
||||
"name": "导出",
|
||||
"value": "Export",
|
||||
"api": "/api/system/user/export/",
|
||||
"method": 1
|
||||
},
|
||||
{
|
||||
"name": "导入",
|
||||
"value": "Import",
|
||||
"api": "/api/system/user/import/",
|
||||
"method": 1
|
||||
},
|
||||
{
|
||||
"name": "编辑",
|
||||
"value": "Update",
|
||||
"api": "/api/system/user/{id}/",
|
||||
"method": 2
|
||||
},
|
||||
{
|
||||
"name": "重设密码",
|
||||
"value": "ResetPassword",
|
||||
"api": "/api/system/user/reset_password/{id}/",
|
||||
"method": 2
|
||||
},
|
||||
{
|
||||
"name": "重置密码",
|
||||
"value": "DefaultPassword",
|
||||
"api": "/api/system/user/reset_to_default_password/{id}/",
|
||||
"method": 2
|
||||
},
|
||||
{
|
||||
"name": "删除",
|
||||
"value": "Delete",
|
||||
"api": "/api/system/user/{id}/",
|
||||
"method": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "接口白名单",
|
||||
"icon": "compass",
|
||||
"sort": 7,
|
||||
"is_link": false,
|
||||
"is_catalog": false,
|
||||
"web_path": "/apiWhiteList",
|
||||
"component": "system/whiteList/index",
|
||||
"component_name": "whiteList",
|
||||
"status": true,
|
||||
"cache": false,
|
||||
"visible": true,
|
||||
"parent": 277,
|
||||
"children": [],
|
||||
"menu_button": [
|
||||
{
|
||||
"name": "查询",
|
||||
"value": "Search",
|
||||
"api": "/api/system/api_white_list/",
|
||||
"method": 0
|
||||
},
|
||||
{
|
||||
"name": "详情",
|
||||
"value": "Retrieve",
|
||||
"api": "/api/system/api_white_list/{id}/",
|
||||
"method": 0
|
||||
},
|
||||
{
|
||||
"name": "新增",
|
||||
"value": "Create",
|
||||
"api": "/api/system/api_white_list/",
|
||||
"method": 1
|
||||
},
|
||||
{
|
||||
"name": "编辑",
|
||||
"value": "Update",
|
||||
"api": "/api/system/api_white_list/{id}/",
|
||||
"method": 2
|
||||
},
|
||||
{
|
||||
"name": "删除",
|
||||
"value": "Delete",
|
||||
"api": "/api/system/api_white_list/{id}/",
|
||||
"method": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"menu_button": []
|
||||
},
|
||||
{
|
||||
"name": "常规配置",
|
||||
"icon": "cogs",
|
||||
"sort": 2,
|
||||
"is_link": false,
|
||||
"is_catalog": true,
|
||||
"web_path": "",
|
||||
"component": "",
|
||||
"component_name": "",
|
||||
"status": true,
|
||||
"cache": false,
|
||||
"visible": true,
|
||||
"parent": null,
|
||||
"children": [
|
||||
{
|
||||
"name": "系统配置",
|
||||
"icon": "desktop",
|
||||
"sort": 0,
|
||||
"is_link": false,
|
||||
"is_catalog": false,
|
||||
"web_path": "/config",
|
||||
"component": "system/config/index",
|
||||
"component_name": "config",
|
||||
"status": true,
|
||||
"cache": false,
|
||||
"visible": true,
|
||||
"parent": 285,
|
||||
"children": [],
|
||||
"menu_button": [
|
||||
{
|
||||
"name": "查询",
|
||||
"value": "Search",
|
||||
"api": "/api/system/system_config/",
|
||||
"method": 0
|
||||
},
|
||||
{
|
||||
"name": "详情",
|
||||
"value": "Retrieve",
|
||||
"api": "/api/system/system_config/{id}/",
|
||||
"method": 0
|
||||
},
|
||||
{
|
||||
"name": "新增",
|
||||
"value": "Create",
|
||||
"api": "/api/system/system_config/",
|
||||
"method": 1
|
||||
},
|
||||
{
|
||||
"name": "编辑",
|
||||
"value": "Update",
|
||||
"api": "/api/system/system_config/{id}/",
|
||||
"method": 2
|
||||
},
|
||||
{
|
||||
"name": "删除",
|
||||
"value": "Delete",
|
||||
"api": "/api/system/system_config/{id}/",
|
||||
"method": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "字典管理",
|
||||
"icon": "book",
|
||||
"sort": 1,
|
||||
"is_link": false,
|
||||
"is_catalog": false,
|
||||
"web_path": "/dictionary",
|
||||
"component": "system/dictionary/index",
|
||||
"component_name": "dictionary",
|
||||
"status": true,
|
||||
"cache": false,
|
||||
"visible": true,
|
||||
"parent": 285,
|
||||
"children": [],
|
||||
"menu_button": [
|
||||
{
|
||||
"name": "查询",
|
||||
"value": "Search",
|
||||
"api": "/api/system/dictionary/",
|
||||
"method": 0
|
||||
},
|
||||
{
|
||||
"name": "详情",
|
||||
"value": "Retrieve",
|
||||
"api": "/api/system/dictionary/{id}/",
|
||||
"method": 0
|
||||
},
|
||||
{
|
||||
"name": "新增",
|
||||
"value": "Create",
|
||||
"api": "/api/system/dictionary/",
|
||||
"method": 1
|
||||
},
|
||||
{
|
||||
"name": "编辑",
|
||||
"value": "Update",
|
||||
"api": "/api/system/dictionary/{id}/",
|
||||
"method": 2
|
||||
},
|
||||
{
|
||||
"name": "删除",
|
||||
"value": "Delete",
|
||||
"api": "/api/system/dictionary/{id}/",
|
||||
"method": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "地区管理",
|
||||
"icon": "map",
|
||||
"sort": 2,
|
||||
"is_link": false,
|
||||
"is_catalog": false,
|
||||
"web_path": "/areas",
|
||||
"component": "system/areas/index",
|
||||
"component_name": "areas",
|
||||
"status": true,
|
||||
"cache": false,
|
||||
"visible": true,
|
||||
"parent": 285,
|
||||
"children": [],
|
||||
"menu_button": [
|
||||
{
|
||||
"name": "查询",
|
||||
"value": "Search",
|
||||
"api": "/api/system/area/",
|
||||
"method": 0
|
||||
},
|
||||
{
|
||||
"name": "详情",
|
||||
"value": "Retrieve",
|
||||
"api": "/api/system/area/{id}/",
|
||||
"method": 0
|
||||
},
|
||||
{
|
||||
"name": "新增",
|
||||
"value": "Create",
|
||||
"api": "/api/system/area/",
|
||||
"method": 1
|
||||
},
|
||||
{
|
||||
"name": "编辑",
|
||||
"value": "Update",
|
||||
"api": "/api/system/area/{id}/",
|
||||
"method": 2
|
||||
},
|
||||
{
|
||||
"name": "删除",
|
||||
"value": "Delete",
|
||||
"api": "/api/system/area/{id}/",
|
||||
"method": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "附件管理",
|
||||
"icon": "file-text-o",
|
||||
"sort": 3,
|
||||
"is_link": false,
|
||||
"is_catalog": false,
|
||||
"web_path": "/file",
|
||||
"component": "system/fileList/index",
|
||||
"component_name": "file",
|
||||
"status": true,
|
||||
"cache": false,
|
||||
"visible": true,
|
||||
"parent": 285,
|
||||
"children": [],
|
||||
"menu_button": [
|
||||
{
|
||||
"name": "详情",
|
||||
"value": "Retrieve",
|
||||
"api": "/api/system/file/{id}/",
|
||||
"method": 0
|
||||
},
|
||||
{
|
||||
"name": "查询",
|
||||
"value": "Search",
|
||||
"api": "/api/system/file/",
|
||||
"method": 0
|
||||
},
|
||||
{
|
||||
"name": "编辑",
|
||||
"value": "Update",
|
||||
"api": "/api/system/file/{id}/",
|
||||
"method": 1
|
||||
},
|
||||
{
|
||||
"name": "删除",
|
||||
"value": "Delete",
|
||||
"api": "/api/system/file/{id}/",
|
||||
"method": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"menu_button": []
|
||||
},
|
||||
{
|
||||
"name": "日志管理",
|
||||
"icon": "book",
|
||||
"sort": 3,
|
||||
"is_link": false,
|
||||
"is_catalog": true,
|
||||
"web_path": "",
|
||||
"component": "",
|
||||
"component_name": "",
|
||||
"status": true,
|
||||
"cache": false,
|
||||
"visible": true,
|
||||
"parent": null,
|
||||
"children": [
|
||||
{
|
||||
"name": "登录日志",
|
||||
"icon": "file-text",
|
||||
"sort": 1,
|
||||
"is_link": false,
|
||||
"is_catalog": false,
|
||||
"web_path": "/loginLog",
|
||||
"component": "system/log/loginLog/index",
|
||||
"component_name": "loginLog",
|
||||
"status": true,
|
||||
"cache": false,
|
||||
"visible": true,
|
||||
"parent": 290,
|
||||
"children": [],
|
||||
"menu_button": [
|
||||
{
|
||||
"name": "查询",
|
||||
"value": "Search",
|
||||
"api": "/api/system/login_log/",
|
||||
"method": 0
|
||||
},
|
||||
{
|
||||
"name": "详情",
|
||||
"value": "Retrieve",
|
||||
"api": "/api/system/login_log/{id}/",
|
||||
"method": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "操作日志",
|
||||
"icon": "file-code-o",
|
||||
"sort": 2,
|
||||
"is_link": false,
|
||||
"is_catalog": false,
|
||||
"web_path": "/operationLog",
|
||||
"component": "system/log/operationLog/index",
|
||||
"component_name": "operationLog",
|
||||
"status": true,
|
||||
"cache": false,
|
||||
"visible": true,
|
||||
"parent": 290,
|
||||
"children": [],
|
||||
"menu_button": [
|
||||
{
|
||||
"name": "详情",
|
||||
"value": "Retrieve",
|
||||
"api": "/api/system/operation_log/{id}/",
|
||||
"method": 0
|
||||
},
|
||||
{
|
||||
"name": "查询",
|
||||
"value": "Search",
|
||||
"api": "/api/system/operation_log/",
|
||||
"method": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "前端错误日志",
|
||||
"icon": "bug",
|
||||
"sort": 4,
|
||||
"is_link": false,
|
||||
"is_catalog": false,
|
||||
"web_path": "/frontendLog",
|
||||
"component": "system/log/frontendLog/index",
|
||||
"component_name": "frontendLog",
|
||||
"status": true,
|
||||
"cache": false,
|
||||
"visible": true,
|
||||
"parent": 290,
|
||||
"children": [],
|
||||
"menu_button": []
|
||||
}
|
||||
],
|
||||
"menu_button": []
|
||||
},
|
||||
{
|
||||
"name": "DVAdmin官网",
|
||||
"icon": "external-link",
|
||||
"sort": 4,
|
||||
"is_link": true,
|
||||
"is_catalog": false,
|
||||
"web_path": "https://django-vue-admin.com",
|
||||
"component": "",
|
||||
"component_name": "",
|
||||
"status": true,
|
||||
"cache": false,
|
||||
"visible": true,
|
||||
"parent": null,
|
||||
"children": [],
|
||||
"menu_button": []
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
[
|
||||
{
|
||||
"name": "管理员",
|
||||
"key": "admin",
|
||||
"sort": 1,
|
||||
"status": true,
|
||||
"admin": true,
|
||||
"data_range": 3,
|
||||
"remark": null
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
[
|
||||
{
|
||||
"parent": null,
|
||||
"title": "基础配置",
|
||||
"key": "base",
|
||||
"value": null,
|
||||
"sort": 0,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": null,
|
||||
"placeholder": null,
|
||||
"setting": null,
|
||||
"children": [
|
||||
{
|
||||
"parent": 10,
|
||||
"title": "开启验证码",
|
||||
"key": "captcha_state",
|
||||
"value": true,
|
||||
"sort": 1,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 9,
|
||||
"rule": [
|
||||
{
|
||||
"message": "必填项不能为空",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"placeholder": "请选择",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"parent": 10,
|
||||
"title": "创建用户默认密码",
|
||||
"key": "default_password",
|
||||
"value": "admin123456",
|
||||
"sort": 2,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": [
|
||||
{
|
||||
"message": "必填项不能为空",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"placeholder": "请输入默认密码",
|
||||
"setting": null,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"parent": null,
|
||||
"title": "登录页配置",
|
||||
"key": "login",
|
||||
"value": null,
|
||||
"sort": 1,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": null,
|
||||
"placeholder": null,
|
||||
"setting": null,
|
||||
"children": [
|
||||
{
|
||||
"parent": 1,
|
||||
"title": "网站名称",
|
||||
"key": "site_name",
|
||||
"value": "企业级后台管理系统",
|
||||
"sort": 1,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": [
|
||||
{
|
||||
"message": "必填项不能为空",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"placeholder": "请输入网站名称",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"parent": 1,
|
||||
"title": "登录网站logo",
|
||||
"key": "site_logo",
|
||||
"value": null,
|
||||
"sort": 2,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 7,
|
||||
"rule": [],
|
||||
"placeholder": "请上传网站logo",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"parent": 1,
|
||||
"title": "登录页背景图",
|
||||
"key": "login_background",
|
||||
"value": null,
|
||||
"sort": 3,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 7,
|
||||
"rule": [],
|
||||
"placeholder": "请上传登录背景页",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"parent": 1,
|
||||
"title": "版权信息",
|
||||
"key": "copyright",
|
||||
"value": "2021-2022 django-vue-admin.com 版权所有",
|
||||
"sort": 4,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": [
|
||||
{
|
||||
"message": "必填项不能为空",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"placeholder": "请输入版权信息",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"parent": 1,
|
||||
"title": "备案信息",
|
||||
"key": "keep_record",
|
||||
"value": "晋ICP备18005113号-3",
|
||||
"sort": 5,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": [
|
||||
{
|
||||
"message": "必填项不能为空",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"placeholder": "请输入备案信息",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"parent": 1,
|
||||
"title": "帮助链接",
|
||||
"key": "help_url",
|
||||
"value": "https://django-vue-admin.com",
|
||||
"sort": 6,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": "",
|
||||
"placeholder": "请输入帮助信息",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"parent": 1,
|
||||
"title": "隐私链接",
|
||||
"key": "privacy_url",
|
||||
"value": "#",
|
||||
"sort": 7,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": [],
|
||||
"placeholder": "请填写隐私链接",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"parent": 1,
|
||||
"title": "条款链接",
|
||||
"key": "clause_url",
|
||||
"value": "#",
|
||||
"sort": 8,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": [],
|
||||
"placeholder": "请输入条款链接",
|
||||
"setting": null,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
[
|
||||
{
|
||||
"username": "admin",
|
||||
"email": "dvadmin@django-vue-admin.com",
|
||||
"mobile": "18888888888",
|
||||
"avatar": "",
|
||||
"name": "管理员",
|
||||
"gender": 1,
|
||||
"user_type": 0,
|
||||
"dept": 1,
|
||||
"role": [],
|
||||
"first_name": "",
|
||||
"last_name": "",
|
||||
"is_staff": true,
|
||||
"is_active": true,
|
||||
"password": "pbkdf2_sha256$260000$g17x5wlSiW1FZAh1Eudchw$ZeSAqj3Xak0io8v/pmPW0BX9EX5R2zFXDwbbD68oBFk=",
|
||||
"last_login": null,
|
||||
"is_superuser": false
|
||||
},
|
||||
{
|
||||
"username": "superadmin",
|
||||
"email": "dvadmin@django-vue-admin.com",
|
||||
"mobile": "13333333333",
|
||||
"avatar": null,
|
||||
"name": "超级管理员",
|
||||
"gender": 1,
|
||||
"user_type": 0,
|
||||
"dept": 1,
|
||||
"role": [],
|
||||
"first_name": "",
|
||||
"last_name": "",
|
||||
"is_staff": true,
|
||||
"is_active": true,
|
||||
"password": "pbkdf2_sha256$260000$g17x5wlSiW1FZAh1Eudchw$ZeSAqj3Xak0io8v/pmPW0BX9EX5R2zFXDwbbD68oBFk=",
|
||||
"last_login": null,
|
||||
"is_superuser": true
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
# 初始化
|
||||
import os
|
||||
|
||||
import django
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "application.settings")
|
||||
django.setup()
|
||||
|
||||
from dvadmin.system.views.user import UsersInitSerializer
|
||||
from dvadmin.system.views.menu import MenuInitSerializer
|
||||
from dvadmin.utils.core_initialize import CoreInitialize
|
||||
from dvadmin.system.views.role import RoleInitSerializer
|
||||
from dvadmin.system.views.api_white_list import ApiWhiteListInitSerializer
|
||||
from dvadmin.system.views.dept import DeptInitSerializer
|
||||
from dvadmin.system.views.dictionary import DictionaryInitSerializer
|
||||
from dvadmin.system.views.system_config import SystemConfigInitSerializer
|
||||
|
||||
|
||||
class Initialize(CoreInitialize):
|
||||
|
||||
def init_dept(self):
|
||||
"""
|
||||
初始化部门信息
|
||||
"""
|
||||
self.init_base(DeptInitSerializer, unique_fields=['name', 'parent'])
|
||||
|
||||
def init_role(self):
|
||||
"""
|
||||
初始化角色信息
|
||||
"""
|
||||
self.init_base(RoleInitSerializer, unique_fields=['key'])
|
||||
|
||||
def init_users(self):
|
||||
"""
|
||||
初始化用户信息
|
||||
"""
|
||||
self.init_base(UsersInitSerializer, unique_fields=['username'])
|
||||
|
||||
def init_menu(self):
|
||||
"""
|
||||
初始化菜单信息
|
||||
"""
|
||||
self.init_base(MenuInitSerializer, unique_fields=['name', 'web_path', 'component', 'component_name'])
|
||||
|
||||
def init_api_white_list(self):
|
||||
"""
|
||||
初始API白名单
|
||||
"""
|
||||
self.init_base(ApiWhiteListInitSerializer, unique_fields=['url', 'method', ])
|
||||
|
||||
def init_dictionary(self):
|
||||
"""
|
||||
初始化字典表
|
||||
"""
|
||||
self.init_base(DictionaryInitSerializer, unique_fields=['value', 'parent', ])
|
||||
|
||||
def init_system_config(self):
|
||||
"""
|
||||
初始化系统配置表
|
||||
"""
|
||||
self.init_base(SystemConfigInitSerializer, unique_fields=['key', 'parent', ])
|
||||
|
||||
def run(self):
|
||||
self.init_dept()
|
||||
self.init_role()
|
||||
self.init_users()
|
||||
self.init_menu()
|
||||
self.init_api_white_list()
|
||||
self.init_dictionary()
|
||||
self.init_system_config()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
Initialize(app='dvadmin.system').run()
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
import json
|
||||
import logging
|
||||
import os
|
||||
|
||||
import django
|
||||
from django.db.models import QuerySet
|
||||
|
||||
from dvadmin.system.views.system_config import SystemConfigInitSerializer
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
|
||||
django.setup()
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
from application.settings import BASE_DIR
|
||||
from dvadmin.system.models import Menu, Users, Dept, Role, ApiWhiteList, Dictionary, SystemConfig
|
||||
from dvadmin.system.views.api_white_list import ApiWhiteListInitSerializer
|
||||
from dvadmin.system.views.dept import DeptInitSerializer
|
||||
from dvadmin.system.views.dictionary import DictionaryInitSerializer
|
||||
from dvadmin.system.views.menu import MenuInitSerializer
|
||||
from dvadmin.system.views.role import RoleInitSerializer
|
||||
from dvadmin.system.views.user import UsersInitSerializer
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
"""
|
||||
生产初始化菜单: python3 manage.py generate_init_json 生成初始化的model名
|
||||
例如:
|
||||
全部生成:python3 manage.py generate_init_json
|
||||
只生成某个model的: python3 manage.py generate_init_json users
|
||||
"""
|
||||
|
||||
def serializer_data(self, serializer, query_set: QuerySet):
|
||||
serializer = serializer(query_set, many=True)
|
||||
data = json.loads(json.dumps(serializer.data, ensure_ascii=False))
|
||||
with open(os.path.join(BASE_DIR, f'init_{query_set.model._meta.model_name}.json'), 'w') as f:
|
||||
json.dump(data, f, indent=4, ensure_ascii=False)
|
||||
return
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument("generate_name", nargs="*", type=str, help="初始化生成的表名")
|
||||
|
||||
def generate_users(self):
|
||||
self.serializer_data(UsersInitSerializer, Users.objects.all())
|
||||
|
||||
def generate_role(self):
|
||||
self.serializer_data(RoleInitSerializer, Role.objects.all())
|
||||
|
||||
def generate_dept(self):
|
||||
self.serializer_data(DeptInitSerializer, Dept.objects.filter(parent_id__isnull=True))
|
||||
|
||||
def generate_menu(self):
|
||||
self.serializer_data(MenuInitSerializer, Menu.objects.filter(parent_id__isnull=True))
|
||||
|
||||
def generate_api_white_list(self):
|
||||
self.serializer_data(ApiWhiteListInitSerializer, ApiWhiteList.objects.all())
|
||||
|
||||
def generate_dictionary(self):
|
||||
self.serializer_data(DictionaryInitSerializer, Dictionary.objects.filter(parent_id__isnull=True))
|
||||
|
||||
def generate_system_config(self):
|
||||
self.serializer_data(SystemConfigInitSerializer, SystemConfig.objects.filter(parent_id__isnull=True))
|
||||
|
||||
def handle(self, *args, **options):
|
||||
generate_name = options.get('generate_name')
|
||||
generate_name_dict = {
|
||||
"users": self.generate_users,
|
||||
"role": self.generate_role,
|
||||
"dept": self.generate_dept,
|
||||
"menu": self.generate_menu,
|
||||
"api_white_list": self.generate_api_white_list,
|
||||
"dictionary": self.generate_dictionary,
|
||||
"system_config": self.generate_system_config,
|
||||
}
|
||||
if not generate_name:
|
||||
for ele in generate_name_dict.keys():
|
||||
generate_name_dict[ele]()
|
||||
return
|
||||
|
||||
for generate_name in generate_name:
|
||||
if generate_name not in generate_name_dict:
|
||||
print(f"该初始化方法尚未配置\n{generate_name_dict}")
|
||||
raise Exception(f"该初始化方法尚未配置,已配置项:{list(generate_name_dict.keys())}")
|
||||
generate_name_dict[generate_name]()
|
||||
return
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# with open(os.path.join(BASE_DIR, 'temp_init_menu.json')) as f:
|
||||
# for menu_data in json.load(f):
|
||||
# menu_data['creator'] = 1
|
||||
# menu_data['modifier'] = 1
|
||||
# menu_data['dept_belong_id'] = 1
|
||||
# request.user = Users.objects.order_by('create_datetime').first()
|
||||
# serializer = MenuInitSerializer(data=menu_data, request=request)
|
||||
# serializer.is_valid(raise_exception=True)
|
||||
# serializer.save()
|
||||
a = Users.objects.filter()
|
||||
print(type(Users.objects.filter()))
|
||||
|
|
@ -13,27 +13,41 @@ class Command(BaseCommand):
|
|||
"""
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument('init_name', nargs='*', type=str, )
|
||||
parser.add_argument('-y', nargs='*')
|
||||
parser.add_argument('-Y', nargs='*')
|
||||
parser.add_argument('-n', nargs='*')
|
||||
parser.add_argument('-N', nargs='*')
|
||||
parser.add_argument(
|
||||
"init_name",
|
||||
nargs="*",
|
||||
type=str,
|
||||
)
|
||||
parser.add_argument("-y", nargs="*")
|
||||
parser.add_argument("-Y", nargs="*")
|
||||
parser.add_argument("-n", nargs="*")
|
||||
parser.add_argument("-N", nargs="*")
|
||||
|
||||
def handle(self, *args, **options):
|
||||
reset = False
|
||||
if isinstance(options.get('y'), list) or isinstance(options.get('Y'), list):
|
||||
if isinstance(options.get("y"), list) or isinstance(options.get("Y"), list):
|
||||
reset = True
|
||||
if isinstance(options.get('n'), list) or isinstance(options.get('N'), list):
|
||||
if isinstance(options.get("n"), list) or isinstance(options.get("N"), list):
|
||||
reset = False
|
||||
print(f"正在准备初始化数据,{'如有初始化数据,将会不做操作跳过' if not reset else '初始数据将会先删除后新增'}...")
|
||||
|
||||
for app in settings.INSTALLED_APPS:
|
||||
|
||||
try:
|
||||
exec(f"""
|
||||
exec(
|
||||
f"""
|
||||
from {app}.fixtures.initialize import Initialize
|
||||
Initialize(reset={reset},app="{app}").run()
|
||||
"""
|
||||
)
|
||||
except ModuleNotFoundError:
|
||||
# 兼容之前版本初始化
|
||||
try:
|
||||
exec(
|
||||
f"""
|
||||
from {app}.initialize import main
|
||||
main(reset={reset})
|
||||
""")
|
||||
except ModuleNotFoundError:
|
||||
pass
|
||||
"""
|
||||
)
|
||||
except ModuleNotFoundError:
|
||||
pass
|
||||
print("初始化数据完成!")
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ import pypinyin
|
|||
from django.core.management import BaseCommand
|
||||
from django.db import connection
|
||||
|
||||
from application import dispatch
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
|
||||
django.setup()
|
||||
from application.settings import BASE_DIR
|
||||
|
|
@ -45,7 +47,7 @@ def area_list(code_list, pcode=None, depth=1):
|
|||
|
||||
|
||||
def main():
|
||||
with open(os.path.join(BASE_DIR, 'dvadmin', 'system', 'util', 'pca-code.json'), 'r',encoding="utf-8") as load_f:
|
||||
with open(os.path.join(BASE_DIR, 'dvadmin', 'system', 'util', 'pca-code.json'), 'r', encoding="utf-8") as load_f:
|
||||
code_list = json.load(load_f)
|
||||
area_list(code_list)
|
||||
if Area.objects.count() == 0:
|
||||
|
|
@ -68,9 +70,9 @@ class Command(BaseCommand):
|
|||
|
||||
print(f"正在准备初始化省份数据...")
|
||||
|
||||
if hasattr(connection, 'tenant') and connection.tenant.schema_name:
|
||||
if dispatch.is_tenants_mode():
|
||||
from django_tenants.utils import get_tenant_model
|
||||
from django_tenants.utils import tenant_context,schema_context
|
||||
from django_tenants.utils import tenant_context
|
||||
for tenant in get_tenant_model().objects.exclude(schema_name='public'):
|
||||
with tenant_context(tenant):
|
||||
print(f"租户[{connection.tenant.schema_name}]初始化数据开始...")
|
||||
|
|
@ -79,4 +81,3 @@ class Command(BaseCommand):
|
|||
else:
|
||||
main()
|
||||
print("省份数据初始化数据完成!")
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import os
|
|||
from django.contrib.auth.models import AbstractUser
|
||||
from django.db import models
|
||||
|
||||
from application import dispatch
|
||||
from dvadmin.utils.models import CoreModel, table_prefix
|
||||
|
||||
STATUS_CHOICES = (
|
||||
|
|
@ -19,10 +20,11 @@ class Users(AbstractUser, CoreModel):
|
|||
avatar = models.CharField(max_length=255, verbose_name="头像", null=True, blank=True, help_text="头像")
|
||||
name = models.CharField(max_length=40, verbose_name="姓名", help_text="姓名")
|
||||
GENDER_CHOICES = (
|
||||
(0, "女"),
|
||||
(0, "未知"),
|
||||
(1, "男"),
|
||||
(2, "女"),
|
||||
)
|
||||
gender = models.IntegerField(choices=GENDER_CHOICES, default=1, verbose_name="性别", null=True, blank=True,
|
||||
gender = models.IntegerField(choices=GENDER_CHOICES, default=0, verbose_name="性别", null=True, blank=True,
|
||||
help_text="性别")
|
||||
USER_TYPE = (
|
||||
(0, "后台用户"),
|
||||
|
|
@ -107,17 +109,6 @@ class Dept(CoreModel):
|
|||
ordering = ('sort',)
|
||||
|
||||
|
||||
class Button(CoreModel):
|
||||
name = models.CharField(max_length=64, unique=True, verbose_name="权限名称", help_text="权限名称")
|
||||
value = models.CharField(max_length=64, unique=True, verbose_name="权限值", help_text="权限值")
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "system_button"
|
||||
verbose_name = '权限标识表'
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ('-name',)
|
||||
|
||||
|
||||
class Menu(CoreModel):
|
||||
parent = models.ForeignKey(to='Menu', on_delete=models.CASCADE, verbose_name="上级菜单", null=True, blank=True,
|
||||
db_constraint=False, help_text="上级菜单")
|
||||
|
|
@ -166,22 +157,37 @@ class MenuButton(CoreModel):
|
|||
|
||||
|
||||
class Dictionary(CoreModel):
|
||||
code = models.CharField(max_length=100, blank=True, null=True, verbose_name="编码", help_text="编码")
|
||||
label = models.CharField(max_length=100, blank=True, null=True, verbose_name="显示名称", help_text="显示名称")
|
||||
value = models.CharField(max_length=100, blank=True, null=True, verbose_name="实际值", help_text="实际值")
|
||||
TYPE_LIST = (
|
||||
(0, 'text'),
|
||||
(1, 'number'),
|
||||
(2, 'date'),
|
||||
(3, 'datetime'),
|
||||
(4, 'time'),
|
||||
(5, 'files'),
|
||||
(6, 'boolean'),
|
||||
(7, 'images'),
|
||||
)
|
||||
label = models.CharField(max_length=100, blank=True, null=True, verbose_name="字典名称", help_text="字典名称")
|
||||
value = models.CharField(max_length=200, blank=True, null=True, verbose_name="字典编号", help_text="字典编号/实际值")
|
||||
parent = models.ForeignKey(to='self', related_name='sublist', db_constraint=False, on_delete=models.PROTECT,
|
||||
blank=True, null=True,
|
||||
verbose_name="父级", help_text="父级")
|
||||
status = models.BooleanField(default=True, blank=True, verbose_name="状态", help_text="状态")
|
||||
blank=True, null=True, verbose_name="父级", help_text="父级")
|
||||
type = models.IntegerField(choices=TYPE_LIST, default=0, verbose_name="数据值类型", help_text="数据值类型")
|
||||
color = models.CharField(max_length=20, blank=True, null=True, verbose_name="颜色", help_text="颜色")
|
||||
is_value = models.BooleanField(default=False, verbose_name="是否为value值", help_text="是否为value值,用来做具体值存放")
|
||||
status = models.BooleanField(default=True, verbose_name="状态", help_text="状态")
|
||||
sort = models.IntegerField(default=1, verbose_name="显示排序", null=True, blank=True, help_text="显示排序")
|
||||
remark = models.CharField(max_length=2000, blank=True, null=True, verbose_name="备注", help_text="备注")
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + 'dictionary'
|
||||
db_table = table_prefix + 'system_dictionary'
|
||||
verbose_name = "字典表"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ('sort',)
|
||||
|
||||
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
|
||||
super().save(force_insert, force_update, using, update_fields)
|
||||
dispatch.refresh_dictionary() # 有更新则刷新字典配置
|
||||
|
||||
|
||||
class OperationLog(CoreModel):
|
||||
request_modular = models.CharField(max_length=64, verbose_name="请求模块", null=True, blank=True, help_text="请求模块")
|
||||
|
|
@ -223,7 +229,7 @@ class FileList(CoreModel):
|
|||
super(FileList, self).save(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + 'file_list'
|
||||
db_table = table_prefix + 'system_file_list'
|
||||
verbose_name = '文件管理'
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ('-create_datetime',)
|
||||
|
|
@ -240,7 +246,7 @@ class Area(CoreModel):
|
|||
db_constraint=False, null=True, blank=True, help_text="父地区编码")
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "area"
|
||||
db_table = table_prefix + "system_area"
|
||||
verbose_name = '地区表'
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ('code',)
|
||||
|
|
@ -271,26 +277,29 @@ class SystemConfig(CoreModel):
|
|||
parent = models.ForeignKey(to='self', verbose_name='父级', on_delete=models.CASCADE,
|
||||
db_constraint=False, null=True, blank=True, help_text="父级")
|
||||
title = models.CharField(max_length=50, verbose_name="标题", help_text="标题")
|
||||
key = models.CharField(max_length=20, verbose_name="键", help_text="键")
|
||||
key = models.CharField(max_length=20, verbose_name="键", help_text="键", db_index=True)
|
||||
value = models.JSONField(max_length=100, verbose_name="值", help_text="值", null=True, blank=True)
|
||||
sort = models.IntegerField(default=0, verbose_name="排序", help_text="排序", blank=True)
|
||||
status = models.BooleanField(default=False, verbose_name="启用状态", help_text="启用状态")
|
||||
status = models.BooleanField(default=True, verbose_name="启用状态", help_text="启用状态")
|
||||
data_options = models.JSONField(verbose_name="数据options", help_text="数据options", null=True, blank=True)
|
||||
FORM_ITEM_TYPE_LIST = (
|
||||
(0, 'text'),
|
||||
(1, 'textarea'),
|
||||
(2, 'number'),
|
||||
(3, 'select'),
|
||||
(4, 'radio'),
|
||||
(1, 'datetime'),
|
||||
(2, 'date'),
|
||||
(3, 'textarea'),
|
||||
(4, 'select'),
|
||||
(5, 'checkbox'),
|
||||
(6, 'date'),
|
||||
(7, 'datetime'),
|
||||
(8, 'time'),
|
||||
(9, 'imgs'),
|
||||
(10, 'files'),
|
||||
(6, 'radio'),
|
||||
(7, 'img'),
|
||||
(8, 'file'),
|
||||
(9, 'switch'),
|
||||
(10, 'number'),
|
||||
(11, 'array'),
|
||||
(12, 'foreignkey'),
|
||||
(13, 'manytomany'),
|
||||
(12, 'imgs'),
|
||||
(13, 'foreignkey'),
|
||||
(14, 'manytomany'),
|
||||
(15, 'time'),
|
||||
|
||||
)
|
||||
form_item_type = models.IntegerField(choices=FORM_ITEM_TYPE_LIST, verbose_name="表单类型", help_text="表单类型", default=0,
|
||||
blank=True)
|
||||
|
|
@ -303,10 +312,15 @@ class SystemConfig(CoreModel):
|
|||
verbose_name = '系统配置表'
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ('sort',)
|
||||
unique_together = (("key", "parent_id"),)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.title}"
|
||||
|
||||
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
|
||||
super().save(force_insert, force_update, using, update_fields)
|
||||
dispatch.refresh_system_config() # 有更新则刷新系统配置
|
||||
|
||||
|
||||
class LoginLog(CoreModel):
|
||||
LOGIN_TYPE_CHOICES = (
|
||||
|
|
|
|||
|
|
@ -1,17 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
@author: 猿小天
|
||||
@contact: QQ:1638245306
|
||||
@Created on: 2021/6/1 001 23:05
|
||||
@Remark: 系统管理的路由文件
|
||||
"""
|
||||
from django.urls import path
|
||||
from rest_framework import routers
|
||||
|
||||
from dvadmin.system.views.api_white_list import ApiWhiteListViewSet
|
||||
from dvadmin.system.views.area import AreaViewSet
|
||||
from dvadmin.system.views.button import ButtonViewSet
|
||||
from dvadmin.system.views.dept import DeptViewSet
|
||||
from dvadmin.system.views.dictionary import DictionaryViewSet
|
||||
from dvadmin.system.views.file_list import FileViewSet
|
||||
|
|
@ -25,7 +16,6 @@ from dvadmin.system.views.user import UserViewSet
|
|||
|
||||
system_url = routers.SimpleRouter()
|
||||
system_url.register(r'menu', MenuViewSet)
|
||||
system_url.register(r'button', ButtonViewSet)
|
||||
system_url.register(r'menu_button', MenuButtonViewSet)
|
||||
system_url.register(r'role', RoleViewSet)
|
||||
system_url.register(r'dept', DeptViewSet)
|
||||
|
|
@ -42,6 +32,7 @@ urlpatterns = [
|
|||
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/import/', UserViewSet.as_view({'get': 'import_data', 'post': 'import_data'})),
|
||||
|
|
@ -51,5 +42,6 @@ urlpatterns = [
|
|||
path('system_config/get_relation_info/', SystemConfigViewSet.as_view({'get': 'get_relation_info'})),
|
||||
path('login_log/', LoginLogViewSet.as_view({'get': 'list'})),
|
||||
path('login_log/<int:pk>/', LoginLogViewSet.as_view({'get': 'retrieve'})),
|
||||
path('dept_lazy_tree/', DeptViewSet.as_view({'get': 'dept_lazy_tree'})),
|
||||
]
|
||||
urlpatterns += system_url.urls
|
||||
|
|
|
|||
|
|
@ -22,6 +22,21 @@ class ApiWhiteListSerializer(CustomModelSerializer):
|
|||
read_only_fields = ["id"]
|
||||
|
||||
|
||||
class ApiWhiteListInitSerializer(CustomModelSerializer):
|
||||
"""
|
||||
初始化获取数信息(用于生成初始化json文件)
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = ApiWhiteList
|
||||
fields = ['url', 'method', 'enable_datasource', 'creator', 'dept_belong_id']
|
||||
read_only_fields = ["id"]
|
||||
extra_kwargs = {
|
||||
'creator': {'write_only': True},
|
||||
'dept_belong_id': {'write_only': True}
|
||||
}
|
||||
|
||||
|
||||
class ApiWhiteListViewSet(CustomModelViewSet):
|
||||
"""
|
||||
接口白名单
|
||||
|
|
@ -33,4 +48,4 @@ class ApiWhiteListViewSet(CustomModelViewSet):
|
|||
"""
|
||||
queryset = ApiWhiteList.objects.all()
|
||||
serializer_class = ApiWhiteListSerializer
|
||||
# permission_classes = []
|
||||
# permission_classes = []
|
||||
|
|
|
|||
|
|
@ -1,36 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
@author: 猿小天
|
||||
@contact: QQ:1638245306
|
||||
@Created on: 2021/6/3 003 0:30
|
||||
@Remark: 按钮权限管理
|
||||
"""
|
||||
from dvadmin.system.models import Button
|
||||
from dvadmin.utils.serializers import CustomModelSerializer
|
||||
from dvadmin.utils.viewset import CustomModelViewSet
|
||||
|
||||
|
||||
class ButtonSerializer(CustomModelSerializer):
|
||||
"""
|
||||
按钮权限-序列化器
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = Button
|
||||
fields = "__all__"
|
||||
read_only_fields = ["id"]
|
||||
|
||||
|
||||
class ButtonViewSet(CustomModelViewSet):
|
||||
"""
|
||||
按钮权限接口
|
||||
list:查询
|
||||
create:新增
|
||||
update:修改
|
||||
retrieve:单例
|
||||
destroy:删除
|
||||
"""
|
||||
queryset = Button.objects.all()
|
||||
serializer_class = ButtonSerializer
|
||||
extra_filter_backends = []
|
||||
|
|
@ -1,15 +1,14 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
@author: 猿小天
|
||||
@contact: QQ:1638245306
|
||||
@Created on: 2021/6/3 003 0:30
|
||||
@Remark: 角色管理
|
||||
@author: H0nGzA1
|
||||
@contact: QQ:2505811377
|
||||
@Remark: 部门管理
|
||||
"""
|
||||
from rest_framework import serializers
|
||||
|
||||
from dvadmin.system.models import Dept
|
||||
from dvadmin.utils.json_response import SuccessResponse
|
||||
from dvadmin.utils.json_response import DetailResponse, SuccessResponse
|
||||
from dvadmin.utils.serializers import CustomModelSerializer
|
||||
from dvadmin.utils.viewset import CustomModelViewSet
|
||||
|
||||
|
|
@ -18,13 +17,60 @@ class DeptSerializer(CustomModelSerializer):
|
|||
"""
|
||||
部门-序列化器
|
||||
"""
|
||||
parent_name = serializers.CharField(read_only=True,source='parent.name')
|
||||
parent_name = serializers.CharField(read_only=True, source='parent.name')
|
||||
has_children = serializers.SerializerMethodField()
|
||||
|
||||
def get_has_children(self, obj: Dept):
|
||||
return Dept.objects.filter(parent_id=obj.id).count()
|
||||
|
||||
class Meta:
|
||||
model = Dept
|
||||
fields = "__all__"
|
||||
fields = '__all__'
|
||||
read_only_fields = ["id"]
|
||||
|
||||
|
||||
class DeptInitSerializer(CustomModelSerializer):
|
||||
"""
|
||||
递归深度获取数信息(用于生成初始化json文件)
|
||||
"""
|
||||
children = serializers.SerializerMethodField()
|
||||
|
||||
def get_children(self, obj: Dept):
|
||||
data = []
|
||||
instance = Dept.objects.filter(parent_id=obj.id)
|
||||
if instance:
|
||||
serializer = DeptInitSerializer(instance=instance, many=True)
|
||||
data = serializer.data
|
||||
return data
|
||||
|
||||
def save(self, **kwargs):
|
||||
instance = super().save(**kwargs)
|
||||
children = self.initial_data.get('children')
|
||||
if children:
|
||||
for menu_data in children:
|
||||
menu_data['parent'] = instance.id
|
||||
filter_data = {
|
||||
"name": menu_data['name'],
|
||||
"parent": menu_data['parent']
|
||||
}
|
||||
instance_obj = Dept.objects.filter(**filter_data).first()
|
||||
serializer = DeptInitSerializer(instance_obj, data=menu_data, request=self.request)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
|
||||
return instance
|
||||
|
||||
class Meta:
|
||||
model = Dept
|
||||
fields = ['name', 'sort', 'owner', 'phone', 'email', 'status', 'parent', 'creator', 'dept_belong_id',
|
||||
'children']
|
||||
extra_kwargs = {
|
||||
'creator': {'write_only': True},
|
||||
'dept_belong_id': {'write_only': True}
|
||||
}
|
||||
read_only_fields = ['id', 'children']
|
||||
|
||||
|
||||
class DeptCreateUpdateSerializer(CustomModelSerializer):
|
||||
"""
|
||||
部门管理 创建/更新时的列化器
|
||||
|
|
@ -54,13 +100,40 @@ class DeptViewSet(CustomModelViewSet):
|
|||
serializer_class = DeptSerializer
|
||||
create_serializer_class = DeptCreateUpdateSerializer
|
||||
update_serializer_class = DeptCreateUpdateSerializer
|
||||
filter_fields = ['name', 'id', 'parent']
|
||||
search_fields = []
|
||||
|
||||
# extra_filter_backends = []
|
||||
|
||||
# def list(self, request, *args, **kwargs):
|
||||
# queryset = self.filter_queryset(self.get_queryset())
|
||||
# page = self.paginate_queryset(queryset)
|
||||
# if page is not None:
|
||||
# serializer = self.get_serializer(page, many=True, request=request)
|
||||
# return self.get_paginated_response(serializer.data)
|
||||
# serializer = self.get_serializer(queryset, many=True, request=request)
|
||||
# return SuccessResponse(data=serializer.data, msg="获取成功")
|
||||
def list(self, request, *args, **kwargs):
|
||||
# 如果懒加载,则只返回父级
|
||||
queryset = self.filter_queryset(self.get_queryset())
|
||||
lazy = self.request.query_params.get('lazy')
|
||||
parent = self.request.query_params.get('parent')
|
||||
if lazy:
|
||||
# 如果懒加载模式,返回全部
|
||||
if not parent:
|
||||
if self.request.user.is_superuser:
|
||||
queryset = queryset.filter(parent__isnull=True)
|
||||
else:
|
||||
queryset = queryset.filter(id=self.request.user.dept_id)
|
||||
serializer = self.get_serializer(queryset, many=True, request=request)
|
||||
return SuccessResponse(data=serializer.data, msg="获取成功")
|
||||
|
||||
page = self.paginate_queryset(queryset)
|
||||
if page is not None:
|
||||
serializer = self.get_serializer(page, many=True, request=request)
|
||||
return self.get_paginated_response(serializer.data)
|
||||
serializer = self.get_serializer(queryset, many=True, request=request)
|
||||
return SuccessResponse(data=serializer.data, msg="获取成功")
|
||||
|
||||
def dept_lazy_tree(self, request, *args, **kwargs):
|
||||
parent = self.request.query_params.get('parent')
|
||||
queryset = self.filter_queryset(self.get_queryset())
|
||||
if not parent:
|
||||
if self.request.user.is_superuser:
|
||||
queryset = queryset.filter(parent__isnull=True)
|
||||
else:
|
||||
queryset = queryset.filter(id=self.request.user.dept_id)
|
||||
data = queryset.filter(status=True).order_by('sort').values('name', 'id', 'parent')
|
||||
return DetailResponse(data=data, msg="获取成功")
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@
|
|||
@Remark: 字典管理
|
||||
"""
|
||||
from rest_framework import serializers
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from application import dispatch
|
||||
from dvadmin.system.models import Dictionary
|
||||
from dvadmin.utils.json_response import SuccessResponse
|
||||
from dvadmin.utils.serializers import CustomModelSerializer
|
||||
|
|
@ -25,6 +27,48 @@ class DictionarySerializer(CustomModelSerializer):
|
|||
read_only_fields = ["id"]
|
||||
|
||||
|
||||
class DictionaryInitSerializer(CustomModelSerializer):
|
||||
"""
|
||||
初始化获取数信息(用于生成初始化json文件)
|
||||
"""
|
||||
children = serializers.SerializerMethodField()
|
||||
|
||||
def get_children(self, obj: Dictionary):
|
||||
data = []
|
||||
instance = Dictionary.objects.filter(parent_id=obj.id)
|
||||
if instance:
|
||||
serializer = DictionaryInitSerializer(instance=instance, many=True)
|
||||
data = serializer.data
|
||||
return data
|
||||
|
||||
def save(self, **kwargs):
|
||||
instance = super().save(**kwargs)
|
||||
children = self.initial_data.get('children')
|
||||
# 菜单表
|
||||
if children:
|
||||
for data in children:
|
||||
data['parent'] = instance.id
|
||||
filter_data = {
|
||||
"value": data['value'],
|
||||
"parent": data['parent']
|
||||
}
|
||||
instance_obj = Dictionary.objects.filter(**filter_data).first()
|
||||
serializer = DictionaryInitSerializer(instance_obj, data=data, request=self.request)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
return instance
|
||||
|
||||
class Meta:
|
||||
model = Dictionary
|
||||
fields = ['label', 'value', 'parent', 'type', 'color', 'is_value', 'status', 'sort', 'remark', 'creator',
|
||||
'dept_belong_id', 'children']
|
||||
read_only_fields = ["id"]
|
||||
extra_kwargs = {
|
||||
'creator': {'write_only': True},
|
||||
'dept_belong_id': {'write_only': True}
|
||||
}
|
||||
|
||||
|
||||
class DictionaryCreateUpdateSerializer(CustomModelSerializer):
|
||||
"""
|
||||
字典管理 创建/更新时的列化器
|
||||
|
|
@ -35,26 +79,6 @@ class DictionaryCreateUpdateSerializer(CustomModelSerializer):
|
|||
fields = '__all__'
|
||||
|
||||
|
||||
class DictionaryTreeSerializer(CustomModelSerializer):
|
||||
"""
|
||||
字典表的树形序列化器
|
||||
"""
|
||||
children = serializers.SerializerMethodField(read_only=True)
|
||||
|
||||
def get_children(self, instance):
|
||||
queryset = Dictionary.objects.filter(parent=instance.id).filter(status=1)
|
||||
if queryset:
|
||||
serializer = DictionaryTreeSerializer(queryset, many=True)
|
||||
return serializer.data
|
||||
else:
|
||||
return None
|
||||
|
||||
class Meta:
|
||||
model = Dictionary
|
||||
fields = "__all__"
|
||||
read_only_fields = ["id"]
|
||||
|
||||
|
||||
class DictionaryViewSet(CustomModelViewSet):
|
||||
"""
|
||||
字典管理接口
|
||||
|
|
@ -68,3 +92,26 @@ class DictionaryViewSet(CustomModelViewSet):
|
|||
serializer_class = DictionarySerializer
|
||||
extra_filter_backends = []
|
||||
search_fields = ['label']
|
||||
|
||||
|
||||
class InitDictionaryViewSet(APIView):
|
||||
"""
|
||||
获取初始化配置
|
||||
"""
|
||||
authentication_classes = []
|
||||
permission_classes = []
|
||||
queryset = Dictionary.objects.all()
|
||||
|
||||
def get(self, request):
|
||||
dictionary_key = self.request.query_params.get('dictionary_key')
|
||||
if dictionary_key:
|
||||
if dictionary_key == 'all':
|
||||
data = [ele for ele in dispatch.get_dictionary_config().values()]
|
||||
if not data:
|
||||
dispatch.refresh_dictionary()
|
||||
data = [ele for ele in dispatch.get_dictionary_config().values()]
|
||||
else:
|
||||
data = self.queryset.filter(parent__value=dictionary_key, status=True).values('label', 'value', 'type',
|
||||
'color')
|
||||
return SuccessResponse(data=data, msg="获取成功")
|
||||
return SuccessResponse(data=[], msg="获取成功")
|
||||
|
|
|
|||
|
|
@ -1,11 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
@author: 猿小天
|
||||
@contact: QQ:1638245306
|
||||
@Created on: 2021/8/9 009 20:48
|
||||
@Remark:
|
||||
"""
|
||||
from rest_framework import serializers
|
||||
|
||||
from dvadmin.system.models import FileList
|
||||
|
|
@ -17,7 +9,7 @@ class FileSerializer(CustomModelSerializer):
|
|||
url = serializers.SerializerMethodField(read_only=True)
|
||||
|
||||
def get_url(self, instance):
|
||||
return 'media/'+str(instance.url)
|
||||
return 'media/' + str(instance.url)
|
||||
|
||||
class Meta:
|
||||
model = FileList
|
||||
|
|
|
|||
|
|
@ -1,11 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
@author: 猿小天
|
||||
@contact: QQ:1638245306
|
||||
@Created on: 2021/6/2 002 14:20
|
||||
@Remark:登录视图
|
||||
"""
|
||||
import base64
|
||||
import hashlib
|
||||
from datetime import datetime, timedelta
|
||||
|
|
@ -22,9 +14,11 @@ from rest_framework.views import APIView
|
|||
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
|
||||
from rest_framework_simplejwt.views import TokenObtainPairView
|
||||
|
||||
from application import settings
|
||||
from django.conf import settings
|
||||
|
||||
from application import dispatch
|
||||
from dvadmin.system.models import Users
|
||||
from dvadmin.utils.json_response import SuccessResponse, ErrorResponse, DetailResponse
|
||||
from dvadmin.utils.json_response import ErrorResponse, DetailResponse
|
||||
from dvadmin.utils.request_util import save_login_log
|
||||
from dvadmin.utils.serializers import CustomModelSerializer
|
||||
from dvadmin.utils.validator import CustomValidationError
|
||||
|
|
@ -35,21 +29,24 @@ class CaptchaView(APIView):
|
|||
permission_classes = []
|
||||
|
||||
@swagger_auto_schema(
|
||||
responses={
|
||||
'200': openapi.Response('获取成功')
|
||||
},
|
||||
responses={"200": openapi.Response("获取成功")},
|
||||
security=[],
|
||||
operation_id='captcha-get',
|
||||
operation_description='验证码获取',
|
||||
operation_id="captcha-get",
|
||||
operation_description="验证码获取",
|
||||
)
|
||||
def get(self, request):
|
||||
hashkey = CaptchaStore.generate_key()
|
||||
id = CaptchaStore.objects.filter(hashkey=hashkey).first().id
|
||||
imgage = captcha_image(request, hashkey)
|
||||
# 将图片转换为base64
|
||||
image_base = base64.b64encode(imgage.content)
|
||||
json_data = {"key": id, "image_base": "data:image/png;base64," + image_base.decode('utf-8')}
|
||||
return SuccessResponse(data=json_data)
|
||||
data = {}
|
||||
if dispatch.get_system_config_values("base.captcha_state"):
|
||||
hashkey = CaptchaStore.generate_key()
|
||||
id = CaptchaStore.objects.filter(hashkey=hashkey).first().id
|
||||
imgage = captcha_image(request, hashkey)
|
||||
# 将图片转换为base64
|
||||
image_base = base64.b64encode(imgage.content)
|
||||
data = {
|
||||
"key": id,
|
||||
"image_base": "data:image/png;base64," + image_base.decode("utf-8"),
|
||||
}
|
||||
return DetailResponse(data=data)
|
||||
|
||||
|
||||
class LoginSerializer(TokenObtainPairSerializer):
|
||||
|
|
@ -57,53 +54,55 @@ class LoginSerializer(TokenObtainPairSerializer):
|
|||
登录的序列化器:
|
||||
重写djangorestframework-simplejwt的序列化器
|
||||
"""
|
||||
captcha = serializers.CharField(max_length=6, required=False, allow_null=True)
|
||||
|
||||
captcha = serializers.CharField(
|
||||
max_length=6, required=False, allow_null=True, allow_blank=True
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Users
|
||||
fields = "__all__"
|
||||
read_only_fields = ["id"]
|
||||
|
||||
default_error_messages = {
|
||||
'no_active_account': _('账号/密码不正确')
|
||||
}
|
||||
default_error_messages = {"no_active_account": _("账号/密码错误")}
|
||||
|
||||
def validate(self, attrs):
|
||||
captcha = self.initial_data.get('captcha', None)
|
||||
if settings.CAPTCHA_STATE:
|
||||
captcha = self.initial_data.get("captcha", None)
|
||||
if dispatch.get_system_config_values("base.captcha_state"):
|
||||
if captcha is None:
|
||||
raise CustomValidationError("验证码不能为空")
|
||||
self.image_code = CaptchaStore.objects.filter(
|
||||
id=self.initial_data['captchaKey']).first()
|
||||
id=self.initial_data["captchaKey"]
|
||||
).first()
|
||||
five_minute_ago = datetime.now() - timedelta(hours=0, minutes=5, seconds=0)
|
||||
if self.image_code and five_minute_ago > self.image_code.expiration:
|
||||
self.image_code and self.image_code.delete()
|
||||
raise CustomValidationError('验证码过期')
|
||||
raise CustomValidationError("验证码过期")
|
||||
else:
|
||||
if self.image_code and (self.image_code.response == captcha or self.image_code.challenge == captcha):
|
||||
if self.image_code and (
|
||||
self.image_code.response == captcha
|
||||
or self.image_code.challenge == captcha
|
||||
):
|
||||
self.image_code and self.image_code.delete()
|
||||
else:
|
||||
self.image_code and self.image_code.delete()
|
||||
raise CustomValidationError("图片验证码错误")
|
||||
data = super().validate(attrs)
|
||||
data['name'] = self.user.name
|
||||
data['userId'] = self.user.id
|
||||
data['avatar'] = self.user.avatar
|
||||
request = self.context.get('request')
|
||||
data["name"] = self.user.name
|
||||
data["userId"] = self.user.id
|
||||
data["avatar"] = self.user.avatar
|
||||
request = self.context.get("request")
|
||||
request.user = self.user
|
||||
# 记录登录日志
|
||||
save_login_log(request=request)
|
||||
return {
|
||||
"code": 2000,
|
||||
"msg": "请求成功",
|
||||
"data": data
|
||||
}
|
||||
return {"code": 2000, "msg": "请求成功", "data": data}
|
||||
|
||||
|
||||
class LoginView(TokenObtainPairView):
|
||||
"""
|
||||
登录接口
|
||||
"""
|
||||
|
||||
serializer_class = LoginSerializer
|
||||
permission_classes = []
|
||||
|
||||
|
|
@ -118,31 +117,22 @@ class LoginTokenSerializer(TokenObtainPairSerializer):
|
|||
fields = "__all__"
|
||||
read_only_fields = ["id"]
|
||||
|
||||
default_error_messages = {
|
||||
'no_active_account': _('账号/密码不正确')
|
||||
}
|
||||
default_error_messages = {"no_active_account": _("账号/密码不正确")}
|
||||
|
||||
def validate(self, attrs):
|
||||
if not getattr(settings, 'LOGIN_NO_CAPTCHA_AUTH', False):
|
||||
return {
|
||||
"code": 4000,
|
||||
"msg": "该接口暂未开通!",
|
||||
"data": None
|
||||
}
|
||||
if not getattr(settings, "LOGIN_NO_CAPTCHA_AUTH", False):
|
||||
return {"code": 4000, "msg": "该接口暂未开通!", "data": None}
|
||||
data = super().validate(attrs)
|
||||
data['name'] = self.user.name
|
||||
data['userId'] = self.user.id
|
||||
return {
|
||||
"code": 2000,
|
||||
"msg": "请求成功",
|
||||
"data": data
|
||||
}
|
||||
data["name"] = self.user.name
|
||||
data["userId"] = self.user.id
|
||||
return {"code": 2000, "msg": "请求成功", "data": data}
|
||||
|
||||
|
||||
class LoginTokenView(TokenObtainPairView):
|
||||
"""
|
||||
登录获取token接口
|
||||
"""
|
||||
|
||||
serializer_class = LoginTokenSerializer
|
||||
permission_classes = []
|
||||
|
||||
|
|
@ -154,27 +144,32 @@ class LogoutView(APIView):
|
|||
|
||||
class ApiLoginSerializer(CustomModelSerializer):
|
||||
"""接口文档登录-序列化器"""
|
||||
|
||||
username = serializers.CharField()
|
||||
password = serializers.CharField()
|
||||
|
||||
class Meta:
|
||||
model = Users
|
||||
fields = ['username', 'password']
|
||||
fields = ["username", "password"]
|
||||
|
||||
|
||||
class ApiLogin(APIView):
|
||||
"""接口文档的登录接口"""
|
||||
|
||||
serializer_class = ApiLoginSerializer
|
||||
authentication_classes = []
|
||||
permission_classes = []
|
||||
|
||||
def post(self, request):
|
||||
username = request.data.get('username')
|
||||
password = request.data.get('password')
|
||||
user_obj = auth.authenticate(request, username=username,
|
||||
password=hashlib.md5(password.encode(encoding='UTF-8')).hexdigest())
|
||||
username = request.data.get("username")
|
||||
password = request.data.get("password")
|
||||
user_obj = auth.authenticate(
|
||||
request,
|
||||
username=username,
|
||||
password=hashlib.md5(password.encode(encoding="UTF-8")).hexdigest(),
|
||||
)
|
||||
if user_obj:
|
||||
login(request, user_obj)
|
||||
return redirect('/')
|
||||
return redirect("/")
|
||||
else:
|
||||
return ErrorResponse(msg="账号/密码错误")
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@
|
|||
from rest_framework import serializers
|
||||
from rest_framework.decorators import action
|
||||
|
||||
from dvadmin.system.models import Menu, MenuButton, Button
|
||||
from dvadmin.system.models import Menu, MenuButton
|
||||
from dvadmin.system.views.menu_button import MenuButtonSerializer
|
||||
from dvadmin.utils.json_response import SuccessResponse
|
||||
from dvadmin.utils.serializers import CustomModelSerializer
|
||||
from dvadmin.utils.viewset import CustomModelViewSet
|
||||
|
|
@ -46,6 +47,72 @@ class MenuCreateSerializer(CustomModelSerializer):
|
|||
read_only_fields = ["id"]
|
||||
|
||||
|
||||
class MenuInitSerializer(CustomModelSerializer):
|
||||
"""
|
||||
递归深度获取数信息(用于生成初始化json文件)
|
||||
"""
|
||||
name = serializers.CharField(required=False)
|
||||
children = serializers.SerializerMethodField()
|
||||
menu_button = serializers.SerializerMethodField()
|
||||
|
||||
def get_children(self, obj: Menu):
|
||||
data = []
|
||||
instance = Menu.objects.filter(parent_id=obj.id)
|
||||
if instance:
|
||||
serializer = MenuInitSerializer(instance=instance, many=True)
|
||||
data = serializer.data
|
||||
return data
|
||||
|
||||
def get_menu_button(self, obj: Menu):
|
||||
data = []
|
||||
instance = MenuButton.objects.filter(menu_id=obj.id).order_by('method')
|
||||
if instance:
|
||||
data = list(instance.values('name', 'value', 'api', 'method'))
|
||||
return data
|
||||
|
||||
def save(self, **kwargs):
|
||||
instance = super().save(**kwargs)
|
||||
children = self.initial_data.get('children')
|
||||
menu_button = self.initial_data.get('menu_button')
|
||||
# 菜单表
|
||||
if children:
|
||||
for menu_data in children:
|
||||
menu_data['parent'] = instance.id
|
||||
filter_data = {
|
||||
"name": menu_data['name'],
|
||||
"web_path": menu_data['web_path'],
|
||||
"component": menu_data['component'],
|
||||
"component_name": menu_data['component_name'],
|
||||
}
|
||||
instance_obj = Menu.objects.filter(**filter_data).first()
|
||||
serializer = MenuInitSerializer(instance_obj, data=menu_data, request=self.request)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
# 菜单按钮
|
||||
if menu_button:
|
||||
for menu_button_data in menu_button:
|
||||
menu_button_data['menu'] = instance.id
|
||||
filter_data = {
|
||||
"menu": menu_button_data['menu'],
|
||||
"value": menu_button_data['value']
|
||||
}
|
||||
instance_obj = MenuButton.objects.filter(**filter_data).first()
|
||||
serializer = MenuButtonSerializer(instance_obj, data=menu_button_data, request=self.request)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
return instance
|
||||
|
||||
class Meta:
|
||||
model = Menu
|
||||
fields = ['name', 'icon', 'sort', 'is_link', 'is_catalog', 'web_path', 'component', 'component_name', 'status',
|
||||
'cache', 'visible', 'parent', 'children', 'menu_button', 'creator', 'dept_belong_id']
|
||||
extra_kwargs = {
|
||||
'creator': {'write_only': True},
|
||||
'dept_belong_id': {'write_only': True}
|
||||
}
|
||||
read_only_fields = ['id', 'children']
|
||||
|
||||
|
||||
class WebRouterSerializer(CustomModelSerializer):
|
||||
"""
|
||||
前端菜单路由的简单序列化器
|
||||
|
|
@ -57,11 +124,11 @@ class WebRouterSerializer(CustomModelSerializer):
|
|||
def get_menuPermission(self, instance):
|
||||
# 判断是否是超级管理员
|
||||
if self.request.user.is_superuser:
|
||||
return Button.objects.values_list('value', flat=True)
|
||||
return MenuButton.objects.values_list('value', flat=True)
|
||||
else:
|
||||
# 根据当前角色获取权限按钮id集合
|
||||
permissionIds = self.request.user.role.values_list('permission', flat=True)
|
||||
queryset = MenuButton.objects.filter(id__in=permissionIds,menu=instance.id).values_list('value', flat=True)
|
||||
queryset = MenuButton.objects.filter(id__in=permissionIds, menu=instance.id).values_list('value', flat=True)
|
||||
if queryset:
|
||||
return queryset
|
||||
else:
|
||||
|
|
@ -87,7 +154,7 @@ class MenuViewSet(CustomModelViewSet):
|
|||
create_serializer_class = MenuCreateSerializer
|
||||
update_serializer_class = MenuCreateSerializer
|
||||
search_fields = ['name', 'status']
|
||||
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 = []
|
||||
|
||||
@action(methods=['GET'], detail=True, permission_classes=[])
|
||||
|
|
@ -100,4 +167,4 @@ class MenuViewSet(CustomModelViewSet):
|
|||
queryset = Menu.objects.filter(id__in=menuIds, status=1)
|
||||
serializer = WebRouterSerializer(queryset, many=True, request=request)
|
||||
data = serializer.data
|
||||
return SuccessResponse(data=data,total=len(data),msg="获取成功")
|
||||
return SuccessResponse(data=data, total=len(data), msg="获取成功")
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
"""
|
||||
from rest_framework import serializers
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
|
||||
from dvadmin.system.models import Role, Menu
|
||||
from dvadmin.system.views.dept import DeptSerializer
|
||||
|
|
@ -31,6 +30,22 @@ class RoleSerializer(CustomModelSerializer):
|
|||
read_only_fields = ["id"]
|
||||
|
||||
|
||||
class RoleInitSerializer(CustomModelSerializer):
|
||||
"""
|
||||
初始化获取数信息(用于生成初始化json文件)
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = Role
|
||||
fields = ['name', 'key', 'sort', 'status', 'admin', 'data_range', 'remark',
|
||||
'creator', 'dept_belong_id']
|
||||
read_only_fields = ["id"]
|
||||
extra_kwargs = {
|
||||
'creator': {'write_only': True},
|
||||
'dept_belong_id': {'write_only': True}
|
||||
}
|
||||
|
||||
|
||||
class RoleCreateUpdateSerializer(CustomModelSerializer):
|
||||
"""
|
||||
角色管理 创建/更新时的列化器
|
||||
|
|
@ -90,4 +105,3 @@ class RoleViewSet(CustomModelViewSet):
|
|||
queryset = Menu.objects.filter(status=1).all()
|
||||
serializer = MenuPermissonSerializer(queryset, many=True)
|
||||
return SuccessResponse(data=serializer.data)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,9 +10,10 @@ import django_filters
|
|||
from django.db.models import Q
|
||||
from django_filters.rest_framework import BooleanFilter
|
||||
from rest_framework import serializers
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from application import dispatch
|
||||
from dvadmin.system.models import SystemConfig
|
||||
from dvadmin.utils.filters import DataLevelPermissionsFilter
|
||||
from dvadmin.utils.json_response import DetailResponse, SuccessResponse, ErrorResponse
|
||||
from dvadmin.utils.models import get_all_models_objects
|
||||
from dvadmin.utils.serializers import CustomModelSerializer
|
||||
|
|
@ -31,17 +32,59 @@ class SystemConfigCreateSerializer(CustomModelSerializer):
|
|||
fields = "__all__"
|
||||
read_only_fields = ["id"]
|
||||
|
||||
|
||||
def validate_key(self, value):
|
||||
"""
|
||||
验证key是否允许重复
|
||||
parent为空时不允许重复,反之允许
|
||||
"""
|
||||
instance = SystemConfig.objects.filter(key=value,parent__isnull=True).exists()
|
||||
instance = SystemConfig.objects.filter(key=value, parent__isnull=True).exists()
|
||||
if instance:
|
||||
raise CustomValidationError('已存在相同变量名')
|
||||
return value
|
||||
|
||||
|
||||
class SystemConfigInitSerializer(CustomModelSerializer):
|
||||
"""
|
||||
初始化获取数信息(用于生成初始化json文件)
|
||||
"""
|
||||
children = serializers.SerializerMethodField()
|
||||
|
||||
def get_children(self, obj: SystemConfig):
|
||||
data = []
|
||||
instance = SystemConfig.objects.filter(parent_id=obj.id)
|
||||
if instance:
|
||||
serializer = SystemConfigInitSerializer(instance=instance, many=True)
|
||||
data = serializer.data
|
||||
return data
|
||||
|
||||
def save(self, **kwargs):
|
||||
instance = super().save(**kwargs)
|
||||
children = self.initial_data.get('children')
|
||||
# 菜单表
|
||||
if children:
|
||||
for data in children:
|
||||
data['parent'] = instance.id
|
||||
filter_data = {
|
||||
"key": data['key'],
|
||||
"parent": data['parent']
|
||||
}
|
||||
instance_obj = SystemConfig.objects.filter(**filter_data).first()
|
||||
serializer = SystemConfigInitSerializer(instance_obj, data=data, request=self.request)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
return instance
|
||||
|
||||
class Meta:
|
||||
model = SystemConfig
|
||||
fields = ['parent', 'title', 'key', 'value', 'sort', 'status', 'data_options', 'form_item_type', 'rule',
|
||||
'placeholder', 'setting', 'creator', 'dept_belong_id', 'children']
|
||||
read_only_fields = ["id"]
|
||||
extra_kwargs = {
|
||||
'creator': {'write_only': True},
|
||||
'dept_belong_id': {'write_only': True}
|
||||
}
|
||||
|
||||
|
||||
class SystemConfigSerializer(CustomModelSerializer):
|
||||
"""
|
||||
系统配置-序列化器
|
||||
|
|
@ -112,17 +155,9 @@ class SystemConfigFilter(django_filters.rest_framework.FilterSet):
|
|||
fields = ['id', 'parent', 'status', 'parent__isnull']
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class SystemConfigViewSet(CustomModelViewSet):
|
||||
"""
|
||||
系统配置接口
|
||||
list:查询
|
||||
create:新增
|
||||
update:修改
|
||||
retrieve:详情
|
||||
destroy:删除
|
||||
"""
|
||||
queryset = SystemConfig.objects.order_by('sort', 'create_datetime')
|
||||
serializer_class = SystemConfigChinldernSerializer
|
||||
|
|
@ -152,7 +187,7 @@ class SystemConfigViewSet(CustomModelViewSet):
|
|||
res = [ele.get('table') for ele in get_all_models_objects().values()]
|
||||
return DetailResponse(msg="获取成功", data=res)
|
||||
|
||||
def get_table_data(self, request,pk):
|
||||
def get_table_data(self, request, pk):
|
||||
"""
|
||||
动态获取关联表的数据
|
||||
"""
|
||||
|
|
@ -162,7 +197,7 @@ class SystemConfigViewSet(CustomModelViewSet):
|
|||
setting = instance.setting
|
||||
if setting is None:
|
||||
return ErrorResponse(msg="查询出错了~")
|
||||
table = setting.get('table') #获取model名
|
||||
table = setting.get('table') # 获取model名
|
||||
model = get_all_models_objects(table).get("object", {})
|
||||
# 自己判断一下不存在
|
||||
queryset = model.objects.values()
|
||||
|
|
@ -181,15 +216,14 @@ class SystemConfigViewSet(CustomModelViewSet):
|
|||
return self.get_paginated_response(queryset)
|
||||
return SuccessResponse(msg="获取成功", data=queryset, total=len(queryset))
|
||||
|
||||
|
||||
def get_relation_info(self,request):
|
||||
def get_relation_info(self, request):
|
||||
"""
|
||||
查询关联的模板信息
|
||||
"""
|
||||
body = request.query_params
|
||||
var_name = body.get('varName',None)
|
||||
table = body.get('table',None)
|
||||
instance = SystemConfig.objects.filter(key=var_name,setting__table=table).first()
|
||||
var_name = body.get('varName', None)
|
||||
table = body.get('table', None)
|
||||
instance = SystemConfig.objects.filter(key=var_name, setting__table=table).first()
|
||||
if instance is None:
|
||||
return ErrorResponse(msg="未获取到关联信息")
|
||||
relation_id = body.get('relationIds', None)
|
||||
|
|
@ -204,4 +238,19 @@ class SystemConfigViewSet(CustomModelViewSet):
|
|||
if queryset is None:
|
||||
return ErrorResponse(msg="未获取到关联信息")
|
||||
serializer = SystemConfigChinldernSerializer(queryset.parent)
|
||||
return DetailResponse(msg="查询成功",data=serializer.data)
|
||||
return DetailResponse(msg="查询成功", data=serializer.data)
|
||||
|
||||
|
||||
class InitSettingsViewSet(APIView):
|
||||
"""
|
||||
获取初始化配置
|
||||
"""
|
||||
authentication_classes = []
|
||||
permission_classes = []
|
||||
|
||||
def get(self, request):
|
||||
data = dispatch.get_system_config()
|
||||
if not data:
|
||||
dispatch.refresh_system_config()
|
||||
data = dispatch.get_system_config()
|
||||
return DetailResponse(data=data)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
@author: 猿小天
|
||||
@contact: QQ:1638245306
|
||||
@Created on: 2021/6/3 003 0:30
|
||||
@Remark: 用户管理
|
||||
"""
|
||||
import hashlib
|
||||
|
||||
from django.contrib.auth.hashers import make_password
|
||||
|
|
@ -13,6 +5,7 @@ from rest_framework import serializers
|
|||
from rest_framework.decorators import action
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
|
||||
from application import dispatch
|
||||
from dvadmin.system.models import Users
|
||||
from dvadmin.utils.json_response import ErrorResponse, DetailResponse
|
||||
from dvadmin.utils.serializers import CustomModelSerializer
|
||||
|
|
@ -28,9 +21,26 @@ class UserSerializer(CustomModelSerializer):
|
|||
class Meta:
|
||||
model = Users
|
||||
read_only_fields = ["id"]
|
||||
exclude = ['password']
|
||||
exclude = ["password"]
|
||||
extra_kwargs = {
|
||||
'post': {'required': False},
|
||||
"post": {"required": False},
|
||||
}
|
||||
|
||||
|
||||
class UsersInitSerializer(CustomModelSerializer):
|
||||
"""
|
||||
初始化获取数信息(用于生成初始化json文件)
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = Users
|
||||
fields = ["username", "email", 'mobile', 'avatar', "name", 'gender', 'user_type', "dept", 'user_type',
|
||||
'first_name', 'last_name', 'email', 'is_staff', 'is_active', 'creator', 'dept_belong_id',
|
||||
'password', 'last_login', 'is_superuser']
|
||||
read_only_fields = ['id']
|
||||
extra_kwargs = {
|
||||
'creator': {'write_only': True},
|
||||
'dept_belong_id': {'write_only': True}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -38,14 +48,31 @@ class UserCreateSerializer(CustomModelSerializer):
|
|||
"""
|
||||
用户新增-序列化器
|
||||
"""
|
||||
username = serializers.CharField(max_length=50,
|
||||
validators=[CustomUniqueValidator(queryset=Users.objects.all(), message="账号必须唯一")])
|
||||
password = serializers.CharField(required=False, default=make_password(
|
||||
hashlib.md5('admin123456'.encode(encoding='UTF-8')).hexdigest()))
|
||||
|
||||
username = serializers.CharField(
|
||||
max_length=50,
|
||||
validators=[
|
||||
CustomUniqueValidator(queryset=Users.objects.all(), message="账号必须唯一")
|
||||
],
|
||||
)
|
||||
password = serializers.CharField(
|
||||
required=False,
|
||||
)
|
||||
|
||||
def validate_password(self, value):
|
||||
"""
|
||||
对密码进行验证
|
||||
"""
|
||||
password = self.initial_data.get("password")
|
||||
if password:
|
||||
return make_password(value)
|
||||
return value
|
||||
|
||||
def save(self, **kwargs):
|
||||
data = super().save(**kwargs)
|
||||
data.post.set(self.initial_data.get('post', []))
|
||||
data.dept_belong_id = data.dept_id
|
||||
data.save()
|
||||
data.post.set(self.initial_data.get("post", []))
|
||||
return data
|
||||
|
||||
class Meta:
|
||||
|
|
@ -53,7 +80,7 @@ class UserCreateSerializer(CustomModelSerializer):
|
|||
fields = "__all__"
|
||||
read_only_fields = ["id"]
|
||||
extra_kwargs = {
|
||||
'post': {'required': False},
|
||||
"post": {"required": False},
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -61,21 +88,34 @@ class UserUpdateSerializer(CustomModelSerializer):
|
|||
"""
|
||||
用户修改-序列化器
|
||||
"""
|
||||
username = serializers.CharField(max_length=50,
|
||||
validators=[CustomUniqueValidator(queryset=Users.objects.all(), message="账号必须唯一")])
|
||||
password = serializers.CharField(required=False, allow_blank=True)
|
||||
|
||||
username = serializers.CharField(
|
||||
max_length=50,
|
||||
validators=[
|
||||
CustomUniqueValidator(queryset=Users.objects.all(), message="账号必须唯一")
|
||||
],
|
||||
)
|
||||
# password = serializers.CharField(required=False, allow_blank=True)
|
||||
mobile = serializers.CharField(
|
||||
max_length=50,
|
||||
validators=[
|
||||
CustomUniqueValidator(queryset=Users.objects.all(), message="手机号必须唯一")
|
||||
],
|
||||
)
|
||||
|
||||
def save(self, **kwargs):
|
||||
data = super().save(**kwargs)
|
||||
data.post.set(self.initial_data.get('post', []))
|
||||
data.dept_belong_id = data.dept_id
|
||||
data.save()
|
||||
data.post.set(self.initial_data.get("post", []))
|
||||
return data
|
||||
|
||||
class Meta:
|
||||
model = Users
|
||||
read_only_fields = ["id"]
|
||||
read_only_fields = ["id", "password"]
|
||||
fields = "__all__"
|
||||
extra_kwargs = {
|
||||
'post': {'required': False, 'read_only': True},
|
||||
"post": {"required": False, "read_only": True},
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -83,22 +123,35 @@ class ExportUserProfileSerializer(CustomModelSerializer):
|
|||
"""
|
||||
用户导出 序列化器
|
||||
"""
|
||||
last_login = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False, read_only=True)
|
||||
dept__deptName = serializers.CharField(source='dept.deptName', default='')
|
||||
dept__owner = serializers.CharField(source='dept.owner', default='')
|
||||
gender = serializers.CharField(source='get_gender_display', read_only=True)
|
||||
|
||||
last_login = serializers.DateTimeField(
|
||||
format="%Y-%m-%d %H:%M:%S", required=False, read_only=True
|
||||
)
|
||||
dept__deptName = serializers.CharField(source="dept.deptName", default="")
|
||||
dept__owner = serializers.CharField(source="dept.owner", default="")
|
||||
gender = serializers.CharField(source="get_gender_display", read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Users
|
||||
fields = ('username', 'name', 'email', 'mobile', 'gender', 'is_active', 'last_login', 'dept__deptName',
|
||||
'dept__owner')
|
||||
fields = (
|
||||
"username",
|
||||
"name",
|
||||
"email",
|
||||
"mobile",
|
||||
"gender",
|
||||
"is_active",
|
||||
"last_login",
|
||||
"dept__deptName",
|
||||
"dept__owner",
|
||||
)
|
||||
|
||||
|
||||
class UserProfileImportSerializer(CustomModelSerializer):
|
||||
|
||||
def save(self, **kwargs):
|
||||
data = super().save(**kwargs)
|
||||
password = hashlib.new('md5', str(self.initial_data.get('password', '')).encode(encoding='UTF-8')).hexdigest()
|
||||
password = hashlib.new(
|
||||
"md5", str(self.initial_data.get("password", "")).encode(encoding="UTF-8")
|
||||
).hexdigest()
|
||||
data.set_password(password)
|
||||
data.save()
|
||||
return data
|
||||
|
|
@ -106,15 +159,22 @@ class UserProfileImportSerializer(CustomModelSerializer):
|
|||
def run_validation(self, data={}):
|
||||
# 把excel 数据进行格式转换
|
||||
if type(data) is dict:
|
||||
data['role'] = str(data['role']).split(',')
|
||||
data['dept_id'] = str(data['dept']).split(',')
|
||||
data['gender'] = {'男': '1', '女': '0', '未知': '2'}.get(data['gender'])
|
||||
data['is_active'] = {'启用': True, '禁用': False}.get(data['is_active'])
|
||||
data["role"] = str(data["role"]).split(",")
|
||||
data["dept_id"] = str(data["dept"]).split(",")
|
||||
data["gender"] = {"男": "1", "女": "0", "未知": "2"}.get(data["gender"])
|
||||
data["is_active"] = {"启用": True, "禁用": False}.get(data["is_active"])
|
||||
return super().run_validation(data)
|
||||
|
||||
class Meta:
|
||||
model = Users
|
||||
exclude = ('password', 'post', 'user_permissions', 'groups', 'is_superuser', 'date_joined')
|
||||
exclude = (
|
||||
"password",
|
||||
"post",
|
||||
"user_permissions",
|
||||
"groups",
|
||||
"is_superuser",
|
||||
"date_joined",
|
||||
)
|
||||
|
||||
|
||||
class UserViewSet(CustomModelViewSet):
|
||||
|
|
@ -126,29 +186,49 @@ class UserViewSet(CustomModelViewSet):
|
|||
retrieve:单例
|
||||
destroy:删除
|
||||
"""
|
||||
|
||||
queryset = Users.objects.exclude(is_superuser=1).all()
|
||||
serializer_class = UserSerializer
|
||||
create_serializer_class = UserCreateSerializer
|
||||
update_serializer_class = UserUpdateSerializer
|
||||
filter_fields = ['name', 'username', 'gender', 'is_active', 'dept', 'user_type']
|
||||
# filter_fields = {
|
||||
# 'name': ['icontains'],
|
||||
# 'username': ['icontains'],
|
||||
# 'gender': ['icontains'],
|
||||
# 'is_active': ['icontains'],
|
||||
# 'dept': ['exact'],
|
||||
# }
|
||||
search_fields = ['username', 'name', 'gender', 'dept__name', 'role__name']
|
||||
# filter_fields = ["name", "username", "gender", "is_active", "dept", "user_type"]
|
||||
filter_fields = {
|
||||
"name": ["icontains"],
|
||||
"username": ["exact"],
|
||||
"gender": ["icontains"],
|
||||
"is_active": ["icontains"],
|
||||
"dept": ["exact"],
|
||||
"user_type": ["exact"],
|
||||
}
|
||||
search_fields = ["username", "name", "gender", "dept__name", "role__name"]
|
||||
# 导出
|
||||
export_field_label = ['用户账号', '用户名称', '用户邮箱', '手机号码', '用户性别', '帐号状态', '最后登录时间', '部门名称', '部门负责人']
|
||||
export_field_label = [
|
||||
"用户账号",
|
||||
"用户名称",
|
||||
"用户邮箱",
|
||||
"手机号码",
|
||||
"用户性别",
|
||||
"帐号状态",
|
||||
"最后登录时间",
|
||||
"部门名称",
|
||||
"部门负责人",
|
||||
]
|
||||
export_serializer_class = ExportUserProfileSerializer
|
||||
# 导入
|
||||
import_serializer_class = UserProfileImportSerializer
|
||||
import_field_dict = {'username': '登录账号', 'name': '用户名称', 'email': '用户邮箱', 'mobile': '手机号码',
|
||||
'gender': '用户性别(男/女/未知)',
|
||||
'is_active': '帐号状态(启用/禁用)', 'password': '登录密码', 'dept': '部门ID', 'role': '角色ID'}
|
||||
import_field_dict = {
|
||||
"username": "登录账号",
|
||||
"name": "用户名称",
|
||||
"email": "用户邮箱",
|
||||
"mobile": "手机号码",
|
||||
"gender": "用户性别(男/女/未知)",
|
||||
"is_active": "帐号状态(启用/禁用)",
|
||||
"password": "登录密码",
|
||||
"dept": "部门ID",
|
||||
"role": "角色ID",
|
||||
}
|
||||
|
||||
@action(methods=['GET'], detail=True, permission_classes=[IsAuthenticated])
|
||||
@action(methods=["GET"], detail=True, permission_classes=[IsAuthenticated])
|
||||
def user_info(self, request):
|
||||
"""获取当前用户信息"""
|
||||
user = request.user
|
||||
|
|
@ -157,25 +237,25 @@ class UserViewSet(CustomModelViewSet):
|
|||
"mobile": user.mobile,
|
||||
"gender": user.gender,
|
||||
"email": user.email,
|
||||
'avatar':user.avatar
|
||||
"avatar": user.avatar,
|
||||
}
|
||||
return DetailResponse(data=result, msg="获取成功")
|
||||
|
||||
@action(methods=['PUT'], detail=True, permission_classes=[IsAuthenticated])
|
||||
@action(methods=["PUT"], detail=True, permission_classes=[IsAuthenticated])
|
||||
def update_user_info(self, request):
|
||||
"""修改当前用户信息"""
|
||||
user = request.user
|
||||
Users.objects.filter(id=user.id).update(**request.data)
|
||||
return DetailResponse(data=None, msg="修改成功")
|
||||
|
||||
@action(methods=['PUT'], detail=True, permission_classes=[IsAuthenticated])
|
||||
@action(methods=["PUT"], detail=True, permission_classes=[IsAuthenticated])
|
||||
def change_password(self, request, *args, **kwargs):
|
||||
"""密码修改"""
|
||||
instance = Users.objects.filter(id=kwargs.get('pk')).first()
|
||||
instance = Users.objects.filter(id=kwargs.get("pk")).first()
|
||||
data = request.data
|
||||
old_pwd = data.get('oldPassword')
|
||||
new_pwd = data.get('newPassword')
|
||||
new_pwd2 = data.get('newPassword2')
|
||||
old_pwd = data.get("oldPassword")
|
||||
new_pwd = data.get("newPassword")
|
||||
new_pwd2 = data.get("newPassword2")
|
||||
if instance:
|
||||
if new_pwd != new_pwd2:
|
||||
return ErrorResponse(msg="两次密码不匹配")
|
||||
|
|
@ -188,15 +268,26 @@ class UserViewSet(CustomModelViewSet):
|
|||
else:
|
||||
return ErrorResponse(msg="未获取到用户")
|
||||
|
||||
@action(methods=['PUT'], detail=True)
|
||||
@action(methods=["PUT"], detail=True, permission_classes=[IsAuthenticated])
|
||||
def reset_to_default_password(self, request, *args, **kwargs):
|
||||
"""恢复默认密码"""
|
||||
instance = Users.objects.filter(id=kwargs.get("pk")).first()
|
||||
if instance:
|
||||
instance.set_password(dispatch.get_system_config_values("base.default_password"))
|
||||
instance.save()
|
||||
return DetailResponse(data=None, msg="密码重置成功")
|
||||
else:
|
||||
return ErrorResponse(msg="未获取到用户")
|
||||
|
||||
@action(methods=["PUT"], detail=True)
|
||||
def reset_password(self, request, pk):
|
||||
"""
|
||||
密码重置
|
||||
"""
|
||||
instance = Users.objects.filter(id=pk).first()
|
||||
data = request.data
|
||||
new_pwd = data.get('newPassword')
|
||||
new_pwd2 = data.get('newPassword2')
|
||||
new_pwd = data.get("newPassword")
|
||||
new_pwd2 = data.get("newPassword2")
|
||||
if instance:
|
||||
if new_pwd != new_pwd2:
|
||||
return ErrorResponse(msg="两次密码不匹配")
|
||||
|
|
|
|||
|
|
@ -1,5 +1,12 @@
|
|||
# 初始化基类
|
||||
import json
|
||||
import os
|
||||
|
||||
from django.apps import apps
|
||||
from rest_framework import request
|
||||
|
||||
from application import settings
|
||||
from dvadmin.system.models import Users
|
||||
|
||||
|
||||
class CoreInitialize:
|
||||
|
|
@ -8,14 +15,43 @@ class CoreInitialize:
|
|||
"""
|
||||
creator_id = None
|
||||
reset = False
|
||||
request = request
|
||||
file_path = None
|
||||
|
||||
def __init__(self, reset=False, creator_id=None):
|
||||
def __init__(self, reset=False, creator_id=None, app=None):
|
||||
"""
|
||||
reset: 是否重置初始化数据
|
||||
creator_id: 创建人id
|
||||
"""
|
||||
self.reset = reset or self.reset
|
||||
self.creator_id = creator_id or self.creator_id
|
||||
self.app = app or ''
|
||||
self.request.user = Users.objects.order_by('create_datetime').first()
|
||||
|
||||
def init_base(self, Serializer, unique_fields=None):
|
||||
model = Serializer.Meta.model
|
||||
path_file = os.path.join(apps.get_app_config(self.app.split('.')[-1]).path, 'fixtures',
|
||||
f'init_{Serializer.Meta.model._meta.model_name}.json')
|
||||
if not os.path.isfile(path_file):
|
||||
return
|
||||
with open(path_file,encoding="utf-8") as f:
|
||||
for data in json.load(f):
|
||||
filter_data = {}
|
||||
# 配置过滤条件,如果有唯一标识字段则使用唯一标识字段,否则使用全部字段
|
||||
if unique_fields:
|
||||
for field in unique_fields:
|
||||
if field in data:
|
||||
filter_data[field] = data[field]
|
||||
else:
|
||||
for key, value in data.items():
|
||||
if isinstance(value, list) or value == None or value == '':
|
||||
continue
|
||||
filter_data[key] = value
|
||||
instance = model.objects.filter(**filter_data).first()
|
||||
serializer = Serializer(instance, data=data, request=self.request)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
print(f"[{self.app}][{model._meta.model_name}]初始化完成")
|
||||
|
||||
def save(self, obj, data: list, name=None, no_reset=False):
|
||||
name = name or obj._meta.verbose_name
|
||||
|
|
@ -31,7 +67,7 @@ class CoreInitialize:
|
|||
new_data = {}
|
||||
for key, value in ele.items():
|
||||
# 判断传的 value 为 list 的多对多进行抽离,使用set 进行更新
|
||||
if isinstance(value, list):
|
||||
if isinstance(value, list) and value and isinstance(value[0], int):
|
||||
m2m_dict[key] = value
|
||||
else:
|
||||
new_data[key] = value
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@
|
|||
@Remark: 自定义过滤器
|
||||
"""
|
||||
import operator
|
||||
from collections import OrderedDict
|
||||
import re
|
||||
from collections import OrderedDict
|
||||
from functools import reduce
|
||||
|
||||
import six
|
||||
|
|
@ -32,13 +32,13 @@ def get_dept(dept_id: int, dept_all_list=None, dept_list=None):
|
|||
:return:
|
||||
"""
|
||||
if not dept_all_list:
|
||||
dept_all_list = Dept.objects.all().values('id', 'parent')
|
||||
dept_all_list = Dept.objects.all().values("id", "parent")
|
||||
if dept_list is None:
|
||||
dept_list = [dept_id]
|
||||
for ele in dept_all_list:
|
||||
if ele.get('parent') == dept_id:
|
||||
dept_list.append(ele.get('id'))
|
||||
get_dept(ele.get('id'), dept_all_list, dept_list)
|
||||
if ele.get("parent") == dept_id:
|
||||
dept_list.append(ele.get("id"))
|
||||
get_dept(ele.get("id"), dept_all_list, dept_list)
|
||||
return list(set(dept_list))
|
||||
|
||||
|
||||
|
|
@ -54,20 +54,26 @@ class DataLevelPermissionsFilter(BaseFilterBackend):
|
|||
4. 只为仅本人数据权限时只返回过滤本人数据,并且部门为自己本部门(考虑到用户会变部门,只能看当前用户所在的部门数据)
|
||||
5. 自定数据权限 获取部门,根据部门过滤
|
||||
"""
|
||||
|
||||
def filter_queryset(self, request, queryset, view):
|
||||
"""
|
||||
接口白名单是否认证数据权限
|
||||
"""
|
||||
api = request.path # 当前请求接口
|
||||
method = request.method # 当前请求方法
|
||||
methodList = ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']
|
||||
methodList = ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
|
||||
method = methodList.index(method)
|
||||
# ***接口白名单***
|
||||
api_white_list = ApiWhiteList.objects.filter(enable_datasource=False).values(permission__api=F('url'),
|
||||
permission__method=F('method'))
|
||||
api_white_list = ApiWhiteList.objects.filter(enable_datasource=False).values(
|
||||
permission__api=F("url"), permission__method=F("method")
|
||||
)
|
||||
api_white_list = [
|
||||
str(item.get('permission__api').replace('{id}', '.*?')) + ":" + str(item.get('permission__method')) for item
|
||||
in api_white_list if item.get('permission__api')]
|
||||
str(item.get("permission__api").replace("{id}", ".*?"))
|
||||
+ ":"
|
||||
+ str(item.get("permission__method"))
|
||||
for item in api_white_list
|
||||
if item.get("permission__api")
|
||||
]
|
||||
for item in api_white_list:
|
||||
new_api = api + ":" + str(method)
|
||||
matchObj = re.match(item, new_api, re.M | re.I)
|
||||
|
|
@ -81,16 +87,16 @@ class DataLevelPermissionsFilter(BaseFilterBackend):
|
|||
"""
|
||||
if request.user.is_superuser == 0:
|
||||
# 0. 获取用户的部门id,没有部门则返回空
|
||||
user_dept_id = getattr(request.user, 'dept_id', None)
|
||||
user_dept_id = getattr(request.user, "dept_id", None)
|
||||
if not user_dept_id:
|
||||
return queryset.none()
|
||||
|
||||
# 1. 判断过滤的数据是否有创建人所在部门 "dept_belong_id" 字段
|
||||
if not getattr(queryset.model, 'dept_belong_id', None):
|
||||
if not getattr(queryset.model, "dept_belong_id", None):
|
||||
return queryset
|
||||
|
||||
# 2. 如果用户没有关联角色则返回本部门数据
|
||||
if not hasattr(request.user, 'role'):
|
||||
if not hasattr(request.user, "role"):
|
||||
return queryset.filter(dept_belong_id=user_dept_id)
|
||||
|
||||
# 3. 根据所有角色 获取所有权限范围
|
||||
|
|
@ -99,28 +105,41 @@ class DataLevelPermissionsFilter(BaseFilterBackend):
|
|||
# (2, "本部门数据权限"),
|
||||
# (3, "全部数据权限"),
|
||||
# (4, "自定数据权限")
|
||||
role_list = request.user.role.filter(status=1).values('admin', 'data_range')
|
||||
dataScope_list = [] # 权限范围列表
|
||||
role_list = request.user.role.filter(status=1).values("admin", "data_range")
|
||||
dataScope_list = [] # 权限范围列表
|
||||
for ele in role_list:
|
||||
# 判断用户是否为超级管理员角色/如果拥有[全部数据权限]则返回所有数据
|
||||
if 3 == ele.get('data_range') or ele.get('admin') == True:
|
||||
if 3 == ele.get("data_range") or ele.get("admin") == True:
|
||||
return queryset
|
||||
dataScope_list.append(ele.get('data_range'))
|
||||
dataScope_list.append(ele.get("data_range"))
|
||||
dataScope_list = list(set(dataScope_list))
|
||||
|
||||
# 4. 只为仅本人数据权限时只返回过滤本人数据,并且部门为自己本部门(考虑到用户会变部门,只能看当前用户所在的部门数据)
|
||||
if 0 in dataScope_list:
|
||||
return queryset.filter(creator=request.user, dept_belong_id=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 == 4:
|
||||
dept_list.extend(request.user.role.filter(status=1).values_list('dept__id', flat=True))
|
||||
dept_list.extend(
|
||||
request.user.role.filter(status=1).values_list(
|
||||
"dept__id", flat=True
|
||||
)
|
||||
)
|
||||
elif ele == 2:
|
||||
dept_list.append(user_dept_id)
|
||||
elif ele == 1:
|
||||
dept_list.extend(get_dept(user_dept_id, ))
|
||||
dept_list.append(user_dept_id)
|
||||
dept_list.extend(
|
||||
get_dept(
|
||||
user_dept_id,
|
||||
)
|
||||
)
|
||||
if queryset.model._meta.model_name == 'dept':
|
||||
return queryset.filter(id__in=list(set(dept_list)))
|
||||
return queryset.filter(dept_belong_id__in=list(set(dept_list)))
|
||||
else:
|
||||
return queryset
|
||||
|
|
@ -128,11 +147,11 @@ class DataLevelPermissionsFilter(BaseFilterBackend):
|
|||
|
||||
class CustomDjangoFilterBackend(DjangoFilterBackend):
|
||||
lookup_prefixes = {
|
||||
'^': 'istartswith',
|
||||
'=': 'iexact',
|
||||
'@': 'search',
|
||||
'$': 'iregex',
|
||||
'~': 'icontains'
|
||||
"^": "istartswith",
|
||||
"=": "iexact",
|
||||
"@": "search",
|
||||
"$": "iregex",
|
||||
"~": "icontains",
|
||||
}
|
||||
|
||||
def construct_search(self, field_name):
|
||||
|
|
@ -140,12 +159,14 @@ class CustomDjangoFilterBackend(DjangoFilterBackend):
|
|||
if lookup:
|
||||
field_name = field_name[1:]
|
||||
else:
|
||||
lookup = 'icontains'
|
||||
lookup = "icontains"
|
||||
return LOOKUP_SEP.join([field_name, lookup])
|
||||
|
||||
def find_filter_lookups(self, orm_lookups, search_term_key):
|
||||
for lookup in orm_lookups:
|
||||
if lookup.find(search_term_key) >= 0:
|
||||
# if lookup.find(search_term_key) >= 0:
|
||||
# 修复条件搜索错误 bug
|
||||
if lookup == search_term_key:
|
||||
return lookup
|
||||
return None
|
||||
|
||||
|
|
@ -153,39 +174,43 @@ class CustomDjangoFilterBackend(DjangoFilterBackend):
|
|||
"""
|
||||
Return the `FilterSet` class used to filter the queryset.
|
||||
"""
|
||||
filterset_class = getattr(view, 'filterset_class', None)
|
||||
filterset_fields = getattr(view, 'filterset_fields', None)
|
||||
filterset_class = getattr(view, "filterset_class", None)
|
||||
filterset_fields = getattr(view, "filterset_fields", None)
|
||||
|
||||
# TODO: remove assertion in 2.1
|
||||
if filterset_class is None and hasattr(view, 'filter_class'):
|
||||
if filterset_class is None and hasattr(view, "filter_class"):
|
||||
utils.deprecate(
|
||||
"`%s.filter_class` attribute should be renamed `filterset_class`."
|
||||
% view.__class__.__name__)
|
||||
filterset_class = getattr(view, 'filter_class', None)
|
||||
% view.__class__.__name__
|
||||
)
|
||||
filterset_class = getattr(view, "filter_class", None)
|
||||
|
||||
# TODO: remove assertion in 2.1
|
||||
if filterset_fields is None and hasattr(view, 'filter_fields'):
|
||||
if filterset_fields is None and hasattr(view, "filter_fields"):
|
||||
utils.deprecate(
|
||||
"`%s.filter_fields` attribute should be renamed `filterset_fields`."
|
||||
% view.__class__.__name__)
|
||||
filterset_fields = getattr(view, 'filter_fields', None)
|
||||
% view.__class__.__name__
|
||||
)
|
||||
filterset_fields = getattr(view, "filter_fields", None)
|
||||
|
||||
if filterset_class:
|
||||
filterset_model = filterset_class._meta.model
|
||||
|
||||
# FilterSets do not need to specify a Meta class
|
||||
if filterset_model and queryset is not None:
|
||||
assert issubclass(queryset.model, filterset_model), \
|
||||
'FilterSet model %s does not match queryset model %s' % \
|
||||
(filterset_model, queryset.model)
|
||||
assert issubclass(
|
||||
queryset.model, filterset_model
|
||||
), "FilterSet model %s does not match queryset model %s" % (
|
||||
filterset_model,
|
||||
queryset.model,
|
||||
)
|
||||
|
||||
return filterset_class
|
||||
|
||||
if filterset_fields and queryset is not None:
|
||||
MetaBase = getattr(self.filterset_base, 'Meta', object)
|
||||
MetaBase = getattr(self.filterset_base, "Meta", object)
|
||||
|
||||
class AutoFilterSet(self.filterset_base):
|
||||
|
||||
@classmethod
|
||||
def get_filters(cls):
|
||||
"""
|
||||
|
|
@ -206,6 +231,7 @@ class CustomDjangoFilterBackend(DjangoFilterBackend):
|
|||
field = get_model_field(cls._meta.model, field_name)
|
||||
from django.db import models
|
||||
from timezone_field import TimeZoneField
|
||||
|
||||
# 不进行 过滤的model 类
|
||||
if isinstance(field, (models.JSONField, TimeZoneField)):
|
||||
continue
|
||||
|
|
@ -222,16 +248,20 @@ class CustomDjangoFilterBackend(DjangoFilterBackend):
|
|||
continue
|
||||
|
||||
if field is not None:
|
||||
filters[filter_name] = cls.filter_for_field(field, field_name, lookup_expr)
|
||||
filters[filter_name] = cls.filter_for_field(
|
||||
field, field_name, lookup_expr
|
||||
)
|
||||
|
||||
# Allow Meta.fields to contain declared filters *only* when a list/tuple
|
||||
if isinstance(cls._meta.fields, (list, tuple)):
|
||||
undefined = [f for f in undefined if f not in cls.declared_filters]
|
||||
undefined = [
|
||||
f for f in undefined if f not in cls.declared_filters
|
||||
]
|
||||
|
||||
if undefined:
|
||||
raise TypeError(
|
||||
"'Meta.fields' must not contain non-model field names: %s"
|
||||
% ', '.join(undefined)
|
||||
% ", ".join(undefined)
|
||||
)
|
||||
|
||||
# Add in declared filters. This is necessary since we don't enforce adding
|
||||
|
|
@ -251,14 +281,21 @@ class CustomDjangoFilterBackend(DjangoFilterBackend):
|
|||
filterset = self.get_filterset(request, queryset, view)
|
||||
if filterset is None:
|
||||
return queryset
|
||||
if filterset.__class__.__name__ == 'AutoFilterSet':
|
||||
if filterset.__class__.__name__ == "AutoFilterSet":
|
||||
queryset = filterset.queryset
|
||||
orm_lookups = []
|
||||
for search_field in filterset.filters:
|
||||
if isinstance(filterset.filters[search_field], CharFilter):
|
||||
orm_lookups.append(self.construct_search(six.text_type(search_field)))
|
||||
orm_lookups.append(
|
||||
self.construct_search(six.text_type(search_field))
|
||||
)
|
||||
else:
|
||||
orm_lookups.append(search_field)
|
||||
orm_lookups = (
|
||||
orm_lookups
|
||||
if isinstance(filterset.__class__._meta.fields, (list, tuple))
|
||||
else filterset.filters.keys()
|
||||
)
|
||||
conditions = []
|
||||
queries = []
|
||||
for search_term_key in filterset.data.keys():
|
||||
|
|
|
|||
|
|
@ -15,8 +15,7 @@ def import_to_data(file_url, field_data):
|
|||
:return:
|
||||
"""
|
||||
# 读取excel 文件
|
||||
file_path = os.path.join(settings.MEDIA_ROOT, file_url)
|
||||
file_path_dir = os.path.join(settings.BASE_DIR, file_path)
|
||||
file_path_dir = os.path.join(settings.BASE_DIR, file_url)
|
||||
workbook = openpyxl.load_workbook(file_path_dir)
|
||||
table = workbook[workbook.sheetnames[0]]
|
||||
# 创建一个空列表,存储Excel的数据
|
||||
|
|
|
|||
|
|
@ -190,12 +190,15 @@ def get_ip_analysis(ip):
|
|||
}
|
||||
if ip != 'unknown' and ip:
|
||||
if getattr(settings, 'ENABLE_LOGIN_ANALYSIS_LOG', True):
|
||||
res = requests.post(url='https://ip.django-vue-admin.com/ip/analysis', data=json.dumps({"ip": ip}))
|
||||
if res.status_code == 200:
|
||||
res_data = res.json()
|
||||
if res_data.get('code') == 0:
|
||||
data = res_data.get('data')
|
||||
return data
|
||||
try:
|
||||
res = requests.get(url='https://ip.django-vue-admin.com/ip/analysis', params={"ip": ip}, timeout=5)
|
||||
if res.status_code == 200:
|
||||
res_data = res.json()
|
||||
if res_data.get('code') == 0:
|
||||
data = res_data.get('data')
|
||||
return data
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return data
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -17,37 +17,46 @@ from dvadmin.system.models import Users
|
|||
from django_restql.mixins import DynamicFieldsMixin
|
||||
|
||||
|
||||
|
||||
class CustomModelSerializer(DynamicFieldsMixin,ModelSerializer):
|
||||
class CustomModelSerializer(DynamicFieldsMixin, ModelSerializer):
|
||||
"""
|
||||
增强DRF的ModelSerializer,可自动更新模型的审计字段记录
|
||||
(1)self.request能获取到rest_framework.request.Request对象
|
||||
"""
|
||||
|
||||
# 修改人的审计字段名称, 默认modifier, 继承使用时可自定义覆盖
|
||||
modifier_field_id = 'modifier'
|
||||
modifier_field_id = "modifier"
|
||||
modifier_name = serializers.SerializerMethodField(read_only=True)
|
||||
|
||||
def get_modifier_name(self, instance):
|
||||
if not hasattr(instance, 'modifier'):
|
||||
if not hasattr(instance, "modifier"):
|
||||
return None
|
||||
queryset = Users.objects.filter(username=instance.modifier).values_list('name', flat=True).first()
|
||||
queryset = (
|
||||
Users.objects.filter(id=instance.modifier)
|
||||
.values_list("name", flat=True)
|
||||
.first()
|
||||
)
|
||||
if queryset:
|
||||
return queryset
|
||||
return None
|
||||
|
||||
# 创建人的审计字段名称, 默认creator, 继承使用时可自定义覆盖
|
||||
creator_field_id = 'creator'
|
||||
creator_name = serializers.SlugRelatedField(slug_field="name", source="creator", read_only=True)
|
||||
creator_field_id = "creator"
|
||||
creator_name = serializers.SlugRelatedField(
|
||||
slug_field="name", source="creator", read_only=True
|
||||
)
|
||||
# 数据所属部门字段
|
||||
dept_belong_id_field_name = 'dept_belong_id'
|
||||
dept_belong_id_field_name = "dept_belong_id"
|
||||
# 添加默认时间返回格式
|
||||
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)
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
def __init__(self, instance=None, data=empty, request=None, **kwargs):
|
||||
super().__init__(instance, data, **kwargs)
|
||||
self.request: Request = request or self.context.get('request', None)
|
||||
self.request: Request = request or self.context.get("request", None)
|
||||
|
||||
def save(self, **kwargs):
|
||||
return super().save(**kwargs)
|
||||
|
|
@ -60,30 +69,36 @@ class CustomModelSerializer(DynamicFieldsMixin,ModelSerializer):
|
|||
if self.creator_field_id in self.fields.fields:
|
||||
validated_data[self.creator_field_id] = self.request.user
|
||||
|
||||
if self.dept_belong_id_field_name in self.fields.fields and validated_data.get(
|
||||
self.dept_belong_id_field_name, None) is None:
|
||||
validated_data[self.dept_belong_id_field_name] = getattr(self.request.user, 'dept_id', None)
|
||||
if (
|
||||
self.dept_belong_id_field_name in self.fields.fields
|
||||
and validated_data.get(self.dept_belong_id_field_name, None) is None
|
||||
):
|
||||
validated_data[self.dept_belong_id_field_name] = getattr(
|
||||
self.request.user, "dept_id", None
|
||||
)
|
||||
return super().create(validated_data)
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
if self.request:
|
||||
if hasattr(self.instance, self.modifier_field_id):
|
||||
setattr(self.instance, self.modifier_field_id, self.get_request_user_id())
|
||||
setattr(
|
||||
self.instance, self.modifier_field_id, self.get_request_user_id()
|
||||
)
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
def get_request_username(self):
|
||||
if getattr(self.request, 'user', None):
|
||||
return getattr(self.request.user, 'username', None)
|
||||
if getattr(self.request, "user", None):
|
||||
return getattr(self.request.user, "username", None)
|
||||
return None
|
||||
|
||||
def get_request_name(self):
|
||||
if getattr(self.request, 'user', None):
|
||||
return getattr(self.request.user, 'name', None)
|
||||
if getattr(self.request, "user", None):
|
||||
return getattr(self.request.user, "name", None)
|
||||
return None
|
||||
|
||||
def get_request_user_id(self):
|
||||
if getattr(self.request, 'user', None):
|
||||
return getattr(self.request.user, 'id', None)
|
||||
if getattr(self.request, "user", None):
|
||||
return getattr(self.request.user, "id", None)
|
||||
return None
|
||||
|
||||
# @cached_property
|
||||
|
|
@ -132,4 +147,3 @@ class CustomModelSerializer(DynamicFieldsMixin,ModelSerializer):
|
|||
# fields.pop(field, None)
|
||||
#
|
||||
# return fields
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
version: "3"
|
||||
services:
|
||||
DVAdmin-web:
|
||||
container_name: DVAdmin-web
|
||||
dvadmin-web:
|
||||
container_name: dvadmin-web
|
||||
ports:
|
||||
- "8080:8080"
|
||||
build:
|
||||
|
|
@ -15,20 +15,20 @@ services:
|
|||
- "8080"
|
||||
networks:
|
||||
network:
|
||||
ipv4_address: 177.7.0.11
|
||||
ipv4_address: 177.8.0.11
|
||||
|
||||
DVAdmin-django:
|
||||
dvadmin-django:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./docker_env/django/Dockerfile
|
||||
container_name: DVAdmin-django
|
||||
container_name: dvadmin-django
|
||||
working_dir: /backend
|
||||
# 打开mysql 时,打开此选项
|
||||
# depends_on:
|
||||
# - DVAdmin-mysql
|
||||
# - dvadmin-mysql
|
||||
environment:
|
||||
PYTHONUNBUFFERED: 1
|
||||
DATABASE_HOST: DVAdmin-mysql
|
||||
DATABASE_HOST: dvadmin-mysql
|
||||
TZ: Asia/Shanghai
|
||||
volumes:
|
||||
- ./backend:/backend
|
||||
|
|
@ -40,11 +40,11 @@ services:
|
|||
restart: always
|
||||
networks:
|
||||
network:
|
||||
ipv4_address: 177.7.0.12
|
||||
ipv4_address: 177.8.0.12
|
||||
|
||||
# DVAdmin-mysql:
|
||||
# dvadmin-mysql:
|
||||
# image: mysql:5.7
|
||||
# container_name: DVAdmin-mysql
|
||||
# container_name: dvadmin-mysql
|
||||
# #使用该参数,container内的root拥有真正的root权限,否则,container内的root只是外部的一个普通用户权限
|
||||
# #设置为true,不然数据卷可能挂载不了,启动不起
|
||||
## privileged: true
|
||||
|
|
@ -66,22 +66,22 @@ services:
|
|||
# - "./docker_env/mysql/logs:/logs"
|
||||
# networks:
|
||||
# network:
|
||||
# ipv4_address: 177.7.0.13
|
||||
# ipv4_address: 177.8.0.13
|
||||
|
||||
|
||||
# 如果使用celery 插件,请自行打开此注释
|
||||
# DVAdmin-celery:
|
||||
# dvadmin-celery:
|
||||
# build:
|
||||
# context: .
|
||||
# dockerfile: ./docker_env/celery/Dockerfile
|
||||
# # image: django:2.2
|
||||
# container_name: DVAdmin-celery
|
||||
# container_name: dvadmin-celery
|
||||
# working_dir: /backend
|
||||
# depends_on:
|
||||
# - DVAdmin-mysql
|
||||
# - dvadmin-mysql
|
||||
# environment:
|
||||
# PYTHONUNBUFFERED: 1
|
||||
# DATABASE_HOST: DVAdmin-mysql
|
||||
# DATABASE_HOST: dvadmin-mysql
|
||||
# TZ: Asia/Shanghai
|
||||
# volumes:
|
||||
# - ./backend:/backend
|
||||
|
|
@ -89,12 +89,12 @@ services:
|
|||
# restart: always
|
||||
# networks:
|
||||
# network:
|
||||
# ipv4_address: 177.7.0.14
|
||||
# ipv4_address: 177.8.0.14
|
||||
|
||||
networks:
|
||||
network:
|
||||
ipam:
|
||||
driver: default
|
||||
config:
|
||||
- subnet: '177.7.0.0/16'
|
||||
- subnet: '177.8.0.0/16'
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ server {
|
|||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
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;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.php index.htm;
|
||||
|
|
@ -18,7 +18,7 @@ server {
|
|||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
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;
|
||||
rewrite ^/api/(.*)$ /$1 break; #重写
|
||||
proxy_pass http://177.7.0.12:8000/; # 设置代理服务器的协议和地址
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# 开发环境
|
||||
NODE_ENV=development
|
||||
# 页面 title 前缀
|
||||
VUE_APP_TITLE=DVAdmin
|
||||
VUE_APP_TITLE=企业级后台管理系统
|
||||
# 启用权限管理
|
||||
VUE_APP_PM_ENABLED = true
|
||||
# 后端接口地址及端口(域名)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ NODE_ENV=production
|
|||
# 标记当前构建方式
|
||||
VUE_APP_BUILD_MODE=PREVIEW
|
||||
# 页面 title 前缀
|
||||
VUE_APP_TITLE=DVAdmin
|
||||
VUE_APP_TITLE=企业级后台管理系统
|
||||
# 显示源码按钮
|
||||
VUE_APP_SCOURCE_LINK=FALSE
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# 测试环境
|
||||
|
||||
# 页面 title 前缀
|
||||
VUE_APP_TITLE=DVAdmin
|
||||
VUE_APP_TITLE=企业级后台管理系统
|
||||
# 启用权限管理
|
||||
VUE_APP_PM_ENABLED = true
|
||||
# 后端接口地址及端口(域名)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
"ua-parser-js": "^0.7.20",
|
||||
"vue": "^2.6.11",
|
||||
"vue-i18n": "^8.15.1",
|
||||
"vue-infinite-scroll": "^2.0.2",
|
||||
"vue-router": "^3.1.3",
|
||||
"vue-splitpane": "^1.0.6",
|
||||
"vuex": "^3.1.2",
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 225 KiB |
|
After Width: | Height: | Size: 927 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
|
@ -58,10 +58,201 @@
|
|||
text-decoration: none;
|
||||
}
|
||||
|
||||
.d2-home__loading {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
margin-bottom: 20px;
|
||||
#loader-wrapper {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 999999;
|
||||
}
|
||||
#loader {
|
||||
display: block;
|
||||
position: relative;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
margin: -75px 0 0 -75px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid transparent;
|
||||
/* COLOR 1 */
|
||||
border-top-color: #FFF;
|
||||
-webkit-animation: spin 2s linear infinite;
|
||||
/* Chrome, Opera 15+, Safari 5+ */
|
||||
-ms-animation: spin 2s linear infinite;
|
||||
/* Chrome, Opera 15+, Safari 5+ */
|
||||
-moz-animation: spin 2s linear infinite;
|
||||
/* Chrome, Opera 15+, Safari 5+ */
|
||||
-o-animation: spin 2s linear infinite;
|
||||
/* Chrome, Opera 15+, Safari 5+ */
|
||||
animation: spin 2s linear infinite;
|
||||
/* Chrome, Firefox 16+, IE 10+, Opera */
|
||||
z-index: 1001;
|
||||
}
|
||||
#loader:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 5px;
|
||||
right: 5px;
|
||||
bottom: 5px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid transparent;
|
||||
/* COLOR 2 */
|
||||
border-top-color: #FFF;
|
||||
-webkit-animation: spin 3s linear infinite;
|
||||
/* Chrome, Opera 15+, Safari 5+ */
|
||||
-moz-animation: spin 3s linear infinite;
|
||||
/* Chrome, Opera 15+, Safari 5+ */
|
||||
-o-animation: spin 3s linear infinite;
|
||||
/* Chrome, Opera 15+, Safari 5+ */
|
||||
-ms-animation: spin 3s linear infinite;
|
||||
/* Chrome, Opera 15+, Safari 5+ */
|
||||
animation: spin 3s linear infinite;
|
||||
/* Chrome, Firefox 16+, IE 10+, Opera */
|
||||
}
|
||||
#loader:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
left: 15px;
|
||||
right: 15px;
|
||||
bottom: 15px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid transparent;
|
||||
border-top-color: #FFF;
|
||||
/* COLOR 3 */
|
||||
-moz-animation: spin 1.5s linear infinite;
|
||||
/* Chrome, Opera 15+, Safari 5+ */
|
||||
-o-animation: spin 1.5s linear infinite;
|
||||
/* Chrome, Opera 15+, Safari 5+ */
|
||||
-ms-animation: spin 1.5s linear infinite;
|
||||
/* Chrome, Opera 15+, Safari 5+ */
|
||||
-webkit-animation: spin 1.5s linear infinite;
|
||||
/* Chrome, Opera 15+, Safari 5+ */
|
||||
animation: spin 1.5s linear infinite;
|
||||
/* Chrome, Firefox 16+, IE 10+, Opera */
|
||||
}
|
||||
@-webkit-keyframes spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
/* Chrome, Opera 15+, Safari 3.1+ */
|
||||
-ms-transform: rotate(0deg);
|
||||
/* IE 9 */
|
||||
transform: rotate(0deg);
|
||||
/* Firefox 16+, IE 10+, Opera */
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
/* Chrome, Opera 15+, Safari 3.1+ */
|
||||
-ms-transform: rotate(360deg);
|
||||
/* IE 9 */
|
||||
transform: rotate(360deg);
|
||||
/* Firefox 16+, IE 10+, Opera */
|
||||
}
|
||||
}
|
||||
@keyframes spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
/* Chrome, Opera 15+, Safari 3.1+ */
|
||||
-ms-transform: rotate(0deg);
|
||||
/* IE 9 */
|
||||
transform: rotate(0deg);
|
||||
/* Firefox 16+, IE 10+, Opera */
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
/* Chrome, Opera 15+, Safari 3.1+ */
|
||||
-ms-transform: rotate(360deg);
|
||||
/* IE 9 */
|
||||
transform: rotate(360deg);
|
||||
/* Firefox 16+, IE 10+, Opera */
|
||||
}
|
||||
}
|
||||
#loader-wrapper .loader-section {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 51%;
|
||||
height: 100%;
|
||||
background: #49a9ee;
|
||||
/* Old browsers */
|
||||
z-index: 1000;
|
||||
-webkit-transform: translateX(0);
|
||||
/* Chrome, Opera 15+, Safari 3.1+ */
|
||||
-ms-transform: translateX(0);
|
||||
/* IE 9 */
|
||||
transform: translateX(0);
|
||||
/* Firefox 16+, IE 10+, Opera */
|
||||
}
|
||||
#loader-wrapper .loader-section.section-left {
|
||||
left: 0;
|
||||
}
|
||||
#loader-wrapper .loader-section.section-right {
|
||||
right: 0;
|
||||
}
|
||||
/* Loaded */
|
||||
.loaded #loader-wrapper .loader-section.section-left {
|
||||
-webkit-transform: translateX(-100%);
|
||||
/* Chrome, Opera 15+, Safari 3.1+ */
|
||||
-ms-transform: translateX(-100%);
|
||||
/* IE 9 */
|
||||
transform: translateX(-100%);
|
||||
/* Firefox 16+, IE 10+, Opera */
|
||||
-webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
|
||||
transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
|
||||
}
|
||||
.loaded #loader-wrapper .loader-section.section-right {
|
||||
-webkit-transform: translateX(100%);
|
||||
/* Chrome, Opera 15+, Safari 3.1+ */
|
||||
-ms-transform: translateX(100%);
|
||||
/* IE 9 */
|
||||
transform: translateX(100%);
|
||||
/* Firefox 16+, IE 10+, Opera */
|
||||
-webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
|
||||
transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
|
||||
}
|
||||
.loaded #loader {
|
||||
opacity: 0;
|
||||
-webkit-transition: all 0.3s ease-out;
|
||||
transition: all 0.3s ease-out;
|
||||
}
|
||||
.loaded #loader-wrapper {
|
||||
visibility: hidden;
|
||||
-webkit-transform: translateY(-100%);
|
||||
/* Chrome, Opera 15+, Safari 3.1+ */
|
||||
-ms-transform: translateY(-100%);
|
||||
/* IE 9 */
|
||||
transform: translateY(-100%);
|
||||
/* Firefox 16+, IE 10+, Opera */
|
||||
-webkit-transition: all 0.3s 1s ease-out;
|
||||
transition: all 0.3s 1s ease-out;
|
||||
}
|
||||
/* JavaScript Turned Off */
|
||||
.no-js #loader-wrapper {
|
||||
display: none;
|
||||
}
|
||||
.no-js h1 {
|
||||
color: #222222;
|
||||
}
|
||||
#loader-wrapper .load_title {
|
||||
font-family: 'Open Sans';
|
||||
color: #FFF;
|
||||
font-size: 14px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
z-index: 9999999999999;
|
||||
position: absolute;
|
||||
top: 60%;
|
||||
opacity: 1;
|
||||
line-height: 30px;
|
||||
}
|
||||
#loader-wrapper .load_title span {
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
font-size: 14px;
|
||||
color: #FFF;
|
||||
opacity: 0.5;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
|
|
@ -78,15 +269,11 @@
|
|||
</strong>
|
||||
</noscript>
|
||||
<div id="app">
|
||||
<div class="d2-home">
|
||||
<div class="d2-home__main">
|
||||
<img class="d2-home__loading" src="./image/loading/loading-spin.svg" alt="loading">
|
||||
</div>
|
||||
<div class="d2-home__footer">
|
||||
<a href="https://gitee.com/liqianglog/django-vue-admin" target="_blank">
|
||||
https://gitee.com/liqianglog/django-vue-admin
|
||||
</a>
|
||||
</div>
|
||||
<div id="loader-wrapper">
|
||||
<div id="loader"></div>
|
||||
<div class="loader-section section-left"></div>
|
||||
<div class="loader-section section-right"></div>
|
||||
<div class="load_title">正在加载中,请耐心等待...</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 使用 CDN 加速的 JS 文件,配置在 vue.config.js 下 -->
|
||||
|
|
|
|||
|
|
@ -69,3 +69,65 @@
|
|||
*::-webkit-scrollbar-thumb:hover {
|
||||
background-color: #bbb;
|
||||
}
|
||||
.el-drawer__header{
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
border-radius: 4px 4px 0 0;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
/*设置抽屉样式*/
|
||||
.el-drawer__header span{
|
||||
margin: 0;
|
||||
color: rgba(0,0,0,.85);
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
line-height: 22px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.el-drawer__header .el-tag{
|
||||
background-color: #ecf5ff;
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
color: #409eff;
|
||||
border: 1px solid #d9ecff;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
white-space: nowrap;
|
||||
height: 24px;
|
||||
padding: 0 8px;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.el-drawer__close-btn{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
display: block;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
padding: 0;
|
||||
color: rgba(0,0,0,.45);
|
||||
font-weight: 700;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
line-height: 56px;
|
||||
text-align: center;
|
||||
text-transform: none;
|
||||
text-decoration: none;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
cursor: pointer;
|
||||
transition: color .3s;
|
||||
text-rendering: auto;
|
||||
}
|
||||
.el-dialog__close{
|
||||
font-weight: 700;
|
||||
font-size: 16px;
|
||||
}
|
||||
.el-drawer__body .d2-container-full {
|
||||
border: none!important;
|
||||
/* border-top: none; */
|
||||
/* border-bottom: none; */
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,9 @@
|
|||
v-if="show"
|
||||
class="d2-source"
|
||||
:class="{ 'd2-source--active': isActive }"
|
||||
@click="handleClick">
|
||||
<d2-icon name="code"/> 本页源码
|
||||
@click="handleClick"
|
||||
>
|
||||
<d2-icon name="code" /> 本页源码
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -51,11 +52,11 @@ export default {
|
|||
$paddingLR: 15px;
|
||||
$paddingTB: 7px;
|
||||
$fontSize: 12px;
|
||||
$rightOuter: $paddingLR / 2;
|
||||
$rightOuter: calc($paddingLR / 2);
|
||||
opacity: 0;
|
||||
position: fixed;
|
||||
z-index: 9999;
|
||||
right: - $borderRadius - $rightOuter;
|
||||
right: -$borderRadius - $rightOuter;
|
||||
bottom: 20px;
|
||||
font-size: $fontSize;
|
||||
line-height: $fontSize;
|
||||
|
|
@ -63,17 +64,17 @@ export default {
|
|||
border-radius: $borderRadius;
|
||||
padding: $paddingTB $paddingLR;
|
||||
padding-right: $borderRadius + $paddingLR;
|
||||
background-color: rgba(#000, .7);
|
||||
background-color: rgba(#000, 0.7);
|
||||
border: 1px solid #000;
|
||||
color: #FFF;
|
||||
transition: all .3s;
|
||||
color: #fff;
|
||||
transition: all 0.3s;
|
||||
@extend %unable-select;
|
||||
&.d2-source--active {
|
||||
opacity: 1;
|
||||
}
|
||||
&:hover {
|
||||
right: - $borderRadius;
|
||||
background-color: rgba(#000, .9);
|
||||
right: -$borderRadius;
|
||||
background-color: rgba(#000, 0.9);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ export default {
|
|||
...defaultElProps.columns
|
||||
]
|
||||
} else {
|
||||
defaultElProps.radioConfig = this.elProps.radioConfig
|
||||
defaultElProps.radioConfig = this.elProps
|
||||
? this.elProps.radioConfig
|
||||
: {}
|
||||
defaultElProps.columns = [
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export function getButtonSettings (objectSettings) {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
// v2.0.2 中已弃用,改为 vm.dictionary('button_status_bool')
|
||||
// 启用 true/ 禁用 false
|
||||
export const BUTTON_STATUS_BOOL = getButtonSettings([{ label: '启用', value: true }, { label: '禁用', value: false }])
|
||||
|
||||
|
|
@ -30,3 +30,5 @@ export const BUTTON_STATUS_NUMBER = getButtonSettings([{ label: '启用', value:
|
|||
export const BUTTON_WHETHER_NUMBER = getButtonSettings([{ label: '是', value: 1 }, { label: '否', value: 0 }])
|
||||
// 是 true/ 否 false
|
||||
export const BUTTON_WHETHER_BOOL = getButtonSettings([{ label: '是', value: true }, { label: '否', value: false }])
|
||||
// 用户类型
|
||||
export const USER_TYPE = getButtonSettings([{ label: '后台用户', value: 0 }, { label: '前台用户', value: 1 }])
|
||||
|
|
|
|||
|
|
@ -0,0 +1,118 @@
|
|||
export default {
|
||||
'image-uploader': {
|
||||
form: { component: { name: 'd2p-file-uploader', props: { elProps: { listType: 'picture-card', accept: '.png,.jpeg,.jpg,.ico,.bmp,.gif' } } } },
|
||||
component: { name: 'd2p-images-format' },
|
||||
view: {
|
||||
component: { props: { height: 100, width: 100 } }
|
||||
},
|
||||
align: 'center',
|
||||
// 提交时,处理数据
|
||||
valueResolve (row, col) {
|
||||
const value = row[col.key]
|
||||
if (value != null) {
|
||||
if (value.length >= 0) {
|
||||
if (value instanceof Array) {
|
||||
row[col.key] = value.toString()
|
||||
} else {
|
||||
row[col.key] = value
|
||||
}
|
||||
} else {
|
||||
row[col.key] = null
|
||||
}
|
||||
}
|
||||
},
|
||||
// 接收时,处理数据
|
||||
valueBuilder (row, col) {
|
||||
const value = row[col.key]
|
||||
if (value != null && value) {
|
||||
row[col.key] = value.split(',')
|
||||
}
|
||||
}
|
||||
},
|
||||
'avatar-uploader': {
|
||||
form: { component: { name: 'd2p-file-uploader', props: { elProps: { limit: 1, listType: 'avatar', accept: '.png,.jpeg,.jpg,.ico,.bmp,.gif', showFileList: false } } } },
|
||||
component: { name: 'd2p-images-format' },
|
||||
view: {
|
||||
component: { props: { height: 100, width: 100 } }
|
||||
},
|
||||
align: 'center',
|
||||
// 提交时,处理数据
|
||||
valueResolve (row, col) {
|
||||
const value = row[col.key]
|
||||
if (value != null) {
|
||||
if (value.length >= 0) {
|
||||
if (value instanceof Array) {
|
||||
row[col.key] = value.toString()
|
||||
} else {
|
||||
row[col.key] = value
|
||||
}
|
||||
} else {
|
||||
row[col.key] = null
|
||||
}
|
||||
}
|
||||
},
|
||||
// 接收时,处理数据
|
||||
valueBuilder (row, col) {
|
||||
const value = row[col.key]
|
||||
if (value != null && value) {
|
||||
row[col.key] = value.split(',')
|
||||
}
|
||||
}
|
||||
},
|
||||
'file-uploader': {
|
||||
form: { component: { name: 'd2p-file-uploader', props: { elProps: { listType: 'text' } } } },
|
||||
component: { name: 'd2p-files-format' },
|
||||
// 提交时,处理数据
|
||||
valueResolve (row, col) {
|
||||
const value = row[col.key]
|
||||
if (value != null) {
|
||||
if (value.length >= 0) {
|
||||
if (value instanceof Array) {
|
||||
row[col.key] = value.toString()
|
||||
} else {
|
||||
row[col.key] = value
|
||||
}
|
||||
} else {
|
||||
row[col.key] = null
|
||||
}
|
||||
}
|
||||
},
|
||||
// 接收时,处理数据
|
||||
valueBuilder (row, col) {
|
||||
const value = row[col.key]
|
||||
if (value != null && value) {
|
||||
row[col.key] = value.split(',')
|
||||
}
|
||||
}
|
||||
},
|
||||
'avatar-cropper': {
|
||||
form: { component: { name: 'd2p-cropper-uploader', props: { accept: '.png,.jpeg,.jpg,.ico,.bmp,.gif', cropper: { viewMode: 1 } } } },
|
||||
component: { name: 'd2p-images-format' },
|
||||
align: 'center',
|
||||
view: {
|
||||
component: { props: { height: 100, width: 100 } }
|
||||
},
|
||||
// 提交时,处理数据
|
||||
valueResolve (row, col) {
|
||||
const value = row[col.key]
|
||||
if (value != null) {
|
||||
if (value.length >= 0) {
|
||||
if (value instanceof Array) {
|
||||
row[col.key] = value.toString()
|
||||
} else {
|
||||
row[col.key] = value
|
||||
}
|
||||
} else {
|
||||
row[col.key] = null
|
||||
}
|
||||
}
|
||||
},
|
||||
// 接收时,处理数据
|
||||
valueBuilder (row, col) {
|
||||
const value = row[col.key]
|
||||
if (value != null && value) {
|
||||
row[col.key] = value.split(',')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -15,7 +15,11 @@ import {
|
|||
import { request } from '@/api/service'
|
||||
import util from '@/libs/util'
|
||||
import XEUtils from 'xe-utils'
|
||||
import store from '@/store/index'
|
||||
import { urlPrefix as deptPrefix } from '@/views/system/dept/api'
|
||||
import types from '@/config/d2p-extends/types'
|
||||
import { checkPlugins } from '@/views/plugins'
|
||||
const uploadUrl = util.baseURL() + 'api/system/file/'
|
||||
|
||||
/**
|
||||
// vxe0
|
||||
|
|
@ -31,7 +35,11 @@ Vue.use(d2CrudX, { name: 'd2-crud-x' })
|
|||
|
||||
// // 官方版【此处为演示与官方版共存而引入,全新项目中可以用d2-crud-x完全替代官方版】
|
||||
// Vue.use(d2Crud)
|
||||
|
||||
/**
|
||||
* @description 校验插件是否安装
|
||||
* @param {String} pluginName 插件名称
|
||||
*/
|
||||
Vue.prototype.checkPlugins = checkPlugins
|
||||
// 引入d2CrudPlus
|
||||
Vue.use(d2CrudPlus, {
|
||||
starTip: false,
|
||||
|
|
@ -105,7 +113,7 @@ Vue.use(D2pFullEditor, {
|
|||
Vue.use(D2pDemoExtend)
|
||||
Vue.use(D2pFileUploader)
|
||||
Vue.use(D2pUploader, {
|
||||
defaultType: 'cos',
|
||||
defaultType: 'form',
|
||||
cos: {
|
||||
domain: 'https://d2p-demo-1251260344.cos.ap-guangzhou.myqcloud.com',
|
||||
bucket: 'd2p-demo-1251260344',
|
||||
|
|
@ -159,15 +167,49 @@ Vue.use(D2pUploader, {
|
|||
domain: 'http://d2p.file.veryreader.com'
|
||||
},
|
||||
form: {
|
||||
action: util.baseURL() + 'upload/form/upload',
|
||||
name: 'file'
|
||||
action: uploadUrl,
|
||||
name: 'file',
|
||||
data: {}, // 上传附加参数
|
||||
headers () {
|
||||
return {
|
||||
Authorization: 'JWT ' + util.cookies.get('token')
|
||||
}
|
||||
},
|
||||
type: 'form',
|
||||
successHandle (ret, option) {
|
||||
if (ret.data === null || ret.data === '') {
|
||||
throw new Error('上传失败')
|
||||
}
|
||||
return { url: util.baseURL() + ret.data.url, key: option.data.key }
|
||||
},
|
||||
withCredentials: false // 是否带cookie
|
||||
}
|
||||
})
|
||||
|
||||
d2CrudPlus.util.columnResolve.addTypes(types)
|
||||
// 修改官方字段类型
|
||||
const selectType = d2CrudPlus.util.columnResolve.getType('select')
|
||||
selectType.component.props.color = 'auto' // 修改官方的字段类型,设置为支持自动染色
|
||||
|
||||
// 获取字典配置
|
||||
Vue.prototype.dictionary = function (name) {
|
||||
return store.state.d2admin.dictionary.data[name]
|
||||
}
|
||||
// 获取字典label值
|
||||
Vue.prototype.getDictionaryLabel = function (name, value) {
|
||||
const data = store.state.d2admin.dictionary.data[name]
|
||||
if (data && data instanceof Array) {
|
||||
for (var i = 0, len = data.length; i < len; i++) {
|
||||
if (data[i].value === value) {
|
||||
return data[i].label
|
||||
}
|
||||
}
|
||||
return ''
|
||||
}
|
||||
return store.state.d2admin.dictionary.data[name]
|
||||
}
|
||||
// 获取系统配置
|
||||
Vue.prototype.systemConfig = function (name) {
|
||||
return store.state.d2admin.settings.data[name]
|
||||
}
|
||||
// 默认Columns 结尾 showForm:显示在form中,showTable:显示在table中
|
||||
Vue.prototype.commonEndColumns = function (param = {}) {
|
||||
/**
|
||||
|
|
@ -257,7 +299,7 @@ Vue.prototype.commonEndColumns = function (param = {}) {
|
|||
type: 'table-selector',
|
||||
dict: {
|
||||
cache: true,
|
||||
url: '/api/system/dept/?limit=999&status=1',
|
||||
url: deptPrefix,
|
||||
isTree: true,
|
||||
value: 'id', // 数据字典中value字段的属性名
|
||||
label: 'name', // 数据字典中label字段的属性名
|
||||
|
|
@ -268,6 +310,7 @@ Vue.prototype.commonEndColumns = function (param = {}) {
|
|||
}) => {
|
||||
return request({
|
||||
url: url,
|
||||
params: { limit: 999, status: 1 }
|
||||
}).then(ret => {
|
||||
return ret.data.data
|
||||
})
|
||||
|
|
|
|||
|
|
@ -28,10 +28,21 @@
|
|||
:action="action"
|
||||
:headers="headers"
|
||||
:limit="1"
|
||||
:disabled="fileList.length===1"
|
||||
:on-success="handleAvatarSuccess">
|
||||
<!-- <el-image v-if="userInfo.avatar" :src="userInfo.avatar" :preview-src-list="[userInfo.avatar]" style="width: 100px;height: 100px" alt="头像"></el-image>-->
|
||||
<!-- <i v-else class="el-icon-plus avatar-uploader-icon" style="width: 100px;height: 100px"></i>-->
|
||||
:disabled="fileList.length === 1"
|
||||
:on-success="handleAvatarSuccess"
|
||||
>
|
||||
<!-- <el-image
|
||||
v-if="userInfo.avatar"
|
||||
:src="userInfo.avatar"
|
||||
:preview-src-list="[userInfo.avatar]"
|
||||
style="width: 100px; height: 100px"
|
||||
alt="头像"
|
||||
></el-image>
|
||||
<i
|
||||
v-else
|
||||
class="el-icon-plus avatar-uploader-icon"
|
||||
style="width: 100px; height: 100px"
|
||||
></i> -->
|
||||
<i class="el-icon-plus"></i>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
|
|
@ -149,7 +160,7 @@ export default {
|
|||
headers: {
|
||||
Authorization: 'JWT ' + util.cookies.get('token')
|
||||
},
|
||||
fileList:[],
|
||||
fileList: [],
|
||||
userInfo: {
|
||||
name: '',
|
||||
gender: '',
|
||||
|
|
@ -159,9 +170,7 @@ export default {
|
|||
},
|
||||
userInforules: {
|
||||
name: [{ required: true, message: '请输入昵称', trigger: 'blur' }],
|
||||
mobile: [
|
||||
{ pattern: /^1[3|4|5|7|8]\d{9}$/, message: '请输入正确手机号' }
|
||||
]
|
||||
mobile: [{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确手机号' }]
|
||||
},
|
||||
userPasswordInfo: {
|
||||
oldPassword: '',
|
||||
|
|
@ -197,7 +206,7 @@ export default {
|
|||
params: {}
|
||||
}).then((res) => {
|
||||
_self.userInfo = res.data
|
||||
_self.fileList = [{name:'avatar.png',url:res.data.avatar}]
|
||||
_self.fileList = [{ name: 'avatar.png', url: res.data.avatar }]
|
||||
})
|
||||
},
|
||||
/**
|
||||
|
|
@ -278,10 +287,10 @@ export default {
|
|||
* @param res
|
||||
* @param file
|
||||
*/
|
||||
handleAvatarSuccess(res, file) {
|
||||
console.log(11,res)
|
||||
this.fileList =[{ url: util.baseURL() + res.data.url, name:file.name }]
|
||||
this.userInfo.avatar = util.baseURL() + res.data.url;
|
||||
handleAvatarSuccess (res, file) {
|
||||
console.log(11, res)
|
||||
this.fileList = [{ url: util.baseURL() + res.data.url, name: file.name }]
|
||||
this.userInfo.avatar = util.baseURL() + res.data.url
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import cookies from './util.cookies'
|
||||
import db from './util.db'
|
||||
import log from './util.log'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
const util = {
|
||||
cookies,
|
||||
db,
|
||||
|
|
@ -34,7 +36,7 @@ util.open = function (url) {
|
|||
*/
|
||||
util.baseURL = function () {
|
||||
var baseURL = process.env.VUE_APP_API
|
||||
if (window.pluginsAll && window.pluginsAll.indexOf('dvadmin-tenant') !== -1) {
|
||||
if (window.pluginsAll && window.pluginsAll.indexOf('dvadmin-tenant-web') !== -1) {
|
||||
// document.domain
|
||||
var host = baseURL.split('/')[2]
|
||||
var prot = host.split(':')[1] || 80
|
||||
|
|
@ -46,5 +48,33 @@ util.baseURL = function () {
|
|||
}
|
||||
return baseURL
|
||||
}
|
||||
/**
|
||||
* 自动生成ID
|
||||
*/
|
||||
util.autoCreateCode = function () {
|
||||
return dayjs().format('YYYYMMDDHHmmssms') + Math.round(Math.random() * 80 + 20)
|
||||
}
|
||||
/**
|
||||
* 自动生成短 ID
|
||||
*/
|
||||
util.autoShortCreateCode = function () {
|
||||
var Num = ''
|
||||
for (var i = 0; i < 4; i++) {
|
||||
Num += Math.floor(Math.random() * 10)
|
||||
}
|
||||
return dayjs().format('YYMMDD') + Num
|
||||
}
|
||||
|
||||
/**
|
||||
* 生产随机字符串
|
||||
*/
|
||||
util.randomString = function (e) {
|
||||
e = e || 32
|
||||
var t = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'
|
||||
var a = t.length
|
||||
var n = ''
|
||||
for (let i = 0; i < e; i++) n += t.charAt(Math.floor(Math.random() * a))
|
||||
return n
|
||||
}
|
||||
|
||||
export default util
|
||||
|
|
|
|||
|
|
@ -42,6 +42,11 @@ new Vue({
|
|||
store,
|
||||
i18n,
|
||||
render: h => h(App),
|
||||
beforeCreate () {
|
||||
// 初始化配置
|
||||
this.$store.dispatch('d2admin/settings/load')
|
||||
this.$store.dispatch('d2admin/dictionary/load')
|
||||
},
|
||||
created () {
|
||||
|
||||
// 处理路由 得到每一级的路由设置
|
||||
|
|
|
|||
|
|
@ -29,43 +29,7 @@ function supplementPath (menu) {
|
|||
|
||||
export const menuHeader = supplementPath([])
|
||||
|
||||
// export const menuHeader = supplementPath([
|
||||
// { path: '/index', title: '控制台', icon: 'home' },
|
||||
// {
|
||||
// title: '页面',
|
||||
// icon: 'folder-o',
|
||||
// children: [
|
||||
// { path: '/page1', title: '页面 1' },
|
||||
// { path: '/page2', title: '页面 2' },
|
||||
// { path: '/page3', title: '页面 3' }
|
||||
// ]
|
||||
// }
|
||||
// ])
|
||||
|
||||
export const menuAside = supplementPath([])
|
||||
// export const menuAside = supplementPath([
|
||||
// { path: '/index', title: '控制台', icon: 'home' },
|
||||
// {
|
||||
// title: '系统管理',
|
||||
// icon: 'folder-o',
|
||||
// children: [
|
||||
// // { path: '/page1', title: '页面 1' },
|
||||
// // { path: '/page2', title: '页面 2' },
|
||||
// // { path: '/page3', title: '页面 3' },
|
||||
// { path: '/menu', title: '菜单' },
|
||||
// { path: '/user', title: '用户' },
|
||||
// { path: '/button', title: '按钮' },
|
||||
// { path: '/role', title: '角色' },
|
||||
// { path: '/dept', title: '部门' },
|
||||
// { path: '/rolePermission', title: '角色权限' },
|
||||
// {
|
||||
// title: '日志管理', children: [
|
||||
// { path: '/operationLog', title: '操作日志' },
|
||||
// ]
|
||||
// },
|
||||
// ]
|
||||
// }
|
||||
// ])
|
||||
|
||||
// 请求菜单数据,用于解析路由和侧边栏菜单
|
||||
export const getMenu = function () {
|
||||
|
|
|
|||
|
|
@ -65,6 +65,8 @@ router.beforeEach(async (to, from, next) => {
|
|||
store.commit('d2admin/page/init', routes)
|
||||
|
||||
router.addRoutes(routes)
|
||||
// routes.forEach(route => router.addRoute(route))
|
||||
|
||||
const menu = handleAsideMenu(ret)
|
||||
const aside = handleAsideMenu(ret.filter(value => value.visible === true))
|
||||
store.commit('d2admin/menu/asideSet', aside) // 设置侧边栏菜单
|
||||
|
|
|
|||
|
|
@ -16,22 +16,24 @@ export default {
|
|||
namespaced: true,
|
||||
actions: {
|
||||
/**
|
||||
* @description 登录
|
||||
* @param {Object} context
|
||||
* @param {Object} data
|
||||
* @param {Object} data username {String} 用户账号
|
||||
* @param {Object} data password {String} 密码
|
||||
* @param {Object} data route {Object} 登录成功后定向的路由对象 任何 vue-router 支持的格式
|
||||
* @param {Object} data request function 请求方法
|
||||
* @description 登录
|
||||
* @param {Object} context
|
||||
* @param {Object} payload username {String} 用户账号
|
||||
* @param {Object} payload password {String} 密码
|
||||
* @param {Object} payload route {Object} 登录成功后定向的路由对象 任何 vue-router 支持的格式
|
||||
*/
|
||||
async login ({ dispatch }, data) {
|
||||
let request = data.request
|
||||
if (request) {
|
||||
delete data.request
|
||||
} else {
|
||||
request = SYS_USER_LOGIN
|
||||
}
|
||||
let res = await request(data)
|
||||
async login ({ dispatch }, {
|
||||
username = '',
|
||||
password = '',
|
||||
captcha = '',
|
||||
captchaKey = ''
|
||||
} = {}) {
|
||||
let res = await SYS_USER_LOGIN({
|
||||
username,
|
||||
password,
|
||||
captcha,
|
||||
captchaKey
|
||||
})
|
||||
// 设置 cookie 一定要存 uuid 和 token 两个 cookie
|
||||
// 整个系统依赖这两个数据进行校验和存储
|
||||
// uuid 是用户身份唯一标识 用户注册的时候确定 并且不可改变 不可重复
|
||||
|
|
@ -42,19 +44,19 @@ export default {
|
|||
util.cookies.set('token', res.access)
|
||||
util.cookies.set('refresh', res.refresh)
|
||||
// 设置 vuex 用户信息
|
||||
await dispatch('d2admin/user/set', { name: res.name, user_id: res.userId,avatar:res.avatar }, { root: true })
|
||||
await dispatch('d2admin/user/set', { name: res.name, user_id: res.userId, avatar: res.avatar }, { root: true })
|
||||
// 用户登录后从持久化数据加载一系列的设置
|
||||
await dispatch('load')
|
||||
},
|
||||
/**
|
||||
* @description 注销用户并返回登录页面
|
||||
* @param {Object} context
|
||||
* @param {Object} payload confirm {Boolean} 是否需要确认
|
||||
*/
|
||||
* @description 注销用户并返回登录页面
|
||||
* @param {Object} context
|
||||
* @param {Object} payload confirm {Boolean} 是否需要确认
|
||||
*/
|
||||
logout ({ commit, dispatch }, { confirm = false } = {}) {
|
||||
/**
|
||||
* @description 注销
|
||||
*/
|
||||
* @description 注销
|
||||
*/
|
||||
async function logout () {
|
||||
await SYS_USER_LOGOUT({ refresh: util.cookies.get('refresh') }).then(() => {
|
||||
// 删除cookie
|
||||
|
|
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
import { request } from '@/api/service'
|
||||
|
||||
export const urlPrefix = '/api/init/dictionary/'
|
||||
export const BUTTON_VALUE_TO_COLOR_MAPPING = {
|
||||
1: 'success',
|
||||
true: 'success',
|
||||
0: 'danger',
|
||||
false: 'danger',
|
||||
Search: 'warning', // 查询
|
||||
Update: 'primary', // 编辑
|
||||
Create: 'success', // 新增
|
||||
Retrieve: 'info', // 单例
|
||||
Delete: 'danger' // 删除
|
||||
}
|
||||
|
||||
export function getButtonSettings (objectSettings) {
|
||||
return objectSettings.map(item => {
|
||||
return {
|
||||
label: item.label,
|
||||
value: item.value,
|
||||
color: item.color || BUTTON_VALUE_TO_COLOR_MAPPING[item.value]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 系统配置
|
||||
export default {
|
||||
namespaced: true,
|
||||
state: {
|
||||
data: {} // 字典值集合
|
||||
},
|
||||
actions: {
|
||||
/**
|
||||
* @description 本地加载配置
|
||||
* @param {Object} context
|
||||
* @param {String} key
|
||||
*/
|
||||
async load ({ state, dispatch, commit }, key = 'all') {
|
||||
const query = { dictionary_key: key }
|
||||
request({
|
||||
url: urlPrefix,
|
||||
params: query,
|
||||
method: 'get'
|
||||
}).then(async res => {
|
||||
// store 赋值
|
||||
var newData = {}
|
||||
if (key === 'all') {
|
||||
res.data.data.map(data => {
|
||||
data.children.map((children, index) => {
|
||||
switch (children.type) {
|
||||
case 1:
|
||||
children.value = Number(children.value)
|
||||
break
|
||||
case 6:
|
||||
children.value = children.value === 'true'
|
||||
break
|
||||
}
|
||||
})
|
||||
newData[data.value] = getButtonSettings(data.children)
|
||||
})
|
||||
state.data = newData
|
||||
} else {
|
||||
state.data = res.data.data[key]
|
||||
}
|
||||
})
|
||||
}
|
||||
/**
|
||||
* @description 获取配置
|
||||
* @param {Object} state state
|
||||
* @param {Object} dispatch dispatch
|
||||
* @param {String} key 字典值
|
||||
* @param {String} isCache 是否缓存
|
||||
*/
|
||||
},
|
||||
mutations: {
|
||||
/**
|
||||
* @description 设置配置
|
||||
* @param {Object} state state
|
||||
* @param {Boolean} key active
|
||||
* @param {Boolean} value active
|
||||
*/
|
||||
async set (state, key, value) {
|
||||
state.data[key] = value
|
||||
},
|
||||
/**
|
||||
* @description 获取配置
|
||||
* @param {Object} state state
|
||||
* @param {Boolean} key active
|
||||
*/
|
||||
async get (state, key) {
|
||||
return state.data[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
import { request } from '@/api/service'
|
||||
|
||||
export const urlPrefix = '/api/init/settings/'
|
||||
|
||||
// 系统配置
|
||||
export default {
|
||||
namespaced: true,
|
||||
state: {
|
||||
data: {}
|
||||
},
|
||||
actions: {
|
||||
/**
|
||||
* @description 请求最新配置
|
||||
* @param {Object} context
|
||||
*/
|
||||
async init ({ state, dispatch, commit }) {
|
||||
// 请求配置
|
||||
request({
|
||||
url: urlPrefix,
|
||||
method: 'get'
|
||||
}).then(async res => {
|
||||
// 赋值
|
||||
await dispatch('d2admin/db/set', {
|
||||
dbName: 'sys',
|
||||
path: 'settings.init',
|
||||
value: res.data,
|
||||
user: true
|
||||
}, { root: true })
|
||||
dispatch('load')
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @description 本地加载配置
|
||||
* @param {Object} context
|
||||
*/
|
||||
async load ({ state, dispatch, commit }) {
|
||||
// store 赋值
|
||||
state.data = await dispatch('d2admin/db/get', {
|
||||
dbName: 'sys',
|
||||
path: 'settings.init',
|
||||
defaultValue: {},
|
||||
user: true
|
||||
}, { root: true })
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
/**
|
||||
* @description 获取配置
|
||||
* @param {Object} state state
|
||||
* @param {String} key active
|
||||
* @param {Object} value active
|
||||
*/
|
||||
async get (state, key, value) {
|
||||
return state[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,4 @@
|
|||
import { request } from '@/api/service'
|
||||
import util from '@/libs/util'
|
||||
const uploadUrl = process.env.VUE_APP_API + '/api/system/img/'
|
||||
export const crudOptions = (vm) => {
|
||||
return {
|
||||
pageOptions: {
|
||||
|
|
@ -85,20 +83,6 @@ export const crudOptions = (vm) => {
|
|||
form: {
|
||||
component: {
|
||||
props: {
|
||||
uploader: {
|
||||
action: uploadUrl,
|
||||
name: 'file',
|
||||
headers: {
|
||||
Authorization: 'JWT ' + util.cookies.get('token')
|
||||
},
|
||||
type: 'form',
|
||||
successHandle (ret, option) {
|
||||
if (ret.data == null || ret.data === '') {
|
||||
throw new Error('上传失败')
|
||||
}
|
||||
return { url: ret.data.data.url, key: option.data.key }
|
||||
}
|
||||
},
|
||||
elProps: { // 与el-uploader 配置一致
|
||||
multiple: false,
|
||||
limit: 5 // 限制5个文件
|
||||
|
|
@ -108,26 +92,6 @@ export const crudOptions = (vm) => {
|
|||
span: 24
|
||||
},
|
||||
helper: '限制文件大小不能超过50k'
|
||||
},
|
||||
valueResolve (row, col) {
|
||||
const value = row[col.key]
|
||||
if (value != null && value instanceof Array) {
|
||||
if (value.length >= 0) {
|
||||
row[col.key] = value[0]
|
||||
} else {
|
||||
row[col.key] = null
|
||||
}
|
||||
}
|
||||
},
|
||||
component: {
|
||||
props: {
|
||||
buildUrl (value, item) {
|
||||
if (value && value.indexOf('http') !== 0) {
|
||||
return '/api/upload/form/download?key=' + value
|
||||
}
|
||||
return value
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -139,20 +103,6 @@ export const crudOptions = (vm) => {
|
|||
form: {
|
||||
component: {
|
||||
props: {
|
||||
uploader: {
|
||||
action: uploadUrl,
|
||||
name: 'file',
|
||||
headers: {
|
||||
Authorization: 'JWT ' + util.cookies.get('token')
|
||||
},
|
||||
type: 'form',
|
||||
successHandle (ret, option) {
|
||||
if (ret.data == null || ret.data === '') {
|
||||
throw new Error('上传失败')
|
||||
}
|
||||
return { url: ret.data.data.url, key: option.data.key }
|
||||
}
|
||||
},
|
||||
elProps: { // 与el-uploader 配置一致
|
||||
multiple: false,
|
||||
limit: 5 // 限制5个文件
|
||||
|
|
@ -162,26 +112,6 @@ export const crudOptions = (vm) => {
|
|||
span: 24
|
||||
},
|
||||
helper: '限制文件大小不能超过50k'
|
||||
},
|
||||
valueResolve (row, col) {
|
||||
const value = row[col.key]
|
||||
if (value != null && value instanceof Array) {
|
||||
if (value.length >= 0) {
|
||||
row[col.key] = value[0]
|
||||
} else {
|
||||
row[col.key] = null
|
||||
}
|
||||
}
|
||||
},
|
||||
component: {
|
||||
props: {
|
||||
buildUrl (value, item) {
|
||||
if (value && value.indexOf('http') !== 0) {
|
||||
return '/api/upload/form/download?key=' + value
|
||||
}
|
||||
return value
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
import { BUTTON_STATUS_BOOL } from '@/config/button'
|
||||
|
||||
import { request } from '@/api/service'
|
||||
|
||||
export const crudOptions = (vm) => {
|
||||
|
|
@ -234,7 +232,7 @@ export const crudOptions = (vm) => {
|
|||
width: 90,
|
||||
type: 'radio',
|
||||
dict: {
|
||||
data: BUTTON_STATUS_BOOL
|
||||
data: vm.dictionary('button_status_bool')
|
||||
},
|
||||
form: {
|
||||
value: true,
|
||||
|
|
|
|||
|
|
@ -1,167 +0,0 @@
|
|||
/*
|
||||
* @创建文件时间: 2021-06-03 00:34:42
|
||||
* @Auther: 猿小天
|
||||
* @最后修改人: 猿小天
|
||||
* @最后修改时间: 2021-11-19 22:18:47
|
||||
* 联系Qq:1638245306
|
||||
* @文件介绍: 权限配置
|
||||
*/
|
||||
export const crudOptions = (vm) => {
|
||||
return {
|
||||
pageOptions: {
|
||||
compact: true
|
||||
},
|
||||
options: {
|
||||
tableType: 'vxe-table',
|
||||
rowKey: true,
|
||||
width: '100%',
|
||||
height: '100%' // 表格高度100%, 使用toolbar必须设置
|
||||
},
|
||||
rowHandle: {
|
||||
edit: {
|
||||
thin: true,
|
||||
text: '编辑',
|
||||
disabled () {
|
||||
return !vm.hasPermissions('Update')
|
||||
}
|
||||
},
|
||||
remove: {
|
||||
thin: true,
|
||||
text: '删除',
|
||||
disabled () {
|
||||
return !vm.hasPermissions('Delete')
|
||||
}
|
||||
}
|
||||
},
|
||||
indexRow: { // 或者直接传true,不显示title,不居中
|
||||
title: '序号',
|
||||
align: 'center',
|
||||
width: 100
|
||||
},
|
||||
viewOptions: {
|
||||
disabled: true,
|
||||
componentType: 'form'
|
||||
},
|
||||
formOptions: {
|
||||
defaultSpan: 24, // 默认的表单 span
|
||||
width: '35%'
|
||||
},
|
||||
columns: [{
|
||||
title: '关键词',
|
||||
key: 'search',
|
||||
show: false,
|
||||
disabled: true,
|
||||
search: {
|
||||
disabled: false
|
||||
},
|
||||
form: {
|
||||
disabled: true,
|
||||
component: {
|
||||
placeholder: '请输入关键字'
|
||||
}
|
||||
},
|
||||
view: { // 查看对话框组件的单独配置
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'ID',
|
||||
key: 'id',
|
||||
show: false,
|
||||
width: 90,
|
||||
form: {
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '名称',
|
||||
key: 'name',
|
||||
sortable: true,
|
||||
search: {
|
||||
disabled: false
|
||||
},
|
||||
|
||||
type: 'input',
|
||||
form: {
|
||||
rules: [ // 表单校验规则
|
||||
{ required: true, message: '名称必填项' }
|
||||
],
|
||||
component: {
|
||||
placeholder: '请输入名称'
|
||||
},
|
||||
itemProps: {
|
||||
class: { yxtInput: true }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'key值',
|
||||
key: 'value',
|
||||
sortable: true,
|
||||
search: {
|
||||
disabled: false
|
||||
},
|
||||
|
||||
type: 'input',
|
||||
form: {
|
||||
rules: [ // 表单校验规则
|
||||
{ required: true, message: 'key值必填项' }
|
||||
],
|
||||
component: {
|
||||
placeholder: '请输入key值'
|
||||
},
|
||||
itemProps: {
|
||||
class: { yxtInput: true }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
key: 'description',
|
||||
show: false,
|
||||
search: {
|
||||
disabled: true
|
||||
},
|
||||
type: 'textarea',
|
||||
form: {
|
||||
component: {
|
||||
placeholder: '请输入内容',
|
||||
showWordLimit: true,
|
||||
maxlength: '200',
|
||||
props: {
|
||||
type: 'textarea'
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
title: '创建人',
|
||||
show: false,
|
||||
width: 100,
|
||||
key: 'modifier_name',
|
||||
form: {
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '更新时间',
|
||||
key: 'update_datetime',
|
||||
width: 160,
|
||||
type: 'datetime',
|
||||
sortable: true,
|
||||
form: {
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'create_datetime',
|
||||
width: 160,
|
||||
type: 'datetime',
|
||||
sortable: true,
|
||||
form: {
|
||||
disabled: true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -16,9 +16,16 @@
|
|||
<el-form-item label="表单类型" prop="form_item_type">
|
||||
<el-select v-model="form.form_item_type" placeholder="请选择" clearable>
|
||||
<el-option :label="item.label" :value="item.value" :key="index"
|
||||
v-for="(item,index) in typeOptions"></el-option>
|
||||
v-for="(item,index) in dictionary('config_form_type')"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="[4,5,6].indexOf(form.form_item_type)>-1"
|
||||
label="字典key"
|
||||
prop="setting"
|
||||
:rules="[{required: true,message: '不能为空'}]">
|
||||
<el-input v-model="form.setting" placeholder="请输入dictionary中key值" clearable></el-input>
|
||||
</el-form-item>
|
||||
<div v-if="[13,14].indexOf(form.form_item_type)>-1">
|
||||
<associationTable ref="associationTable" v-model="form.setting"
|
||||
@updateVal="associationTableUpdate"></associationTable>
|
||||
|
|
@ -81,8 +88,8 @@ export default {
|
|||
message: '请输入'
|
||||
},
|
||||
{
|
||||
pattern: /^[A-Za-z0-9]+$/,
|
||||
message: '只支持字母和数字的输入'
|
||||
pattern: /^[A-Za-z0-9_]+$/,
|
||||
message: '请输入数字、字母或下划线'
|
||||
}
|
||||
],
|
||||
form_item_type: [
|
||||
|
|
@ -94,23 +101,6 @@ export default {
|
|||
},
|
||||
// 父级内容
|
||||
parentOptions: [],
|
||||
// 表单类型
|
||||
typeOptions: [
|
||||
{ value: 0, label: '短文本' },
|
||||
{ value: 1, label: '长文本' },
|
||||
{ value: 2, label: '数字框' },
|
||||
{ value: 3, label: '选择框' },
|
||||
{ value: 4, label: '单选框' },
|
||||
{ value: 5, label: '复选框' },
|
||||
{ value: 6, label: '日期' },
|
||||
{ value: 7, label: '日期时间' },
|
||||
{ value: 8, label: '时间' },
|
||||
{ value: 9, label: '图片' },
|
||||
{ value: 10, label: '文件' },
|
||||
{ value: 11, label: '数组' },
|
||||
{ value: 12, label: '关联表' },
|
||||
{ value: 13, label: '关联表(多选)' }
|
||||
],
|
||||
ruleOptions: [
|
||||
{
|
||||
label: '必填项',
|
||||
|
|
@ -119,6 +109,10 @@ export default {
|
|||
{
|
||||
label: '邮箱',
|
||||
value: '{ "type": "email", "message": "请输入正确的邮箱地址"}'
|
||||
},
|
||||
{
|
||||
label: 'URL地址',
|
||||
value: '{ "type": "url", "message": "请输入正确的URL地址"}'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -162,7 +156,6 @@ export default {
|
|||
const that = this
|
||||
return new Promise(function (resolve, reject) {
|
||||
if (that.$refs.associationTable) {
|
||||
console.log(that.$refs.associationTable.onSubmit())
|
||||
if (!that.$refs.associationTable.onSubmit()) {
|
||||
// eslint-disable-next-line prefer-promise-reject-errors
|
||||
return reject(false)
|
||||
|
|
@ -5,9 +5,9 @@
|
|||
<el-col :span="12">变量值</el-col>
|
||||
<el-col :span="4" :offset="4">变量名</el-col>
|
||||
</el-row>
|
||||
<el-form ref="form" :model="form" label-width="100px" label-position="left" style="margin-top: 20px">
|
||||
<el-form ref="form" :model="form" label-width="140px" label-position="left" style="margin-top: 20px">
|
||||
<el-form-item :label="item.title" :prop="['array'].indexOf(item.form_item_type_label) >-1?'':item.key"
|
||||
:key="index" :rules="item.rule"
|
||||
:key="index" :rules="item.rule || []"
|
||||
v-for="(item,index) in formList"
|
||||
|
||||
>
|
||||
|
|
@ -17,19 +17,83 @@
|
|||
:type="item.form_item_type_label"
|
||||
v-model="form[item.key]" :placeholder="item.placeholder" clearable></el-input>
|
||||
|
||||
<el-input-number :key="index" v-else-if="item.form_item_type_label==='number'" v-model="form[item.key]"
|
||||
<el-input-number :key="index" v-else-if="item.form_item_type_label === 'number'" v-model="form[item.key]"
|
||||
:min="0"></el-input-number>
|
||||
<!-- datetime、date、time -->
|
||||
<el-date-picker
|
||||
v-else-if="['datetime','date','time'].indexOf(item.form_item_type_label) >-1"
|
||||
v-model="form[item.key]"
|
||||
:key="index"
|
||||
:type="item.form_item_type_label"
|
||||
:placeholder="item.placeholder">
|
||||
</el-date-picker>
|
||||
<!-- select -->
|
||||
<el-select
|
||||
:key="index"
|
||||
v-else-if="item.form_item_type_label === 'select'"
|
||||
v-model="form[item.key]"
|
||||
:placeholder="item.placeholder"
|
||||
clearable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in dictionary(item.setting) || []"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<!-- checkbox -->
|
||||
<el-checkbox-group
|
||||
:key="index"
|
||||
v-else-if="item.form_item_type_label === 'checkbox'"
|
||||
v-model="form[item.key]"
|
||||
:placeholder="item.placeholder"
|
||||
>
|
||||
<el-checkbox
|
||||
v-for="item in dictionary(item.setting) || []"
|
||||
:key="item.value"
|
||||
:label="item.value"
|
||||
:value="item.value">
|
||||
{{ item.label }}
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
<!-- radio -->
|
||||
<el-radio-group
|
||||
:key="index"
|
||||
v-else-if="item.form_item_type_label === 'radio'"
|
||||
v-model="form[item.key]"
|
||||
:placeholder="item.placeholder"
|
||||
clearable
|
||||
>
|
||||
<el-radio
|
||||
v-for="item in dictionary(item.setting) || []"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value">
|
||||
{{ item.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
<!-- switch -->
|
||||
<el-switch
|
||||
:key="index"
|
||||
v-else-if="item.form_item_type_label === 'switch'"
|
||||
v-model="form[item.key]"
|
||||
active-color="#13ce66"
|
||||
inactive-color="#ff4949">
|
||||
</el-switch>
|
||||
<!-- 图片 -->
|
||||
<div v-else-if="['img','imgs'].indexOf(item.form_item_type_label) >-1" :key="index">
|
||||
<el-upload
|
||||
:action="imgUploadUrl"
|
||||
:action="uploadUrl"
|
||||
:headers="uploadHeaders"
|
||||
name="url"
|
||||
name="file"
|
||||
:accept="'image/*'"
|
||||
:on-preview="handlePictureCardPreview"
|
||||
:on-success="(response, file, fileList)=>{handleUploadSuccess(response, file, fileList,item.key)}"
|
||||
:on-error="handleError"
|
||||
:on-exceed="handleExceed"
|
||||
:before-remove="(file, fileList)=>{beforeRemove(file, fileList, item.key)}"
|
||||
:multiple="item.form_item_type_label!=='img'"
|
||||
:limit="item.form_item_type_label==='img'?1:5"
|
||||
:ref="'imgUpload_'+item.key"
|
||||
:data-keyname="item.key"
|
||||
|
|
@ -43,6 +107,30 @@
|
|||
<img width="100%" :src="dialogImageUrl" alt="">
|
||||
</el-dialog>
|
||||
</div>
|
||||
<!-- 文件 -->
|
||||
<div v-else-if="['file'].indexOf(item.form_item_type_label) >-1" :key="index">
|
||||
<el-upload
|
||||
:action="uploadUrl"
|
||||
:headers="uploadHeaders"
|
||||
name="file"
|
||||
:on-preview="handlePictureCardPreview"
|
||||
:on-success="(response, file, fileList)=>{handleUploadSuccess(response, file, fileList,item.key)}"
|
||||
:on-error="handleError"
|
||||
:on-exceed="handleExceed"
|
||||
:before-remove="(file, fileList)=>{beforeRemove(file, fileList, item.key)}"
|
||||
:limit="5"
|
||||
:ref="'fileUpload_'+item.key"
|
||||
:data-keyname="item.key"
|
||||
:file-list="item.value"
|
||||
list-type="picture-card"
|
||||
>
|
||||
<i class="el-icon-plus"></i>
|
||||
<div slot="tip" class="el-upload__tip">选取图片后,需手动上传到服务器,并且只能上传jpg/png文件</div>
|
||||
</el-upload>
|
||||
<el-dialog :visible.sync="dialogImgVisible">
|
||||
<img width="100%" :src="dialogImageUrl" alt="">
|
||||
</el-dialog>
|
||||
</div>
|
||||
<!-- 关联表 -->
|
||||
<div v-else-if="['foreignkey','manytomany'].indexOf(item.form_item_type_label) >-1" :key="index">
|
||||
<table-selector
|
||||
|
|
@ -56,7 +144,7 @@
|
|||
label: item.setting.field,
|
||||
}"
|
||||
:pagination="true"
|
||||
:multiple="item.form_item_type_label==='manytomany'?true:false"
|
||||
:multiple="item.form_item_type_label ==='manytomany'"
|
||||
></table-selector>
|
||||
</div>
|
||||
<!-- 数组 -->
|
||||
|
|
@ -171,8 +259,7 @@ export default {
|
|||
}
|
||||
]
|
||||
},
|
||||
imgUploadUrl: util.baseURL() + 'api/system/img/',
|
||||
// imgUploadUrl: 'http://public.yuanxiaotian.com:8000/api/system/img/',
|
||||
uploadUrl: util.baseURL() + 'api/system/file/',
|
||||
uploadHeaders: {
|
||||
Authorization: 'JWT ' + util.cookies.get('token')
|
||||
},
|
||||
|
|
@ -191,7 +278,15 @@ export default {
|
|||
const form = {}
|
||||
for (const item of data) {
|
||||
const key = item.key
|
||||
form[key] = item.value
|
||||
if (item.value) {
|
||||
form[key] = item.value
|
||||
} else {
|
||||
if ([5, 12, 14].indexOf(item.form_item_type) !== -1) {
|
||||
form[key] = []
|
||||
} else {
|
||||
form[key] = undefined
|
||||
}
|
||||
}
|
||||
if (item.form_item_type_label === 'array') {
|
||||
that.$nextTick(() => {
|
||||
const tableName = 'xTable_' + key
|
||||
|
|
@ -237,24 +332,25 @@ export default {
|
|||
item.value = tableData
|
||||
}
|
||||
// 赋值操作
|
||||
if (keys[index] === item.key) {
|
||||
if (item.form_item_type_label !== 'array') {
|
||||
item.value = values[index]
|
||||
}
|
||||
// 必填项的验证
|
||||
if (['img', 'imgs'].indexOf(item.form_item_type_label) > -1) {
|
||||
for (const arr of item.rule) {
|
||||
if (arr.required && item.value === null) {
|
||||
that.$message.error(item.title + '不能为空')
|
||||
return
|
||||
keys.map((mapKey, mapIndex) => {
|
||||
if (mapKey === item.key) {
|
||||
if (item.form_item_type_label !== 'array') {
|
||||
item.value = values[mapIndex]
|
||||
}
|
||||
// 必填项的验证
|
||||
if (['img', 'imgs'].indexOf(item.form_item_type_label) > -1) {
|
||||
for (const arr of item.rule) {
|
||||
if (arr.required && item.value === null) {
|
||||
that.$message.error(item.title + '不能为空')
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
that.$refs.form.clearValidate()
|
||||
that.$refs.form.validate((valid) => {
|
||||
console.log(this.formList)
|
||||
if (valid) {
|
||||
api.saveContent(this.options.id,
|
||||
this.formList).then(res => {
|
||||
|
|
@ -272,10 +368,16 @@ export default {
|
|||
const $table = this.$refs[tableName][0]
|
||||
const { tableData } = $table.getTableData()
|
||||
const tableLength = tableData.length
|
||||
if (tableLength !== 0) {
|
||||
if (tableLength === 0) {
|
||||
const { row: newRow } = $table.insert()
|
||||
console.log(newRow)
|
||||
} else {
|
||||
const errMap = await $table.validate().catch(errMap => errMap)
|
||||
if (errMap) {
|
||||
this.$message.error('校验不通过!')
|
||||
} else {
|
||||
const { row: newRow } = $table.insert()
|
||||
console.log(newRow)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -292,13 +394,6 @@ export default {
|
|||
this.dialogImageUrl = file.url
|
||||
this.dialogImgVisible = true
|
||||
},
|
||||
// 上传提交
|
||||
submitUpload (key) {
|
||||
const refName = 'imgUpload_' + key
|
||||
const ref = this.$refs[refName][0]
|
||||
ref.submit()
|
||||
this.uploadImgKey = key
|
||||
},
|
||||
// 判断是否为图片
|
||||
// 封装一个判断图片文件后缀名的方法
|
||||
isImage (fileName) {
|
||||
|
|
@ -314,20 +409,20 @@ export default {
|
|||
msg
|
||||
} = response
|
||||
if (code === 2000) {
|
||||
const { url } = response.data.data
|
||||
const { url } = response.data
|
||||
const { name } = file
|
||||
const type = that.isImage(name)
|
||||
if (!type) {
|
||||
this.$message.error('只允许上传图片')
|
||||
} else {
|
||||
const uploadImgKey = that.form[imgKey]
|
||||
if (!uploadImgKey) {
|
||||
if (!uploadImgKey || uploadImgKey === '') {
|
||||
that.form[imgKey] = []
|
||||
}
|
||||
// console.log(len)
|
||||
const dict = {
|
||||
name: name,
|
||||
url: url
|
||||
url: util.baseURL() + url
|
||||
}
|
||||
that.form[imgKey].push(dict)
|
||||
}
|
||||
|
|
@ -342,6 +437,14 @@ export default {
|
|||
// 上传超出限制
|
||||
handleExceed () {
|
||||
this.$message.error('超过文件上传数量')
|
||||
},
|
||||
// 删除时的钩子
|
||||
beforeRemove (file, fileList, key) {
|
||||
var index = 0
|
||||
this.form[key].map((value, inx) => {
|
||||
if (value.uid === file.uid) index = inx
|
||||
})
|
||||
this.form[key].splice(index, 1)
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
|
|
@ -58,17 +58,23 @@
|
|||
:label="item.title"
|
||||
:name="item.key"
|
||||
>
|
||||
<formContent :options="item" :editableTabsItem="item"></formContent>
|
||||
<span slot="label" v-if="item.icon"><i :class="item.icon" style="font-weight: 1000;font-size: 16px;"></i></span>
|
||||
<el-row v-if="item.icon">
|
||||
<el-col :offset="4" :span="8">
|
||||
<addContent></addContent>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<formContent v-else :options="item" :editableTabsItem="item"></formContent>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</d2-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import addTabs from './components/addTabs'
|
||||
import addTabs from '@/views/system/config/components/addTabs'
|
||||
import * as api from './api'
|
||||
import addContent from './components/addContent'
|
||||
import formContent from './components/formContent'
|
||||
import addContent from '@/views/system/config/components/addContent'
|
||||
import formContent from '@/views/system/config/components/formContent'
|
||||
|
||||
export default {
|
||||
name: 'config',
|
||||
|
|
@ -81,7 +87,7 @@ export default {
|
|||
return {
|
||||
tabsDrawer: false,
|
||||
contentDrawer: false,
|
||||
editableTabsValue: 'basic',
|
||||
editableTabsValue: 'base',
|
||||
editableTabs: [],
|
||||
tabIndex: 2
|
||||
}
|
||||
|
|
@ -93,6 +99,11 @@ export default {
|
|||
parent__isnull: true
|
||||
}).then(res => {
|
||||
const { data } = res.data
|
||||
data.push({
|
||||
title: '无',
|
||||
icon: 'el-icon-plus',
|
||||
key: 'null'
|
||||
})
|
||||
this.editableTabs = data
|
||||
})
|
||||
}
|
||||
|
|
@ -1,30 +1,18 @@
|
|||
/*
|
||||
* @创建文件时间: 2021-06-01 22:41:21
|
||||
* @Auther: 猿小天
|
||||
* @最后修改人: 猿小天
|
||||
* @最后修改时间: 2021-09-26 21:17:30
|
||||
* 联系Qq:1638245306
|
||||
* @文件介绍: 部门管理接口
|
||||
*/
|
||||
import { request } from '@/api/service'
|
||||
import XEUtils from 'xe-utils'
|
||||
export const urlPrefix = '/api/system/dept/'
|
||||
|
||||
/**
|
||||
* 列表查询
|
||||
*/
|
||||
export function GetList (query) {
|
||||
query.limit = 999
|
||||
// query.limit = 999;
|
||||
return request({
|
||||
url: urlPrefix,
|
||||
method: 'get',
|
||||
params: query
|
||||
}).then(res => {
|
||||
// 将列表数据转换为树形数据
|
||||
res.data.data = XEUtils.toArrayTree(res.data.data, { parentKey: 'parent', strict: false })
|
||||
return res
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
|
|
@ -46,6 +34,7 @@ export function UpdateObj (obj) {
|
|||
data: obj
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*/
|
||||
|
|
@ -56,3 +45,14 @@ export function DelObj (id) {
|
|||
data: { id }
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 部门懒加载
|
||||
*/
|
||||
export function DeptLazy (query) {
|
||||
return request({
|
||||
url: '/api/system/dept_lazy_tree/',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +1,27 @@
|
|||
import { request } from '@/api/service'
|
||||
import { BUTTON_STATUS_BOOL } from '@/config/button'
|
||||
import { urlPrefix as deptPrefix } from './api'
|
||||
import XEUtils from 'xe-utils'
|
||||
import * as api from './api'
|
||||
export const crudOptions = (vm) => {
|
||||
return {
|
||||
pagination: false,
|
||||
// pagination: false,
|
||||
pageOptions: {
|
||||
compact: true
|
||||
},
|
||||
options: {
|
||||
// tableType: 'vxe-table',
|
||||
// rowKey: true, // 必须设置,true or false
|
||||
tableType: 'vxe-table',
|
||||
rowKey: true, // 必须设置,true or false
|
||||
rowId: 'id',
|
||||
height: '100%', // 表格高度100%, 使用toolbar必须设置
|
||||
highlightCurrentRow: false,
|
||||
defaultExpandAll: true
|
||||
// treeConfig: { // 树形数据配置
|
||||
// expandAll: true,
|
||||
// children: 'children',
|
||||
// }
|
||||
defaultExpandAll: true,
|
||||
treeConfig: {
|
||||
lazy: true,
|
||||
hasChild: 'has_children',
|
||||
loadMethod: ({ row }) => {
|
||||
return api.GetList({ parent: row.id, lazy: true }).then(ret => {
|
||||
return ret.data.data
|
||||
})
|
||||
},
|
||||
iconLoaded: 'el-icon-loading' // 美化loading图标
|
||||
}
|
||||
},
|
||||
rowHandle: {
|
||||
width: 140,
|
||||
|
|
@ -44,7 +47,8 @@ export const crudOptions = (vm) => {
|
|||
}
|
||||
}
|
||||
},
|
||||
indexRow: { // 或者直接传true,不显示title,不居中
|
||||
indexRow: {
|
||||
// 或者直接传true,不显示title,不居中
|
||||
title: '序号',
|
||||
align: 'center',
|
||||
width: 100
|
||||
|
|
@ -56,186 +60,235 @@ export const crudOptions = (vm) => {
|
|||
formOptions: {
|
||||
defaultSpan: 12 // 默认的表单 span
|
||||
},
|
||||
columns: [{
|
||||
title: '关键词',
|
||||
key: 'search',
|
||||
show: false,
|
||||
disabled: true,
|
||||
search: {
|
||||
disabled: false
|
||||
},
|
||||
form: {
|
||||
columns: [
|
||||
{
|
||||
title: '关键词',
|
||||
key: 'search',
|
||||
show: false,
|
||||
disabled: true,
|
||||
component: {
|
||||
props: {
|
||||
clearable: true
|
||||
search: {
|
||||
disabled: false
|
||||
},
|
||||
form: {
|
||||
disabled: true,
|
||||
component: {
|
||||
props: {
|
||||
clearable: true
|
||||
},
|
||||
placeholder: '请输入关键词'
|
||||
}
|
||||
},
|
||||
view: {
|
||||
// 查看对话框组件的单独配置
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'ID',
|
||||
key: 'id',
|
||||
show: false,
|
||||
disabled: true,
|
||||
width: 90,
|
||||
form: {
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
show: false,
|
||||
title: '上级部门',
|
||||
key: 'parent',
|
||||
type: 'tree-selector',
|
||||
dict: {
|
||||
isTree: true,
|
||||
label: 'name',
|
||||
value: 'id',
|
||||
cache: false,
|
||||
getData: (url, dict, { form, component }) => { // 配置此参数会覆盖全局的getRemoteDictFunc
|
||||
return api.DeptLazy().then(ret => { return ret.data })
|
||||
},
|
||||
placeholder: '请输入关键词'
|
||||
}
|
||||
},
|
||||
view: { // 查看对话框组件的单独配置
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'ID',
|
||||
key: 'id',
|
||||
show: false,
|
||||
disabled: true,
|
||||
width: 90,
|
||||
form: {
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '上级部门',
|
||||
key: 'parent',
|
||||
show: false,
|
||||
search: {
|
||||
disabled: true
|
||||
},
|
||||
type: 'cascader',
|
||||
dict: {
|
||||
cache: false,
|
||||
url: deptPrefix + '?limit=999&status=1',
|
||||
isTree: true,
|
||||
value: 'id', // 数据字典中value字段的属性名
|
||||
label: 'name', // 数据字典中label字段的属性名
|
||||
children: 'children', // 数据字典中children字段的属性名
|
||||
getData: (url, dict) => { // 配置此参数会覆盖全局的getRemoteDictFunc
|
||||
return request({ url: url }).then(ret => {
|
||||
const data = XEUtils.toArrayTree(ret.data.data, { parentKey: 'parent', strict: true })
|
||||
return [{ id: '0', name: '根节点', children: data }]
|
||||
})
|
||||
}
|
||||
},
|
||||
form: {
|
||||
component: {
|
||||
span: 12,
|
||||
|
||||
props: {
|
||||
elProps: {
|
||||
clearable: true,
|
||||
showAllLevels: false, // 仅显示最后一级
|
||||
props: {
|
||||
checkStrictly: true, // 可以不需要选到最后一级
|
||||
emitPath: false,
|
||||
clearable: true
|
||||
getNodes (values, data) {
|
||||
// 配置行展示远程获取nodes
|
||||
return new Promise((resolve, reject) => {
|
||||
const row = vm.getEditRow()
|
||||
resolve(row.parent !== null ? [{ name: row.parent_name, id: row.parent }] : [])
|
||||
})
|
||||
}
|
||||
},
|
||||
form: {
|
||||
helper: '默认留空为根节点',
|
||||
component: {
|
||||
span: 12,
|
||||
props: {
|
||||
multiple: false,
|
||||
elProps: {
|
||||
lazy: true,
|
||||
hasChild: 'has_children',
|
||||
load (node, resolve) {
|
||||
// 懒加载
|
||||
api.DeptLazy({ parent: node.data.id }).then((data) => {
|
||||
resolve(data.data)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '部门名称',
|
||||
key: 'name',
|
||||
sortable: true,
|
||||
treeNode: true, // 设置为树形列
|
||||
search: {
|
||||
disabled: false,
|
||||
component: {
|
||||
props: {
|
||||
clearable: true
|
||||
},
|
||||
// {
|
||||
// title: '上级部门',
|
||||
// key: 'parent',
|
||||
// show: false,
|
||||
// search: {
|
||||
// disabled: true
|
||||
// },
|
||||
// type: 'cascader',
|
||||
// dict: {
|
||||
// cache: false,
|
||||
// url: deptPrefix,
|
||||
// isTree: true,
|
||||
// value: 'id', // 数据字典中value字段的属性名
|
||||
// label: 'name', // 数据字典中label字段的属性名
|
||||
// children: 'children', // 数据字典中children字段的属性名
|
||||
// getData: (url, dict) => { // 配置此参数会覆盖全局的getRemoteDictFunc
|
||||
// return request({ url: url, params: { limit: 999, status: 1 } }).then(ret => {
|
||||
// const data = XEUtils.toArrayTree(ret.data.data, { parentKey: 'parent', strict: true })
|
||||
// return [{ id: null, name: '根节点', children: data }]
|
||||
// })
|
||||
// }
|
||||
// },
|
||||
// form: {
|
||||
// component: {
|
||||
// span: 12,
|
||||
|
||||
// props: {
|
||||
// elProps: {
|
||||
// clearable: true,
|
||||
// showAllLevels: false, // 仅显示最后一级
|
||||
// props: {
|
||||
// checkStrictly: true, // 可以不需要选到最后一级
|
||||
// emitPath: false,
|
||||
// clearable: true
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
{
|
||||
title: '部门名称',
|
||||
key: 'name',
|
||||
sortable: true,
|
||||
treeNode: true, // 设置为树形列
|
||||
search: {
|
||||
disabled: false,
|
||||
component: {
|
||||
props: {
|
||||
clearable: true
|
||||
}
|
||||
}
|
||||
},
|
||||
width: 180,
|
||||
type: 'input',
|
||||
form: {
|
||||
rules: [
|
||||
// 表单校验规则
|
||||
{ required: true, message: '部门名称必填项' }
|
||||
],
|
||||
component: {
|
||||
span: 12,
|
||||
props: {
|
||||
clearable: true
|
||||
},
|
||||
placeholder: '请输入部门名称'
|
||||
},
|
||||
itemProps: {
|
||||
class: { yxtInput: true }
|
||||
}
|
||||
}
|
||||
},
|
||||
width: 180,
|
||||
type: 'input',
|
||||
form: {
|
||||
rules: [ // 表单校验规则
|
||||
{ required: true, message: '部门名称必填项' }
|
||||
],
|
||||
component: {
|
||||
span: 12,
|
||||
props: {
|
||||
clearable: true
|
||||
},
|
||||
placeholder: '请输入部门名称'
|
||||
},
|
||||
itemProps: {
|
||||
class: { yxtInput: true }
|
||||
{
|
||||
title: '负责人',
|
||||
key: 'owner',
|
||||
sortable: true,
|
||||
form: {
|
||||
component: {
|
||||
span: 12,
|
||||
props: {
|
||||
clearable: true
|
||||
},
|
||||
placeholder: '请输入负责人'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '负责人',
|
||||
key: 'owner',
|
||||
sortable: true,
|
||||
form: {
|
||||
component: {
|
||||
span: 12,
|
||||
props: {
|
||||
clearable: true
|
||||
},
|
||||
placeholder: '请输入负责人'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '联系电话',
|
||||
key: 'phone',
|
||||
sortable: true,
|
||||
form: {
|
||||
component: {
|
||||
span: 12,
|
||||
props: {
|
||||
clearable: true
|
||||
},
|
||||
placeholder: '请输入联系电话'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '邮箱',
|
||||
key: 'email',
|
||||
sortable: true,
|
||||
form: {
|
||||
component: {
|
||||
span: 12,
|
||||
props: {
|
||||
clearable: true
|
||||
},
|
||||
placeholder: '请输入邮箱'
|
||||
},
|
||||
rules: [
|
||||
{ type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change'] }
|
||||
]
|
||||
}
|
||||
}, {
|
||||
title: '排序',
|
||||
key: 'sort',
|
||||
sortable: true,
|
||||
width: 80,
|
||||
type: 'number',
|
||||
form: {
|
||||
value: 1,
|
||||
component: {
|
||||
span: 12,
|
||||
placeholder: '请选择序号'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
key: 'status',
|
||||
sortable: true,
|
||||
search: {
|
||||
disabled: false
|
||||
},
|
||||
width: 90,
|
||||
type: 'radio',
|
||||
dict: {
|
||||
data: BUTTON_STATUS_BOOL
|
||||
{
|
||||
title: '联系电话',
|
||||
key: 'phone',
|
||||
sortable: true,
|
||||
form: {
|
||||
component: {
|
||||
span: 12,
|
||||
props: {
|
||||
clearable: true
|
||||
},
|
||||
placeholder: '请输入联系电话'
|
||||
}
|
||||
}
|
||||
},
|
||||
form: {
|
||||
value: true,
|
||||
component: {
|
||||
span: 12,
|
||||
placeholder: '请选择状态'
|
||||
{
|
||||
title: '邮箱',
|
||||
key: 'email',
|
||||
sortable: true,
|
||||
form: {
|
||||
component: {
|
||||
span: 12,
|
||||
props: {
|
||||
clearable: true
|
||||
},
|
||||
placeholder: '请输入邮箱'
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
type: 'email',
|
||||
message: '请输入正确的邮箱地址',
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
key: 'sort',
|
||||
sortable: true,
|
||||
width: 80,
|
||||
type: 'number',
|
||||
form: {
|
||||
value: 1,
|
||||
component: {
|
||||
span: 12,
|
||||
placeholder: '请选择序号'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
key: 'status',
|
||||
sortable: true,
|
||||
search: {
|
||||
disabled: false
|
||||
},
|
||||
width: 90,
|
||||
type: 'radio',
|
||||
dict: {
|
||||
data: vm.dictionary('button_status_bool')
|
||||
},
|
||||
form: {
|
||||
value: true,
|
||||
component: {
|
||||
span: 12,
|
||||
placeholder: '请选择状态'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
].concat(vm.commonEndColumns())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,3 @@
|
|||
<!--
|
||||
* @创建文件时间: 2021-06-01 22:41:21
|
||||
* @Auther: 猿小天
|
||||
* @最后修改人: 猿小天
|
||||
* @最后修改时间: 2021-07-31 22:35:15
|
||||
* 联系Qq:1638245306
|
||||
* @文件介绍: 部门管理
|
||||
-->
|
||||
<template>
|
||||
<d2-container :class="{ 'page-compact': crud.pageOptions.compact }">
|
||||
<!-- <template slot="header">测试页面1</template>-->
|
||||
|
|
@ -52,6 +44,7 @@ export default {
|
|||
return crudOptions(this)
|
||||
},
|
||||
pageRequest (query) {
|
||||
query.lazy = true
|
||||
return api.GetList(query)
|
||||
},
|
||||
addRequest (row) {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,3 @@
|
|||
/*
|
||||
* @创建文件时间: 2021-06-01 22:41:21
|
||||
* @Auther: 猿小天
|
||||
* @最后修改人: 猿小天
|
||||
* @最后修改时间: 2021-08-09 20:21:47
|
||||
* 联系Qq:1638245306
|
||||
* @文件介绍: 字典管理接口
|
||||
*/
|
||||
import { request } from '@/api/service'
|
||||
import XEUtils from 'xe-utils'
|
||||
export const urlPrefix = '/api/system/dictionary/'
|
||||
|
|
@ -14,7 +6,6 @@ export const urlPrefix = '/api/system/dictionary/'
|
|||
* 列表查询
|
||||
*/
|
||||
export function GetList (query) {
|
||||
query.limit = 999
|
||||
return request({
|
||||
url: urlPrefix,
|
||||
method: 'get',
|
||||
|
|
|
|||
|
|
@ -1,8 +1,3 @@
|
|||
import { request } from '@/api/service'
|
||||
import { BUTTON_STATUS_NUMBER } from '@/config/button'
|
||||
import { urlPrefix as dictionaryPrefix } from './api'
|
||||
import XEUtils from 'xe-utils'
|
||||
|
||||
export const crudOptions = (vm) => {
|
||||
return {
|
||||
|
||||
|
|
@ -22,7 +17,7 @@ export const crudOptions = (vm) => {
|
|||
}
|
||||
},
|
||||
rowHandle: {
|
||||
width: 140,
|
||||
width: 230,
|
||||
view: {
|
||||
thin: true,
|
||||
text: '',
|
||||
|
|
@ -43,12 +38,18 @@ export const crudOptions = (vm) => {
|
|||
disabled () {
|
||||
return !vm.hasPermissions('Delete')
|
||||
}
|
||||
}
|
||||
},
|
||||
custom: [{
|
||||
text: ' 字典配置',
|
||||
type: 'success',
|
||||
size: 'small',
|
||||
emit: 'dictionaryConfigure'
|
||||
}]
|
||||
},
|
||||
indexRow: { // 或者直接传true,不显示title,不居中
|
||||
title: '序号',
|
||||
align: 'center',
|
||||
width: 100
|
||||
width: 80
|
||||
},
|
||||
viewOptions: {
|
||||
componentType: 'form'
|
||||
|
|
@ -89,77 +90,8 @@ export const crudOptions = (vm) => {
|
|||
}
|
||||
},
|
||||
{
|
||||
title: '父级字典',
|
||||
key: 'parent',
|
||||
show: false,
|
||||
search: {
|
||||
disabled: true
|
||||
},
|
||||
type: 'cascader',
|
||||
dict: {
|
||||
cache: false,
|
||||
url: dictionaryPrefix + '?status=1&limit=999',
|
||||
isTree: true,
|
||||
value: 'id', // 数据字典中value字段的属性名
|
||||
label: 'label', // 数据字典中label字段的属性名
|
||||
children: 'children', // 数据字典中children字段的属性名
|
||||
getData: (url, dict) => { // 配置此参数会覆盖全局的getRemoteDictFunc
|
||||
return request({ url: url }).then(ret => {
|
||||
return [{ id: null, label: '根节点', children: XEUtils.toArrayTree(ret.data.data, { parentKey: 'parent', strict: true }) }]
|
||||
})
|
||||
}
|
||||
|
||||
},
|
||||
form: {
|
||||
component: {
|
||||
props: {
|
||||
elProps: {
|
||||
clearable: true,
|
||||
showAllLevels: false, // 仅显示最后一级
|
||||
props: {
|
||||
checkStrictly: true, // 可以不需要选到最后一级
|
||||
emitPath: false,
|
||||
clearable: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '编码',
|
||||
key: 'code',
|
||||
sortable: true,
|
||||
treeNode: true,
|
||||
search: {
|
||||
disabled: true,
|
||||
component: {
|
||||
props: {
|
||||
clearable: true
|
||||
}
|
||||
}
|
||||
},
|
||||
type: 'input',
|
||||
form: {
|
||||
editDisabled: true,
|
||||
rules: [ // 表单校验规则
|
||||
{ required: true, message: '编码必填项' }
|
||||
],
|
||||
component: {
|
||||
props: {
|
||||
clearable: true
|
||||
},
|
||||
placeholder: '请输入编码'
|
||||
},
|
||||
itemProps: {
|
||||
class: { yxtInput: true }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '显示值',
|
||||
title: '字典名称',
|
||||
key: 'label',
|
||||
sortable: true,
|
||||
|
||||
search: {
|
||||
disabled: false,
|
||||
|
|
@ -173,13 +105,13 @@ export const crudOptions = (vm) => {
|
|||
type: 'input',
|
||||
form: {
|
||||
rules: [ // 表单校验规则
|
||||
{ required: true, message: '显示值必填项' }
|
||||
{ required: true, message: '字典名称必填项' }
|
||||
],
|
||||
component: {
|
||||
props: {
|
||||
clearable: true
|
||||
},
|
||||
placeholder: '请输入显示值'
|
||||
placeholder: '请输入字典名称'
|
||||
},
|
||||
itemProps: {
|
||||
class: { yxtInput: true }
|
||||
|
|
@ -187,10 +119,8 @@ export const crudOptions = (vm) => {
|
|||
}
|
||||
},
|
||||
{
|
||||
title: '实际值',
|
||||
title: '字典编号',
|
||||
key: 'value',
|
||||
sortable: true,
|
||||
|
||||
search: {
|
||||
disabled: true,
|
||||
component: {
|
||||
|
|
@ -199,20 +129,25 @@ export const crudOptions = (vm) => {
|
|||
}
|
||||
}
|
||||
},
|
||||
|
||||
type: 'input',
|
||||
form: {
|
||||
rules: [ // 表单校验规则
|
||||
{ required: true, message: '实际值必填项' }
|
||||
{ required: true, message: '字典编号必填项' }
|
||||
],
|
||||
component: {
|
||||
props: {
|
||||
clearable: true
|
||||
},
|
||||
placeholder: '请输入实际值'
|
||||
placeholder: '请输入字典编号'
|
||||
},
|
||||
itemProps: {
|
||||
class: { yxtInput: true }
|
||||
},
|
||||
helper: {
|
||||
render (h) {
|
||||
return (< el-alert title="使用方法:vm.dictionary('字典编号')" type="warning"/>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -220,33 +155,51 @@ export const crudOptions = (vm) => {
|
|||
{
|
||||
title: '状态',
|
||||
key: 'status',
|
||||
sortable: true,
|
||||
width: 90,
|
||||
search: {
|
||||
disabled: false
|
||||
},
|
||||
|
||||
type: 'radio',
|
||||
dict: {
|
||||
data: BUTTON_STATUS_NUMBER
|
||||
data: vm.dictionary('button_status_bool')
|
||||
},
|
||||
component: {
|
||||
props: {
|
||||
options: []
|
||||
}
|
||||
},
|
||||
form: {
|
||||
value: 1,
|
||||
rules: [ // 表单校验规则
|
||||
{ required: true, message: '状态必填项' }
|
||||
],
|
||||
value: true,
|
||||
component: {
|
||||
placeholder: '请选择状态'
|
||||
},
|
||||
itemProps: {
|
||||
class: { yxtInput: true }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
key: 'sort',
|
||||
sortable: true,
|
||||
|
||||
width: 90,
|
||||
type: 'number',
|
||||
form: {
|
||||
value: 1,
|
||||
component: {
|
||||
},
|
||||
itemProps: {
|
||||
class: { yxtInput: true }
|
||||
}
|
||||
}
|
||||
}
|
||||
].concat(vm.commonEndColumns())
|
||||
].concat(vm.commonEndColumns({
|
||||
description: {
|
||||
showForm: true,
|
||||
showTable: true
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
<template>
|
||||
<d2-container :class="{ 'page-compact': crud.pageOptions.compact }">
|
||||
<!-- <template slot="header">测试页面1</template>-->
|
||||
<d2-crud-x ref="d2Crud" v-bind="_crudProps" v-on="_crudListeners">
|
||||
<d2-crud-x ref="d2Crud" v-bind="_crudProps" v-on="_crudListeners" @dictionaryConfigure="dictionaryConfigure">
|
||||
<div slot="header">
|
||||
<crud-search
|
||||
ref="search"
|
||||
|
|
@ -30,6 +30,15 @@
|
|||
/>
|
||||
</div>
|
||||
</d2-crud-x>
|
||||
<el-drawer
|
||||
:visible.sync="drawer"
|
||||
:size="700">
|
||||
<div slot="title">
|
||||
<span>字典列表</span>
|
||||
<el-tag size="small" style="margin-left: 10px">{{dictionaryRow.label}}</el-tag>
|
||||
</div>
|
||||
<sub-dictionary style="margin-top: 80px;margin-left: 10px" :dictionaryRow="dictionaryRow"></sub-dictionary>
|
||||
</el-drawer>
|
||||
</d2-container>
|
||||
</template>
|
||||
|
||||
|
|
@ -37,17 +46,23 @@
|
|||
import * as api from './api'
|
||||
import { crudOptions } from './crud'
|
||||
import { d2CrudPlus } from 'd2-crud-plus'
|
||||
import SubDictionary from '@/views/system/dictionary/subDictionary/index'
|
||||
export default {
|
||||
name: 'dictionary',
|
||||
components: { SubDictionary },
|
||||
mixins: [d2CrudPlus.crud],
|
||||
data () {
|
||||
return {}
|
||||
return {
|
||||
drawer: false,
|
||||
dictionaryRow: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getCrudOptions () {
|
||||
return crudOptions(this)
|
||||
},
|
||||
pageRequest (query) {
|
||||
query.is_value = false
|
||||
return api.GetList(query)
|
||||
},
|
||||
addRequest (row) {
|
||||
|
|
@ -61,13 +76,10 @@ export default {
|
|||
delRequest (row) {
|
||||
return api.DelObj(row.id)
|
||||
},
|
||||
// 授权
|
||||
createPermission (scope) {
|
||||
this.$router.push({
|
||||
name: 'menuButton',
|
||||
params: { id: scope.row.id },
|
||||
query: { name: scope.row.name }
|
||||
})
|
||||
// 字典配置
|
||||
dictionaryConfigure (scope) {
|
||||
this.drawer = true
|
||||
this.dictionaryRow = scope.row
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +1,24 @@
|
|||
/*
|
||||
* @创建文件时间: 2021-06-01 22:41:21
|
||||
* @Auther: 猿小天
|
||||
* @最后修改人: 猿小天
|
||||
* @最后修改时间: 2021-07-04 22:39:11
|
||||
* 联系Qq:1638245306
|
||||
* @文件介绍: 权限管理接口
|
||||
*/
|
||||
import { request } from '@/api/service'
|
||||
import XEUtils from 'xe-utils'
|
||||
export const urlPrefix = '/api/system/dictionary/'
|
||||
|
||||
export const urlPrefix = '/api/system/button/'
|
||||
|
||||
/**
|
||||
* 列表查询
|
||||
*/
|
||||
export function GetList (query) {
|
||||
return request({
|
||||
url: urlPrefix,
|
||||
method: 'get',
|
||||
data: query
|
||||
params: query
|
||||
}).then(res => {
|
||||
// 将列表数据转换为树形数据
|
||||
res.data.data = XEUtils.toArrayTree(res.data.data, { parentKey: 'parent' })
|
||||
return res
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
export function createObj (obj) {
|
||||
return request({
|
||||
url: urlPrefix,
|
||||
|
|
@ -25,6 +27,9 @@ export function createObj (obj) {
|
|||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改
|
||||
*/
|
||||
export function UpdateObj (obj) {
|
||||
return request({
|
||||
url: urlPrefix + obj.id + '/',
|
||||
|
|
@ -32,6 +37,9 @@ export function UpdateObj (obj) {
|
|||
data: obj
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 删除
|
||||
*/
|
||||
export function DelObj (id) {
|
||||
return request({
|
||||
url: urlPrefix + id + '/',
|
||||
|
|
@ -0,0 +1,304 @@
|
|||
export const crudOptions = (vm) => {
|
||||
return {
|
||||
|
||||
pageOptions: {
|
||||
compact: true
|
||||
},
|
||||
options: {
|
||||
rowId: 'id',
|
||||
height: '100%', // 表格高度100%, 使用toolbar必须设置
|
||||
border: false
|
||||
},
|
||||
rowHandle: {
|
||||
width: 140,
|
||||
view: {
|
||||
thin: true,
|
||||
text: '',
|
||||
disabled () {
|
||||
return !vm.hasPermissions('Retrieve')
|
||||
}
|
||||
},
|
||||
edit: {
|
||||
thin: true,
|
||||
text: '',
|
||||
disabled () {
|
||||
return !vm.hasPermissions('Update')
|
||||
}
|
||||
},
|
||||
remove: {
|
||||
thin: true,
|
||||
text: '',
|
||||
disabled () {
|
||||
return !vm.hasPermissions('Delete')
|
||||
}
|
||||
}
|
||||
},
|
||||
viewOptions: {
|
||||
componentType: 'form'
|
||||
},
|
||||
formOptions: {
|
||||
appendToBody: true, // 子表格必须 否则弹出对话框无法显示最顶层
|
||||
defaultSpan: 24, // 默认的表单 span
|
||||
width: '35%'
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
title: '名称',
|
||||
key: 'label',
|
||||
|
||||
search: {
|
||||
disabled: false,
|
||||
component: {
|
||||
props: {
|
||||
clearable: true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
type: 'input',
|
||||
form: {
|
||||
rules: [ // 表单校验规则
|
||||
{ required: true, message: '名称必填项' }
|
||||
],
|
||||
component: {
|
||||
props: {
|
||||
clearable: true
|
||||
},
|
||||
placeholder: '请输入名称'
|
||||
},
|
||||
itemProps: {
|
||||
class: { yxtInput: true }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '数据值类型',
|
||||
type: 'select',
|
||||
key: 'type',
|
||||
search: {
|
||||
disabled: true,
|
||||
component: {
|
||||
props: {
|
||||
clearable: true
|
||||
}
|
||||
}
|
||||
},
|
||||
show: false,
|
||||
dict: {
|
||||
data: [
|
||||
{ label: 'text', value: 0 },
|
||||
{ label: 'number', value: 1 },
|
||||
{ label: 'date', value: 2 },
|
||||
{ label: 'datetime', value: 3 },
|
||||
{ label: 'time', value: 4 },
|
||||
{ label: 'file', value: 5 },
|
||||
{ label: 'boolean', value: 6 },
|
||||
{ label: 'images', value: 7 }
|
||||
]
|
||||
},
|
||||
form: {
|
||||
rules: [ // 表单校验规则
|
||||
{ required: true, message: '数据值类型必填项' }
|
||||
],
|
||||
value: 0,
|
||||
component: {
|
||||
props: {
|
||||
clearable: true
|
||||
},
|
||||
placeholder: '请选择数据值类型'
|
||||
},
|
||||
itemProps: {
|
||||
class: { yxtInput: true }
|
||||
},
|
||||
valueChange (key, value, form, { getColumn, mode, component, immediate, getComponent }) {
|
||||
const template = vm.getEditFormTemplate('value')
|
||||
// 选择框重新选择后,情况value值
|
||||
if (!immediate) {
|
||||
form.value = undefined
|
||||
}
|
||||
if (value === 0) {
|
||||
template.component.name = 'el-input'
|
||||
} else if (value === 1) {
|
||||
template.component.name = 'el-input-number'
|
||||
} else if (value === 2) {
|
||||
template.component.name = 'el-date-picker'
|
||||
template.component.props = {
|
||||
type: 'date',
|
||||
valueFormat: 'yyyy-MM-dd'
|
||||
}
|
||||
} else if (value === 3) {
|
||||
template.component.name = 'el-date-picker'
|
||||
template.component.props = {
|
||||
type: 'datetime',
|
||||
valueFormat: 'yyyy-MM-dd HH:mm:ss'
|
||||
}
|
||||
} else if (value === 4) {
|
||||
template.component.name = 'el-time-picker'
|
||||
template.component.props = {
|
||||
pickerOptions: {
|
||||
arrowControl: true
|
||||
},
|
||||
valueFormat: 'HH:mm:ss'
|
||||
}
|
||||
} else if (value === 5) {
|
||||
template.component.name = 'd2p-file-uploader'
|
||||
template.component.props = { elProps: { listType: 'text' } }
|
||||
} else if (value === 6) {
|
||||
template.component.name = 'dict-switch'
|
||||
template.component.value = true
|
||||
template.component.props = {
|
||||
dict: {
|
||||
data: [
|
||||
{ label: '是', value: 'true' },
|
||||
{ label: '否', value: 'false' }
|
||||
]
|
||||
}
|
||||
}
|
||||
} else if (value === 7) {
|
||||
template.component.name = 'd2p-cropper-uploader'
|
||||
template.component.props = { accept: '.png,.jpeg,.jpg,.ico,.bmp,.gif', cropper: { viewMode: 1 } }
|
||||
}
|
||||
},
|
||||
valueChangeImmediate: true
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '数据值',
|
||||
key: 'value',
|
||||
search: {
|
||||
disabled: true,
|
||||
component: {
|
||||
props: {
|
||||
clearable: true
|
||||
}
|
||||
}
|
||||
},
|
||||
view: {
|
||||
component: { props: { height: 100, width: 100 } }
|
||||
},
|
||||
// 提交时,处理数据
|
||||
valueResolve (row, col) {
|
||||
const value = row[col.key]
|
||||
const type = row.type
|
||||
if (type === 5 || type === 7) {
|
||||
if (value != null) {
|
||||
if (value.length >= 0) {
|
||||
if (value instanceof Array) {
|
||||
row[col.key] = value.toString()
|
||||
} else {
|
||||
row[col.key] = value
|
||||
}
|
||||
} else {
|
||||
row[col.key] = null
|
||||
}
|
||||
}
|
||||
} else {
|
||||
row[col.key] = value
|
||||
}
|
||||
},
|
||||
// 接收时,处理数据
|
||||
valueBuilder (row, col) {
|
||||
const value = row[col.key]
|
||||
const type = row.type
|
||||
if (type === 5 || type === 7) {
|
||||
if (value != null && value) {
|
||||
row[col.key] = value.split(',')
|
||||
}
|
||||
} else {
|
||||
row[col.key] = value
|
||||
}
|
||||
},
|
||||
type: 'input',
|
||||
form: {
|
||||
rules: [ // 表单校验规则
|
||||
{ required: true, message: '数据值必填项' }
|
||||
],
|
||||
component: {
|
||||
props: {
|
||||
clearable: true
|
||||
},
|
||||
placeholder: '请输入数据值'
|
||||
},
|
||||
itemProps: {
|
||||
class: { yxtInput: true }
|
||||
}
|
||||
}
|
||||
}, {
|
||||
title: '状态',
|
||||
key: 'status',
|
||||
width: 80,
|
||||
search: {
|
||||
disabled: false
|
||||
},
|
||||
type: 'radio',
|
||||
dict: {
|
||||
data: vm.dictionary('button_status_bool')
|
||||
},
|
||||
form: {
|
||||
value: true,
|
||||
rules: [ // 表单校验规则
|
||||
{ required: true, message: '状态必填项' }
|
||||
],
|
||||
component: {
|
||||
},
|
||||
itemProps: {
|
||||
class: { yxtInput: true }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
key: 'sort',
|
||||
width: 70,
|
||||
type: 'number',
|
||||
form: {
|
||||
value: 1,
|
||||
component: {
|
||||
},
|
||||
rules: [ // 表单校验规则
|
||||
{ required: true, message: '排序必填项' }
|
||||
],
|
||||
itemProps: {
|
||||
class: { yxtInput: true }
|
||||
}
|
||||
}
|
||||
}, {
|
||||
title: '标签颜色',
|
||||
key: 'color',
|
||||
width: 90,
|
||||
search: {
|
||||
disabled: true
|
||||
},
|
||||
type: 'select',
|
||||
dict: {
|
||||
data: [
|
||||
{ label: 'success', value: 'success', color: 'success' },
|
||||
{ label: 'primary', value: 'primary', color: 'primary' },
|
||||
{ label: 'info', value: 'info', color: 'info' },
|
||||
{ label: 'danger', value: 'danger', color: 'danger' },
|
||||
{ label: 'warning', value: 'warning', color: 'warning' }
|
||||
]
|
||||
},
|
||||
form: {
|
||||
component: {
|
||||
props: {
|
||||
clearable: true
|
||||
}
|
||||
},
|
||||
itemProps: {
|
||||
class: { yxtInput: true }
|
||||
}
|
||||
}
|
||||
}
|
||||
].concat(vm.commonEndColumns({
|
||||
update_datetime: {
|
||||
showForm: false,
|
||||
showTable: false
|
||||
},
|
||||
create_datetime: {
|
||||
showForm: false,
|
||||
showTable: false
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +1,6 @@
|
|||
<!--
|
||||
* @创建文件时间: 2021-06-01 22:41:21
|
||||
* @Auther: 猿小天
|
||||
* @最后修改人: 猿小天
|
||||
* @最后修改时间: 2021-07-29 22:17:28
|
||||
* 联系Qq:1638245306
|
||||
* @文件介绍:
|
||||
-->
|
||||
<template>
|
||||
<d2-container :class="{ 'page-compact': crud.pageOptions.compact }">
|
||||
<!-- <template slot="header">测试页面1</template>-->
|
||||
<d2-crud-x
|
||||
ref="d2Crud"
|
||||
v-bind="_crudProps"
|
||||
v-on="_crudListeners"
|
||||
@createPermission="createPermission"
|
||||
>
|
||||
<d2-container>
|
||||
<d2-crud-x ref="d2Crud" v-bind="_crudProps" v-on="_crudListeners">
|
||||
<div slot="header">
|
||||
<crud-search
|
||||
ref="search"
|
||||
|
|
@ -22,11 +8,7 @@
|
|||
@submit="handleSearch"
|
||||
/>
|
||||
<el-button-group>
|
||||
<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
v-permission="'Create'"
|
||||
@click="addRow"
|
||||
<el-button size="small" type="primary" @click="addRow"
|
||||
><i class="el-icon-plus" /> 新增</el-button
|
||||
>
|
||||
</el-button-group>
|
||||
|
|
@ -47,41 +29,53 @@ import * as api from './api'
|
|||
import { crudOptions } from './crud'
|
||||
import { d2CrudPlus } from 'd2-crud-plus'
|
||||
export default {
|
||||
name: 'buttons',
|
||||
name: 'subDictionary',
|
||||
mixins: [d2CrudPlus.crud],
|
||||
props: {
|
||||
// 容器样式
|
||||
dictionaryRow: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
dictionaryRow () {
|
||||
this.doRefresh({ from: 'load' })
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {}
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getCrudOptions () {
|
||||
return crudOptions(this)
|
||||
},
|
||||
pageRequest (query) {
|
||||
query.is_value = true
|
||||
query.parent = this.dictionaryRow.id
|
||||
return api.GetList(query)
|
||||
},
|
||||
addRequest (row) {
|
||||
console.log('api', api)
|
||||
d2CrudPlus.util.dict.clear()
|
||||
row.is_value = true
|
||||
row.parent = this.dictionaryRow.id
|
||||
return api.createObj(row)
|
||||
},
|
||||
updateRequest (row) {
|
||||
console.log('----', row)
|
||||
d2CrudPlus.util.dict.clear()
|
||||
row.is_value = true
|
||||
row.parent = this.dictionaryRow.id
|
||||
return api.UpdateObj(row)
|
||||
},
|
||||
delRequest (row) {
|
||||
return api.DelObj(row.id)
|
||||
},
|
||||
// 授权
|
||||
createPermission (scope) {
|
||||
console.log('custom btn:', scope)
|
||||
this.$message(
|
||||
'自定义操作按钮:' + scope.row.data + ',index:' + scope.index
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
.yxtInput {
|
||||
.el-form-item__label {
|
||||
color: #49a1ff;
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
import util from '@/libs/util'
|
||||
|
||||
export const crudOptions = (vm) => {
|
||||
return {
|
||||
pageOptions: {
|
||||
|
|
@ -92,11 +90,7 @@ export const crudOptions = (vm) => {
|
|||
search: {
|
||||
disabled: true
|
||||
},
|
||||
width: 220,
|
||||
valueBuilder (row, key) {
|
||||
console.log(row, key)
|
||||
row.url = `${util.baseURL()}media/${row.url}`
|
||||
}
|
||||
width: 220
|
||||
},
|
||||
{
|
||||
title: '文件MD5',
|
||||
|
|
@ -107,18 +101,7 @@ export const crudOptions = (vm) => {
|
|||
},
|
||||
form: {
|
||||
disabled: false
|
||||
},
|
||||
valueResolve (row, col) {
|
||||
const value = row[col.key]
|
||||
if (value != null && value instanceof Array) {
|
||||
if (value.length >= 0) {
|
||||
row[col.key] = value[0]
|
||||
} else {
|
||||
row[col.key] = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ export const crudOptions = (vm) => {
|
|||
type: 'input',
|
||||
form: {
|
||||
component: {
|
||||
placeholder: '请输入操作系统'
|
||||
placeholder: '请输入运营商'
|
||||
}
|
||||
}
|
||||
}, {
|
||||
|
|
@ -126,7 +126,7 @@ export const crudOptions = (vm) => {
|
|||
form: {
|
||||
disabled: true,
|
||||
component: {
|
||||
placeholder: '请输入州'
|
||||
placeholder: '请输入大州'
|
||||
}
|
||||
},
|
||||
component: { props: { color: 'auto' } } // 自动染色
|
||||
|
|
@ -265,7 +265,7 @@ export const crudOptions = (vm) => {
|
|||
type: 'input',
|
||||
form: {
|
||||
component: {
|
||||
placeholder: '请输入操作系统'
|
||||
placeholder: '请输入浏览器名'
|
||||
}
|
||||
}
|
||||
}, {
|
||||
|
|
@ -276,7 +276,7 @@ export const crudOptions = (vm) => {
|
|||
type: 'input',
|
||||
form: {
|
||||
component: {
|
||||
placeholder: '请输入操作系统'
|
||||
placeholder: '请输入agent信息'
|
||||
}
|
||||
}
|
||||
}, {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,3 @@
|
|||
/*
|
||||
* @创建文件时间: 2021-06-02 10:33:33
|
||||
* @Auther: 猿小天
|
||||
* @最后修改人: 猿小天
|
||||
* @最后修改时间: 2021-08-12 22:53:38
|
||||
* 联系Qq:1638245306
|
||||
* @文件介绍: 登录的接口
|
||||
*/
|
||||
|
||||
import { request } from '@/api/service'
|
||||
|
||||
export function SYS_USER_LOGIN (data) {
|
||||
|
|
@ -31,3 +22,10 @@ export function getCaptcha () {
|
|||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function getCaptchaStatus () {
|
||||
return request({
|
||||
url: 'api/captcha/status/',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,239 @@
|
|||
<template>
|
||||
<div class="page-login"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions } from 'vuex'
|
||||
import localeMixin from '@/locales/mixin.js'
|
||||
import * as api from '@/views/system/login/api'
|
||||
|
||||
export default {
|
||||
mixins: [localeMixin],
|
||||
beforeCreate () {
|
||||
// 初始化配置
|
||||
this.$store.dispatch('d2admin/settings/init')
|
||||
},
|
||||
data () {
|
||||
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',
|
||||
backgroundImage: 'url(' + this.loginBackground + ')',
|
||||
// 表单
|
||||
formLogin: {
|
||||
username: '',
|
||||
password: '',
|
||||
captcha: ''
|
||||
},
|
||||
// 表单校验
|
||||
rules: {
|
||||
username: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入用户名',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
password: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入密码',
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
},
|
||||
captchaKey: null,
|
||||
image_base: null,
|
||||
// 快速登录,用于dev开发环境
|
||||
selectUsersDialogVisible: false,
|
||||
users: [
|
||||
{
|
||||
name: '超管',
|
||||
username: 'superadmin',
|
||||
password: 'admin123456'
|
||||
},
|
||||
{
|
||||
name: '管理员',
|
||||
username: 'admin',
|
||||
password: 'admin123456'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
beforeDestroy () {
|
||||
},
|
||||
methods: {
|
||||
...mapActions('d2admin/account', ['login']),
|
||||
/**
|
||||
* 获取验证码
|
||||
*/
|
||||
getCaptcha () {
|
||||
if (this.captchaState !== undefined && !this.captchaState) return
|
||||
api.getCaptcha().then((ret) => {
|
||||
this.formLogin.captcha = null
|
||||
this.captchaKey = ret.data.key
|
||||
this.image_base = ret.data.image_base
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @description 提交表单
|
||||
*/
|
||||
// 提交登录信息
|
||||
submit () {
|
||||
const that = this
|
||||
this.$refs.loginForm.validate((valid) => {
|
||||
if (valid) {
|
||||
// 登录
|
||||
// 注意 这里的演示没有传验证码
|
||||
// 具体需要传递的数据请自行修改代码
|
||||
this.login({
|
||||
username: that.formLogin.username,
|
||||
password: that.$md5(that.formLogin.password),
|
||||
captcha: that.formLogin.captcha,
|
||||
captchaKey: that.captchaKey
|
||||
})
|
||||
.then(() => {
|
||||
// 重定向对象不存在则返回顶层路径
|
||||
this.$router.replace(this.$route.query.redirect || '/')
|
||||
})
|
||||
.catch(() => {
|
||||
this.getCaptcha()
|
||||
})
|
||||
} else {
|
||||
// 登录表单校验失败
|
||||
this.$message.error('表单校验失败,请检查')
|
||||
}
|
||||
})
|
||||
},
|
||||
// 快速登录
|
||||
handleUserBtnClick (user) {
|
||||
this.formLogin.username = user.username
|
||||
this.formLogin.password = user.password
|
||||
// this.submit()
|
||||
this.selectUsersDialogVisible = false
|
||||
if (!this.captchaState) {
|
||||
this.submit()
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.$store.dispatch('d2admin/db/databaseClear')
|
||||
this.getCaptcha()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// ----
|
||||
.page-login {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-image: url(./image/bg.jpg);
|
||||
background-position: center 0;
|
||||
background-repeat: no-repeat;
|
||||
background-attachment: fixed;
|
||||
background-size: cover;
|
||||
-webkit-background-size: cover; /* 兼容Webkit内核浏览器如Chrome和Safari */
|
||||
-o-background-size: cover; /* 兼容Opera */
|
||||
zoom: 1;
|
||||
}
|
||||
|
||||
::v-deep .el-card__body {
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border-radius: 30px;
|
||||
padding: 0;
|
||||
margin-top: 12%;
|
||||
}
|
||||
|
||||
.right-card {
|
||||
float: right;
|
||||
text-align: center;
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.right-card h1 {
|
||||
color: #098dee;
|
||||
margin-bottom: 40px;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.button-login {
|
||||
width: 100%;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
::v-deep .el-input-group__append {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
// footer
|
||||
.page-login--content-footer {
|
||||
margin-top: 10%;
|
||||
padding: 1em 0;
|
||||
|
||||
.page-login--content-footer-locales {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
margin-bottom: 15px;
|
||||
font-size: 12px;
|
||||
line-height: 12px;
|
||||
text-align: center;
|
||||
color: $color-text-normal;
|
||||
|
||||
a {
|
||||
color: $color-text-normal;
|
||||
margin: 0 0.5em;
|
||||
|
||||
&:hover {
|
||||
color: $color-text-main;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.page-login--content-footer-copyright {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 12px;
|
||||
line-height: 12px;
|
||||
text-align: center;
|
||||
color: $color-text-normal;
|
||||
|
||||
a {
|
||||
color: $color-text-normal;
|
||||
}
|
||||
}
|
||||
|
||||
.page-login--content-footer-options {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
font-size: 12px;
|
||||
line-height: 12px;
|
||||
text-align: center;
|
||||
|
||||
a {
|
||||
color: $color-text-normal;
|
||||
margin: 0 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,557 @@
|
|||
/*--
|
||||
Author: W3layouts
|
||||
Author URL: http://w3layouts.com
|
||||
--*/
|
||||
|
||||
/* reset code */
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body,
|
||||
html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: #585858;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
font-family: 'Kumbh Sans', sans-serif;
|
||||
}
|
||||
|
||||
/* wrapper */
|
||||
.wrapper {
|
||||
width: 100%;
|
||||
padding-right: 15px;
|
||||
padding-left: 15px;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
@media (min-width: 576px) {
|
||||
.wrapper {
|
||||
max-width: 540px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.wrapper {
|
||||
max-width: 720px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.wrapper {
|
||||
max-width: 960px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.wrapper {
|
||||
max-width: 1280px;
|
||||
}
|
||||
}
|
||||
|
||||
/* /wrapper */
|
||||
|
||||
.d-grid {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
button,
|
||||
input,
|
||||
select {
|
||||
-webkit-appearance: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
button,
|
||||
.btn,
|
||||
select {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
p,
|
||||
ul,
|
||||
ol {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
background: #f1f1f1;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
form,
|
||||
fieldset {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
.login-code{
|
||||
max-width: 400px;
|
||||
}
|
||||
.el-input-group__append, .el-input-group__prepend{
|
||||
padding: 0;
|
||||
}
|
||||
.page-login--logo{
|
||||
margin: 0 auto;
|
||||
top: 10px;
|
||||
left: 52%;
|
||||
position: absolute;
|
||||
}
|
||||
/*-- //Reset-Code --*/
|
||||
|
||||
/*-- form styling --*/
|
||||
.w3l-form-info {
|
||||
padding-top: 6em;
|
||||
}
|
||||
.w3l-signinform{
|
||||
padding: 40px 40px;
|
||||
min-height: 100vh;
|
||||
background-size: cover;
|
||||
-webkit-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-ms-background-size: cover;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
align-items:center;
|
||||
}
|
||||
.w3l-signinform::before{
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
min-height: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
|
||||
.btn-block {
|
||||
display: block;
|
||||
width: 50%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.btn:active {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
color: #232005;
|
||||
background-color: #ffd900;
|
||||
margin-top: 30px;
|
||||
outline: none;
|
||||
width: 100%;
|
||||
padding: 15px 15px;
|
||||
cursor: pointer;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
border-radius:6px;
|
||||
-webkit-border-radius:6px;
|
||||
-moz-border-radius:6px;
|
||||
-ms-border-radius:6px;
|
||||
-o-border-radius:6px;
|
||||
border: none;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color:#eac803;
|
||||
}
|
||||
|
||||
.form-row.bottom {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.form-row .form-check input[type="checkbox"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.form-row .form-check input[type="checkbox"]+label:before {
|
||||
border-radius: 3px;
|
||||
border: 1px solid #e2e2e2;
|
||||
color: transparent;
|
||||
content: "\2714";
|
||||
display: inline-block;
|
||||
height: 18px;
|
||||
margin-right: 5px;
|
||||
transition: 0.2s;
|
||||
vertical-align: inherit;
|
||||
width: 18px;
|
||||
text-align: center;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.form-row .form-check input[type="checkbox"]:checked+label:before {
|
||||
background-color: #ffd900;
|
||||
border-color: #ffd900;
|
||||
color: #232005;
|
||||
}
|
||||
|
||||
.form-row .form-check input[type="checkbox"]+label {
|
||||
cursor: pointer;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.w3_info h2 {
|
||||
display: inline-block;
|
||||
font-size: 24px;
|
||||
line-height: 35px;
|
||||
margin-bottom: 20px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.w3_info h4 {
|
||||
display: inline-block;
|
||||
font-size: 15px;
|
||||
padding: 8px 0px;
|
||||
color: #444;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
.w3_info h1 {
|
||||
font-size: 36px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
margin-bottom: 0.4em;
|
||||
line-height: 40px;
|
||||
}
|
||||
.w3_info {
|
||||
padding: 1em 1em;
|
||||
background: transparent;
|
||||
max-width: 450px;
|
||||
display: grid;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.left_grid_info {
|
||||
padding: 6em 0;
|
||||
}
|
||||
.w3l_form {
|
||||
padding: 0px;
|
||||
flex-basis: 50%;
|
||||
-webkit-flex-basis: 50%;
|
||||
background: #dad1f8;
|
||||
}
|
||||
/*.w3_info p {*/
|
||||
/* padding-bottom: 30px;*/
|
||||
/* text-align: center;*/
|
||||
/*}*/
|
||||
/*.w3_info p.sub-para {*/
|
||||
/* padding-bottom: 40px;*/
|
||||
/* text-align:left;*/
|
||||
/* color:#fff;*/
|
||||
/* opacity:0.9;*/
|
||||
/* line-height:28px;*/
|
||||
/*}*/
|
||||
p.account,
|
||||
p.account a {
|
||||
text-align: center;
|
||||
padding-top: 20px;
|
||||
padding-bottom: 0px;
|
||||
font-size: 16px;
|
||||
color: #fff;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
p.account a {
|
||||
color: #ffd900;
|
||||
}
|
||||
|
||||
p.account a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a.forgot {
|
||||
color: #ffeb3b;
|
||||
margin-top: 2px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
a.forgot:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
h3.w3ls {
|
||||
margin: 10px 0px;
|
||||
padding-left: 60px;
|
||||
}
|
||||
|
||||
h3.agileits {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 890px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
|
||||
h5 {
|
||||
text-align: center;
|
||||
margin: 10px 0px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #000;
|
||||
}
|
||||
.footer {
|
||||
padding-top: 3em;
|
||||
}
|
||||
.footer p {
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
line-height: 28px;
|
||||
color: #fff;
|
||||
opacity:0.9;
|
||||
}
|
||||
|
||||
.footer p a {
|
||||
color: #ffd900;
|
||||
}
|
||||
|
||||
.footer p a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
p.continue {
|
||||
margin-top: 25px;
|
||||
padding: 0;
|
||||
margin-bottom: 20px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
p.continue span {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
p.continue span:before {
|
||||
position: absolute;
|
||||
content: '';
|
||||
height: 1px;
|
||||
background: #fff;
|
||||
width: 89%;
|
||||
left: -100%;
|
||||
top: 5px;
|
||||
}
|
||||
|
||||
p.continue span:after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
height: 1px;
|
||||
background: #fff;
|
||||
width: 89%;
|
||||
right: -100%;
|
||||
top: 5px;
|
||||
}
|
||||
|
||||
::-webkit-input-placeholder {
|
||||
/* Edge */
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
:-ms-input-placeholder {
|
||||
/* Internet Explorer 10-11 */
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
::placeholder {
|
||||
color:#fff;
|
||||
}
|
||||
|
||||
/** Responsive **/
|
||||
|
||||
@media screen and (max-width: 1024px) {
|
||||
.left_grid_info h3 {
|
||||
font-size: 2em;
|
||||
}
|
||||
.page-login--logo{
|
||||
display:none
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 991px) {
|
||||
.w3_info h2 {
|
||||
font-size: 24px;
|
||||
}
|
||||
.page-login--logo{
|
||||
display:none
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 35px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 900px) {
|
||||
|
||||
.left_grid_info h4 {
|
||||
font-size: 1em;
|
||||
}
|
||||
.page-login--logo{
|
||||
display:none
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px) {
|
||||
.w3_info h2 {
|
||||
font-size: 23px;
|
||||
}
|
||||
.page-login--logo{
|
||||
display:none
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
.w3_info {
|
||||
margin-right: auto;
|
||||
}
|
||||
.page-login--logo{
|
||||
display:none
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 736px) {
|
||||
.w3_info h2 {
|
||||
font-size: 22px;
|
||||
}
|
||||
.page-login--logo{
|
||||
display:none
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 667px) {
|
||||
|
||||
.w3l-form-info {
|
||||
margin: 20px 0 30px;
|
||||
}
|
||||
.page-login--logo{
|
||||
display:none
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 640px) {
|
||||
h1 {
|
||||
font-size: 37px;
|
||||
}
|
||||
.page-login--logo{
|
||||
display:none
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width:568px) {
|
||||
.w3l_form {
|
||||
padding: 0em;
|
||||
}
|
||||
h1 {
|
||||
font-size: 34px;
|
||||
}
|
||||
.page-login--logo{
|
||||
display:none
|
||||
}
|
||||
.w3_info {
|
||||
padding:0;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 415px) {
|
||||
h1 {
|
||||
font-size: 32px;
|
||||
}
|
||||
.left_grid_info p {
|
||||
font-size: 13px;
|
||||
}
|
||||
.page-login--logo{
|
||||
display:none
|
||||
}
|
||||
.w3l-signinform{
|
||||
padding: 40px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 384px) {
|
||||
.w3l-signinform{
|
||||
padding: 30px 15px;
|
||||
}
|
||||
.page-login--logo{
|
||||
display:none
|
||||
}
|
||||
.social-login {
|
||||
grid-auto-flow: row;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 375px) {
|
||||
.left_grid_info h3 {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
.page-login--logo{
|
||||
display:none
|
||||
}
|
||||
.form-row.bottom {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
a.forgot {
|
||||
margin-top: 17px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 320px) {
|
||||
h1 {
|
||||
font-size: 25px;
|
||||
}
|
||||
.page-login--logo{
|
||||
display:none
|
||||
}
|
||||
.w3_info h2 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
padding: 13px 12px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="email"],
|
||||
input[type="password"] {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.footer p {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.footer p a {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
/** /Responsive **/
|
||||
|
||||
/*-- //form styling --*/
|
||||
|
After Width: | Height: | Size: 434 KiB |
|
After Width: | Height: | Size: 223 KiB |
|
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 29 KiB |