Merge remote-tracking branch 'origin/v2.x' into local-v2.x
|
@ -1,3 +1,6 @@
|
||||||
/backend/venv
|
/backend/venv
|
||||||
/backend/.idea
|
/backend/.idea
|
||||||
.idea
|
.idea
|
||||||
|
|
||||||
|
.history/
|
||||||
|
.vscode/
|
|
@ -88,11 +88,11 @@ ENV/
|
||||||
.idea/
|
.idea/
|
||||||
*.db
|
*.db
|
||||||
.DS_Store
|
.DS_Store
|
||||||
__pycache__
|
**/migrations/*.py
|
||||||
**/migrations
|
|
||||||
!**/migrations/__init__.py
|
!**/migrations/__init__.py
|
||||||
*.pyc
|
*.pyc
|
||||||
conf/
|
conf/
|
||||||
!conf/env.example.py
|
!conf/env.example.py
|
||||||
db.sqlite3
|
db.sqlite3
|
||||||
media/
|
media/
|
||||||
|
__pypackages__/
|
|
@ -27,108 +27,111 @@ from conf.env import *
|
||||||
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
|
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
|
||||||
|
|
||||||
# SECURITY WARNING: keep the secret key used in production secret!
|
# 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插件路径到环境变量中
|
||||||
PLUGINS_PATH = os.path.join(BASE_DIR, 'plugins')
|
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))
|
||||||
|
|
||||||
[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('__')]
|
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!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = locals().get('DEBUG', True)
|
DEBUG = locals().get("DEBUG", True)
|
||||||
ALLOWED_HOSTS = locals().get('ALLOWED_HOSTS', ['*'])
|
ALLOWED_HOSTS = locals().get("ALLOWED_HOSTS", ["*"])
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
'django.contrib.auth',
|
"django.contrib.auth",
|
||||||
'django.contrib.contenttypes',
|
"django.contrib.contenttypes",
|
||||||
'django.contrib.sessions',
|
"django.contrib.sessions",
|
||||||
'django.contrib.messages',
|
"django.contrib.messages",
|
||||||
'django.contrib.staticfiles',
|
"django.contrib.staticfiles",
|
||||||
'django_comment_migrate',
|
"django_comment_migrate",
|
||||||
'rest_framework',
|
"rest_framework",
|
||||||
'django_filters',
|
"django_filters",
|
||||||
'corsheaders', # 注册跨域app
|
"corsheaders", # 注册跨域app
|
||||||
'dvadmin.system',
|
"dvadmin.system",
|
||||||
'drf_yasg',
|
"drf_yasg",
|
||||||
'captcha',
|
"captcha",
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
'django.middleware.security.SecurityMiddleware',
|
"django.middleware.security.SecurityMiddleware",
|
||||||
'whitenoise.middleware.WhiteNoiseMiddleware',
|
"whitenoise.middleware.WhiteNoiseMiddleware",
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||||
'corsheaders.middleware.CorsMiddleware', # 跨域中间件
|
"corsheaders.middleware.CorsMiddleware", # 跨域中间件
|
||||||
'django.middleware.common.CommonMiddleware',
|
"django.middleware.common.CommonMiddleware",
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
"django.middleware.csrf.CsrfViewMiddleware",
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
"django.contrib.messages.middleware.MessageMiddleware",
|
||||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||||
'dvadmin.utils.middleware.ApiLoggingMiddleware',
|
"dvadmin.utils.middleware.ApiLoggingMiddleware",
|
||||||
]
|
]
|
||||||
|
|
||||||
ROOT_URLCONF = 'application.urls'
|
ROOT_URLCONF = "application.urls"
|
||||||
|
|
||||||
TEMPLATES = [
|
TEMPLATES = [
|
||||||
{
|
{
|
||||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||||
'DIRS': [os.path.join(BASE_DIR, 'templates')],
|
"DIRS": [os.path.join(BASE_DIR, "templates")],
|
||||||
'APP_DIRS': True,
|
"APP_DIRS": True,
|
||||||
'OPTIONS': {
|
"OPTIONS": {
|
||||||
'context_processors': [
|
"context_processors": [
|
||||||
'django.template.context_processors.debug',
|
"django.template.context_processors.debug",
|
||||||
'django.template.context_processors.request',
|
"django.template.context_processors.request",
|
||||||
'django.contrib.auth.context_processors.auth',
|
"django.contrib.auth.context_processors.auth",
|
||||||
'django.contrib.messages.context_processors.messages',
|
"django.contrib.messages.context_processors.messages",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
WSGI_APPLICATION = 'application.wsgi.application'
|
WSGI_APPLICATION = "application.wsgi.application"
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
|
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
|
||||||
|
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
'default': {
|
"default": {
|
||||||
'ENGINE': DATABASE_ENGINE,
|
"ENGINE": DATABASE_ENGINE,
|
||||||
'NAME': DATABASE_NAME,
|
"NAME": DATABASE_NAME,
|
||||||
'USER': DATABASE_USER,
|
"USER": DATABASE_USER,
|
||||||
'PASSWORD': DATABASE_PASSWORD,
|
"PASSWORD": DATABASE_PASSWORD,
|
||||||
'HOST': DATABASE_HOST,
|
"HOST": DATABASE_HOST,
|
||||||
'PORT': DATABASE_PORT,
|
"PORT": DATABASE_PORT,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AUTH_USER_MODEL = 'system.Users'
|
AUTH_USER_MODEL = "system.Users"
|
||||||
USERNAME_FIELD = 'username'
|
USERNAME_FIELD = "username"
|
||||||
|
|
||||||
# Password validation
|
# Password validation
|
||||||
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
|
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
|
||||||
|
|
||||||
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
|
# Internationalization
|
||||||
# https://docs.djangoproject.com/en/3.2/topics/i18n/
|
# 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
|
USE_I18N = True
|
||||||
|
|
||||||
|
@ -139,13 +142,13 @@ USE_TZ = False
|
||||||
# Static files (CSS, JavaScript, Images)
|
# Static files (CSS, JavaScript, Images)
|
||||||
# https://docs.djangoproject.com/en/3.2/howto/static-files/
|
# https://docs.djangoproject.com/en/3.2/howto/static-files/
|
||||||
|
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = "/static/"
|
||||||
# # 设置django的静态文件目录
|
# # 设置django的静态文件目录
|
||||||
STATICFILES_DIRS = [
|
STATICFILES_DIRS = [
|
||||||
os.path.join(BASE_DIR, "static"),
|
os.path.join(BASE_DIR, "static"),
|
||||||
]
|
]
|
||||||
|
|
||||||
MEDIA_ROOT = 'media' # 项目下的目录
|
MEDIA_ROOT = "media" # 项目下的目录
|
||||||
MEDIA_URL = "/media/" # 跟STATIC_URL类似,指定用户可以通过这个url找到文件
|
MEDIA_URL = "/media/" # 跟STATIC_URL类似,指定用户可以通过这个url找到文件
|
||||||
|
|
||||||
# 收集静态文件,必须将 MEDIA_ROOT,STATICFILES_DIRS先注释
|
# 收集静态文件,必须将 MEDIA_ROOT,STATICFILES_DIRS先注释
|
||||||
|
@ -166,78 +169,82 @@ CORS_ALLOW_CREDENTIALS = True # 指明在跨域访问中,后端是否支持
|
||||||
# ================================================= #
|
# ================================================= #
|
||||||
|
|
||||||
# log 配置部分BEGIN #
|
# log 配置部分BEGIN #
|
||||||
SERVER_LOGS_FILE = os.path.join(BASE_DIR, 'logs', 'server.log')
|
SERVER_LOGS_FILE = os.path.join(BASE_DIR, "logs", "server.log")
|
||||||
ERROR_LOGS_FILE = os.path.join(BASE_DIR, 'logs', 'error.log')
|
ERROR_LOGS_FILE = os.path.join(BASE_DIR, "logs", "error.log")
|
||||||
if not os.path.exists(os.path.join(BASE_DIR, 'logs')):
|
if not os.path.exists(os.path.join(BASE_DIR, "logs")):
|
||||||
os.makedirs(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] 这是一条日志:
|
# 格式:[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'
|
STANDARD_LOG_FORMAT = (
|
||||||
CONSOLE_LOG_FORMAT = '[%(asctime)s][%(name)s.%(funcName)s():%(lineno)d] [%(levelname)s] %(message)s'
|
"[%(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 = {
|
LOGGING = {
|
||||||
'version': 1,
|
"version": 1,
|
||||||
'disable_existing_loggers': False,
|
"disable_existing_loggers": False,
|
||||||
'formatters': {
|
"formatters": {
|
||||||
'standard': {
|
"standard": {"format": STANDARD_LOG_FORMAT},
|
||||||
'format': STANDARD_LOG_FORMAT
|
"console": {
|
||||||
|
"format": CONSOLE_LOG_FORMAT,
|
||||||
|
"datefmt": "%Y-%m-%d %H:%M:%S",
|
||||||
},
|
},
|
||||||
'console': {
|
"file": {
|
||||||
'format': CONSOLE_LOG_FORMAT,
|
"format": CONSOLE_LOG_FORMAT,
|
||||||
'datefmt': '%Y-%m-%d %H:%M:%S',
|
"datefmt": "%Y-%m-%d %H:%M:%S",
|
||||||
},
|
|
||||||
'file': {
|
|
||||||
'format': CONSOLE_LOG_FORMAT,
|
|
||||||
'datefmt': '%Y-%m-%d %H:%M:%S',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'handlers': {
|
"handlers": {
|
||||||
'file': {
|
"file": {
|
||||||
'level': 'INFO',
|
"level": "INFO",
|
||||||
'class': 'logging.handlers.RotatingFileHandler',
|
"class": "logging.handlers.RotatingFileHandler",
|
||||||
'filename': SERVER_LOGS_FILE,
|
"filename": SERVER_LOGS_FILE,
|
||||||
'maxBytes': 1024 * 1024 * 100, # 100 MB
|
"maxBytes": 1024 * 1024 * 100, # 100 MB
|
||||||
'backupCount': 5, # 最多备份5个
|
"backupCount": 5, # 最多备份5个
|
||||||
'formatter': 'standard',
|
"formatter": "standard",
|
||||||
'encoding': 'utf-8',
|
"encoding": "utf-8",
|
||||||
},
|
},
|
||||||
'error': {
|
"error": {
|
||||||
'level': 'ERROR',
|
"level": "ERROR",
|
||||||
'class': 'logging.handlers.RotatingFileHandler',
|
"class": "logging.handlers.RotatingFileHandler",
|
||||||
'filename': ERROR_LOGS_FILE,
|
"filename": ERROR_LOGS_FILE,
|
||||||
'maxBytes': 1024 * 1024 * 100, # 100 MB
|
"maxBytes": 1024 * 1024 * 100, # 100 MB
|
||||||
'backupCount': 3, # 最多备份3个
|
"backupCount": 3, # 最多备份3个
|
||||||
'formatter': 'standard',
|
"formatter": "standard",
|
||||||
'encoding': 'utf-8',
|
"encoding": "utf-8",
|
||||||
},
|
},
|
||||||
'console': {
|
"console": {
|
||||||
'level': 'INFO',
|
"level": "INFO",
|
||||||
'class': 'logging.StreamHandler',
|
"class": "logging.StreamHandler",
|
||||||
'formatter': 'console',
|
"formatter": "console",
|
||||||
}
|
|
||||||
},
|
},
|
||||||
'loggers': {
|
},
|
||||||
|
"loggers": {
|
||||||
# default日志
|
# default日志
|
||||||
'': {
|
"": {
|
||||||
'handlers': ['console', 'error', 'file'],
|
"handlers": ["console", "error", "file"],
|
||||||
'level': 'INFO',
|
"level": "INFO",
|
||||||
},
|
},
|
||||||
'django': {
|
"django": {
|
||||||
'handlers': ['console', 'error', 'file'],
|
"handlers": ["console", "error", "file"],
|
||||||
'level': 'INFO',
|
"level": "INFO",
|
||||||
|
"propagate": False,
|
||||||
},
|
},
|
||||||
'scripts': {
|
"scripts": {
|
||||||
'handlers': ['console', 'error', 'file'],
|
"handlers": ["console", "error", "file"],
|
||||||
'level': 'INFO',
|
"level": "INFO",
|
||||||
|
"propagate": False,
|
||||||
},
|
},
|
||||||
# 数据库相关日志
|
# 数据库相关日志
|
||||||
'django.db.backends': {
|
"django.db.backends": {
|
||||||
'handlers': [],
|
"handlers": [],
|
||||||
'propagate': True,
|
"propagate": True,
|
||||||
'level': 'INFO',
|
"level": "INFO",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# ================================================= #
|
# ================================================= #
|
||||||
|
@ -245,34 +252,32 @@ LOGGING = {
|
||||||
# ================================================= #
|
# ================================================= #
|
||||||
|
|
||||||
REST_FRAMEWORK = {
|
REST_FRAMEWORK = {
|
||||||
'DATETIME_FORMAT': "%Y-%m-%d %H:%M:%S", # 日期时间格式配置
|
"DATETIME_FORMAT": "%Y-%m-%d %H:%M:%S", # 日期时间格式配置
|
||||||
'DATE_FORMAT': "%Y-%m-%d",
|
"DATE_FORMAT": "%Y-%m-%d",
|
||||||
'DEFAULT_FILTER_BACKENDS': (
|
"DEFAULT_FILTER_BACKENDS": (
|
||||||
# 'django_filters.rest_framework.DjangoFilterBackend',
|
# 'django_filters.rest_framework.DjangoFilterBackend',
|
||||||
'dvadmin.utils.filters.CustomDjangoFilterBackend',
|
"dvadmin.utils.filters.CustomDjangoFilterBackend",
|
||||||
'rest_framework.filters.SearchFilter',
|
"rest_framework.filters.SearchFilter",
|
||||||
'rest_framework.filters.OrderingFilter',
|
"rest_framework.filters.OrderingFilter",
|
||||||
),
|
),
|
||||||
'DEFAULT_PAGINATION_CLASS': 'dvadmin.utils.pagination.CustomPagination', # 自定义分页
|
"DEFAULT_PAGINATION_CLASS": "dvadmin.utils.pagination.CustomPagination", # 自定义分页
|
||||||
'DEFAULT_AUTHENTICATION_CLASSES': (
|
"DEFAULT_AUTHENTICATION_CLASSES": (
|
||||||
'rest_framework_simplejwt.authentication.JWTAuthentication',
|
"rest_framework_simplejwt.authentication.JWTAuthentication",
|
||||||
'rest_framework.authentication.SessionAuthentication',
|
"rest_framework.authentication.SessionAuthentication",
|
||||||
),
|
),
|
||||||
'DEFAULT_PERMISSION_CLASSES': [
|
"DEFAULT_PERMISSION_CLASSES": [
|
||||||
'rest_framework.permissions.IsAuthenticated', # 只有经过身份认证确定用户身份才能访问
|
"rest_framework.permissions.IsAuthenticated", # 只有经过身份认证确定用户身份才能访问
|
||||||
# 'rest_framework.permissions.IsAdminUser', # is_staff=True才能访问 —— 管理员(员工)权限
|
# 'rest_framework.permissions.IsAdminUser', # is_staff=True才能访问 —— 管理员(员工)权限
|
||||||
# 'rest_framework.permissions.AllowAny', # 允许所有
|
# 'rest_framework.permissions.AllowAny', # 允许所有
|
||||||
# 'rest_framework.permissions.IsAuthenticatedOrReadOnly', # 有身份 或者 只读访问(self.list,self.retrieve)
|
# 'rest_framework.permissions.IsAuthenticatedOrReadOnly', # 有身份 或者 只读访问(self.list,self.retrieve)
|
||||||
],
|
],
|
||||||
'EXCEPTION_HANDLER': 'dvadmin.utils.exception.CustomExceptionHandler', # 自定义的异常处理
|
"EXCEPTION_HANDLER": "dvadmin.utils.exception.CustomExceptionHandler", # 自定义的异常处理
|
||||||
}
|
}
|
||||||
# ================================================= #
|
# ================================================= #
|
||||||
# ******************** 登录方式配置 ******************** #
|
# ******************** 登录方式配置 ******************** #
|
||||||
# ================================================= #
|
# ================================================= #
|
||||||
|
|
||||||
AUTHENTICATION_BACKENDS = [
|
AUTHENTICATION_BACKENDS = ["dvadmin.utils.backends.CustomBackend"]
|
||||||
'dvadmin.utils.backends.CustomBackend'
|
|
||||||
]
|
|
||||||
# ================================================= #
|
# ================================================= #
|
||||||
# ****************** simplejwt配置 ***************** #
|
# ****************** simplejwt配置 ***************** #
|
||||||
# ================================================= #
|
# ================================================= #
|
||||||
|
@ -280,12 +285,12 @@ from datetime import timedelta
|
||||||
|
|
||||||
SIMPLE_JWT = {
|
SIMPLE_JWT = {
|
||||||
# token有效时长
|
# token有效时长
|
||||||
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=120),
|
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=120),
|
||||||
# token刷新后的有效时间
|
# token刷新后的有效时间
|
||||||
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
|
"REFRESH_TOKEN_LIFETIME": timedelta(days=1),
|
||||||
# 设置前缀
|
# 设置前缀
|
||||||
'AUTH_HEADER_TYPES': ('JWT',),
|
"AUTH_HEADER_TYPES": ("JWT",),
|
||||||
'ROTATE_REFRESH_TOKENS': True,
|
"ROTATE_REFRESH_TOKENS": True,
|
||||||
}
|
}
|
||||||
|
|
||||||
# ====================================#
|
# ====================================#
|
||||||
|
@ -293,72 +298,72 @@ SIMPLE_JWT = {
|
||||||
# ====================================#
|
# ====================================#
|
||||||
SWAGGER_SETTINGS = {
|
SWAGGER_SETTINGS = {
|
||||||
# 基础样式
|
# 基础样式
|
||||||
'SECURITY_DEFINITIONS': {
|
"SECURITY_DEFINITIONS": {"basic": {"type": "basic"}},
|
||||||
"basic": {
|
|
||||||
'type': 'basic'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
# 如果需要登录才能够查看接口文档, 登录的链接使用restframework自带的.
|
# 如果需要登录才能够查看接口文档, 登录的链接使用restframework自带的.
|
||||||
|
"LOGIN_URL": "apiLogin/",
|
||||||
'LOGIN_URL': 'apiLogin/',
|
|
||||||
# 'LOGIN_URL': 'rest_framework:login',
|
# 'LOGIN_URL': 'rest_framework:login',
|
||||||
'LOGOUT_URL': 'rest_framework:logout',
|
"LOGOUT_URL": "rest_framework:logout",
|
||||||
# 'DOC_EXPANSION': None,
|
# 'DOC_EXPANSION': None,
|
||||||
# 'SHOW_REQUEST_HEADERS':True,
|
# 'SHOW_REQUEST_HEADERS':True,
|
||||||
# 'USE_SESSION_AUTH': True,
|
# 'USE_SESSION_AUTH': True,
|
||||||
# 'DOC_EXPANSION': 'list',
|
# 'DOC_EXPANSION': 'list',
|
||||||
# 接口文档中方法列表以首字母升序排列
|
# 接口文档中方法列表以首字母升序排列
|
||||||
'APIS_SORTER': 'alpha',
|
"APIS_SORTER": "alpha",
|
||||||
# 如果支持json提交, 则接口文档中包含json输入框
|
# 如果支持json提交, 则接口文档中包含json输入框
|
||||||
'JSON_EDITOR': True,
|
"JSON_EDITOR": True,
|
||||||
# 方法列表字母排序
|
# 方法列表字母排序
|
||||||
'OPERATIONS_SORTER': 'alpha',
|
"OPERATIONS_SORTER": "alpha",
|
||||||
'VALIDATOR_URL': None,
|
"VALIDATOR_URL": None,
|
||||||
'AUTO_SCHEMA_TYPE': 2, # 分组根据url层级分,0、1 或 2 层
|
"AUTO_SCHEMA_TYPE": 2, # 分组根据url层级分,0、1 或 2 层
|
||||||
'DEFAULT_AUTO_SCHEMA_CLASS': 'dvadmin.utils.swagger.CustomSwaggerAutoSchema',
|
"DEFAULT_AUTO_SCHEMA_CLASS": "dvadmin.utils.swagger.CustomSwaggerAutoSchema",
|
||||||
}
|
}
|
||||||
|
|
||||||
# ================================================= #
|
# ================================================= #
|
||||||
# **************** 验证码配置 ******************* #
|
# **************** 验证码配置 ******************* #
|
||||||
# ================================================= #
|
# ================================================= #
|
||||||
CAPTCHA_STATE = True
|
CAPTCHA_STATE = locals().get("CAPTCHA_STATE", False)
|
||||||
CAPTCHA_IMAGE_SIZE = (160, 60) # 设置 captcha 图片大小
|
CAPTCHA_IMAGE_SIZE = (160, 60) # 设置 captcha 图片大小
|
||||||
CAPTCHA_LENGTH = 4 # 字符个数
|
CAPTCHA_LENGTH = 4 # 字符个数
|
||||||
CAPTCHA_TIMEOUT = 1 # 超时(minutes)
|
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_FONT_SIZE = 40 # 字体大小
|
||||||
CAPTCHA_FOREGROUND_COLOR = '#0033FF' # 前景色
|
CAPTCHA_FOREGROUND_COLOR = "#64DAAA" # 前景色
|
||||||
CAPTCHA_BACKGROUND_COLOR = '#F5F7F4' # 背景色
|
CAPTCHA_BACKGROUND_COLOR = "#F5F7F4" # 背景色
|
||||||
CAPTCHA_NOISE_FUNCTIONS = (
|
CAPTCHA_NOISE_FUNCTIONS = (
|
||||||
'captcha.helpers.noise_arcs', # 线
|
"captcha.helpers.noise_arcs", # 线
|
||||||
'captcha.helpers.noise_dots', # 点
|
# "captcha.helpers.noise_dots", # 点
|
||||||
)
|
)
|
||||||
# CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.random_char_challenge' #字母验证码
|
# 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_ENABLE = True
|
||||||
# API_LOG_METHODS = 'ALL' # ['POST', 'DELETE']
|
# 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 = {
|
API_MODEL_MAP = {
|
||||||
"/token/": "登录模块",
|
"/token/": "登录模块",
|
||||||
"/api/login/": "登录模块",
|
"/api/login/": "登录模块",
|
||||||
"/api/plugins_market/plugins/": "插件市场",
|
"/api/plugins_market/plugins/": "插件市场",
|
||||||
}
|
}
|
||||||
# 表前缀
|
|
||||||
TABLE_PREFIX = "dvadmin_"
|
|
||||||
DJANGO_CELERY_BEAT_TZ_AWARE = False
|
DJANGO_CELERY_BEAT_TZ_AWARE = False
|
||||||
CELERY_TIMEZONE = 'Asia/Shanghai' # celery 时区问题
|
CELERY_TIMEZONE = "Asia/Shanghai" # celery 时区问题
|
||||||
# 静态页面压缩
|
# 静态页面压缩
|
||||||
STATICFILES_STORAGE = 'whitenoise.storage.CompressedStaticFilesStorage'
|
STATICFILES_STORAGE = "whitenoise.storage.CompressedStaticFilesStorage"
|
||||||
# 初始化需要执行的列表,用来初始化后执行
|
|
||||||
INITIALIZE_RESET_LIST = []
|
|
||||||
ALL_MODELS_OBJECTS = [] # 所有app models 对象
|
ALL_MODELS_OBJECTS = [] # 所有app models 对象
|
||||||
# dvadmin 插件
|
# dvadmin 插件
|
||||||
REGISTER_PLUGINS = (
|
REGISTER_PLUGINS = (
|
||||||
# ""
|
# ""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 初始化需要执行的列表,用来初始化后执行
|
||||||
|
INITIALIZE_LIST = []
|
||||||
|
INITIALIZE_RESET_LIST = []
|
||||||
|
# 表前缀
|
||||||
|
TABLE_PREFIX = locals().get('TABLE_PREFIX', "")
|
||||||
|
DEFAULT_PASSWORD = locals().get("DEFAULT_PASSWORD", "admin123456")
|
||||||
|
|
|
@ -23,13 +23,21 @@ from rest_framework_simplejwt.views import (
|
||||||
)
|
)
|
||||||
|
|
||||||
from application import settings
|
from application import settings
|
||||||
from dvadmin.system.views.login import LoginView, CaptchaView, ApiLogin, LogoutView
|
from dvadmin.system.views.login import (
|
||||||
|
LoginView,
|
||||||
|
CaptchaStatusView,
|
||||||
|
CaptchaView,
|
||||||
|
ApiLogin,
|
||||||
|
LogoutView,
|
||||||
|
)
|
||||||
|
from dvadmin.system.views.system_config import InitSettingsViewSet
|
||||||
|
from dvadmin.system.views.dictionary import InitDictionaryViewSet
|
||||||
from dvadmin.utils.swagger import CustomOpenAPISchemaGenerator
|
from dvadmin.utils.swagger import CustomOpenAPISchemaGenerator
|
||||||
|
|
||||||
schema_view = get_schema_view(
|
schema_view = get_schema_view(
|
||||||
openapi.Info(
|
openapi.Info(
|
||||||
title="Snippets API",
|
title="Snippets API",
|
||||||
default_version='v1',
|
default_version="v1",
|
||||||
description="Test description",
|
description="Test description",
|
||||||
terms_of_service="https://www.google.com/policies/terms/",
|
terms_of_service="https://www.google.com/policies/terms/",
|
||||||
contact=openapi.Contact(email="contact@snippets.local"),
|
contact=openapi.Contact(email="contact@snippets.local"),
|
||||||
|
@ -38,20 +46,38 @@ schema_view = get_schema_view(
|
||||||
public=True,
|
public=True,
|
||||||
permission_classes=(permissions.AllowAny,),
|
permission_classes=(permissions.AllowAny,),
|
||||||
generator_class=CustomOpenAPISchemaGenerator,
|
generator_class=CustomOpenAPISchemaGenerator,
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = (
|
||||||
re_path(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0),
|
[
|
||||||
name='schema-json'),
|
re_path(
|
||||||
path('', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
|
r"^swagger(?P<format>\.json|\.yaml)$",
|
||||||
path(r'redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
|
schema_view.without_ui(cache_timeout=0),
|
||||||
path('api/system/', include('dvadmin.system.urls')),
|
name="schema-json",
|
||||||
path('api/login/', LoginView.as_view(), name='token_obtain_pair'),
|
),
|
||||||
path('api/logout/', LogoutView.as_view(), name='token_obtain_pair'),
|
path(
|
||||||
path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
|
"",
|
||||||
re_path(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
|
schema_view.with_ui("swagger", cache_timeout=0),
|
||||||
path('api/captcha/', CaptchaView.as_view()),
|
name="schema-swagger-ui",
|
||||||
path('apiLogin/', ApiLogin.as_view()),
|
),
|
||||||
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + static(settings.STATIC_URL,
|
path(
|
||||||
document_root=settings.STATIC_URL)
|
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/captcha/status/", CaptchaStatusView.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)
|
||||||
|
)
|
||||||
|
|
|
@ -3,17 +3,17 @@ import os
|
||||||
from application.settings import BASE_DIR
|
from application.settings import BASE_DIR
|
||||||
|
|
||||||
# ================================================= #
|
# ================================================= #
|
||||||
# ************** 数据库 配置 ************** #
|
# *************** mysql数据库 配置 *************** #
|
||||||
# ================================================= #
|
# ================================================= #
|
||||||
|
|
||||||
# 数据库 ENGINE ,默认演示使用 sqlite3 数据库,正式环境建议使用 mysql 数据库
|
# 数据库 ENGINE ,默认演示使用 sqlite3 数据库,正式环境建议使用 mysql 数据库
|
||||||
# sqlite3 设置
|
# sqlite3 设置
|
||||||
DATABASE_ENGINE = "django.db.backends.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时,改为此配置
|
# 使用mysql时,改为此配置
|
||||||
# DATABASE_ENGINE = "django.db.backends.mysql"
|
# DATABASE_ENGINE = "django.db.backends.mysql"
|
||||||
# DATABASE_NAME = 'django-vue-admin' # mysql 时使用
|
# DATABASE_NAME = 'django-vue-admin' # mysql 时使用
|
||||||
|
|
||||||
# 数据库地址 改为自己数据库地址
|
# 数据库地址 改为自己数据库地址
|
||||||
DATABASE_HOST = "127.0.0.1"
|
DATABASE_HOST = "127.0.0.1"
|
||||||
# # 数据库端口
|
# # 数据库端口
|
||||||
|
@ -23,16 +23,29 @@ DATABASE_USER = "root"
|
||||||
# # 数据库密码
|
# # 数据库密码
|
||||||
DATABASE_PASSWORD = "123456"
|
DATABASE_PASSWORD = "123456"
|
||||||
|
|
||||||
|
# 表前缀
|
||||||
|
TABLE_PREFIX = "sys_"
|
||||||
# ================================================= #
|
# ================================================= #
|
||||||
# ************** redis配置,无redis 可不进行配置 ************** #
|
# ******** redis配置,无redis 可不进行配置 ******** #
|
||||||
# ================================================= #
|
# ================================================= #
|
||||||
# REDIS_PASSWORD = ''
|
# REDIS_PASSWORD = ''
|
||||||
# REDIS_HOST = '127.0.0.1'
|
# REDIS_HOST = '127.0.0.1'
|
||||||
# REDIS_URL = f'redis://:{REDIS_PASSWORD or ""}@{REDIS_HOST}:6380'
|
# REDIS_URL = f'redis://:{REDIS_PASSWORD or ""}@{REDIS_HOST}:6380'
|
||||||
# ================================================= #
|
# ================================================= #
|
||||||
# ************** 其他 配置 ************** #
|
# ****************** 功能 启停 ******************* #
|
||||||
# ================================================= #
|
# ================================================= #
|
||||||
DEBUG = True # 线上环境请设置为True
|
DEBUG = True
|
||||||
|
# 启动登录详细概略获取(通过调用api获取ip详细地址。如果是内网,关闭即可)
|
||||||
|
ENABLE_LOGIN_ANALYSIS_LOG = True
|
||||||
|
# 是否启用登录验证码,不需要可以设置为False,线上环境建议开启
|
||||||
|
CAPTCHA_STATE = True
|
||||||
|
# 登录接口 /api/token/ 是否需要验证码认证,用于测试,正式环境建议取消
|
||||||
|
LOGIN_NO_CAPTCHA_AUTH = True
|
||||||
|
# ================================================= #
|
||||||
|
# ****************** 其他 配置 ******************* #
|
||||||
|
# ================================================= #
|
||||||
|
|
||||||
ALLOWED_HOSTS = ["*"]
|
ALLOWED_HOSTS = ["*"]
|
||||||
LOGIN_NO_CAPTCHA_AUTH = True # 登录接口 /api/token/ 是否需要验证码认证,用于测试,正式环境建议取消
|
|
||||||
ENABLE_LOGIN_ANALYSIS_LOG = True # 启动登录详细概略获取(通过调用api获取ip详细地址)
|
# 默认密码
|
||||||
|
DEFAULT_PASSWORD = "admin123456"
|
||||||
|
|
|
@ -13,27 +13,33 @@ class Command(BaseCommand):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
def add_arguments(self, parser):
|
||||||
parser.add_argument('init_name', nargs='*', type=str, )
|
parser.add_argument(
|
||||||
parser.add_argument('-y', nargs='*')
|
"init_name",
|
||||||
parser.add_argument('-Y', nargs='*')
|
nargs="*",
|
||||||
parser.add_argument('-n', nargs='*')
|
type=str,
|
||||||
parser.add_argument('-N', nargs='*')
|
)
|
||||||
|
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):
|
def handle(self, *args, **options):
|
||||||
reset = False
|
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
|
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
|
reset = False
|
||||||
print(f"正在准备初始化数据,{'如有初始化数据,将会不做操作跳过' if not reset else '初始数据将会先删除后新增'}...")
|
print(f"正在准备初始化数据,{'如有初始化数据,将会不做操作跳过' if not reset else '初始数据将会先删除后新增'}...")
|
||||||
|
|
||||||
for app in settings.INSTALLED_APPS:
|
for app in settings.INSTALLED_APPS:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
exec(f"""
|
exec(
|
||||||
|
f"""
|
||||||
from {app}.initialize import main
|
from {app}.initialize import main
|
||||||
main(reset={reset})
|
main(reset={reset})
|
||||||
""")
|
"""
|
||||||
|
)
|
||||||
except ModuleNotFoundError:
|
except ModuleNotFoundError:
|
||||||
pass
|
pass
|
||||||
print("初始化数据完成!")
|
print("初始化数据完成!")
|
||||||
|
|
|
@ -19,10 +19,11 @@ class Users(AbstractUser, CoreModel):
|
||||||
avatar = models.CharField(max_length=255, verbose_name="头像", null=True, blank=True, help_text="头像")
|
avatar = models.CharField(max_length=255, verbose_name="头像", null=True, blank=True, help_text="头像")
|
||||||
name = models.CharField(max_length=40, verbose_name="姓名", help_text="姓名")
|
name = models.CharField(max_length=40, verbose_name="姓名", help_text="姓名")
|
||||||
GENDER_CHOICES = (
|
GENDER_CHOICES = (
|
||||||
(0, "女"),
|
(0, "未知"),
|
||||||
(1, "男"),
|
(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="性别")
|
help_text="性别")
|
||||||
USER_TYPE = (
|
USER_TYPE = (
|
||||||
(0, "后台用户"),
|
(0, "后台用户"),
|
||||||
|
@ -166,13 +167,23 @@ class MenuButton(CoreModel):
|
||||||
|
|
||||||
|
|
||||||
class Dictionary(CoreModel):
|
class Dictionary(CoreModel):
|
||||||
code = models.CharField(max_length=100, blank=True, null=True, verbose_name="编码", help_text="编码")
|
TYPE_LIST = (
|
||||||
label = models.CharField(max_length=100, blank=True, null=True, verbose_name="显示名称", help_text="显示名称")
|
(0, 'text'),
|
||||||
value = models.CharField(max_length=100, blank=True, null=True, verbose_name="实际值", help_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,
|
parent = models.ForeignKey(to='self', related_name='sublist', db_constraint=False, on_delete=models.PROTECT,
|
||||||
blank=True, null=True,
|
blank=True, null=True, verbose_name="父级", help_text="父级")
|
||||||
verbose_name="父级", help_text="父级")
|
type = models.IntegerField(choices=TYPE_LIST, default=0, verbose_name="数据值类型", help_text="数据值类型")
|
||||||
status = models.BooleanField(default=True, blank=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="显示排序")
|
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="备注")
|
remark = models.CharField(max_length=2000, blank=True, null=True, verbose_name="备注", help_text="备注")
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
@Remark: 字典管理
|
@Remark: 字典管理
|
||||||
"""
|
"""
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
from rest_framework.views import APIView
|
||||||
|
|
||||||
from dvadmin.system.models import Dictionary
|
from dvadmin.system.models import Dictionary
|
||||||
from dvadmin.utils.json_response import SuccessResponse
|
from dvadmin.utils.json_response import SuccessResponse
|
||||||
|
@ -42,16 +43,15 @@ class DictionaryTreeSerializer(CustomModelSerializer):
|
||||||
children = serializers.SerializerMethodField(read_only=True)
|
children = serializers.SerializerMethodField(read_only=True)
|
||||||
|
|
||||||
def get_children(self, instance):
|
def get_children(self, instance):
|
||||||
queryset = Dictionary.objects.filter(parent=instance.id).filter(status=1)
|
queryset = Dictionary.objects.filter(parent=instance.id).filter(status=1).values('label', 'value', 'type')
|
||||||
if queryset:
|
if queryset:
|
||||||
serializer = DictionaryTreeSerializer(queryset, many=True)
|
return queryset
|
||||||
return serializer.data
|
|
||||||
else:
|
else:
|
||||||
return None
|
return []
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Dictionary
|
model = Dictionary
|
||||||
fields = "__all__"
|
fields = ['id', 'value', 'children']
|
||||||
read_only_fields = ["id"]
|
read_only_fields = ["id"]
|
||||||
|
|
||||||
|
|
||||||
|
@ -68,3 +68,24 @@ class DictionaryViewSet(CustomModelViewSet):
|
||||||
serializer_class = DictionarySerializer
|
serializer_class = DictionarySerializer
|
||||||
extra_filter_backends = []
|
extra_filter_backends = []
|
||||||
search_fields = ['label']
|
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':
|
||||||
|
queryset = self.queryset.filter(status=True, is_value=False)
|
||||||
|
serializer = DictionaryTreeSerializer(queryset, many=True, request=request)
|
||||||
|
data = serializer.data
|
||||||
|
else:
|
||||||
|
data = self.queryset.filter(parent__value=dictionary_key, status=True).values('label', 'value', 'type')
|
||||||
|
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 rest_framework import serializers
|
||||||
|
|
||||||
from dvadmin.system.models import FileList
|
from dvadmin.system.models import FileList
|
||||||
|
|
|
@ -1,11 +1,3 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
@author: 猿小天
|
|
||||||
@contact: QQ:1638245306
|
|
||||||
@Created on: 2021/6/2 002 14:20
|
|
||||||
@Remark:登录视图
|
|
||||||
"""
|
|
||||||
import base64
|
import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
@ -24,7 +16,7 @@ from rest_framework_simplejwt.views import TokenObtainPairView
|
||||||
|
|
||||||
from application import settings
|
from application import settings
|
||||||
from dvadmin.system.models import Users
|
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.request_util import save_login_log
|
||||||
from dvadmin.utils.serializers import CustomModelSerializer
|
from dvadmin.utils.serializers import CustomModelSerializer
|
||||||
from dvadmin.utils.validator import CustomValidationError
|
from dvadmin.utils.validator import CustomValidationError
|
||||||
|
@ -35,21 +27,33 @@ class CaptchaView(APIView):
|
||||||
permission_classes = []
|
permission_classes = []
|
||||||
|
|
||||||
@swagger_auto_schema(
|
@swagger_auto_schema(
|
||||||
responses={
|
responses={"200": openapi.Response("获取成功")},
|
||||||
'200': openapi.Response('获取成功')
|
|
||||||
},
|
|
||||||
security=[],
|
security=[],
|
||||||
operation_id='captcha-get',
|
operation_id="captcha-get",
|
||||||
operation_description='验证码获取',
|
operation_description="验证码获取",
|
||||||
)
|
)
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
|
data = {}
|
||||||
|
if settings.CAPTCHA_STATE:
|
||||||
hashkey = CaptchaStore.generate_key()
|
hashkey = CaptchaStore.generate_key()
|
||||||
id = CaptchaStore.objects.filter(hashkey=hashkey).first().id
|
id = CaptchaStore.objects.filter(hashkey=hashkey).first().id
|
||||||
imgage = captcha_image(request, hashkey)
|
imgage = captcha_image(request, hashkey)
|
||||||
# 将图片转换为base64
|
# 将图片转换为base64
|
||||||
image_base = base64.b64encode(imgage.content)
|
image_base = base64.b64encode(imgage.content)
|
||||||
json_data = {"key": id, "image_base": "data:image/png;base64," + image_base.decode('utf-8')}
|
data = {
|
||||||
return SuccessResponse(data=json_data)
|
"key": id,
|
||||||
|
"image_base": "data:image/png;base64," + image_base.decode("utf-8"),
|
||||||
|
}
|
||||||
|
return DetailResponse(data=data)
|
||||||
|
|
||||||
|
|
||||||
|
class CaptchaStatusView(APIView):
|
||||||
|
|
||||||
|
authentication_classes = []
|
||||||
|
permission_classes = []
|
||||||
|
|
||||||
|
def get(self, request):
|
||||||
|
return DetailResponse(data={"status": settings.CAPTCHA_STATE})
|
||||||
|
|
||||||
|
|
||||||
class LoginSerializer(TokenObtainPairSerializer):
|
class LoginSerializer(TokenObtainPairSerializer):
|
||||||
|
@ -57,53 +61,55 @@ class LoginSerializer(TokenObtainPairSerializer):
|
||||||
登录的序列化器:
|
登录的序列化器:
|
||||||
重写djangorestframework-simplejwt的序列化器
|
重写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:
|
class Meta:
|
||||||
model = Users
|
model = Users
|
||||||
fields = "__all__"
|
fields = "__all__"
|
||||||
read_only_fields = ["id"]
|
read_only_fields = ["id"]
|
||||||
|
|
||||||
default_error_messages = {
|
default_error_messages = {"no_active_account": _("账号/密码错误")}
|
||||||
'no_active_account': _('账号/密码不正确')
|
|
||||||
}
|
|
||||||
|
|
||||||
def validate(self, attrs):
|
def validate(self, attrs):
|
||||||
captcha = self.initial_data.get('captcha', None)
|
captcha = self.initial_data.get("captcha", None)
|
||||||
if settings.CAPTCHA_STATE:
|
if settings.CAPTCHA_STATE:
|
||||||
if captcha is None:
|
if captcha is None:
|
||||||
raise CustomValidationError("验证码不能为空")
|
raise CustomValidationError("验证码不能为空")
|
||||||
self.image_code = CaptchaStore.objects.filter(
|
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)
|
five_minute_ago = datetime.now() - timedelta(hours=0, minutes=5, seconds=0)
|
||||||
if self.image_code and five_minute_ago > self.image_code.expiration:
|
if self.image_code and five_minute_ago > self.image_code.expiration:
|
||||||
self.image_code and self.image_code.delete()
|
self.image_code and self.image_code.delete()
|
||||||
raise CustomValidationError('验证码过期')
|
raise CustomValidationError("验证码过期")
|
||||||
else:
|
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()
|
self.image_code and self.image_code.delete()
|
||||||
else:
|
else:
|
||||||
self.image_code and self.image_code.delete()
|
self.image_code and self.image_code.delete()
|
||||||
raise CustomValidationError("图片验证码错误")
|
raise CustomValidationError("图片验证码错误")
|
||||||
data = super().validate(attrs)
|
data = super().validate(attrs)
|
||||||
data['name'] = self.user.name
|
data["name"] = self.user.name
|
||||||
data['userId'] = self.user.id
|
data["userId"] = self.user.id
|
||||||
data['avatar'] = self.user.avatar
|
data["avatar"] = self.user.avatar
|
||||||
request = self.context.get('request')
|
request = self.context.get("request")
|
||||||
request.user = self.user
|
request.user = self.user
|
||||||
# 记录登录日志
|
# 记录登录日志
|
||||||
save_login_log(request=request)
|
save_login_log(request=request)
|
||||||
return {
|
return {"code": 2000, "msg": "请求成功", "data": data}
|
||||||
"code": 2000,
|
|
||||||
"msg": "请求成功",
|
|
||||||
"data": data
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class LoginView(TokenObtainPairView):
|
class LoginView(TokenObtainPairView):
|
||||||
"""
|
"""
|
||||||
登录接口
|
登录接口
|
||||||
"""
|
"""
|
||||||
|
|
||||||
serializer_class = LoginSerializer
|
serializer_class = LoginSerializer
|
||||||
permission_classes = []
|
permission_classes = []
|
||||||
|
|
||||||
|
@ -118,31 +124,22 @@ class LoginTokenSerializer(TokenObtainPairSerializer):
|
||||||
fields = "__all__"
|
fields = "__all__"
|
||||||
read_only_fields = ["id"]
|
read_only_fields = ["id"]
|
||||||
|
|
||||||
default_error_messages = {
|
default_error_messages = {"no_active_account": _("账号/密码不正确")}
|
||||||
'no_active_account': _('账号/密码不正确')
|
|
||||||
}
|
|
||||||
|
|
||||||
def validate(self, attrs):
|
def validate(self, attrs):
|
||||||
if not getattr(settings, 'LOGIN_NO_CAPTCHA_AUTH', False):
|
if not getattr(settings, "LOGIN_NO_CAPTCHA_AUTH", False):
|
||||||
return {
|
return {"code": 4000, "msg": "该接口暂未开通!", "data": None}
|
||||||
"code": 4000,
|
|
||||||
"msg": "该接口暂未开通!",
|
|
||||||
"data": None
|
|
||||||
}
|
|
||||||
data = super().validate(attrs)
|
data = super().validate(attrs)
|
||||||
data['name'] = self.user.name
|
data["name"] = self.user.name
|
||||||
data['userId'] = self.user.id
|
data["userId"] = self.user.id
|
||||||
return {
|
return {"code": 2000, "msg": "请求成功", "data": data}
|
||||||
"code": 2000,
|
|
||||||
"msg": "请求成功",
|
|
||||||
"data": data
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class LoginTokenView(TokenObtainPairView):
|
class LoginTokenView(TokenObtainPairView):
|
||||||
"""
|
"""
|
||||||
登录获取token接口
|
登录获取token接口
|
||||||
"""
|
"""
|
||||||
|
|
||||||
serializer_class = LoginTokenSerializer
|
serializer_class = LoginTokenSerializer
|
||||||
permission_classes = []
|
permission_classes = []
|
||||||
|
|
||||||
|
@ -154,27 +151,31 @@ class LogoutView(APIView):
|
||||||
|
|
||||||
class ApiLoginSerializer(CustomModelSerializer):
|
class ApiLoginSerializer(CustomModelSerializer):
|
||||||
"""接口文档登录-序列化器"""
|
"""接口文档登录-序列化器"""
|
||||||
|
|
||||||
username = serializers.CharField()
|
username = serializers.CharField()
|
||||||
password = serializers.CharField()
|
password = serializers.CharField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Users
|
model = Users
|
||||||
fields = ['username', 'password']
|
fields = ["username", "password"]
|
||||||
|
|
||||||
|
|
||||||
class ApiLogin(APIView):
|
class ApiLogin(APIView):
|
||||||
"""接口文档的登录接口"""
|
"""接口文档的登录接口"""
|
||||||
|
|
||||||
serializer_class = ApiLoginSerializer
|
serializer_class = ApiLoginSerializer
|
||||||
authentication_classes = []
|
authentication_classes = []
|
||||||
permission_classes = []
|
permission_classes = []
|
||||||
|
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
username = request.data.get('username')
|
username = request.data.get("username")
|
||||||
password = request.data.get('password')
|
password = request.data.get("password")
|
||||||
user_obj = auth.authenticate(request, username=username,
|
if user_obj := auth.authenticate(
|
||||||
password=hashlib.md5(password.encode(encoding='UTF-8')).hexdigest())
|
request,
|
||||||
if user_obj:
|
username=username,
|
||||||
|
password=hashlib.md5(password.encode(encoding="UTF-8")).hexdigest(),
|
||||||
|
):
|
||||||
login(request, user_obj)
|
login(request, user_obj)
|
||||||
return redirect('/')
|
return redirect("/")
|
||||||
else:
|
else:
|
||||||
return ErrorResponse(msg="账号/密码错误")
|
return ErrorResponse(msg="账号/密码错误")
|
||||||
|
|
|
@ -10,9 +10,9 @@ import django_filters
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django_filters.rest_framework import BooleanFilter
|
from django_filters.rest_framework import BooleanFilter
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
from rest_framework.views import APIView
|
||||||
|
|
||||||
from dvadmin.system.models import SystemConfig
|
from dvadmin.system.models import SystemConfig
|
||||||
from dvadmin.utils.filters import DataLevelPermissionsFilter
|
|
||||||
from dvadmin.utils.json_response import DetailResponse, SuccessResponse, ErrorResponse
|
from dvadmin.utils.json_response import DetailResponse, SuccessResponse, ErrorResponse
|
||||||
from dvadmin.utils.models import get_all_models_objects
|
from dvadmin.utils.models import get_all_models_objects
|
||||||
from dvadmin.utils.serializers import CustomModelSerializer
|
from dvadmin.utils.serializers import CustomModelSerializer
|
||||||
|
@ -31,7 +31,6 @@ class SystemConfigCreateSerializer(CustomModelSerializer):
|
||||||
fields = "__all__"
|
fields = "__all__"
|
||||||
read_only_fields = ["id"]
|
read_only_fields = ["id"]
|
||||||
|
|
||||||
|
|
||||||
def validate_key(self, value):
|
def validate_key(self, value):
|
||||||
"""
|
"""
|
||||||
验证key是否允许重复
|
验证key是否允许重复
|
||||||
|
@ -42,6 +41,7 @@ class SystemConfigCreateSerializer(CustomModelSerializer):
|
||||||
raise CustomValidationError('已存在相同变量名')
|
raise CustomValidationError('已存在相同变量名')
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
class SystemConfigSerializer(CustomModelSerializer):
|
class SystemConfigSerializer(CustomModelSerializer):
|
||||||
"""
|
"""
|
||||||
系统配置-序列化器
|
系统配置-序列化器
|
||||||
|
@ -112,17 +112,9 @@ class SystemConfigFilter(django_filters.rest_framework.FilterSet):
|
||||||
fields = ['id', 'parent', 'status', 'parent__isnull']
|
fields = ['id', 'parent', 'status', 'parent__isnull']
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SystemConfigViewSet(CustomModelViewSet):
|
class SystemConfigViewSet(CustomModelViewSet):
|
||||||
"""
|
"""
|
||||||
系统配置接口
|
系统配置接口
|
||||||
list:查询
|
|
||||||
create:新增
|
|
||||||
update:修改
|
|
||||||
retrieve:详情
|
|
||||||
destroy:删除
|
|
||||||
"""
|
"""
|
||||||
queryset = SystemConfig.objects.order_by('sort', 'create_datetime')
|
queryset = SystemConfig.objects.order_by('sort', 'create_datetime')
|
||||||
serializer_class = SystemConfigChinldernSerializer
|
serializer_class = SystemConfigChinldernSerializer
|
||||||
|
@ -181,7 +173,6 @@ class SystemConfigViewSet(CustomModelViewSet):
|
||||||
return self.get_paginated_response(queryset)
|
return self.get_paginated_response(queryset)
|
||||||
return SuccessResponse(msg="获取成功", data=queryset, total=len(queryset))
|
return SuccessResponse(msg="获取成功", data=queryset, total=len(queryset))
|
||||||
|
|
||||||
|
|
||||||
def get_relation_info(self, request):
|
def get_relation_info(self, request):
|
||||||
"""
|
"""
|
||||||
查询关联的模板信息
|
查询关联的模板信息
|
||||||
|
@ -205,3 +196,24 @@ class SystemConfigViewSet(CustomModelViewSet):
|
||||||
return ErrorResponse(msg="未获取到关联信息")
|
return ErrorResponse(msg="未获取到关联信息")
|
||||||
serializer = SystemConfigChinldernSerializer(queryset.parent)
|
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 = {
|
||||||
|
"site_name": "企业级后台管理系统", # 网站名称
|
||||||
|
"site_logo": "", # 网站logo地址
|
||||||
|
"login_background": "", # 登录页背景图
|
||||||
|
"copyright": "2021-2022 django-vue-admin.com 版权所有", # 版权
|
||||||
|
"keep_record": "晋ICP备18005113号-3", # 备案
|
||||||
|
"help_url": "https://django-vue-admin.com", # 帮助
|
||||||
|
"privacy_url": "#", # 隐私
|
||||||
|
"clause_url": "#", # 条款
|
||||||
|
}
|
||||||
|
return DetailResponse(data=data)
|
||||||
|
|
|
@ -1,13 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
@author: 猿小天
|
|
||||||
@contact: QQ:1638245306
|
|
||||||
@Created on: 2021/6/3 003 0:30
|
|
||||||
@Remark: 用户管理
|
|
||||||
"""
|
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
|
from application import settings
|
||||||
from django.contrib.auth.hashers import make_password
|
from django.contrib.auth.hashers import make_password
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
|
@ -28,9 +21,9 @@ class UserSerializer(CustomModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Users
|
model = Users
|
||||||
read_only_fields = ["id"]
|
read_only_fields = ["id"]
|
||||||
exclude = ['password']
|
exclude = ["password"]
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
'post': {'required': False},
|
"post": {"required": False},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,14 +31,23 @@ class UserCreateSerializer(CustomModelSerializer):
|
||||||
"""
|
"""
|
||||||
用户新增-序列化器
|
用户新增-序列化器
|
||||||
"""
|
"""
|
||||||
username = serializers.CharField(max_length=50,
|
|
||||||
validators=[CustomUniqueValidator(queryset=Users.objects.all(), message="账号必须唯一")])
|
username = serializers.CharField(
|
||||||
password = serializers.CharField(required=False, default=make_password(
|
max_length=50,
|
||||||
hashlib.md5('admin123456'.encode(encoding='UTF-8')).hexdigest()))
|
validators=[
|
||||||
|
CustomUniqueValidator(queryset=Users.objects.all(), message="账号必须唯一")
|
||||||
|
],
|
||||||
|
)
|
||||||
|
password = serializers.CharField(
|
||||||
|
required=False,
|
||||||
|
default=make_password(
|
||||||
|
hashlib.md5(settings.DEFAULT_PASSWORD.encode(encoding="UTF-8")).hexdigest()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def save(self, **kwargs):
|
def save(self, **kwargs):
|
||||||
data = super().save(**kwargs)
|
data = super().save(**kwargs)
|
||||||
data.post.set(self.initial_data.get('post', []))
|
data.post.set(self.initial_data.get("post", []))
|
||||||
return data
|
return data
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -53,7 +55,7 @@ class UserCreateSerializer(CustomModelSerializer):
|
||||||
fields = "__all__"
|
fields = "__all__"
|
||||||
read_only_fields = ["id"]
|
read_only_fields = ["id"]
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
'post': {'required': False},
|
"post": {"required": False},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -61,13 +63,24 @@ class UserUpdateSerializer(CustomModelSerializer):
|
||||||
"""
|
"""
|
||||||
用户修改-序列化器
|
用户修改-序列化器
|
||||||
"""
|
"""
|
||||||
username = serializers.CharField(max_length=50,
|
|
||||||
validators=[CustomUniqueValidator(queryset=Users.objects.all(), message="账号必须唯一")])
|
username = serializers.CharField(
|
||||||
|
max_length=50,
|
||||||
|
validators=[
|
||||||
|
CustomUniqueValidator(queryset=Users.objects.all(), message="账号必须唯一")
|
||||||
|
],
|
||||||
|
)
|
||||||
password = serializers.CharField(required=False, allow_blank=True)
|
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):
|
def save(self, **kwargs):
|
||||||
data = super().save(**kwargs)
|
data = super().save(**kwargs)
|
||||||
data.post.set(self.initial_data.get('post', []))
|
data.post.set(self.initial_data.get("post", []))
|
||||||
return data
|
return data
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -75,7 +88,7 @@ class UserUpdateSerializer(CustomModelSerializer):
|
||||||
read_only_fields = ["id"]
|
read_only_fields = ["id"]
|
||||||
fields = "__all__"
|
fields = "__all__"
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
'post': {'required': False, 'read_only': True},
|
"post": {"required": False, "read_only": True},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -83,22 +96,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='')
|
last_login = serializers.DateTimeField(
|
||||||
dept__owner = serializers.CharField(source='dept.owner', default='')
|
format="%Y-%m-%d %H:%M:%S", required=False, read_only=True
|
||||||
gender = serializers.CharField(source='get_gender_display', 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:
|
class Meta:
|
||||||
model = Users
|
model = Users
|
||||||
fields = ('username', 'name', 'email', 'mobile', 'gender', 'is_active', 'last_login', 'dept__deptName',
|
fields = (
|
||||||
'dept__owner')
|
"username",
|
||||||
|
"name",
|
||||||
|
"email",
|
||||||
|
"mobile",
|
||||||
|
"gender",
|
||||||
|
"is_active",
|
||||||
|
"last_login",
|
||||||
|
"dept__deptName",
|
||||||
|
"dept__owner",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class UserProfileImportSerializer(CustomModelSerializer):
|
class UserProfileImportSerializer(CustomModelSerializer):
|
||||||
|
|
||||||
def save(self, **kwargs):
|
def save(self, **kwargs):
|
||||||
data = super().save(**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.set_password(password)
|
||||||
data.save()
|
data.save()
|
||||||
return data
|
return data
|
||||||
|
@ -106,15 +132,22 @@ class UserProfileImportSerializer(CustomModelSerializer):
|
||||||
def run_validation(self, data={}):
|
def run_validation(self, data={}):
|
||||||
# 把excel 数据进行格式转换
|
# 把excel 数据进行格式转换
|
||||||
if type(data) is dict:
|
if type(data) is dict:
|
||||||
data['role'] = str(data['role']).split(',')
|
data["role"] = str(data["role"]).split(",")
|
||||||
data['dept_id'] = str(data['dept']).split(',')
|
data["dept_id"] = str(data["dept"]).split(",")
|
||||||
data['gender'] = {'男': '1', '女': '0', '未知': '2'}.get(data['gender'])
|
data["gender"] = {"男": "1", "女": "0", "未知": "2"}.get(data["gender"])
|
||||||
data['is_active'] = {'启用': True, '禁用': False}.get(data['is_active'])
|
data["is_active"] = {"启用": True, "禁用": False}.get(data["is_active"])
|
||||||
return super().run_validation(data)
|
return super().run_validation(data)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Users
|
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):
|
class UserViewSet(CustomModelViewSet):
|
||||||
|
@ -126,29 +159,49 @@ class UserViewSet(CustomModelViewSet):
|
||||||
retrieve:单例
|
retrieve:单例
|
||||||
destroy:删除
|
destroy:删除
|
||||||
"""
|
"""
|
||||||
|
|
||||||
queryset = Users.objects.exclude(is_superuser=1).all()
|
queryset = Users.objects.exclude(is_superuser=1).all()
|
||||||
serializer_class = UserSerializer
|
serializer_class = UserSerializer
|
||||||
create_serializer_class = UserCreateSerializer
|
create_serializer_class = UserCreateSerializer
|
||||||
update_serializer_class = UserUpdateSerializer
|
update_serializer_class = UserUpdateSerializer
|
||||||
filter_fields = ['name', 'username', 'gender', 'is_active', 'dept', 'user_type']
|
# filter_fields = ["name", "username", "gender", "is_active", "dept", "user_type"]
|
||||||
# filter_fields = {
|
filter_fields = {
|
||||||
# 'name': ['icontains'],
|
"name": ["icontains"],
|
||||||
# 'username': ['icontains'],
|
"username": ["exact"],
|
||||||
# 'gender': ['icontains'],
|
"gender": ["icontains"],
|
||||||
# 'is_active': ['icontains'],
|
"is_active": ["icontains"],
|
||||||
# 'dept': ['exact'],
|
"dept": ["exact"],
|
||||||
# }
|
"user_type": ["exact"],
|
||||||
search_fields = ['username', 'name', 'gender', 'dept__name', 'role__name']
|
}
|
||||||
|
search_fields = ["username", "name", "gender", "dept__name", "role__name"]
|
||||||
# 导出
|
# 导出
|
||||||
export_field_label = ['用户账号', '用户名称', '用户邮箱', '手机号码', '用户性别', '帐号状态', '最后登录时间', '部门名称', '部门负责人']
|
export_field_label = [
|
||||||
|
"用户账号",
|
||||||
|
"用户名称",
|
||||||
|
"用户邮箱",
|
||||||
|
"手机号码",
|
||||||
|
"用户性别",
|
||||||
|
"帐号状态",
|
||||||
|
"最后登录时间",
|
||||||
|
"部门名称",
|
||||||
|
"部门负责人",
|
||||||
|
]
|
||||||
export_serializer_class = ExportUserProfileSerializer
|
export_serializer_class = ExportUserProfileSerializer
|
||||||
# 导入
|
# 导入
|
||||||
import_serializer_class = UserProfileImportSerializer
|
import_serializer_class = UserProfileImportSerializer
|
||||||
import_field_dict = {'username': '登录账号', 'name': '用户名称', 'email': '用户邮箱', 'mobile': '手机号码',
|
import_field_dict = {
|
||||||
'gender': '用户性别(男/女/未知)',
|
"username": "登录账号",
|
||||||
'is_active': '帐号状态(启用/禁用)', 'password': '登录密码', 'dept': '部门ID', 'role': '角色ID'}
|
"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):
|
def user_info(self, request):
|
||||||
"""获取当前用户信息"""
|
"""获取当前用户信息"""
|
||||||
user = request.user
|
user = request.user
|
||||||
|
@ -157,25 +210,25 @@ class UserViewSet(CustomModelViewSet):
|
||||||
"mobile": user.mobile,
|
"mobile": user.mobile,
|
||||||
"gender": user.gender,
|
"gender": user.gender,
|
||||||
"email": user.email,
|
"email": user.email,
|
||||||
'avatar':user.avatar
|
"avatar": user.avatar,
|
||||||
}
|
}
|
||||||
return DetailResponse(data=result, msg="获取成功")
|
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):
|
def update_user_info(self, request):
|
||||||
"""修改当前用户信息"""
|
"""修改当前用户信息"""
|
||||||
user = request.user
|
user = request.user
|
||||||
Users.objects.filter(id=user.id).update(**request.data)
|
Users.objects.filter(id=user.id).update(**request.data)
|
||||||
return DetailResponse(data=None, msg="修改成功")
|
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):
|
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
|
data = request.data
|
||||||
old_pwd = data.get('oldPassword')
|
old_pwd = data.get("oldPassword")
|
||||||
new_pwd = data.get('newPassword')
|
new_pwd = data.get("newPassword")
|
||||||
new_pwd2 = data.get('newPassword2')
|
new_pwd2 = data.get("newPassword2")
|
||||||
if instance:
|
if instance:
|
||||||
if new_pwd != new_pwd2:
|
if new_pwd != new_pwd2:
|
||||||
return ErrorResponse(msg="两次密码不匹配")
|
return ErrorResponse(msg="两次密码不匹配")
|
||||||
|
@ -188,21 +241,32 @@ class UserViewSet(CustomModelViewSet):
|
||||||
else:
|
else:
|
||||||
return ErrorResponse(msg="未获取到用户")
|
return ErrorResponse(msg="未获取到用户")
|
||||||
|
|
||||||
@action(methods=['PUT'], detail=True)
|
@action(methods=["PUT"], detail=True, permission_classes=[IsAuthenticated])
|
||||||
def reset_password(self, request, pk):
|
def reset_password(self, request, *args, **kwargs):
|
||||||
"""
|
"""重置密码"""
|
||||||
密码重置
|
instance = Users.objects.filter(id=kwargs.get("pk")).first()
|
||||||
"""
|
|
||||||
instance = Users.objects.filter(id=pk).first()
|
|
||||||
data = request.data
|
|
||||||
new_pwd = data.get('newPassword')
|
|
||||||
new_pwd2 = data.get('newPassword2')
|
|
||||||
if instance:
|
if instance:
|
||||||
if new_pwd != new_pwd2:
|
instance.set_password(settings.DEFAULT_PASSWORD)
|
||||||
return ErrorResponse(msg="两次密码不匹配")
|
|
||||||
else:
|
|
||||||
instance.password = make_password(new_pwd)
|
|
||||||
instance.save()
|
instance.save()
|
||||||
return DetailResponse(data=None, msg="修改成功")
|
return DetailResponse(data=None, msg="密码重置成功")
|
||||||
else:
|
else:
|
||||||
return ErrorResponse(msg="未获取到用户")
|
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')
|
||||||
|
# if instance:
|
||||||
|
# if new_pwd != new_pwd2:
|
||||||
|
# return ErrorResponse(msg="两次密码不匹配")
|
||||||
|
# else:
|
||||||
|
# instance.password = make_password(new_pwd)
|
||||||
|
# instance.save()
|
||||||
|
# return DetailResponse(data=None, msg="修改成功")
|
||||||
|
# else:
|
||||||
|
# return ErrorResponse(msg="未获取到用户")
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
@Remark: 自定义过滤器
|
@Remark: 自定义过滤器
|
||||||
"""
|
"""
|
||||||
import operator
|
import operator
|
||||||
from collections import OrderedDict
|
|
||||||
import re
|
import re
|
||||||
|
from collections import OrderedDict
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
@ -32,13 +32,13 @@ def get_dept(dept_id: int, dept_all_list=None, dept_list=None):
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
if not dept_all_list:
|
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:
|
if dept_list is None:
|
||||||
dept_list = [dept_id]
|
dept_list = [dept_id]
|
||||||
for ele in dept_all_list:
|
for ele in dept_all_list:
|
||||||
if ele.get('parent') == dept_id:
|
if ele.get("parent") == dept_id:
|
||||||
dept_list.append(ele.get('id'))
|
dept_list.append(ele.get("id"))
|
||||||
get_dept(ele.get('id'), dept_all_list, dept_list)
|
get_dept(ele.get("id"), dept_all_list, dept_list)
|
||||||
return list(set(dept_list))
|
return list(set(dept_list))
|
||||||
|
|
||||||
|
|
||||||
|
@ -54,20 +54,26 @@ class DataLevelPermissionsFilter(BaseFilterBackend):
|
||||||
4. 只为仅本人数据权限时只返回过滤本人数据,并且部门为自己本部门(考虑到用户会变部门,只能看当前用户所在的部门数据)
|
4. 只为仅本人数据权限时只返回过滤本人数据,并且部门为自己本部门(考虑到用户会变部门,只能看当前用户所在的部门数据)
|
||||||
5. 自定数据权限 获取部门,根据部门过滤
|
5. 自定数据权限 获取部门,根据部门过滤
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def filter_queryset(self, request, queryset, view):
|
def filter_queryset(self, request, queryset, view):
|
||||||
"""
|
"""
|
||||||
接口白名单是否认证数据权限
|
接口白名单是否认证数据权限
|
||||||
"""
|
"""
|
||||||
api = request.path # 当前请求接口
|
api = request.path # 当前请求接口
|
||||||
method = request.method # 当前请求方法
|
method = request.method # 当前请求方法
|
||||||
methodList = ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']
|
methodList = ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
|
||||||
method = methodList.index(method)
|
method = methodList.index(method)
|
||||||
# ***接口白名单***
|
# ***接口白名单***
|
||||||
api_white_list = ApiWhiteList.objects.filter(enable_datasource=False).values(permission__api=F('url'),
|
api_white_list = ApiWhiteList.objects.filter(enable_datasource=False).values(
|
||||||
permission__method=F('method'))
|
permission__api=F("url"), permission__method=F("method")
|
||||||
|
)
|
||||||
api_white_list = [
|
api_white_list = [
|
||||||
str(item.get('permission__api').replace('{id}', '.*?')) + ":" + str(item.get('permission__method')) for item
|
str(item.get("permission__api").replace("{id}", ".*?"))
|
||||||
in api_white_list if item.get('permission__api')]
|
+ ":"
|
||||||
|
+ str(item.get("permission__method"))
|
||||||
|
for item in api_white_list
|
||||||
|
if item.get("permission__api")
|
||||||
|
]
|
||||||
for item in api_white_list:
|
for item in api_white_list:
|
||||||
new_api = api + ":" + str(method)
|
new_api = api + ":" + str(method)
|
||||||
matchObj = re.match(item, new_api, re.M | re.I)
|
matchObj = re.match(item, new_api, re.M | re.I)
|
||||||
|
@ -81,16 +87,16 @@ class DataLevelPermissionsFilter(BaseFilterBackend):
|
||||||
"""
|
"""
|
||||||
if request.user.is_superuser == 0:
|
if request.user.is_superuser == 0:
|
||||||
# 0. 获取用户的部门id,没有部门则返回空
|
# 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:
|
if not user_dept_id:
|
||||||
return queryset.none()
|
return queryset.none()
|
||||||
|
|
||||||
# 1. 判断过滤的数据是否有创建人所在部门 "dept_belong_id" 字段
|
# 1. 判断过滤的数据是否有创建人所在部门 "dept_belong_id" 字段
|
||||||
if not getattr(queryset.model, 'dept_belong_id', None):
|
if not getattr(queryset.model, "dept_belong_id", None):
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
# 2. 如果用户没有关联角色则返回本部门数据
|
# 2. 如果用户没有关联角色则返回本部门数据
|
||||||
if not hasattr(request.user, 'role'):
|
if not hasattr(request.user, "role"):
|
||||||
return queryset.filter(dept_belong_id=user_dept_id)
|
return queryset.filter(dept_belong_id=user_dept_id)
|
||||||
|
|
||||||
# 3. 根据所有角色 获取所有权限范围
|
# 3. 根据所有角色 获取所有权限范围
|
||||||
|
@ -99,28 +105,38 @@ class DataLevelPermissionsFilter(BaseFilterBackend):
|
||||||
# (2, "本部门数据权限"),
|
# (2, "本部门数据权限"),
|
||||||
# (3, "全部数据权限"),
|
# (3, "全部数据权限"),
|
||||||
# (4, "自定数据权限")
|
# (4, "自定数据权限")
|
||||||
role_list = request.user.role.filter(status=1).values('admin', 'data_range')
|
role_list = request.user.role.filter(status=1).values("admin", "data_range")
|
||||||
dataScope_list = [] # 权限范围列表
|
dataScope_list = [] # 权限范围列表
|
||||||
for ele in role_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
|
return queryset
|
||||||
dataScope_list.append(ele.get('data_range'))
|
dataScope_list.append(ele.get("data_range"))
|
||||||
dataScope_list = list(set(dataScope_list))
|
dataScope_list = list(set(dataScope_list))
|
||||||
|
|
||||||
# 4. 只为仅本人数据权限时只返回过滤本人数据,并且部门为自己本部门(考虑到用户会变部门,只能看当前用户所在的部门数据)
|
# 4. 只为仅本人数据权限时只返回过滤本人数据,并且部门为自己本部门(考虑到用户会变部门,只能看当前用户所在的部门数据)
|
||||||
if 0 in dataScope_list:
|
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. 自定数据权限 获取部门,根据部门过滤
|
# 5. 自定数据权限 获取部门,根据部门过滤
|
||||||
dept_list = []
|
dept_list = []
|
||||||
for ele in dataScope_list:
|
for ele in dataScope_list:
|
||||||
if ele == 4:
|
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:
|
elif ele == 2:
|
||||||
dept_list.append(user_dept_id)
|
dept_list.append(user_dept_id)
|
||||||
elif ele == 1:
|
elif ele == 1:
|
||||||
dept_list.extend(get_dept(user_dept_id, ))
|
dept_list.extend(
|
||||||
|
get_dept(
|
||||||
|
user_dept_id,
|
||||||
|
)
|
||||||
|
)
|
||||||
return queryset.filter(dept_belong_id__in=list(set(dept_list)))
|
return queryset.filter(dept_belong_id__in=list(set(dept_list)))
|
||||||
else:
|
else:
|
||||||
return queryset
|
return queryset
|
||||||
|
@ -128,11 +144,11 @@ class DataLevelPermissionsFilter(BaseFilterBackend):
|
||||||
|
|
||||||
class CustomDjangoFilterBackend(DjangoFilterBackend):
|
class CustomDjangoFilterBackend(DjangoFilterBackend):
|
||||||
lookup_prefixes = {
|
lookup_prefixes = {
|
||||||
'^': 'istartswith',
|
"^": "istartswith",
|
||||||
'=': 'iexact',
|
"=": "iexact",
|
||||||
'@': 'search',
|
"@": "search",
|
||||||
'$': 'iregex',
|
"$": "iregex",
|
||||||
'~': 'icontains'
|
"~": "icontains",
|
||||||
}
|
}
|
||||||
|
|
||||||
def construct_search(self, field_name):
|
def construct_search(self, field_name):
|
||||||
|
@ -140,12 +156,14 @@ class CustomDjangoFilterBackend(DjangoFilterBackend):
|
||||||
if lookup:
|
if lookup:
|
||||||
field_name = field_name[1:]
|
field_name = field_name[1:]
|
||||||
else:
|
else:
|
||||||
lookup = 'icontains'
|
lookup = "icontains"
|
||||||
return LOOKUP_SEP.join([field_name, lookup])
|
return LOOKUP_SEP.join([field_name, lookup])
|
||||||
|
|
||||||
def find_filter_lookups(self, orm_lookups, search_term_key):
|
def find_filter_lookups(self, orm_lookups, search_term_key):
|
||||||
for lookup in orm_lookups:
|
for lookup in orm_lookups:
|
||||||
if lookup.find(search_term_key) >= 0:
|
# if lookup.find(search_term_key) >= 0:
|
||||||
|
# 修复条件搜索错误 bug
|
||||||
|
if lookup == search_term_key:
|
||||||
return lookup
|
return lookup
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -153,39 +171,43 @@ class CustomDjangoFilterBackend(DjangoFilterBackend):
|
||||||
"""
|
"""
|
||||||
Return the `FilterSet` class used to filter the queryset.
|
Return the `FilterSet` class used to filter the queryset.
|
||||||
"""
|
"""
|
||||||
filterset_class = getattr(view, 'filterset_class', None)
|
filterset_class = getattr(view, "filterset_class", None)
|
||||||
filterset_fields = getattr(view, 'filterset_fields', None)
|
filterset_fields = getattr(view, "filterset_fields", None)
|
||||||
|
|
||||||
# TODO: remove assertion in 2.1
|
# 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(
|
utils.deprecate(
|
||||||
"`%s.filter_class` attribute should be renamed `filterset_class`."
|
"`%s.filter_class` attribute should be renamed `filterset_class`."
|
||||||
% view.__class__.__name__)
|
% view.__class__.__name__
|
||||||
filterset_class = getattr(view, 'filter_class', None)
|
)
|
||||||
|
filterset_class = getattr(view, "filter_class", None)
|
||||||
|
|
||||||
# TODO: remove assertion in 2.1
|
# 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(
|
utils.deprecate(
|
||||||
"`%s.filter_fields` attribute should be renamed `filterset_fields`."
|
"`%s.filter_fields` attribute should be renamed `filterset_fields`."
|
||||||
% view.__class__.__name__)
|
% view.__class__.__name__
|
||||||
filterset_fields = getattr(view, 'filter_fields', None)
|
)
|
||||||
|
filterset_fields = getattr(view, "filter_fields", None)
|
||||||
|
|
||||||
if filterset_class:
|
if filterset_class:
|
||||||
filterset_model = filterset_class._meta.model
|
filterset_model = filterset_class._meta.model
|
||||||
|
|
||||||
# FilterSets do not need to specify a Meta class
|
# FilterSets do not need to specify a Meta class
|
||||||
if filterset_model and queryset is not None:
|
if filterset_model and queryset is not None:
|
||||||
assert issubclass(queryset.model, filterset_model), \
|
assert issubclass(
|
||||||
'FilterSet model %s does not match queryset model %s' % \
|
queryset.model, filterset_model
|
||||||
(filterset_model, queryset.model)
|
), "FilterSet model %s does not match queryset model %s" % (
|
||||||
|
filterset_model,
|
||||||
|
queryset.model,
|
||||||
|
)
|
||||||
|
|
||||||
return filterset_class
|
return filterset_class
|
||||||
|
|
||||||
if filterset_fields and queryset is not None:
|
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):
|
class AutoFilterSet(self.filterset_base):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_filters(cls):
|
def get_filters(cls):
|
||||||
"""
|
"""
|
||||||
|
@ -206,6 +228,7 @@ class CustomDjangoFilterBackend(DjangoFilterBackend):
|
||||||
field = get_model_field(cls._meta.model, field_name)
|
field = get_model_field(cls._meta.model, field_name)
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from timezone_field import TimeZoneField
|
from timezone_field import TimeZoneField
|
||||||
|
|
||||||
# 不进行 过滤的model 类
|
# 不进行 过滤的model 类
|
||||||
if isinstance(field, (models.JSONField, TimeZoneField)):
|
if isinstance(field, (models.JSONField, TimeZoneField)):
|
||||||
continue
|
continue
|
||||||
|
@ -222,16 +245,20 @@ class CustomDjangoFilterBackend(DjangoFilterBackend):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if field is not None:
|
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
|
# Allow Meta.fields to contain declared filters *only* when a list/tuple
|
||||||
if isinstance(cls._meta.fields, (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:
|
if undefined:
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
"'Meta.fields' must not contain non-model field names: %s"
|
"'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
|
# Add in declared filters. This is necessary since we don't enforce adding
|
||||||
|
@ -251,14 +278,21 @@ class CustomDjangoFilterBackend(DjangoFilterBackend):
|
||||||
filterset = self.get_filterset(request, queryset, view)
|
filterset = self.get_filterset(request, queryset, view)
|
||||||
if filterset is None:
|
if filterset is None:
|
||||||
return queryset
|
return queryset
|
||||||
if filterset.__class__.__name__ == 'AutoFilterSet':
|
if filterset.__class__.__name__ == "AutoFilterSet":
|
||||||
queryset = filterset.queryset
|
queryset = filterset.queryset
|
||||||
orm_lookups = []
|
orm_lookups = []
|
||||||
for search_field in filterset.filters:
|
for search_field in filterset.filters:
|
||||||
if isinstance(filterset.filters[search_field], CharFilter):
|
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:
|
else:
|
||||||
orm_lookups.append(search_field)
|
orm_lookups.append(search_field)
|
||||||
|
orm_lookups = (
|
||||||
|
orm_lookups
|
||||||
|
if isinstance(filterset.__class__._meta.fields, (list, tuple))
|
||||||
|
else filterset.filters.keys()
|
||||||
|
)
|
||||||
conditions = []
|
conditions = []
|
||||||
queries = []
|
queries = []
|
||||||
for search_term_key in filterset.data.keys():
|
for search_term_key in filterset.data.keys():
|
||||||
|
|
|
@ -190,7 +190,7 @@ def get_ip_analysis(ip):
|
||||||
}
|
}
|
||||||
if ip != 'unknown' and ip:
|
if ip != 'unknown' and ip:
|
||||||
if getattr(settings, 'ENABLE_LOGIN_ANALYSIS_LOG', True):
|
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}))
|
res = requests.get(url='https://ip.django-vue-admin.com/ip/analysis', params={"ip": ip})
|
||||||
if res.status_code == 200:
|
if res.status_code == 200:
|
||||||
res_data = res.json()
|
res_data = res.json()
|
||||||
if res_data.get('code') == 0:
|
if res_data.get('code') == 0:
|
||||||
|
|
|
@ -17,37 +17,46 @@ from dvadmin.system.models import Users
|
||||||
from django_restql.mixins import DynamicFieldsMixin
|
from django_restql.mixins import DynamicFieldsMixin
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class CustomModelSerializer(DynamicFieldsMixin, ModelSerializer):
|
class CustomModelSerializer(DynamicFieldsMixin, ModelSerializer):
|
||||||
"""
|
"""
|
||||||
增强DRF的ModelSerializer,可自动更新模型的审计字段记录
|
增强DRF的ModelSerializer,可自动更新模型的审计字段记录
|
||||||
(1)self.request能获取到rest_framework.request.Request对象
|
(1)self.request能获取到rest_framework.request.Request对象
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# 修改人的审计字段名称, 默认modifier, 继承使用时可自定义覆盖
|
# 修改人的审计字段名称, 默认modifier, 继承使用时可自定义覆盖
|
||||||
modifier_field_id = 'modifier'
|
modifier_field_id = "modifier"
|
||||||
modifier_name = serializers.SerializerMethodField(read_only=True)
|
modifier_name = serializers.SerializerMethodField(read_only=True)
|
||||||
|
|
||||||
def get_modifier_name(self, instance):
|
def get_modifier_name(self, instance):
|
||||||
if not hasattr(instance, 'modifier'):
|
if not hasattr(instance, "modifier"):
|
||||||
return None
|
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:
|
if queryset:
|
||||||
return queryset
|
return queryset
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# 创建人的审计字段名称, 默认creator, 继承使用时可自定义覆盖
|
# 创建人的审计字段名称, 默认creator, 继承使用时可自定义覆盖
|
||||||
creator_field_id = 'creator'
|
creator_field_id = "creator"
|
||||||
creator_name = serializers.SlugRelatedField(slug_field="name", source="creator", read_only=True)
|
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)
|
create_datetime = serializers.DateTimeField(
|
||||||
update_datetime = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False)
|
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):
|
def __init__(self, instance=None, data=empty, request=None, **kwargs):
|
||||||
super().__init__(instance, data, **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):
|
def save(self, **kwargs):
|
||||||
return super().save(**kwargs)
|
return super().save(**kwargs)
|
||||||
|
@ -60,30 +69,36 @@ class CustomModelSerializer(DynamicFieldsMixin,ModelSerializer):
|
||||||
if self.creator_field_id in self.fields.fields:
|
if self.creator_field_id in self.fields.fields:
|
||||||
validated_data[self.creator_field_id] = self.request.user
|
validated_data[self.creator_field_id] = self.request.user
|
||||||
|
|
||||||
if self.dept_belong_id_field_name in self.fields.fields and validated_data.get(
|
if (
|
||||||
self.dept_belong_id_field_name, None) is None:
|
self.dept_belong_id_field_name in self.fields.fields
|
||||||
validated_data[self.dept_belong_id_field_name] = getattr(self.request.user, 'dept_id', None)
|
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)
|
return super().create(validated_data)
|
||||||
|
|
||||||
def update(self, instance, validated_data):
|
def update(self, instance, validated_data):
|
||||||
if self.request:
|
if self.request:
|
||||||
if hasattr(self.instance, self.modifier_field_id):
|
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)
|
return super().update(instance, validated_data)
|
||||||
|
|
||||||
def get_request_username(self):
|
def get_request_username(self):
|
||||||
if getattr(self.request, 'user', None):
|
if getattr(self.request, "user", None):
|
||||||
return getattr(self.request.user, 'username', None)
|
return getattr(self.request.user, "username", None)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_request_name(self):
|
def get_request_name(self):
|
||||||
if getattr(self.request, 'user', None):
|
if getattr(self.request, "user", None):
|
||||||
return getattr(self.request.user, 'name', None)
|
return getattr(self.request.user, "name", None)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_request_user_id(self):
|
def get_request_user_id(self):
|
||||||
if getattr(self.request, 'user', None):
|
if getattr(self.request, "user", None):
|
||||||
return getattr(self.request.user, 'id', None)
|
return getattr(self.request.user, "id", None)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# @cached_property
|
# @cached_property
|
||||||
|
@ -132,4 +147,3 @@ class CustomModelSerializer(DynamicFieldsMixin,ModelSerializer):
|
||||||
# fields.pop(field, None)
|
# fields.pop(field, None)
|
||||||
#
|
#
|
||||||
# return fields
|
# return fields
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
version: "3"
|
version: "3"
|
||||||
services:
|
services:
|
||||||
DVAdmin-web:
|
dvadmin-web:
|
||||||
container_name: DVAdmin-web
|
container_name: dvadmin-web
|
||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
build:
|
build:
|
||||||
|
@ -15,20 +15,20 @@ services:
|
||||||
- "8080"
|
- "8080"
|
||||||
networks:
|
networks:
|
||||||
network:
|
network:
|
||||||
ipv4_address: 177.7.0.11
|
ipv4_address: 177.8.0.11
|
||||||
|
|
||||||
DVAdmin-django:
|
dvadmin-django:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: ./docker_env/django/Dockerfile
|
dockerfile: ./docker_env/django/Dockerfile
|
||||||
container_name: DVAdmin-django
|
container_name: dvadmin-django
|
||||||
working_dir: /backend
|
working_dir: /backend
|
||||||
# 打开mysql 时,打开此选项
|
# 打开mysql 时,打开此选项
|
||||||
# depends_on:
|
# depends_on:
|
||||||
# - DVAdmin-mysql
|
# - dvadmin-mysql
|
||||||
environment:
|
environment:
|
||||||
PYTHONUNBUFFERED: 1
|
PYTHONUNBUFFERED: 1
|
||||||
DATABASE_HOST: DVAdmin-mysql
|
DATABASE_HOST: dvadmin-mysql
|
||||||
TZ: Asia/Shanghai
|
TZ: Asia/Shanghai
|
||||||
volumes:
|
volumes:
|
||||||
- ./backend:/backend
|
- ./backend:/backend
|
||||||
|
@ -40,11 +40,11 @@ services:
|
||||||
restart: always
|
restart: always
|
||||||
networks:
|
networks:
|
||||||
network:
|
network:
|
||||||
ipv4_address: 177.7.0.12
|
ipv4_address: 177.8.0.12
|
||||||
|
|
||||||
# DVAdmin-mysql:
|
# dvadmin-mysql:
|
||||||
# image: mysql:5.7
|
# image: mysql:5.7
|
||||||
# container_name: DVAdmin-mysql
|
# container_name: dvadmin-mysql
|
||||||
# #使用该参数,container内的root拥有真正的root权限,否则,container内的root只是外部的一个普通用户权限
|
# #使用该参数,container内的root拥有真正的root权限,否则,container内的root只是外部的一个普通用户权限
|
||||||
# #设置为true,不然数据卷可能挂载不了,启动不起
|
# #设置为true,不然数据卷可能挂载不了,启动不起
|
||||||
## privileged: true
|
## privileged: true
|
||||||
|
@ -66,22 +66,22 @@ services:
|
||||||
# - "./docker_env/mysql/logs:/logs"
|
# - "./docker_env/mysql/logs:/logs"
|
||||||
# networks:
|
# networks:
|
||||||
# network:
|
# network:
|
||||||
# ipv4_address: 177.7.0.13
|
# ipv4_address: 177.8.0.13
|
||||||
|
|
||||||
|
|
||||||
# 如果使用celery 插件,请自行打开此注释
|
# 如果使用celery 插件,请自行打开此注释
|
||||||
# DVAdmin-celery:
|
# dvadmin-celery:
|
||||||
# build:
|
# build:
|
||||||
# context: .
|
# context: .
|
||||||
# dockerfile: ./docker_env/celery/Dockerfile
|
# dockerfile: ./docker_env/celery/Dockerfile
|
||||||
# # image: django:2.2
|
# # image: django:2.2
|
||||||
# container_name: DVAdmin-celery
|
# container_name: dvadmin-celery
|
||||||
# working_dir: /backend
|
# working_dir: /backend
|
||||||
# depends_on:
|
# depends_on:
|
||||||
# - DVAdmin-mysql
|
# - dvadmin-mysql
|
||||||
# environment:
|
# environment:
|
||||||
# PYTHONUNBUFFERED: 1
|
# PYTHONUNBUFFERED: 1
|
||||||
# DATABASE_HOST: DVAdmin-mysql
|
# DATABASE_HOST: dvadmin-mysql
|
||||||
# TZ: Asia/Shanghai
|
# TZ: Asia/Shanghai
|
||||||
# volumes:
|
# volumes:
|
||||||
# - ./backend:/backend
|
# - ./backend:/backend
|
||||||
|
@ -89,12 +89,12 @@ services:
|
||||||
# restart: always
|
# restart: always
|
||||||
# networks:
|
# networks:
|
||||||
# network:
|
# network:
|
||||||
# ipv4_address: 177.7.0.14
|
# ipv4_address: 177.8.0.14
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
network:
|
network:
|
||||||
ipam:
|
ipam:
|
||||||
driver: default
|
driver: default
|
||||||
config:
|
config:
|
||||||
- subnet: '177.7.0.0/16'
|
- subnet: '177.8.0.0/16'
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# 开发环境
|
# 开发环境
|
||||||
NODE_ENV=development
|
NODE_ENV=development
|
||||||
# 页面 title 前缀
|
# 页面 title 前缀
|
||||||
VUE_APP_TITLE=DVAdmin
|
VUE_APP_TITLE=企业级后台管理系统
|
||||||
# 启用权限管理
|
# 启用权限管理
|
||||||
VUE_APP_PM_ENABLED = true
|
VUE_APP_PM_ENABLED = true
|
||||||
# 后端接口地址及端口(域名)
|
# 后端接口地址及端口(域名)
|
||||||
|
|
|
@ -6,7 +6,7 @@ NODE_ENV=production
|
||||||
# 标记当前构建方式
|
# 标记当前构建方式
|
||||||
VUE_APP_BUILD_MODE=PREVIEW
|
VUE_APP_BUILD_MODE=PREVIEW
|
||||||
# 页面 title 前缀
|
# 页面 title 前缀
|
||||||
VUE_APP_TITLE=DVAdmin
|
VUE_APP_TITLE=企业级后台管理系统
|
||||||
# 显示源码按钮
|
# 显示源码按钮
|
||||||
VUE_APP_SCOURCE_LINK=FALSE
|
VUE_APP_SCOURCE_LINK=FALSE
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# 测试环境
|
# 测试环境
|
||||||
|
|
||||||
# 页面 title 前缀
|
# 页面 title 前缀
|
||||||
VUE_APP_TITLE=DVAdmin
|
VUE_APP_TITLE=企业级后台管理系统
|
||||||
# 启用权限管理
|
# 启用权限管理
|
||||||
VUE_APP_PM_ENABLED = true
|
VUE_APP_PM_ENABLED = true
|
||||||
# 后端接口地址及端口(域名)
|
# 后端接口地址及端口(域名)
|
||||||
|
|
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;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.d2-home__loading {
|
#loader-wrapper {
|
||||||
height: 32px;
|
position: fixed;
|
||||||
width: 32px;
|
top: 0;
|
||||||
margin-bottom: 20px;
|
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>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
|
@ -78,15 +269,11 @@
|
||||||
</strong>
|
</strong>
|
||||||
</noscript>
|
</noscript>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<div class="d2-home">
|
<div id="loader-wrapper">
|
||||||
<div class="d2-home__main">
|
<div id="loader"></div>
|
||||||
<img class="d2-home__loading" src="./image/loading/loading-spin.svg" alt="loading">
|
<div class="loader-section section-left"></div>
|
||||||
</div>
|
<div class="loader-section section-right"></div>
|
||||||
<div class="d2-home__footer">
|
<div class="load_title">正在加载中,请耐心等待...</div>
|
||||||
<a href="https://gitee.com/liqianglog/django-vue-admin" target="_blank">
|
|
||||||
https://gitee.com/liqianglog/django-vue-admin
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 使用 CDN 加速的 JS 文件,配置在 vue.config.js 下 -->
|
<!-- 使用 CDN 加速的 JS 文件,配置在 vue.config.js 下 -->
|
||||||
|
|
|
@ -69,3 +69,65 @@
|
||||||
*::-webkit-scrollbar-thumb:hover {
|
*::-webkit-scrollbar-thumb:hover {
|
||||||
background-color: #bbb;
|
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,7 +3,8 @@
|
||||||
v-if="show"
|
v-if="show"
|
||||||
class="d2-source"
|
class="d2-source"
|
||||||
:class="{ 'd2-source--active': isActive }"
|
:class="{ 'd2-source--active': isActive }"
|
||||||
@click="handleClick">
|
@click="handleClick"
|
||||||
|
>
|
||||||
<d2-icon name="code" /> 本页源码
|
<d2-icon name="code" /> 本页源码
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -51,7 +52,7 @@ export default {
|
||||||
$paddingLR: 15px;
|
$paddingLR: 15px;
|
||||||
$paddingTB: 7px;
|
$paddingTB: 7px;
|
||||||
$fontSize: 12px;
|
$fontSize: 12px;
|
||||||
$rightOuter: $paddingLR / 2;
|
$rightOuter: calc($paddingLR / 2);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
|
@ -63,17 +64,17 @@ export default {
|
||||||
border-radius: $borderRadius;
|
border-radius: $borderRadius;
|
||||||
padding: $paddingTB $paddingLR;
|
padding: $paddingTB $paddingLR;
|
||||||
padding-right: $borderRadius + $paddingLR;
|
padding-right: $borderRadius + $paddingLR;
|
||||||
background-color: rgba(#000, .7);
|
background-color: rgba(#000, 0.7);
|
||||||
border: 1px solid #000;
|
border: 1px solid #000;
|
||||||
color: #FFF;
|
color: #fff;
|
||||||
transition: all .3s;
|
transition: all 0.3s;
|
||||||
@extend %unable-select;
|
@extend %unable-select;
|
||||||
&.d2-source--active {
|
&.d2-source--active {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
&:hover {
|
&:hover {
|
||||||
right: -$borderRadius;
|
right: -$borderRadius;
|
||||||
background-color: rgba(#000, .9);
|
background-color: rgba(#000, 0.9);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -19,7 +19,7 @@ export function getButtonSettings (objectSettings) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// v2.0.2 中已弃用,改为 vm.dictionary('button_status_bool')
|
||||||
// 启用 true/ 禁用 false
|
// 启用 true/ 禁用 false
|
||||||
export const BUTTON_STATUS_BOOL = getButtonSettings([{ label: '启用', value: true }, { label: '禁用', value: 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 }])
|
export const BUTTON_WHETHER_NUMBER = getButtonSettings([{ label: '是', value: 1 }, { label: '否', value: 0 }])
|
||||||
// 是 true/ 否 false
|
// 是 true/ 否 false
|
||||||
export const BUTTON_WHETHER_BOOL = getButtonSettings([{ label: '是', value: true }, { label: '否', value: 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,9 @@ import {
|
||||||
import { request } from '@/api/service'
|
import { request } from '@/api/service'
|
||||||
import util from '@/libs/util'
|
import util from '@/libs/util'
|
||||||
import XEUtils from 'xe-utils'
|
import XEUtils from 'xe-utils'
|
||||||
import { urlPrefix as deptPrefix } from '@/views/system/dept/'
|
import store from '@/store/index'
|
||||||
|
import { urlPrefix as deptPrefix } from '@/views/system/dept/api'
|
||||||
|
import types from '@/config/d2p-extends/types'
|
||||||
const uploadUrl = util.baseURL() + 'api/system/file/'
|
const uploadUrl = util.baseURL() + 'api/system/file/'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -163,24 +165,29 @@ Vue.use(D2pUploader, {
|
||||||
action: uploadUrl,
|
action: uploadUrl,
|
||||||
name: 'file',
|
name: 'file',
|
||||||
data: {}, // 上传附加参数
|
data: {}, // 上传附加参数
|
||||||
headers: {
|
headers () {
|
||||||
|
return {
|
||||||
Authorization: 'JWT ' + util.cookies.get('token')
|
Authorization: 'JWT ' + util.cookies.get('token')
|
||||||
|
}
|
||||||
},
|
},
|
||||||
type: 'form',
|
type: 'form',
|
||||||
successHandle (ret, option) {
|
successHandle (ret, option) {
|
||||||
if (ret.data === null || ret.data === '') {
|
if (ret.data === null || ret.data === '') {
|
||||||
throw new Error('上传失败')
|
throw new Error('上传失败')
|
||||||
}
|
}
|
||||||
return { url: ret.data.data.url, key: option.data.key }
|
return { url: util.baseURL() + ret.data.url, key: option.data.key }
|
||||||
},
|
},
|
||||||
withCredentials: false // 是否带cookie
|
withCredentials: false // 是否带cookie
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
d2CrudPlus.util.columnResolve.addTypes(types)
|
||||||
// 修改官方字段类型
|
// 修改官方字段类型
|
||||||
const selectType = d2CrudPlus.util.columnResolve.getType('select')
|
const selectType = d2CrudPlus.util.columnResolve.getType('select')
|
||||||
selectType.component.props.color = 'auto' // 修改官方的字段类型,设置为支持自动染色
|
selectType.component.props.color = 'auto' // 修改官方的字段类型,设置为支持自动染色
|
||||||
|
// 获取字典配置
|
||||||
|
Vue.prototype.dictionary = function (name) {
|
||||||
|
return store.state.d2admin.dictionary.data[name]
|
||||||
|
}
|
||||||
// 默认Columns 结尾 showForm:显示在form中,showTable:显示在table中
|
// 默认Columns 结尾 showForm:显示在form中,showTable:显示在table中
|
||||||
Vue.prototype.commonEndColumns = function (param = {}) {
|
Vue.prototype.commonEndColumns = function (param = {}) {
|
||||||
/**
|
/**
|
||||||
|
@ -270,7 +277,7 @@ Vue.prototype.commonEndColumns = function (param = {}) {
|
||||||
type: 'table-selector',
|
type: 'table-selector',
|
||||||
dict: {
|
dict: {
|
||||||
cache: true,
|
cache: true,
|
||||||
url: deptPrefix + '?limit=999&status=1',
|
url: deptPrefix,
|
||||||
isTree: true,
|
isTree: true,
|
||||||
value: 'id', // 数据字典中value字段的属性名
|
value: 'id', // 数据字典中value字段的属性名
|
||||||
label: 'name', // 数据字典中label字段的属性名
|
label: 'name', // 数据字典中label字段的属性名
|
||||||
|
@ -280,7 +287,8 @@ Vue.prototype.commonEndColumns = function (param = {}) {
|
||||||
component
|
component
|
||||||
}) => {
|
}) => {
|
||||||
return request({
|
return request({
|
||||||
url: url
|
url: url,
|
||||||
|
params: { limit: 999, status: 1 }
|
||||||
}).then(ret => {
|
}).then(ret => {
|
||||||
return ret.data.data
|
return ret.data.data
|
||||||
})
|
})
|
||||||
|
|
|
@ -29,9 +29,20 @@
|
||||||
:headers="headers"
|
:headers="headers"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
:disabled="fileList.length === 1"
|
:disabled="fileList.length === 1"
|
||||||
:on-success="handleAvatarSuccess">
|
: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>-->
|
<!-- <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>
|
<i class="el-icon-plus"></i>
|
||||||
</el-upload>
|
</el-upload>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
@ -159,9 +170,7 @@ export default {
|
||||||
},
|
},
|
||||||
userInforules: {
|
userInforules: {
|
||||||
name: [{ required: true, message: '请输入昵称', trigger: 'blur' }],
|
name: [{ required: true, message: '请输入昵称', trigger: 'blur' }],
|
||||||
mobile: [
|
mobile: [{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确手机号' }]
|
||||||
{ pattern: /^1[3|4|5|7|8]\d{9}$/, message: '请输入正确手机号' }
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
userPasswordInfo: {
|
userPasswordInfo: {
|
||||||
oldPassword: '',
|
oldPassword: '',
|
||||||
|
|
|
@ -42,6 +42,11 @@ new Vue({
|
||||||
store,
|
store,
|
||||||
i18n,
|
i18n,
|
||||||
render: h => h(App),
|
render: h => h(App),
|
||||||
|
beforeCreate () {
|
||||||
|
// 初始化配置
|
||||||
|
this.$store.dispatch('d2admin/settings/load')
|
||||||
|
this.$store.dispatch('d2admin/dictionary/load')
|
||||||
|
},
|
||||||
created () {
|
created () {
|
||||||
|
|
||||||
// 处理路由 得到每一级的路由设置
|
// 处理路由 得到每一级的路由设置
|
||||||
|
|
|
@ -64,7 +64,9 @@ router.beforeEach(async (to, from, next) => {
|
||||||
// 处理路由 得到每一级的路由设置
|
// 处理路由 得到每一级的路由设置
|
||||||
store.commit('d2admin/page/init', routes)
|
store.commit('d2admin/page/init', routes)
|
||||||
|
|
||||||
router.addRoutes(routes)
|
// router.addRoutes(routes)
|
||||||
|
routes.forEach(route => router.addRoute(route))
|
||||||
|
|
||||||
const menu = handleAsideMenu(ret)
|
const menu = handleAsideMenu(ret)
|
||||||
const aside = handleAsideMenu(ret.filter(value => value.visible === true))
|
const aside = handleAsideMenu(ret.filter(value => value.visible === true))
|
||||||
store.commit('d2admin/menu/asideSet', aside) // 设置侧边栏菜单
|
store.commit('d2admin/menu/asideSet', aside) // 设置侧边栏菜单
|
||||||
|
|
|
@ -18,20 +18,22 @@ export default {
|
||||||
/**
|
/**
|
||||||
* @description 登录
|
* @description 登录
|
||||||
* @param {Object} context
|
* @param {Object} context
|
||||||
* @param {Object} data
|
* @param {Object} payload username {String} 用户账号
|
||||||
* @param {Object} data username {String} 用户账号
|
* @param {Object} payload password {String} 密码
|
||||||
* @param {Object} data password {String} 密码
|
* @param {Object} payload route {Object} 登录成功后定向的路由对象 任何 vue-router 支持的格式
|
||||||
* @param {Object} data route {Object} 登录成功后定向的路由对象 任何 vue-router 支持的格式
|
|
||||||
* @param {Object} data request function 请求方法
|
|
||||||
*/
|
*/
|
||||||
async login ({ dispatch }, data) {
|
async login ({ dispatch }, {
|
||||||
let request = data.request
|
username = '',
|
||||||
if (request) {
|
password = '',
|
||||||
delete data.request
|
captcha = '',
|
||||||
} else {
|
captchaKey = ''
|
||||||
request = SYS_USER_LOGIN
|
} = {}) {
|
||||||
}
|
let res = await SYS_USER_LOGIN({
|
||||||
let res = await request(data)
|
username,
|
||||||
|
password,
|
||||||
|
captcha,
|
||||||
|
captchaKey
|
||||||
|
})
|
||||||
// 设置 cookie 一定要存 uuid 和 token 两个 cookie
|
// 设置 cookie 一定要存 uuid 和 token 两个 cookie
|
||||||
// 整个系统依赖这两个数据进行校验和存储
|
// 整个系统依赖这两个数据进行校验和存储
|
||||||
// uuid 是用户身份唯一标识 用户注册的时候确定 并且不可改变 不可重复
|
// uuid 是用户身份唯一标识 用户注册的时候确定 并且不可改变 不可重复
|
||||||
|
|
|
@ -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: 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,72 @@
|
||||||
|
import { request } from '@/api/service'
|
||||||
|
|
||||||
|
export const urlPrefix = '/api/init/settings/'
|
||||||
|
|
||||||
|
// 系统配置
|
||||||
|
export default {
|
||||||
|
namespaced: true,
|
||||||
|
state: {
|
||||||
|
siteName: '', // 网站名称
|
||||||
|
siteLogo: '', // 网站logo地址
|
||||||
|
loginBackground: '', // 登录页背景图
|
||||||
|
copyright: '', // 版权
|
||||||
|
keepRecord: '', // 备案
|
||||||
|
helpUrl: '', // 帮助地址
|
||||||
|
privacyUrl: '', // 隐私
|
||||||
|
clauseUrl: '' // 条款
|
||||||
|
},
|
||||||
|
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 }) {
|
||||||
|
const res = await dispatch('d2admin/db/get', {
|
||||||
|
dbName: 'sys',
|
||||||
|
path: 'settings.init',
|
||||||
|
defaultValue: {},
|
||||||
|
user: true
|
||||||
|
}, { root: true })
|
||||||
|
// store 赋值
|
||||||
|
state.siteName = res.site_name
|
||||||
|
state.siteLogo = res.site_logo
|
||||||
|
state.loginBackground = res.login_background
|
||||||
|
state.copyright = res.copyright
|
||||||
|
state.keepRecord = res.keep_record
|
||||||
|
state.helpUrl = res.help_url
|
||||||
|
state.privacyUrl = res.privacy_url
|
||||||
|
state.clauseUrl = res.clause_url
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
/**
|
||||||
|
* @description 获取配置
|
||||||
|
* @param {Object} state state
|
||||||
|
* @param {String} key active
|
||||||
|
* @param {Object} value active
|
||||||
|
*/
|
||||||
|
async get (state, key, value) {
|
||||||
|
return state[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -92,26 +92,6 @@ export const crudOptions = (vm) => {
|
||||||
span: 24
|
span: 24
|
||||||
},
|
},
|
||||||
helper: '限制文件大小不能超过50k'
|
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -132,26 +112,6 @@ export const crudOptions = (vm) => {
|
||||||
span: 24
|
span: 24
|
||||||
},
|
},
|
||||||
helper: '限制文件大小不能超过50k'
|
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'
|
import { request } from '@/api/service'
|
||||||
|
|
||||||
export const crudOptions = (vm) => {
|
export const crudOptions = (vm) => {
|
||||||
|
@ -234,7 +232,7 @@ export const crudOptions = (vm) => {
|
||||||
width: 90,
|
width: 90,
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
dict: {
|
dict: {
|
||||||
data: BUTTON_STATUS_BOOL
|
data: vm.dictionary('button_status_bool')
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
value: true,
|
value: true,
|
||||||
|
|
|
@ -14,7 +14,7 @@ export function GetList (query) {
|
||||||
return request({
|
return request({
|
||||||
url: urlPrefix,
|
url: urlPrefix,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
data: query
|
params: query
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
export function createObj (obj) {
|
export function createObj (obj) {
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { request } from '@/api/service'
|
import { request } from '@/api/service'
|
||||||
import { BUTTON_STATUS_BOOL } from '@/config/button'
|
|
||||||
import { urlPrefix as deptPrefix } from './api'
|
import { urlPrefix as deptPrefix } from './api'
|
||||||
import XEUtils from 'xe-utils'
|
import XEUtils from 'xe-utils'
|
||||||
export const crudOptions = (vm) => {
|
export const crudOptions = (vm) => {
|
||||||
|
@ -97,15 +96,15 @@ export const crudOptions = (vm) => {
|
||||||
type: 'cascader',
|
type: 'cascader',
|
||||||
dict: {
|
dict: {
|
||||||
cache: false,
|
cache: false,
|
||||||
url: deptPrefix + '?limit=999&status=1',
|
url: deptPrefix,
|
||||||
isTree: true,
|
isTree: true,
|
||||||
value: 'id', // 数据字典中value字段的属性名
|
value: 'id', // 数据字典中value字段的属性名
|
||||||
label: 'name', // 数据字典中label字段的属性名
|
label: 'name', // 数据字典中label字段的属性名
|
||||||
children: 'children', // 数据字典中children字段的属性名
|
children: 'children', // 数据字典中children字段的属性名
|
||||||
getData: (url, dict) => { // 配置此参数会覆盖全局的getRemoteDictFunc
|
getData: (url, dict) => { // 配置此参数会覆盖全局的getRemoteDictFunc
|
||||||
return request({ url: url }).then(ret => {
|
return request({ url: url, params: { limit: 999, status: 1 } }).then(ret => {
|
||||||
const data = XEUtils.toArrayTree(ret.data.data, { parentKey: 'parent', strict: true })
|
const data = XEUtils.toArrayTree(ret.data.data, { parentKey: 'parent', strict: true })
|
||||||
return [{ id: '0', name: '根节点', children: data }]
|
return [{ id: null, name: '根节点', children: data }]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -226,7 +225,7 @@ export const crudOptions = (vm) => {
|
||||||
width: 90,
|
width: 90,
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
dict: {
|
dict: {
|
||||||
data: BUTTON_STATUS_BOOL
|
data: vm.dictionary('button_status_bool')
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
value: true,
|
value: true,
|
||||||
|
|
|
@ -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 { request } from '@/api/service'
|
||||||
import XEUtils from 'xe-utils'
|
import XEUtils from 'xe-utils'
|
||||||
export const urlPrefix = '/api/system/dictionary/'
|
export const urlPrefix = '/api/system/dictionary/'
|
||||||
|
@ -14,7 +6,6 @@ export const urlPrefix = '/api/system/dictionary/'
|
||||||
* 列表查询
|
* 列表查询
|
||||||
*/
|
*/
|
||||||
export function GetList (query) {
|
export function GetList (query) {
|
||||||
query.limit = 999
|
|
||||||
return request({
|
return request({
|
||||||
url: urlPrefix,
|
url: urlPrefix,
|
||||||
method: 'get',
|
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) => {
|
export const crudOptions = (vm) => {
|
||||||
return {
|
return {
|
||||||
|
|
||||||
|
@ -22,7 +17,7 @@ export const crudOptions = (vm) => {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
rowHandle: {
|
rowHandle: {
|
||||||
width: 140,
|
width: 230,
|
||||||
view: {
|
view: {
|
||||||
thin: true,
|
thin: true,
|
||||||
text: '',
|
text: '',
|
||||||
|
@ -43,12 +38,18 @@ export const crudOptions = (vm) => {
|
||||||
disabled () {
|
disabled () {
|
||||||
return !vm.hasPermissions('Delete')
|
return !vm.hasPermissions('Delete')
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
custom: [{
|
||||||
|
text: ' 字典配置',
|
||||||
|
type: 'success',
|
||||||
|
size: 'small',
|
||||||
|
emit: 'dictionaryConfigure'
|
||||||
|
}]
|
||||||
},
|
},
|
||||||
indexRow: { // 或者直接传true,不显示title,不居中
|
indexRow: { // 或者直接传true,不显示title,不居中
|
||||||
title: '序号',
|
title: '序号',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: 100
|
width: 80
|
||||||
},
|
},
|
||||||
viewOptions: {
|
viewOptions: {
|
||||||
componentType: 'form'
|
componentType: 'form'
|
||||||
|
@ -89,77 +90,8 @@ export const crudOptions = (vm) => {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '父级字典',
|
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: '显示值',
|
|
||||||
key: 'label',
|
key: 'label',
|
||||||
sortable: true,
|
|
||||||
|
|
||||||
search: {
|
search: {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
|
@ -173,13 +105,13 @@ export const crudOptions = (vm) => {
|
||||||
type: 'input',
|
type: 'input',
|
||||||
form: {
|
form: {
|
||||||
rules: [ // 表单校验规则
|
rules: [ // 表单校验规则
|
||||||
{ required: true, message: '显示值必填项' }
|
{ required: true, message: '字典名称必填项' }
|
||||||
],
|
],
|
||||||
component: {
|
component: {
|
||||||
props: {
|
props: {
|
||||||
clearable: true
|
clearable: true
|
||||||
},
|
},
|
||||||
placeholder: '请输入显示值'
|
placeholder: '请输入字典名称'
|
||||||
},
|
},
|
||||||
itemProps: {
|
itemProps: {
|
||||||
class: { yxtInput: true }
|
class: { yxtInput: true }
|
||||||
|
@ -187,10 +119,8 @@ export const crudOptions = (vm) => {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '实际值',
|
title: '字典编号',
|
||||||
key: 'value',
|
key: 'value',
|
||||||
sortable: true,
|
|
||||||
|
|
||||||
search: {
|
search: {
|
||||||
disabled: true,
|
disabled: true,
|
||||||
component: {
|
component: {
|
||||||
|
@ -199,20 +129,25 @@ export const crudOptions = (vm) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
type: 'input',
|
type: 'input',
|
||||||
form: {
|
form: {
|
||||||
rules: [ // 表单校验规则
|
rules: [ // 表单校验规则
|
||||||
{ required: true, message: '实际值必填项' }
|
{ required: true, message: '字典编号必填项' }
|
||||||
],
|
],
|
||||||
component: {
|
component: {
|
||||||
props: {
|
props: {
|
||||||
clearable: true
|
clearable: true
|
||||||
},
|
},
|
||||||
placeholder: '请输入实际值'
|
placeholder: '请输入字典编号'
|
||||||
},
|
},
|
||||||
itemProps: {
|
itemProps: {
|
||||||
class: { yxtInput: true }
|
class: { yxtInput: true }
|
||||||
|
},
|
||||||
|
helper: {
|
||||||
|
render (h) {
|
||||||
|
return (< el-alert title="使用方法:vm.dictionary('字典编号')" type="warning"/>
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -220,33 +155,51 @@ export const crudOptions = (vm) => {
|
||||||
{
|
{
|
||||||
title: '状态',
|
title: '状态',
|
||||||
key: 'status',
|
key: 'status',
|
||||||
sortable: true,
|
width: 90,
|
||||||
search: {
|
search: {
|
||||||
disabled: false
|
disabled: false
|
||||||
},
|
},
|
||||||
|
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
dict: {
|
dict: {
|
||||||
data: BUTTON_STATUS_NUMBER
|
data: vm.dictionary('button_status_bool')
|
||||||
|
},
|
||||||
|
component: {
|
||||||
|
props: {
|
||||||
|
options: []
|
||||||
|
}
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
value: 1,
|
rules: [ // 表单校验规则
|
||||||
|
{ required: true, message: '状态必填项' }
|
||||||
|
],
|
||||||
|
value: true,
|
||||||
component: {
|
component: {
|
||||||
|
placeholder: '请选择状态'
|
||||||
|
},
|
||||||
|
itemProps: {
|
||||||
|
class: { yxtInput: true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '排序',
|
title: '排序',
|
||||||
key: 'sort',
|
key: 'sort',
|
||||||
sortable: true,
|
width: 90,
|
||||||
|
|
||||||
type: 'number',
|
type: 'number',
|
||||||
form: {
|
form: {
|
||||||
value: 1,
|
value: 1,
|
||||||
component: {
|
component: {
|
||||||
|
},
|
||||||
|
itemProps: {
|
||||||
|
class: { yxtInput: true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
].concat(vm.commonEndColumns())
|
].concat(vm.commonEndColumns({
|
||||||
|
description: {
|
||||||
|
showForm: true,
|
||||||
|
showTable: true
|
||||||
|
}
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
<template>
|
<template>
|
||||||
<d2-container :class="{ 'page-compact': crud.pageOptions.compact }">
|
<d2-container :class="{ 'page-compact': crud.pageOptions.compact }">
|
||||||
<!-- <template slot="header">测试页面1</template>-->
|
<!-- <template slot="header">测试页面1</template>-->
|
||||||
<d2-crud-x ref="d2Crud" v-bind="_crudProps" v-on="_crudListeners">
|
<d2-crud-x ref="d2Crud" v-bind="_crudProps" v-on="_crudListeners" @dictionaryConfigure="dictionaryConfigure">
|
||||||
<div slot="header">
|
<div slot="header">
|
||||||
<crud-search
|
<crud-search
|
||||||
ref="search"
|
ref="search"
|
||||||
|
@ -30,6 +30,15 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</d2-crud-x>
|
</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>
|
</d2-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -37,17 +46,23 @@
|
||||||
import * as api from './api'
|
import * as api from './api'
|
||||||
import { crudOptions } from './crud'
|
import { crudOptions } from './crud'
|
||||||
import { d2CrudPlus } from 'd2-crud-plus'
|
import { d2CrudPlus } from 'd2-crud-plus'
|
||||||
|
import SubDictionary from '@/views/system/dictionary/subDictionary/index'
|
||||||
export default {
|
export default {
|
||||||
name: 'dictionary',
|
name: 'dictionary',
|
||||||
|
components: { SubDictionary },
|
||||||
mixins: [d2CrudPlus.crud],
|
mixins: [d2CrudPlus.crud],
|
||||||
data () {
|
data () {
|
||||||
return {}
|
return {
|
||||||
|
drawer: false,
|
||||||
|
dictionaryRow: {}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getCrudOptions () {
|
getCrudOptions () {
|
||||||
return crudOptions(this)
|
return crudOptions(this)
|
||||||
},
|
},
|
||||||
pageRequest (query) {
|
pageRequest (query) {
|
||||||
|
query.is_value = false
|
||||||
return api.GetList(query)
|
return api.GetList(query)
|
||||||
},
|
},
|
||||||
addRequest (row) {
|
addRequest (row) {
|
||||||
|
@ -61,13 +76,10 @@ export default {
|
||||||
delRequest (row) {
|
delRequest (row) {
|
||||||
return api.DelObj(row.id)
|
return api.DelObj(row.id)
|
||||||
},
|
},
|
||||||
// 授权
|
// 字典配置
|
||||||
createPermission (scope) {
|
dictionaryConfigure (scope) {
|
||||||
this.$router.push({
|
this.drawer = true
|
||||||
name: 'menuButton',
|
this.dictionaryRow = scope.row
|
||||||
params: { id: scope.row.id },
|
|
||||||
query: { name: scope.row.name }
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
import { request } from '@/api/service'
|
||||||
|
import XEUtils from 'xe-utils'
|
||||||
|
export const urlPrefix = '/api/system/dictionary/'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列表查询
|
||||||
|
*/
|
||||||
|
export function GetList (query) {
|
||||||
|
return request({
|
||||||
|
url: urlPrefix,
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
}).then(res => {
|
||||||
|
// 将列表数据转换为树形数据
|
||||||
|
res.data.data = XEUtils.toArrayTree(res.data.data, { parentKey: 'parent' })
|
||||||
|
return res
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 新增
|
||||||
|
*/
|
||||||
|
export function createObj (obj) {
|
||||||
|
return request({
|
||||||
|
url: urlPrefix,
|
||||||
|
method: 'post',
|
||||||
|
data: obj
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改
|
||||||
|
*/
|
||||||
|
export function UpdateObj (obj) {
|
||||||
|
return request({
|
||||||
|
url: urlPrefix + obj.id + '/',
|
||||||
|
method: 'put',
|
||||||
|
data: obj
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 删除
|
||||||
|
*/
|
||||||
|
export function DelObj (id) {
|
||||||
|
return request({
|
||||||
|
url: urlPrefix + id + '/',
|
||||||
|
method: 'delete',
|
||||||
|
data: { id }
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,279 @@
|
||||||
|
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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
].concat(vm.commonEndColumns({
|
||||||
|
update_datetime: {
|
||||||
|
showForm: false,
|
||||||
|
showTable: false
|
||||||
|
},
|
||||||
|
create_datetime: {
|
||||||
|
showForm: false,
|
||||||
|
showTable: false
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
<template>
|
||||||
|
<d2-container>
|
||||||
|
<d2-crud-x ref="d2Crud" v-bind="_crudProps" v-on="_crudListeners" @dictionaryConfigure="dictionaryConfigure">
|
||||||
|
<div slot="header">
|
||||||
|
<crud-search
|
||||||
|
ref="search"
|
||||||
|
:options="crud.searchOptions"
|
||||||
|
@submit="handleSearch"
|
||||||
|
/>
|
||||||
|
<el-button-group>
|
||||||
|
<el-button size="small" type="primary" @click="addRow"
|
||||||
|
><i class="el-icon-plus" /> 新增</el-button
|
||||||
|
>
|
||||||
|
</el-button-group>
|
||||||
|
<crud-toolbar
|
||||||
|
:search.sync="crud.searchOptions.show"
|
||||||
|
:compact.sync="crud.pageOptions.compact"
|
||||||
|
:columns="crud.columns"
|
||||||
|
@refresh="doRefresh()"
|
||||||
|
@columns-filter-changed="handleColumnsFilterChanged"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</d2-crud-x>
|
||||||
|
<el-drawer
|
||||||
|
title="我是标题"
|
||||||
|
:visible.sync="drawer"
|
||||||
|
size="40%">
|
||||||
|
<span>我来啦!</span>
|
||||||
|
</el-drawer>
|
||||||
|
</d2-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import * as api from './api'
|
||||||
|
import { crudOptions } from './crud'
|
||||||
|
import { d2CrudPlus } from 'd2-crud-plus'
|
||||||
|
export default {
|
||||||
|
name: 'subDictionary',
|
||||||
|
mixins: [d2CrudPlus.crud],
|
||||||
|
props: {
|
||||||
|
// 容器样式
|
||||||
|
dictionaryRow: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
dictionaryRow () {
|
||||||
|
this.doRefresh({ from: 'load' })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
drawer: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getCrudOptions () {
|
||||||
|
return crudOptions(this)
|
||||||
|
},
|
||||||
|
pageRequest (query) {
|
||||||
|
query.is_value = true
|
||||||
|
query.parent = this.dictionaryRow.id
|
||||||
|
return api.GetList(query)
|
||||||
|
},
|
||||||
|
addRequest (row) {
|
||||||
|
d2CrudPlus.util.dict.clear()
|
||||||
|
row.is_value = true
|
||||||
|
row.parent = this.dictionaryRow.id
|
||||||
|
return api.createObj(row)
|
||||||
|
},
|
||||||
|
updateRequest (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)
|
||||||
|
},
|
||||||
|
// 字典配置
|
||||||
|
dictionaryConfigure (scope) {
|
||||||
|
this.drawer = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.yxtInput {
|
||||||
|
.el-form-item__label {
|
||||||
|
color: #49a1ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,5 +1,3 @@
|
||||||
import util from '@/libs/util'
|
|
||||||
|
|
||||||
export const crudOptions = (vm) => {
|
export const crudOptions = (vm) => {
|
||||||
return {
|
return {
|
||||||
pageOptions: {
|
pageOptions: {
|
||||||
|
@ -92,11 +90,7 @@ export const crudOptions = (vm) => {
|
||||||
search: {
|
search: {
|
||||||
disabled: true
|
disabled: true
|
||||||
},
|
},
|
||||||
width: 220,
|
width: 220
|
||||||
valueBuilder (row, key) {
|
|
||||||
console.log(row, key)
|
|
||||||
row.url = `${util.baseURL()}media/${row.url}`
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '文件MD5',
|
title: '文件MD5',
|
||||||
|
@ -107,18 +101,7 @@ export const crudOptions = (vm) => {
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
disabled: false
|
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: '备注',
|
title: '备注',
|
||||||
|
|
|
@ -1,12 +1,3 @@
|
||||||
/*
|
|
||||||
* @创建文件时间: 2021-06-02 10:33:33
|
|
||||||
* @Auther: 猿小天
|
|
||||||
* @最后修改人: 猿小天
|
|
||||||
* @最后修改时间: 2021-08-12 22:53:38
|
|
||||||
* 联系Qq:1638245306
|
|
||||||
* @文件介绍: 登录的接口
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { request } from '@/api/service'
|
import { request } from '@/api/service'
|
||||||
|
|
||||||
export function SYS_USER_LOGIN (data) {
|
export function SYS_USER_LOGIN (data) {
|
||||||
|
@ -31,3 +22,10 @@ export function getCaptcha () {
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getCaptchaStatus () {
|
||||||
|
return request({
|
||||||
|
url: 'api/captcha/status/',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,226 @@
|
||||||
|
<template>
|
||||||
|
<div class="page-login">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapActions, mapState } from 'vuex'
|
||||||
|
import localeMixin from '@/locales/mixin.js'
|
||||||
|
import * as api from '@/views/system/login/api'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
mixins: [localeMixin],
|
||||||
|
computed: {
|
||||||
|
...mapState('d2admin', {
|
||||||
|
siteName: (state) => state.settings.siteName, // 网站名称
|
||||||
|
siteLogo: (state) => state.settings.siteLogo || require('./image/dvadmin.png'), // 网站logo地址
|
||||||
|
loginBackground: (state) => state.settings.loginBackground || require('./image/bg.jpg'), // 登录页背景图
|
||||||
|
copyright: (state) => state.settings.copyright, // 版权
|
||||||
|
keepRecord: (state) => state.settings.keepRecord, // 备案
|
||||||
|
helpUrl: (state) => state.settings.helpUrl, // 帮助
|
||||||
|
privacyUrl: (state) => state.settings.privacyUrl, // 隐私
|
||||||
|
clauseUrl: (state) => state.settings.clauseUrl // 条款
|
||||||
|
})
|
||||||
|
},
|
||||||
|
beforeCreate () {
|
||||||
|
// 初始化配置
|
||||||
|
this.$store.dispatch('d2admin/settings/init')
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
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'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
captcha: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请输入验证码',
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
captchaKey: null,
|
||||||
|
image_base: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
},
|
||||||
|
beforeDestroy () {
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions('d2admin/account', ['login']),
|
||||||
|
/**
|
||||||
|
* 获取验证码
|
||||||
|
*/
|
||||||
|
getCaptcha () {
|
||||||
|
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('表单校验失败,请检查')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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: 52em;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
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 |
|
@ -1,35 +1,18 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="page-login">
|
<div class="w3l-signinform" :style="{background: 'url('+ (loginBackground || require('./image/bg.jpg')) + ') no-repeat center'}">
|
||||||
<div class="page-login--layer page-login--layer-area">
|
<!-- container -->
|
||||||
<ul class="circles">
|
<div class="wrapper">
|
||||||
<li v-for="n in 10" :key="n"></li>
|
<!-- main content -->
|
||||||
</ul>
|
<div class="w3l-form-info">
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="page-login--layer page-login--layer-time"
|
|
||||||
flex="main:center cross:center"
|
|
||||||
>
|
|
||||||
{{ time }}
|
|
||||||
</div>
|
|
||||||
<div class="page-login--layer">
|
|
||||||
<div
|
|
||||||
class="page-login--content"
|
|
||||||
flex="dir:top main:justify cross:stretch box:justify"
|
|
||||||
>
|
|
||||||
<div class="page-login--content-header">
|
|
||||||
<p class="page-login--content-header-motto">
|
|
||||||
时间是一切财富中最宝贵的财富
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="page-login--content-main"
|
|
||||||
flex="dir:top main:center cross:center"
|
|
||||||
>
|
|
||||||
<!-- logo -->
|
<!-- logo -->
|
||||||
<img class="page-login--logo" src="./image/dvadmin.png" />
|
<img class="page-login--logo" :src="siteLogo" width="300"/>
|
||||||
<!-- form -->
|
<div class="w3_info">
|
||||||
<div class="page-login--form">
|
<h2 style="text-align: center;">{{siteName || processTitle}}</h2>
|
||||||
<el-card shadow="never">
|
<el-card shadow="always" class="card">
|
||||||
|
<el-tabs v-model="activeName">
|
||||||
|
<el-tab-pane label="账号密码登录" name="first" stretch>
|
||||||
|
<span slot="label"><span style="margin: 30px;">账号密码登录</span></span>
|
||||||
|
<br>
|
||||||
<el-form
|
<el-form
|
||||||
ref="loginForm"
|
ref="loginForm"
|
||||||
label-position="top"
|
label-position="top"
|
||||||
|
@ -41,19 +24,19 @@
|
||||||
<el-input
|
<el-input
|
||||||
type="text"
|
type="text"
|
||||||
v-model="formLogin.username"
|
v-model="formLogin.username"
|
||||||
|
prefix-icon="el-icon-user-solid"
|
||||||
placeholder="用户名"
|
placeholder="用户名"
|
||||||
>
|
>
|
||||||
<i slot="prepend" class="fa fa-user-circle-o"></i>
|
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="password">
|
<el-form-item prop="password">
|
||||||
<el-input
|
<el-input
|
||||||
type="password"
|
type="password"
|
||||||
v-model="formLogin.password"
|
v-model="formLogin.password"
|
||||||
|
prefix-icon="el-icon-s-promotion"
|
||||||
show-password
|
show-password
|
||||||
placeholder="密码"
|
placeholder="密码"
|
||||||
>
|
>
|
||||||
<i slot="prepend" class="fa fa-keyboard-o"></i>
|
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="captcha">
|
<el-form-item prop="captcha">
|
||||||
|
@ -61,459 +44,71 @@
|
||||||
type="text"
|
type="text"
|
||||||
v-model="formLogin.captcha"
|
v-model="formLogin.captcha"
|
||||||
placeholder="验证码"
|
placeholder="验证码"
|
||||||
|
@keyup.enter.native="submit"
|
||||||
>
|
>
|
||||||
<template slot="append">
|
<template slot="append">
|
||||||
<img
|
<img
|
||||||
class="login-code"
|
class="login-code"
|
||||||
|
height="33px"
|
||||||
|
width="145px"
|
||||||
|
slot="suffix"
|
||||||
:src="image_base"
|
:src="image_base"
|
||||||
@click="getCaptcha"
|
@click="getCaptcha"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-button
|
<button class="btn btn-primary btn-block" @click="submit">登录</button>
|
||||||
size="default"
|
|
||||||
@click="submit"
|
|
||||||
type="primary"
|
|
||||||
class="button-login"
|
|
||||||
>
|
|
||||||
登录
|
|
||||||
</el-button>
|
|
||||||
</el-form>
|
</el-form>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
</el-card>
|
</el-card>
|
||||||
<!-- <p class="page-login--options" flex="main:justify cross:center">
|
<!-- footer -->
|
||||||
<span><d2-icon name="question-circle" /> 忘记密码</span>
|
<div class="footer">
|
||||||
<span>注册用户</span>
|
<p>Copyright © {{copyright}}</p>
|
||||||
</p> -->
|
<p>
|
||||||
<!-- quick login -->
|
<a href="https://beian.miit.gov.cn" target="_blank">{{keepRecord}}</a> |
|
||||||
<!-- <el-button
|
<a :href="helpUrl || '#'" target="_blank">帮助</a> |
|
||||||
class="page-login--quick"
|
<a :href="privacyUrl || '#'" target="_blank">隐私</a> |
|
||||||
size="default"
|
<a :href="clauseUrl || '#'" target="_blank">条款</a>
|
||||||
type="info"
|
|
||||||
@click="dialogVisible = true"
|
|
||||||
>
|
|
||||||
快速选择用户(测试功能)
|
|
||||||
</el-button> -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="page-login--content-footer">
|
|
||||||
<p class="page-login--content-footer-locales">
|
|
||||||
<a
|
|
||||||
v-for="language in $languages"
|
|
||||||
:key="language.value"
|
|
||||||
@click="onChangeLocale(language.value)"
|
|
||||||
>
|
|
||||||
{{ language.label }}
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
<p class="page-login--content-footer-copyright">
|
|
||||||
Copyright
|
|
||||||
<d2-icon name="copyright" />
|
|
||||||
Copyright © 2018-2021 pro.django-vue-admin.com All Rights Reserved.
|
|
||||||
|
|
|
||||||
<a href="https://beian.miit.gov.cn" target="_blank">
|
|
||||||
晋ICP备18005113号-3
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
<p class="page-login--content-footer-options">
|
|
||||||
<a href="#">帮助</a>
|
|
||||||
<a href="#">隐私</a>
|
|
||||||
<a href="#">条款</a>
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- footer -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-dialog title="快速选择用户" :visible.sync="dialogVisible" width="400px">
|
<!-- //main content -->
|
||||||
<el-row :gutter="10" style="margin: -20px 0px -10px 0px">
|
|
||||||
<el-col v-for="(user, index) in users" :key="index" :span="8">
|
|
||||||
<div class="page-login--quick-user" @click="handleUserBtnClick(user)">
|
|
||||||
<d2-icon name="user-circle-o" />
|
|
||||||
<span>{{ user.name }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
<!-- //container -->
|
||||||
</el-row>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import dayjs from 'dayjs'
|
import base from './base.vue'
|
||||||
import { mapActions } from 'vuex'
|
|
||||||
import localeMixin from '@/locales/mixin.js'
|
|
||||||
import * as api from './api'
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [localeMixin],
|
extends: base,
|
||||||
|
name: 'page',
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
timeInterval: null,
|
activeName: 'first'
|
||||||
time: dayjs().format('HH:mm:ss'),
|
|
||||||
// 快速选择用户
|
|
||||||
dialogVisible: false,
|
|
||||||
users: [
|
|
||||||
{
|
|
||||||
name: 'Admin',
|
|
||||||
username: 'admin',
|
|
||||||
password: 'admin'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Editor',
|
|
||||||
username: 'editor',
|
|
||||||
password: 'editor'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'User1',
|
|
||||||
username: 'user1',
|
|
||||||
password: 'user1'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
// 表单
|
|
||||||
formLogin: {
|
|
||||||
username: '',
|
|
||||||
password: '',
|
|
||||||
captcha: ''
|
|
||||||
},
|
|
||||||
// 表单校验
|
|
||||||
rules: {
|
|
||||||
username: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: '请输入用户名',
|
|
||||||
trigger: 'blur'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
password: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: '请输入密码',
|
|
||||||
trigger: 'blur'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
captcha: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: '请输入验证码',
|
|
||||||
trigger: 'blur'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
captchaKey: null,
|
|
||||||
image_base: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted () {
|
|
||||||
this.timeInterval = setInterval(() => {
|
|
||||||
this.refreshTime()
|
|
||||||
}, 1000)
|
|
||||||
},
|
|
||||||
beforeDestroy () {
|
|
||||||
clearInterval(this.timeInterval)
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
...mapActions('d2admin/account', ['login']),
|
|
||||||
refreshTime () {
|
|
||||||
this.time = dayjs().format('HH:mm:ss')
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* @description 接收选择一个用户快速登录的事件
|
|
||||||
* @param {Object} user 用户信息
|
|
||||||
*/
|
|
||||||
handleUserBtnClick (user) {
|
|
||||||
this.formLogin.username = user.username
|
|
||||||
this.formLogin.password = user.password
|
|
||||||
this.submit()
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* @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('表单校验失败,请检查')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* 获取验证码
|
|
||||||
*/
|
|
||||||
getCaptcha () {
|
|
||||||
api.getCaptcha().then((ret) => {
|
|
||||||
this.formLogin.captcha = null
|
|
||||||
this.captchaKey = ret.data.data.key
|
|
||||||
this.image_base = ret.data.data.image_base
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
this.$store.dispatch('d2admin/db/databaseClear')
|
},
|
||||||
this.getCaptcha()
|
mounted () {
|
||||||
}
|
},
|
||||||
|
methods: {}
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss" scoped>
|
||||||
.page-login {
|
@import './css/style.css';
|
||||||
@extend %unable-select;
|
|
||||||
$backgroundColor: #f0f2f5;
|
.copyrights {
|
||||||
// ---
|
text-indent: -9999px;
|
||||||
background-color: $backgroundColor;
|
height: 0;
|
||||||
height: 100%;
|
line-height: 0;
|
||||||
position: relative;
|
font-size: 0;
|
||||||
// 层
|
|
||||||
.page-login--layer {
|
|
||||||
@extend %full;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
.page-login--layer-area {
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
// 时间
|
|
||||||
.page-login--layer-time {
|
|
||||||
font-size: 24em;
|
|
||||||
font-weight: bold;
|
|
||||||
color: rgba(0, 0, 0, 0.03);
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
// 登陆页面控件的容器
|
|
||||||
.page-login--content {
|
|
||||||
height: 100%;
|
|
||||||
min-height: 500px;
|
|
||||||
}
|
|
||||||
// header
|
|
||||||
.page-login--content-header {
|
|
||||||
padding: 1em 0;
|
|
||||||
.page-login--content-header-motto {
|
|
||||||
margin: 0px;
|
|
||||||
padding: 0px;
|
|
||||||
color: $color-text-normal;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// main
|
|
||||||
.page-login--logo {
|
|
||||||
width: 240px;
|
|
||||||
margin-bottom: 2em;
|
|
||||||
margin-top: -2em;
|
|
||||||
}
|
|
||||||
// 登录表单
|
|
||||||
.page-login--form {
|
|
||||||
width: 280px;
|
|
||||||
// 卡片
|
|
||||||
.el-card {
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
// 登录按钮
|
|
||||||
.button-login {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
// 输入框左边的图表区域缩窄
|
|
||||||
.el-input-group__prepend {
|
|
||||||
padding: 0px 14px;
|
|
||||||
}
|
|
||||||
.login-code {
|
|
||||||
height: 40px - 2px;
|
|
||||||
display: block;
|
|
||||||
margin: 0px -20px;
|
|
||||||
border-top-right-radius: 2px;
|
|
||||||
border-bottom-right-radius: 2px;
|
|
||||||
}
|
|
||||||
// 登陆选项
|
|
||||||
.page-login--options {
|
|
||||||
margin: 0px;
|
|
||||||
padding: 0px;
|
|
||||||
font-size: 14px;
|
|
||||||
color: $color-primary;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
.page-login--quick {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 快速选择用户面板
|
|
||||||
.page-login--quick-user {
|
|
||||||
@extend %flex-center-col;
|
|
||||||
padding: 10px 0px;
|
|
||||||
border-radius: 4px;
|
|
||||||
&:hover {
|
|
||||||
background-color: $color-bg;
|
|
||||||
i {
|
|
||||||
color: $color-text-normal;
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
color: $color-text-normal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i {
|
|
||||||
font-size: 36px;
|
|
||||||
color: $color-text-sub;
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
font-size: 12px;
|
|
||||||
margin-top: 10px;
|
|
||||||
color: $color-text-sub;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// footer
|
|
||||||
.page-login--content-footer {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 背景
|
|
||||||
.circles {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
margin: 0px;
|
|
||||||
padding: 0px;
|
|
||||||
li {
|
|
||||||
position: absolute;
|
|
||||||
display: block;
|
|
||||||
list-style: none;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
background: #fff;
|
|
||||||
animation: animate 25s linear infinite;
|
|
||||||
bottom: -200px;
|
|
||||||
@keyframes animate {
|
|
||||||
0% {
|
|
||||||
transform: translateY(0) rotate(0deg);
|
|
||||||
opacity: 1;
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: translateY(-1000px) rotate(720deg);
|
|
||||||
opacity: 0;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&:nth-child(1) {
|
|
||||||
left: 15%;
|
|
||||||
width: 80px;
|
|
||||||
height: 80px;
|
|
||||||
animation-delay: 0s;
|
|
||||||
}
|
|
||||||
&:nth-child(2) {
|
|
||||||
left: 5%;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
animation-delay: 2s;
|
|
||||||
animation-duration: 12s;
|
|
||||||
}
|
|
||||||
&:nth-child(3) {
|
|
||||||
left: 70%;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
animation-delay: 4s;
|
|
||||||
}
|
|
||||||
&:nth-child(4) {
|
|
||||||
left: 40%;
|
|
||||||
width: 60px;
|
|
||||||
height: 60px;
|
|
||||||
animation-delay: 0s;
|
|
||||||
animation-duration: 18s;
|
|
||||||
}
|
|
||||||
&:nth-child(5) {
|
|
||||||
left: 65%;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
animation-delay: 0s;
|
|
||||||
}
|
|
||||||
&:nth-child(6) {
|
|
||||||
left: 75%;
|
|
||||||
width: 150px;
|
|
||||||
height: 150px;
|
|
||||||
animation-delay: 3s;
|
|
||||||
}
|
|
||||||
&:nth-child(7) {
|
|
||||||
left: 35%;
|
|
||||||
width: 200px;
|
|
||||||
height: 200px;
|
|
||||||
animation-delay: 7s;
|
|
||||||
}
|
|
||||||
&:nth-child(8) {
|
|
||||||
left: 50%;
|
|
||||||
width: 25px;
|
|
||||||
height: 25px;
|
|
||||||
animation-delay: 15s;
|
|
||||||
animation-duration: 45s;
|
|
||||||
}
|
|
||||||
&:nth-child(9) {
|
|
||||||
left: 20%;
|
|
||||||
width: 15px;
|
|
||||||
height: 15px;
|
|
||||||
animation-delay: 2s;
|
|
||||||
animation-duration: 35s;
|
|
||||||
}
|
|
||||||
&:nth-child(10) {
|
|
||||||
left: 85%;
|
|
||||||
width: 150px;
|
|
||||||
height: 150px;
|
|
||||||
animation-delay: 0s;
|
|
||||||
animation-duration: 11s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { request } from '@/api/service'
|
import { request } from '@/api/service'
|
||||||
import { BUTTON_STATUS_BOOL, BUTTON_WHETHER_BOOL, BUTTON_VALUE_TO_COLOR_MAPPING } from '@/config/button'
|
import { BUTTON_VALUE_TO_COLOR_MAPPING } from '@/config/button'
|
||||||
import { urlPrefix as menuPrefix } from './api'
|
import { urlPrefix as menuPrefix } from './api'
|
||||||
import { urlPrefix as buttonPrefix } from '../button/api'
|
import { urlPrefix as buttonPrefix } from '../button/api'
|
||||||
import XEUtils from 'xe-utils'
|
import XEUtils from 'xe-utils'
|
||||||
|
@ -27,7 +27,8 @@ export const crudOptions = (vm) => {
|
||||||
options: {
|
options: {
|
||||||
rowId: 'id',
|
rowId: 'id',
|
||||||
height: '100%', // 表格高度100%, 使用toolbar必须设置
|
height: '100%', // 表格高度100%, 使用toolbar必须设置
|
||||||
highlightCurrentRow: false
|
highlightCurrentRow: false,
|
||||||
|
defaultExpandAll: true
|
||||||
},
|
},
|
||||||
rowHandle: {
|
rowHandle: {
|
||||||
view: {
|
view: {
|
||||||
|
@ -129,14 +130,14 @@ export const crudOptions = (vm) => {
|
||||||
},
|
},
|
||||||
type: 'cascader',
|
type: 'cascader',
|
||||||
dict: {
|
dict: {
|
||||||
url: menuPrefix + '?limit=999&status=1&is_catalog=1',
|
url: menuPrefix,
|
||||||
cache: false,
|
cache: false,
|
||||||
isTree: true,
|
isTree: true,
|
||||||
value: 'id', // 数据字典中value字段的属性名
|
value: 'id', // 数据字典中value字段的属性名
|
||||||
label: 'name', // 数据字典中label字段的属性名
|
label: 'name', // 数据字典中label字段的属性名
|
||||||
children: 'children', // 数据字典中children字段的属性名
|
children: 'children', // 数据字典中children字段的属性名
|
||||||
getData: (url, dict, { form, component }) => { // 配置此参数会覆盖全局的getRemoteDictFunc
|
getData: (url, dict, { form, component }) => { // 配置此参数会覆盖全局的getRemoteDictFunc
|
||||||
return request({ url: url }).then(ret => {
|
return request({ url: url, params: { limit: 999, status: 1, is_catalog: 1 } }).then(ret => {
|
||||||
const responseData = ret.data.data
|
const responseData = ret.data.data
|
||||||
const result = XEUtils.toArrayTree(responseData, { parentKey: 'parent', strict: true })
|
const result = XEUtils.toArrayTree(responseData, { parentKey: 'parent', strict: true })
|
||||||
return [{ id: null, name: '根节点', children: result }]
|
return [{ id: null, name: '根节点', children: result }]
|
||||||
|
@ -222,7 +223,7 @@ export const crudOptions = (vm) => {
|
||||||
disabled: true
|
disabled: true
|
||||||
},
|
},
|
||||||
dict: {
|
dict: {
|
||||||
data: BUTTON_WHETHER_BOOL
|
data: vm.dictionary('button_whether_bool')
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
value: false,
|
value: false,
|
||||||
|
@ -237,7 +238,7 @@ export const crudOptions = (vm) => {
|
||||||
width: 70,
|
width: 70,
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
dict: {
|
dict: {
|
||||||
data: BUTTON_WHETHER_BOOL
|
data: vm.dictionary('button_whether_bool')
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
value: false,
|
value: false,
|
||||||
|
@ -395,7 +396,7 @@ export const crudOptions = (vm) => {
|
||||||
width: 50,
|
width: 50,
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
dict: {
|
dict: {
|
||||||
data: BUTTON_WHETHER_BOOL
|
data: vm.dictionary('button_whether_bool')
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
value: false,
|
value: false,
|
||||||
|
@ -423,7 +424,7 @@ export const crudOptions = (vm) => {
|
||||||
width: 75,
|
width: 75,
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
dict: {
|
dict: {
|
||||||
data: BUTTON_WHETHER_BOOL
|
data: vm.dictionary('button_whether_bool')
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
value: true,
|
value: true,
|
||||||
|
@ -448,7 +449,7 @@ export const crudOptions = (vm) => {
|
||||||
width: 70,
|
width: 70,
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
dict: {
|
dict: {
|
||||||
data: BUTTON_STATUS_BOOL
|
data: vm.dictionary('button_status_bool')
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
value: true,
|
value: true,
|
||||||
|
@ -457,6 +458,8 @@ export const crudOptions = (vm) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
].concat(vm.commonEndColumns({ update_datetime: { showTable: false } }))
|
].concat(vm.commonEndColumns({
|
||||||
|
update_datetime: { showTable: false }
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
import { BUTTON_STATUS_BOOL, BUTTON_WHETHER_BOOL } from '@/config/button'
|
|
||||||
|
|
||||||
export const crudOptions = (vm) => {
|
export const crudOptions = (vm) => {
|
||||||
return {
|
return {
|
||||||
pageOptions: {
|
pageOptions: {
|
||||||
|
@ -161,7 +159,7 @@ export const crudOptions = (vm) => {
|
||||||
|
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
dict: {
|
dict: {
|
||||||
data: BUTTON_WHETHER_BOOL
|
data: vm.dictionary('button_whether_bool')
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
value: false,
|
value: false,
|
||||||
|
@ -180,7 +178,7 @@ export const crudOptions = (vm) => {
|
||||||
},
|
},
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
dict: {
|
dict: {
|
||||||
data: BUTTON_STATUS_BOOL
|
data: vm.dictionary('button_status_bool')
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
value: true,
|
value: true,
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
import { request } from '@/api/service'
|
import { request } from '@/api/service'
|
||||||
import { BUTTON_STATUS_BOOL } from '@/config/button'
|
|
||||||
import { urlPrefix as deptPrefix } from '../dept/api'
|
import { urlPrefix as deptPrefix } from '../dept/api'
|
||||||
import util from '@/libs/util'
|
|
||||||
|
|
||||||
export const crudOptions = (vm) => {
|
export const crudOptions = (vm) => {
|
||||||
return {
|
return {
|
||||||
|
@ -9,11 +7,13 @@ export const crudOptions = (vm) => {
|
||||||
compact: true
|
compact: true
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
height: '100%'
|
height: '100%',
|
||||||
|
tableType: 'vxe-table',
|
||||||
|
rowKey: true // 必须设置,true or false
|
||||||
},
|
},
|
||||||
rowHandle: {
|
rowHandle: {
|
||||||
|
width: 230,
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
width: 180,
|
|
||||||
view: {
|
view: {
|
||||||
thin: true,
|
thin: true,
|
||||||
text: '',
|
text: '',
|
||||||
|
@ -37,18 +37,18 @@ export const crudOptions = (vm) => {
|
||||||
},
|
},
|
||||||
custom: [
|
custom: [
|
||||||
{
|
{
|
||||||
thin: true,
|
|
||||||
text: '',
|
|
||||||
size: 'small',
|
|
||||||
type: 'warning',
|
|
||||||
icon: 'el-icon-refresh-left',
|
|
||||||
show () {
|
show () {
|
||||||
return vm.hasPermissions('ResetPwd')
|
return vm.hasPermissions('ResetPassword')
|
||||||
},
|
},
|
||||||
emit: 'resetPwd'
|
disabled () {
|
||||||
|
return !vm.hasPermissions('ResetPassword')
|
||||||
|
},
|
||||||
|
text: '重置密码',
|
||||||
|
type: 'warning',
|
||||||
|
size: 'small',
|
||||||
|
emit: 'resetPassword'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
},
|
},
|
||||||
viewOptions: {
|
viewOptions: {
|
||||||
componentType: 'form'
|
componentType: 'form'
|
||||||
|
@ -59,7 +59,7 @@ export const crudOptions = (vm) => {
|
||||||
indexRow: { // 或者直接传true,不显示title,不居中
|
indexRow: { // 或者直接传true,不显示title,不居中
|
||||||
title: '序号',
|
title: '序号',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: 70
|
width: 60
|
||||||
},
|
},
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
|
@ -83,7 +83,6 @@ export const crudOptions = (vm) => {
|
||||||
{
|
{
|
||||||
title: 'ID',
|
title: 'ID',
|
||||||
key: 'id',
|
key: 'id',
|
||||||
width: 90,
|
|
||||||
disabled: true,
|
disabled: true,
|
||||||
form: {
|
form: {
|
||||||
disabled: true
|
disabled: true
|
||||||
|
@ -95,7 +94,7 @@ export const crudOptions = (vm) => {
|
||||||
search: {
|
search: {
|
||||||
disabled: false
|
disabled: false
|
||||||
},
|
},
|
||||||
width: 140,
|
minWidth: 100,
|
||||||
type: 'input',
|
type: 'input',
|
||||||
form: {
|
form: {
|
||||||
rules: [ // 表单校验规则
|
rules: [ // 表单校验规则
|
||||||
|
@ -118,6 +117,7 @@ export const crudOptions = (vm) => {
|
||||||
{
|
{
|
||||||
title: '姓名',
|
title: '姓名',
|
||||||
key: 'name',
|
key: 'name',
|
||||||
|
minWidth: 90,
|
||||||
search: {
|
search: {
|
||||||
disabled: false
|
disabled: false
|
||||||
},
|
},
|
||||||
|
@ -166,9 +166,9 @@ export const crudOptions = (vm) => {
|
||||||
},
|
},
|
||||||
component: {
|
component: {
|
||||||
span: 12,
|
span: 12,
|
||||||
|
pagination: true,
|
||||||
props: { multiple: false },
|
props: { multiple: false },
|
||||||
elProps: {
|
elProps: {
|
||||||
pagination: true,
|
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
field: 'name',
|
field: 'name',
|
||||||
|
@ -198,7 +198,7 @@ export const crudOptions = (vm) => {
|
||||||
form: {
|
form: {
|
||||||
rules: [
|
rules: [
|
||||||
{ max: 20, message: '请输入正确的手机号码', trigger: 'blur' },
|
{ max: 20, message: '请输入正确的手机号码', trigger: 'blur' },
|
||||||
{ pattern: /^1[3|4|5|7|8]\d{9}$/, message: '请输入正确的手机号码' }
|
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码' }
|
||||||
],
|
],
|
||||||
itemProps: {
|
itemProps: {
|
||||||
class: { yxtInput: true }
|
class: { yxtInput: true }
|
||||||
|
@ -210,7 +210,7 @@ export const crudOptions = (vm) => {
|
||||||
}, {
|
}, {
|
||||||
title: '邮箱',
|
title: '邮箱',
|
||||||
key: 'email',
|
key: 'email',
|
||||||
minWidth: 160,
|
minWidth: 180,
|
||||||
form: {
|
form: {
|
||||||
rules: [
|
rules: [
|
||||||
{ type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change'] }
|
{ type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change'] }
|
||||||
|
@ -226,7 +226,7 @@ export const crudOptions = (vm) => {
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
width: 70,
|
width: 70,
|
||||||
dict: {
|
dict: {
|
||||||
data: [{ label: '男', value: 1 }, { label: '女', value: 0 }]
|
data: vm.dictionary('gender')
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
value: 1,
|
value: 1,
|
||||||
|
@ -235,8 +235,26 @@ export const crudOptions = (vm) => {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
component: { props: { color: 'auto' } } // 自动染色
|
component: { props: { color: 'auto' } } // 自动染色
|
||||||
|
}, {
|
||||||
|
title: '用户类型',
|
||||||
|
key: 'user_type',
|
||||||
|
search: {
|
||||||
|
value: 0,
|
||||||
|
disabled: false
|
||||||
},
|
},
|
||||||
{
|
width: 140,
|
||||||
|
type: 'select',
|
||||||
|
dict: {
|
||||||
|
data: vm.dictionary('user_type')
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
show: false,
|
||||||
|
value: 0,
|
||||||
|
component: {
|
||||||
|
span: 12
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
title: '状态',
|
title: '状态',
|
||||||
key: 'is_active',
|
key: 'is_active',
|
||||||
search: {
|
search: {
|
||||||
|
@ -245,7 +263,7 @@ export const crudOptions = (vm) => {
|
||||||
width: 70,
|
width: 70,
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
dict: {
|
dict: {
|
||||||
data: BUTTON_STATUS_BOOL
|
data: vm.dictionary('button_status_bool')
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
value: true,
|
value: true,
|
||||||
|
@ -257,41 +275,21 @@ export const crudOptions = (vm) => {
|
||||||
{
|
{
|
||||||
title: '头像',
|
title: '头像',
|
||||||
key: 'avatar',
|
key: 'avatar',
|
||||||
type: 'avatar-uploader',
|
type: 'avatar-cropper',
|
||||||
width: 100,
|
width: 60,
|
||||||
align: 'left',
|
align: 'left',
|
||||||
form: {
|
form: {
|
||||||
component: {
|
component: {
|
||||||
props: {
|
props: {
|
||||||
elProps: { // 与el-uploader 配置一致
|
elProps: { // 与el-uploader 配置一致
|
||||||
multiple: true,
|
multiple: false,
|
||||||
limit: 5 // 限制5个文件
|
limit: 1 // 限制5个文件
|
||||||
},
|
},
|
||||||
sizeLimit: 100 * 1024 // 不能超过限制
|
sizeLimit: 500 * 1024 // 不能超过限制
|
||||||
},
|
},
|
||||||
span: 24
|
span: 24
|
||||||
},
|
},
|
||||||
helper: '限制文件大小不能超过50k'
|
helper: '限制文件大小不能超过500k'
|
||||||
},
|
|
||||||
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 util.baseURL() + value
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -325,9 +323,9 @@ export const crudOptions = (vm) => {
|
||||||
},
|
},
|
||||||
component: {
|
component: {
|
||||||
span: 12,
|
span: 12,
|
||||||
|
pagination: true,
|
||||||
props: { multiple: true },
|
props: { multiple: true },
|
||||||
elProps: {
|
elProps: {
|
||||||
pagination: true,
|
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
field: 'name',
|
field: 'name',
|
||||||
|
@ -346,6 +344,9 @@ export const crudOptions = (vm) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
].concat(vm.commonEndColumns({ update_datetime: { showForm: false, showTable: false }, create_datetime: { showForm: false, showTable: true } }))
|
].concat(vm.commonEndColumns({
|
||||||
|
create_datetime: { showTable: false },
|
||||||
|
update_datetime: { showTable: false }
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,7 @@
|
||||||
ref="d2Crud"
|
ref="d2Crud"
|
||||||
v-bind="_crudProps"
|
v-bind="_crudProps"
|
||||||
v-on="_crudListeners"
|
v-on="_crudListeners"
|
||||||
crud.options.tableType="vxe-table"
|
@resetPassword="resetPassword"
|
||||||
@resetPwd="resetPwd"
|
|
||||||
>
|
>
|
||||||
<div slot="header">
|
<div slot="header">
|
||||||
<crud-search
|
<crud-search
|
||||||
|
@ -19,8 +18,9 @@
|
||||||
v-permission="'Create'"
|
v-permission="'Create'"
|
||||||
type="primary"
|
type="primary"
|
||||||
@click="addRow"
|
@click="addRow"
|
||||||
><i class="el-icon-plus" /> 新增</el-button
|
|
||||||
>
|
>
|
||||||
|
<i class="el-icon-plus" /> 新增
|
||||||
|
</el-button>
|
||||||
</el-button-group>
|
</el-button-group>
|
||||||
<crud-toolbar
|
<crud-toolbar
|
||||||
:search.sync="crud.searchOptions.show"
|
:search.sync="crud.searchOptions.show"
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</d2-crud-x>
|
</d2-crud-x>
|
||||||
<el-dialog title="密码重置" :visible.sync="dialogFormVisible" :close-on-click-modal="false">
|
<!-- <el-dialog title="密码重置" :visible.sync="dialogFormVisible" :close-on-click-modal="false">
|
||||||
<el-form :model="resetPwdForm" ref="resetPwdForm" :rules="passwordRules">
|
<el-form :model="resetPwdForm" ref="resetPwdForm" :rules="passwordRules">
|
||||||
<el-form-item label="密码" prop="pwd">
|
<el-form-item label="密码" prop="pwd">
|
||||||
<el-input v-model="resetPwdForm.pwd" type="password" show-password clearable autocomplete="off"></el-input>
|
<el-input v-model="resetPwdForm.pwd" type="password" show-password clearable autocomplete="off"></el-input>
|
||||||
|
@ -44,7 +44,7 @@
|
||||||
<el-button @click="dialogFormVisible = false">取 消</el-button>
|
<el-button @click="dialogFormVisible = false">取 消</el-button>
|
||||||
<el-button type="primary" @click="resetPwdSubmit">确 定</el-button>
|
<el-button type="primary" @click="resetPwdSubmit">确 定</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog> -->
|
||||||
</d2-container>
|
</d2-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -57,43 +57,44 @@ export default {
|
||||||
name: 'user',
|
name: 'user',
|
||||||
mixins: [d2CrudPlus.crud],
|
mixins: [d2CrudPlus.crud],
|
||||||
data () {
|
data () {
|
||||||
var validatePass = (rule, value, callback) => {
|
// var validatePass = (rule, value, callback) => {
|
||||||
const pwdRegex = new RegExp('(?=.*[0-9])(?=.*[a-zA-Z]).{8,30}')
|
// const pwdRegex = new RegExp('(?=.*[0-9])(?=.*[a-zA-Z]).{8,30}')
|
||||||
if (value === '') {
|
// if (value === '') {
|
||||||
callback(new Error('请输入密码'))
|
// callback(new Error('请输入密码'))
|
||||||
} else if (!pwdRegex.test(value)) {
|
// } else if (!pwdRegex.test(value)) {
|
||||||
callback(new Error('您的密码复杂度太低(密码中必须包含字母、数字)'))
|
// callback(new Error('您的密码复杂度太低(密码中必须包含字母、数字)'))
|
||||||
} else {
|
// } else {
|
||||||
if (this.resetPwdForm.pwd2 !== '') {
|
// if (this.resetPwdForm.pwd2 !== '') {
|
||||||
this.$refs.resetPwdForm.validateField('pwd2')
|
// this.$refs.resetPwdForm.validateField('pwd2')
|
||||||
}
|
// }
|
||||||
callback()
|
// callback()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
var validatePass2 = (rule, value, callback) => {
|
// var validatePass2 = (rule, value, callback) => {
|
||||||
if (value === '') {
|
// if (value === '') {
|
||||||
callback(new Error('请再次输入密码'))
|
// callback(new Error('请再次输入密码'))
|
||||||
} else if (value !== this.resetPwdForm.pwd) {
|
// } else if (value !== this.resetPwdForm.pwd) {
|
||||||
callback(new Error('两次输入密码不一致!'))
|
// callback(new Error('两次输入密码不一致!'))
|
||||||
} else {
|
// } else {
|
||||||
callback()
|
// callback()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return {
|
return {
|
||||||
dialogFormVisible: false,
|
// dialogFormVisible: false,
|
||||||
resetPwdForm: {
|
// resetPwdForm: {
|
||||||
id: null,
|
// id: null,
|
||||||
pwd: null,
|
// pwd: null,
|
||||||
pwd2: null
|
// pwd2: null
|
||||||
},
|
// },
|
||||||
passwordRules: {
|
// passwordRules: {
|
||||||
pwd: [{ required: true, message: '必填项' }, { validator: validatePass, trigger: 'blur' }],
|
// pwd: [{ required: true, message: '必填项' }, { validator: validatePass, trigger: 'blur' }],
|
||||||
pwd2: [{ required: true, message: '必填项' }, { validator: validatePass2, trigger: 'blur' }]
|
// pwd2: [{ required: true, message: '必填项' }, { validator: validatePass2, trigger: 'blur' }]
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getCrudOptions () {
|
getCrudOptions () {
|
||||||
|
this.crud.searchOptions.form.user_type = 0
|
||||||
return crudOptions(this)
|
return crudOptions(this)
|
||||||
},
|
},
|
||||||
pageRequest (query) {
|
pageRequest (query) {
|
||||||
|
@ -108,35 +109,40 @@ export default {
|
||||||
delRequest (row) {
|
delRequest (row) {
|
||||||
return api.DelObj(row.id)
|
return api.DelObj(row.id)
|
||||||
},
|
},
|
||||||
// 重置密码弹框
|
resetPassword (scope) {
|
||||||
resetPwd ({ row }) {
|
api.ResetPwd(scope.row).then((res) => {
|
||||||
this.dialogFormVisible = true
|
this.$message.success('密码重置成功')
|
||||||
this.resetPwdForm.id = row.id
|
|
||||||
},
|
|
||||||
// 重置密码确认
|
|
||||||
resetPwdSubmit () {
|
|
||||||
const that = this
|
|
||||||
that.$refs.resetPwdForm.validate((valid) => {
|
|
||||||
if (valid) {
|
|
||||||
const params = {
|
|
||||||
id: that.resetPwdForm.id,
|
|
||||||
newPassword: that.$md5(that.resetPwdForm.pwd),
|
|
||||||
newPassword2: that.$md5(that.resetPwdForm.pwd2)
|
|
||||||
}
|
|
||||||
api.ResetPwd(params).then(res => {
|
|
||||||
that.dialogFormVisible = false
|
|
||||||
that.resetPwdForm = {
|
|
||||||
id: null,
|
|
||||||
pwd: null,
|
|
||||||
pwd2: null
|
|
||||||
}
|
|
||||||
that.$message.success('修改成功')
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
that.$message.error('表单校验失败,请检查')
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// // 重置密码弹框
|
||||||
|
// resetPwd ({ row }) {
|
||||||
|
// this.dialogFormVisible = true
|
||||||
|
// this.resetPwdForm.id = row.id
|
||||||
|
// },
|
||||||
|
// // 重置密码确认
|
||||||
|
// resetPwdSubmit () {
|
||||||
|
// const that = this
|
||||||
|
// that.$refs.resetPwdForm.validate((valid) => {
|
||||||
|
// if (valid) {
|
||||||
|
// const params = {
|
||||||
|
// id: that.resetPwdForm.id,
|
||||||
|
// newPassword: that.$md5(that.resetPwdForm.pwd),
|
||||||
|
// newPassword2: that.$md5(that.resetPwdForm.pwd2)
|
||||||
|
// }
|
||||||
|
// api.ResetPwd(params).then(res => {
|
||||||
|
// that.dialogFormVisible = false
|
||||||
|
// that.resetPwdForm = {
|
||||||
|
// id: null,
|
||||||
|
// pwd: null,
|
||||||
|
// pwd2: null
|
||||||
|
// }
|
||||||
|
// that.$message.success('修改成功')
|
||||||
|
// })
|
||||||
|
// } else {
|
||||||
|
// that.$message.error('表单校验失败,请检查')
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { request } from '@/api/service'
|
import { request } from '@/api/service'
|
||||||
import { BUTTON_STATUS_BOOL } from '@/config/button'
|
|
||||||
|
|
||||||
export const crudOptions = (vm) => {
|
export const crudOptions = (vm) => {
|
||||||
return {
|
return {
|
||||||
|
@ -170,7 +169,7 @@ export const crudOptions = (vm) => {
|
||||||
width: 150,
|
width: 150,
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
dict: {
|
dict: {
|
||||||
data: BUTTON_STATUS_BOOL
|
data: vm.dictionary('button_status_bool')
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
value: true,
|
value: true,
|
||||||
|
|