├── .gitignore ├── LICENSE ├── NOTICE ├── README.en.md ├── README.md ├── backend ├── .gitignore ├── application │ ├── __init__.py │ ├── asgi.py │ ├── celery.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── conf │ └── env.example.py ├── docker_start.sh ├── dvadmin │ ├── system │ │ ├── __init__.py │ │ ├── admin.py │ │ ├── apps.py │ │ ├── initialize.py │ │ ├── management │ │ │ ├── __init__.py │ │ │ └── commands │ │ │ │ ├── __init__.py │ │ │ │ └── init.py │ │ ├── migrations │ │ │ └── __init__.py │ │ ├── models.py │ │ ├── tests.py │ │ ├── urls.py │ │ ├── util │ │ │ ├── init_area.py │ │ │ └── pca-code.json │ │ └── views │ │ │ ├── area.py │ │ │ ├── button.py │ │ │ ├── dept.py │ │ │ ├── dictionary.py │ │ │ ├── file_list.py │ │ │ ├── img_list.py │ │ │ ├── login.py │ │ │ ├── menu.py │ │ │ ├── menu_button.py │ │ │ ├── operation_log.py │ │ │ ├── role.py │ │ │ └── user.py │ └── utils │ │ ├── backends.py │ │ ├── core_initialize.py │ │ ├── exception.py │ │ ├── filters.py │ │ ├── git_utils.py │ │ ├── json_response.py │ │ ├── middleware.py │ │ ├── models.py │ │ ├── pagination.py │ │ ├── permission.py │ │ ├── request_util.py │ │ ├── serializers.py │ │ ├── string_util.py │ │ ├── swagger.py │ │ ├── validator.py │ │ └── viewset.py ├── manage.py ├── plugins │ ├── __init__.py │ └── config.json ├── requirements.txt └── static │ ├── drf-yasg │ ├── immutable.min.js │ ├── insQ.min.js │ ├── redoc-init.js │ ├── redoc-old │ │ └── redoc.min.js │ ├── redoc │ │ ├── redoc-logo.png │ │ └── redoc.min.js │ ├── style.css │ ├── swagger-ui-dist │ │ ├── absolute-path.js │ │ ├── favicon-32x32.png │ │ ├── index.js │ │ ├── oauth2-redirect.html │ │ ├── swagger-ui-bundle.js │ │ ├── swagger-ui-es-bundle-core.js │ │ ├── swagger-ui-es-bundle.js │ │ ├── swagger-ui-standalone-preset.js │ │ └── swagger-ui.css │ ├── swagger-ui-init.js │ └── url-polyfill.min.js │ └── rest_framework │ ├── css │ ├── bootstrap-theme.min.css │ ├── bootstrap-tweaks.css │ ├── bootstrap.min.css │ ├── default.css │ ├── font-awesome-4.0.3.css │ └── prettify.css │ ├── docs │ ├── css │ │ ├── base.css │ │ ├── highlight.css │ │ └── jquery.json-view.min.css │ ├── img │ │ ├── favicon.ico │ │ └── grid.png │ └── js │ │ ├── api.js │ │ ├── highlight.pack.js │ │ └── jquery.json-view.min.js │ ├── fonts │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 │ ├── img │ ├── glyphicons-halflings-white.png │ ├── glyphicons-halflings.png │ └── grid.png │ └── js │ ├── ajax-form.js │ ├── bootstrap.min.js │ ├── coreapi-0.1.1.js │ ├── csrf.js │ ├── default.js │ ├── jquery-3.5.1.min.js │ └── prettify-min.js ├── docker-compose.yml ├── docker_env ├── README.md ├── base-build.sh ├── celery │ └── Dockerfile ├── django │ ├── Dockerfile │ └── DockerfileBuild ├── mysql │ ├── conf.d │ │ └── my.cnf │ └── launch.sh ├── nginx │ └── my.conf ├── requirements-all.txt └── web │ ├── Dockerfile │ └── DockerfileBuild └── web ├── .browserslistrc ├── .editorconfig ├── .env ├── .env.development ├── .env.preview ├── .env.test ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .postcssrc.js ├── LICENSE ├── README.md ├── README.zh.md ├── babel.config.js ├── d2-admin.babel ├── dependencies-cdn.js ├── jest.config.js ├── jsconfig.json ├── package-lock.json ├── package.json ├── public ├── icon-1.ico ├── icon.ico ├── image │ ├── baidu-pan-logo.png │ ├── bbs-go.png │ ├── d2-pub.png │ ├── django-comment-migrate.png │ ├── django-vue-admin.png │ ├── django.png │ ├── gin-vue-admin.png │ ├── jetbrains.jpeg │ ├── loading │ │ └── loading-spin.svg │ ├── ruoyi.png │ ├── simple-ui.png │ └── theme │ │ ├── chester │ │ ├── logo │ │ │ ├── all.png │ │ │ └── icon-only.png │ │ └── preview@2x.png │ │ ├── d2 │ │ ├── logo │ │ │ ├── all.png │ │ │ └── icon-only.png │ │ └── preview@2x.png │ │ ├── element │ │ ├── logo │ │ │ ├── all.png │ │ │ └── icon-only.png │ │ └── preview@2x.png │ │ ├── line │ │ ├── bg.jpg │ │ ├── logo │ │ │ ├── all.png │ │ │ └── icon-only.png │ │ └── preview@2x.png │ │ ├── star │ │ ├── bg.jpg │ │ ├── logo │ │ │ ├── all.png │ │ │ └── icon-only.png │ │ └── preview@2x.png │ │ ├── tomorrow-night-blue │ │ ├── logo │ │ │ ├── all.png │ │ │ └── icon-only.png │ │ └── preview@2x.png │ │ └── violet │ │ ├── logo │ │ ├── all.png │ │ └── icon-only.png │ │ └── preview@2x.png └── index.html ├── src ├── App.vue ├── api │ ├── index.js │ ├── modules │ │ └── sys.user.api.js │ ├── service.js │ └── tools.js ├── assets │ ├── style │ │ ├── animate │ │ │ └── vue-transition.scss │ │ ├── fixed │ │ │ ├── base.scss │ │ │ ├── element.scss │ │ │ ├── markdown.scss │ │ │ ├── n-progress.scss │ │ │ ├── tree-view.scss │ │ │ ├── vue-grid-layout.scss │ │ │ └── vue-splitpane.scss │ │ ├── public-class.scss │ │ ├── public.scss │ │ ├── theme │ │ │ ├── chester │ │ │ │ ├── index.scss │ │ │ │ └── setting.scss │ │ │ ├── d2 │ │ │ │ ├── index.scss │ │ │ │ └── setting.scss │ │ │ ├── element │ │ │ │ ├── index.scss │ │ │ │ └── setting.scss │ │ │ ├── line │ │ │ │ ├── index.scss │ │ │ │ └── setting.scss │ │ │ ├── register.scss │ │ │ ├── star │ │ │ │ ├── index.scss │ │ │ │ └── setting.scss │ │ │ ├── theme-base.scss │ │ │ ├── theme.scss │ │ │ ├── tomorrow-night-blue │ │ │ │ ├── index.scss │ │ │ │ └── setting.scss │ │ │ └── violet │ │ │ │ ├── index.scss │ │ │ │ └── setting.scss │ │ ├── unit │ │ │ └── color.scss │ │ └── yxt-public.scss │ └── svg-icons │ │ ├── icons │ │ ├── d2-admin-text.svg │ │ ├── d2-admin.svg │ │ ├── department.svg │ │ ├── home.svg │ │ ├── log.svg │ │ ├── menu.svg │ │ ├── role.svg │ │ ├── user.svg │ │ └── work.svg │ │ └── index.js ├── components │ ├── d2-container │ │ ├── components │ │ │ ├── d2-container-card-bs.vue │ │ │ ├── d2-container-card.vue │ │ │ ├── d2-container-full-bs.vue │ │ │ ├── d2-container-full.vue │ │ │ ├── d2-container-ghost-bs.vue │ │ │ ├── d2-container-ghost.vue │ │ │ ├── d2-source.vue │ │ │ └── mixins │ │ │ │ ├── bs.js │ │ │ │ └── normal.js │ │ └── index.js │ ├── d2-icon-svg │ │ └── index.vue │ ├── d2-icon │ │ ├── font-awesome-4.7.0 │ │ │ ├── css │ │ │ │ └── font-awesome.min.css │ │ │ └── fonts │ │ │ │ ├── FontAwesome.otf │ │ │ │ ├── fontawesome-webfont.eot │ │ │ │ ├── fontawesome-webfont.svg │ │ │ │ ├── fontawesome-webfont.ttf │ │ │ │ ├── fontawesome-webfont.woff │ │ │ │ └── fontawesome-webfont.woff2 │ │ └── index.vue │ ├── index.js │ └── table-selector │ │ ├── README.md │ │ ├── group.js │ │ ├── index.js │ │ └── table-selector.vue ├── config │ └── button.js ├── i18n.js ├── install.js ├── layout │ └── header-aside │ │ ├── components │ │ ├── contextmenu │ │ │ ├── components │ │ │ │ └── contentmenuList │ │ │ │ │ └── index.vue │ │ │ └── index.vue │ │ ├── header-color │ │ │ └── index.vue │ │ ├── header-fullscreen │ │ │ └── index.vue │ │ ├── header-locales │ │ │ └── index.vue │ │ ├── header-log │ │ │ └── index.vue │ │ ├── header-search │ │ │ └── index.vue │ │ ├── header-size │ │ │ └── index.vue │ │ ├── header-theme │ │ │ ├── components │ │ │ │ └── d2-theme-list │ │ │ │ │ └── index.vue │ │ │ └── index.vue │ │ ├── header-user │ │ │ ├── index.vue │ │ │ └── userinfo.vue │ │ ├── libs │ │ │ └── util.menu.js │ │ ├── menu-header │ │ │ └── index.js │ │ ├── menu-side │ │ │ └── index.js │ │ ├── mixin │ │ │ └── menu.js │ │ ├── panel-search │ │ │ ├── components │ │ │ │ └── panel-search-item │ │ │ │ │ └── index.vue │ │ │ └── index.vue │ │ └── tabs │ │ │ └── index.vue │ │ ├── index.js │ │ ├── layout.vue │ │ └── mixins │ │ └── search.js ├── libs │ ├── util.cookies.js │ ├── util.db.js │ ├── util.import.development.js │ ├── util.import.production.js │ ├── util.import.test.js │ ├── util.js │ └── util.log.js ├── locales │ ├── en.json │ ├── ja.json │ ├── mixin.js │ ├── zh-chs.json │ └── zh-cht.json ├── main.js ├── menu │ └── index.js ├── plugin │ ├── api │ │ └── index.js │ ├── d2admin │ │ └── index.js │ ├── error │ │ └── index.js │ ├── log │ │ └── index.js │ ├── open │ │ └── index.js │ └── permission │ │ ├── directive │ │ └── permission │ │ │ ├── index.js │ │ │ ├── permission.js │ │ │ └── util.permission.js │ │ └── index.js ├── router │ ├── index.js │ └── routes.js ├── setting.js ├── store │ ├── index.js │ └── modules │ │ └── d2admin │ │ ├── index.js │ │ └── modules │ │ ├── account.js │ │ ├── color.js │ │ ├── db.js │ │ ├── fullscreen.js │ │ ├── gray.js │ │ ├── log.js │ │ ├── menu.js │ │ ├── page.js │ │ ├── releases.js │ │ ├── search.js │ │ ├── size.js │ │ ├── theme.js │ │ ├── transition.js │ │ ├── ua.js │ │ └── user.js └── views │ ├── dashboard │ └── workbench │ │ └── index.vue │ ├── demo │ ├── page1 │ │ ├── api.js │ │ ├── crud.js │ │ └── index.vue │ ├── page2 │ │ ├── api.js │ │ ├── crud.js │ │ └── index.vue │ └── page3 │ │ ├── api.js │ │ ├── crud.js │ │ └── index.vue │ ├── dvadmin_plugins │ ├── config.json │ ├── index.js │ └── plugins_market_web │ │ └── pluginsMarket │ │ ├── api.js │ │ └── index.vue │ └── system │ ├── areas │ ├── api.js │ ├── crud.js │ └── index.vue │ ├── button │ ├── api.js │ ├── crud.js │ └── index.vue │ ├── dept │ ├── api.js │ ├── crud.js │ └── index.vue │ ├── dictionary │ ├── api.js │ ├── crud.js │ └── index.vue │ ├── error │ └── 404 │ │ └── index.vue │ ├── fileList │ ├── file │ │ ├── api.js │ │ ├── crud.js │ │ └── index.vue │ └── img │ │ ├── api.js │ │ ├── crud.js │ │ └── index.vue │ ├── function │ ├── redirect │ │ └── index.js │ └── refresh │ │ └── index.js │ ├── index │ ├── components │ │ ├── d2-badge │ │ │ └── index.vue │ │ ├── d2-help-btn │ │ │ ├── image │ │ │ │ ├── d2-help-button@2x.png │ │ │ │ ├── qq.jpg │ │ │ │ ├── we.jpg │ │ │ │ └── we.png │ │ │ └── index.vue │ │ ├── d2-help │ │ │ ├── image │ │ │ │ ├── qq.svg │ │ │ │ └── we.svg │ │ │ └── index.vue │ │ └── d2-page-cover │ │ │ ├── helper.js │ │ │ ├── image │ │ │ ├── darkblue@2x.png │ │ │ └── gif.webp │ │ │ └── index.vue │ ├── image │ │ ├── qr.jpg │ │ └── qr@2x.png │ ├── index.js │ └── page.vue │ ├── log │ ├── frontendLog │ │ └── index.vue │ ├── loginLog │ │ ├── api.js │ │ ├── crud.js │ │ └── index.vue │ └── operationLog │ │ ├── api.js │ │ ├── crud.js │ │ └── index.vue │ ├── login │ ├── api.js │ ├── image │ │ ├── dvadmin.png │ │ ├── login-code.png │ │ └── logo@2x.png │ ├── index.js │ └── page.vue │ ├── menu │ ├── api.js │ ├── crud.js │ └── index.vue │ ├── menuButton │ ├── api.js │ ├── crud.js │ └── index.vue │ ├── role │ ├── api.js │ ├── crud.js │ └── index.vue │ ├── rolePermission │ ├── api.js │ └── index.vue │ └── user │ ├── api.js │ ├── crud.js │ └── index.vue ├── tests └── unit │ └── .eslintrc.js ├── vue.config.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /backend/venv 2 | /backend/.idea 3 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2021 李强 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /README.en.md: -------------------------------------------------------------------------------- 1 | # django-vue-admin-pro 2 | 3 | #### Description 4 | {**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**} 5 | 6 | #### Software Architecture 7 | Software architecture description 8 | 9 | #### Installation 10 | 11 | 1. xxxx 12 | 2. xxxx 13 | 3. xxxx 14 | 15 | #### Instructions 16 | 17 | 1. xxxx 18 | 2. xxxx 19 | 3. xxxx 20 | 21 | #### Contribution 22 | 23 | 1. Fork the repository 24 | 2. Create Feat_xxx branch 25 | 3. Commit your code 26 | 4. Create Pull Request 27 | 28 | 29 | #### Gitee Feature 30 | 31 | 1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md 32 | 2. Gitee blog [blog.gitee.com](https://blog.gitee.com) 33 | 3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) 34 | 4. The most valuable open source project [GVP](https://gitee.com/gvp) 35 | 5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) 36 | 6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) 37 | -------------------------------------------------------------------------------- /backend/.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | *.py[cod] 3 | *$py.class 4 | __pycache__/ 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | develop-eggs/ 12 | dist/ 13 | downloads/ 14 | eggs/ 15 | .eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | 25 | # PyInstaller 26 | # Usually these files are written by a python script from a template 27 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 28 | *.manifest 29 | *.spec 30 | 31 | # Installer logs 32 | pip-log.txt 33 | pip-delete-this-directory.txt 34 | 35 | # Unit test / coverage reports 36 | htmlcov/ 37 | .tox/ 38 | .coverage 39 | .coverage.* 40 | .cache 41 | nosetests.xml 42 | coverage.xml 43 | *,cover 44 | .hypothesis/ 45 | 46 | # Translations 47 | *.mo 48 | *.pot 49 | 50 | # Django stuff: 51 | *.log 52 | local_settings.py 53 | 54 | # Flask stuff: 55 | instance/ 56 | .webassets-cache 57 | 58 | # Scrapy stuff: 59 | .scrapy 60 | 61 | # Sphinx documentation 62 | docs/_build/ 63 | 64 | # PyBuilder 65 | target/ 66 | 67 | # IPython Notebook 68 | .ipynb_checkpoints 69 | 70 | # pyenv 71 | .python-version 72 | 73 | # celery beat schedule file 74 | celerybeat-schedule 75 | 76 | # dotenv 77 | .env 78 | 79 | # virtualenv 80 | venv/ 81 | ENV/ 82 | 83 | # Spyder project settings 84 | .spyderproject 85 | 86 | # Rope project settings 87 | .ropeproject 88 | .idea/ 89 | *.db 90 | .DS_Store 91 | __pycache__ 92 | **/migrations 93 | !**/migrations/__init__.py 94 | *.pyc 95 | conf/ 96 | !conf/env.example.py 97 | db.sqlite3 98 | media/ 99 | -------------------------------------------------------------------------------- /backend/application/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/backend/application/__init__.py -------------------------------------------------------------------------------- /backend/application/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for application project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings') 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /backend/application/celery.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings') 4 | 5 | from django.conf import settings 6 | from celery import platforms 7 | 8 | if getattr(settings, 'PLUGINS_LIST', {}).get('dvadmin_tenant_backend', None): 9 | from tenant_schemas_celery.app import CeleryApp as TenantAwareCeleryApp 10 | app = TenantAwareCeleryApp() 11 | else: 12 | from celery import Celery 13 | 14 | app = Celery(f"application") 15 | app.config_from_object('django.conf:settings') 16 | app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) 17 | platforms.C_FORCE_ROOT = True 18 | -------------------------------------------------------------------------------- /backend/application/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for backend project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /backend/conf/env.example.py: -------------------------------------------------------------------------------- 1 | # ================================================= # 2 | # ************** mysql数据库 配置 ************** # 3 | # ================================================= # 4 | # 数据库地址 5 | DATABASE_ENGINE = "django.db.backends.mysql" 6 | # 数据库地址 改为自己数据库地址 7 | DATABASE_HOST = "127.0.0.1" 8 | # 数据库端口 9 | DATABASE_PORT = 3306 10 | # 数据库用户名 11 | DATABASE_USER = "root" 12 | # 数据库密码 13 | DATABASE_PASSWORD = "123456" 14 | # 数据库名 15 | DATABASE_NAME = "dvadmin_pro" 16 | # ================================================= # 17 | # ************** 其他 配置 ************** # 18 | # ================================================= # 19 | DEBUG = True # 线上环境请设置为True 20 | # 是否启用插件,不需要可以设置为False 21 | ENABLE_PLUGINS = True 22 | ALLOWED_HOSTS = ["*"] 23 | -------------------------------------------------------------------------------- /backend/docker_start.sh: -------------------------------------------------------------------------------- 1 | # python manage.py makemigrations 2 | # python manage.py migrate 3 | # python manage.py init -y 4 | daphne -b 0.0.0.0 -p 8000 application.asgi:application -------------------------------------------------------------------------------- /backend/dvadmin/system/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/backend/dvadmin/system/__init__.py -------------------------------------------------------------------------------- /backend/dvadmin/system/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /backend/dvadmin/system/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class SystemConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'dvadmin.system' 7 | -------------------------------------------------------------------------------- /backend/dvadmin/system/management/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/backend/dvadmin/system/management/__init__.py -------------------------------------------------------------------------------- /backend/dvadmin/system/management/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/backend/dvadmin/system/management/commands/__init__.py -------------------------------------------------------------------------------- /backend/dvadmin/system/management/commands/init.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from django.core.management.base import BaseCommand 4 | 5 | from application import settings 6 | 7 | logger = logging.getLogger(__name__) 8 | 9 | 10 | class Command(BaseCommand): 11 | """ 12 | 项目初始化命令: python manage.py init 13 | """ 14 | 15 | def add_arguments(self, parser): 16 | parser.add_argument('init_name', nargs='*', type=str, ) 17 | parser.add_argument('-y', nargs='*') 18 | parser.add_argument('-Y', nargs='*') 19 | parser.add_argument('-n', nargs='*') 20 | parser.add_argument('-N', nargs='*') 21 | 22 | def handle(self, *args, **options): 23 | reset = False 24 | if isinstance(options.get('y'), list) or isinstance(options.get('Y'), list): 25 | reset = True 26 | if isinstance(options.get('n'), list) or isinstance(options.get('N'), list): 27 | reset = False 28 | print(f"正在准备初始化数据,{'如有初始化数据,将会不做操作跳过' if not reset else '初始数据将会先删除后新增'}...") 29 | 30 | for app in settings.INSTALLED_APPS: 31 | 32 | try: 33 | exec(f""" 34 | from {app}.initialize import main 35 | main(reset={reset}) 36 | """) 37 | except ModuleNotFoundError: 38 | pass 39 | print("初始化数据完成!") 40 | -------------------------------------------------------------------------------- /backend/dvadmin/system/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/backend/dvadmin/system/migrations/__init__.py -------------------------------------------------------------------------------- /backend/dvadmin/system/tests.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/backend/dvadmin/system/tests.py -------------------------------------------------------------------------------- /backend/dvadmin/system/urls.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: 猿小天 5 | @contact: QQ:1638245306 6 | @Created on: 2021/6/1 001 23:05 7 | @Remark: 系统管理的路由文件 8 | """ 9 | from django.urls import path, re_path 10 | from rest_framework import routers 11 | 12 | from dvadmin.system.views.area import AreaViewSet 13 | from dvadmin.system.views.button import ButtonViewSet 14 | from dvadmin.system.views.dept import DeptViewSet 15 | from dvadmin.system.views.dictionary import DictionaryViewSet 16 | from dvadmin.system.views.file_list import FileViewSet 17 | from dvadmin.system.views.img_list import ImgViewSet 18 | from dvadmin.system.views.menu import MenuViewSet 19 | from dvadmin.system.views.menu_button import MenuButtonViewSet 20 | from dvadmin.system.views.operation_log import OperationLogViewSet 21 | from dvadmin.system.views.role import RoleViewSet 22 | from dvadmin.system.views.user import UserViewSet 23 | 24 | system_url = routers.SimpleRouter() 25 | system_url.register(r'menu', MenuViewSet) 26 | system_url.register(r'button', ButtonViewSet) 27 | system_url.register(r'menu_button', MenuButtonViewSet) 28 | system_url.register(r'role', RoleViewSet) 29 | system_url.register(r'dept', DeptViewSet) 30 | system_url.register(r'user', UserViewSet) 31 | system_url.register(r'operation_log', OperationLogViewSet) 32 | system_url.register(r'dictionary', DictionaryViewSet) 33 | system_url.register(r'area', AreaViewSet) 34 | system_url.register(r'img', ImgViewSet) 35 | system_url.register(r'file', FileViewSet) 36 | 37 | urlpatterns = [ 38 | re_path('role/role_id_to_menu/(?P.*?)/', RoleViewSet.as_view({'get': 'roleId_to_menu'})), 39 | path('menu/web_router/', MenuViewSet.as_view({'get': 'web_router'})), 40 | path('user/user_info/', UserViewSet.as_view({'get': 'user_info', 'put': 'update_user_info'})), 41 | re_path('user/change_password/(?P.*?)/', UserViewSet.as_view({'put': 'change_password'})), 42 | ] 43 | urlpatterns += system_url.urls 44 | -------------------------------------------------------------------------------- /backend/dvadmin/system/util/init_area.py: -------------------------------------------------------------------------------- 1 | # 城市联动 2 | """ 3 | 到乡级 使用方法 4 | 1. https://www.npmjs.com/package/china-division 下载数据,把对应的json放入对应目录 5 | 2. 修改此文件中对应json名 6 | 3. 右击执行此py文件进行初始化 7 | """ 8 | import json 9 | import os 10 | 11 | import django 12 | import pypinyin 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings') 15 | django.setup() 16 | from application.settings import BASE_DIR 17 | from dvadmin.system.models import Area 18 | 19 | area_code_list = [] 20 | 21 | 22 | def area_list(code_list, pcode=None, depth=1): 23 | """ 24 | 递归获取所有列表 25 | """ 26 | for code_dict in code_list: 27 | code = code_dict.get('code', None) 28 | name = code_dict.get('name', None) 29 | children = code_dict.get('children', None) 30 | pinyin = ''.join([''.join(i) for i in pypinyin.pinyin(name, style=pypinyin.NORMAL)]) 31 | area_code_list.append( 32 | { 33 | "name": name, 34 | "code": code, 35 | "level": depth, 36 | "pinyin": pinyin, 37 | "initials": pinyin[0].upper() if pinyin else "#", 38 | "pcode_id": pcode, 39 | } 40 | ) 41 | if children: 42 | area_list(code_list=children, pcode=code, depth=depth + 1) 43 | 44 | 45 | def main(): 46 | with open(os.path.join(BASE_DIR, 'dvadmin', 'system', 'util', 'pca-code.json'), 'r') as load_f: 47 | code_list = json.load(load_f) 48 | area_list(code_list) 49 | if Area.objects.count() == 0: 50 | Area.objects.bulk_create([Area(**ele) for ele in area_code_list]) 51 | else: 52 | for ele in area_code_list: 53 | code = ele.pop("code") 54 | Area.objects.update_or_create(code=code, defaults=ele) 55 | 56 | 57 | if __name__ == '__main__': 58 | main() 59 | -------------------------------------------------------------------------------- /backend/dvadmin/system/views/area.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.db.models import Q 3 | from rest_framework import serializers 4 | 5 | from dvadmin.system.models import Area 6 | from dvadmin.utils.json_response import SuccessResponse 7 | from dvadmin.utils.serializers import CustomModelSerializer 8 | from dvadmin.utils.viewset import CustomModelViewSet 9 | 10 | 11 | class AreaSerializer(CustomModelSerializer): 12 | """ 13 | 地区-序列化器 14 | """ 15 | pcode_count = serializers.SerializerMethodField(read_only=True) 16 | 17 | def get_pcode_count(self, instance: Area): 18 | return Area.objects.filter(pcode=instance).count() 19 | 20 | class Meta: 21 | model = Area 22 | fields = "__all__" 23 | read_only_fields = ["id"] 24 | 25 | 26 | class AreaCreateUpdateSerializer(CustomModelSerializer): 27 | """ 28 | 地区管理 创建/更新时的列化器 29 | """ 30 | 31 | class Meta: 32 | model = Area 33 | fields = '__all__' 34 | 35 | 36 | class AreaViewSet(CustomModelViewSet): 37 | """ 38 | 地区管理接口 39 | list:查询 40 | create:新增 41 | update:修改 42 | retrieve:单例 43 | destroy:删除 44 | """ 45 | queryset = Area.objects.all() 46 | serializer_class = AreaSerializer 47 | permission_classes = [] 48 | extra_filter_backends = [] 49 | -------------------------------------------------------------------------------- /backend/dvadmin/system/views/button.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: 猿小天 5 | @contact: QQ:1638245306 6 | @Created on: 2021/6/3 003 0:30 7 | @Remark: 按钮权限管理 8 | """ 9 | from dvadmin.system.models import Button 10 | from dvadmin.utils.serializers import CustomModelSerializer 11 | from dvadmin.utils.viewset import CustomModelViewSet 12 | 13 | 14 | class ButtonSerializer(CustomModelSerializer): 15 | """ 16 | 按钮权限-序列化器 17 | """ 18 | 19 | class Meta: 20 | model = Button 21 | fields = "__all__" 22 | read_only_fields = ["id"] 23 | 24 | 25 | class ButtonViewSet(CustomModelViewSet): 26 | """ 27 | 按钮权限接口 28 | list:查询 29 | create:新增 30 | update:修改 31 | retrieve:单例 32 | destroy:删除 33 | """ 34 | queryset = Button.objects.all() 35 | serializer_class = ButtonSerializer 36 | permission_classes = [] 37 | -------------------------------------------------------------------------------- /backend/dvadmin/system/views/dept.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: 猿小天 5 | @contact: QQ:1638245306 6 | @Created on: 2021/6/3 003 0:30 7 | @Remark: 角色管理 8 | """ 9 | 10 | from dvadmin.system.models import Dept 11 | from dvadmin.utils.filters import DataLevelPermissionsFilter 12 | from dvadmin.utils.json_response import SuccessResponse 13 | from dvadmin.utils.serializers import CustomModelSerializer 14 | from dvadmin.utils.viewset import CustomModelViewSet 15 | 16 | 17 | class DeptSerializer(CustomModelSerializer): 18 | """ 19 | 部门-序列化器 20 | """ 21 | 22 | class Meta: 23 | model = Dept 24 | fields = "__all__" 25 | read_only_fields = ["id"] 26 | 27 | 28 | class DeptCreateUpdateSerializer(CustomModelSerializer): 29 | """ 30 | 部门管理 创建/更新时的列化器 31 | """ 32 | 33 | class Meta: 34 | model = Dept 35 | fields = '__all__' 36 | 37 | 38 | class DeptViewSet(CustomModelViewSet): 39 | """ 40 | 部门管理接口 41 | list:查询 42 | create:新增 43 | update:修改 44 | retrieve:单例 45 | destroy:删除 46 | """ 47 | queryset = Dept.objects.all() 48 | serializer_class = DeptSerializer 49 | permission_classes = [] 50 | 51 | def list(self, request, *args, **kwargs): 52 | queryset = self.filter_queryset(self.get_queryset()) 53 | page = self.paginate_queryset(queryset) 54 | if page is not None: 55 | serializer = self.get_serializer(page, many=True, request=request) 56 | return self.get_paginated_response(serializer.data) 57 | serializer = self.get_serializer(queryset, many=True, request=request) 58 | return SuccessResponse(data=serializer.data, msg="获取成功") 59 | -------------------------------------------------------------------------------- /backend/dvadmin/system/views/dictionary.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: 猿小天 5 | @contact: QQ:1638245306 6 | @Created on: 2021/6/3 003 0:30 7 | @Remark: 字典管理 8 | """ 9 | from rest_framework import serializers 10 | 11 | from dvadmin.system.models import Dictionary 12 | from dvadmin.utils.json_response import SuccessResponse 13 | from dvadmin.utils.serializers import CustomModelSerializer 14 | from dvadmin.utils.viewset import CustomModelViewSet 15 | 16 | 17 | class DictionarySerializer(CustomModelSerializer): 18 | """ 19 | 字典-序列化器 20 | """ 21 | 22 | class Meta: 23 | model = Dictionary 24 | fields = "__all__" 25 | read_only_fields = ["id"] 26 | 27 | 28 | class DictionaryCreateUpdateSerializer(CustomModelSerializer): 29 | """ 30 | 字典管理 创建/更新时的列化器 31 | """ 32 | 33 | class Meta: 34 | model = Dictionary 35 | fields = '__all__' 36 | 37 | 38 | class DictionaryTreeSerializer(CustomModelSerializer): 39 | """ 40 | 字典表的树形序列化器 41 | """ 42 | children = serializers.SerializerMethodField(read_only=True) 43 | 44 | def get_children(self, instance): 45 | queryset = Dictionary.objects.filter(parent=instance.id).filter(status=1) 46 | if queryset: 47 | serializer = DictionaryTreeSerializer(queryset, many=True) 48 | return serializer.data 49 | else: 50 | return None 51 | 52 | class Meta: 53 | model = Dictionary 54 | fields = "__all__" 55 | read_only_fields = ["id"] 56 | 57 | 58 | class DictionaryViewSet(CustomModelViewSet): 59 | """ 60 | 字典管理接口 61 | list:查询 62 | create:新增 63 | update:修改 64 | retrieve:单例 65 | destroy:删除 66 | """ 67 | queryset = Dictionary.objects.all() 68 | serializer_class = DictionarySerializer 69 | extra_filter_backends = [] 70 | permission_classes = [] 71 | search_fields = ['label'] 72 | -------------------------------------------------------------------------------- /backend/dvadmin/system/views/file_list.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: 猿小天 5 | @contact: QQ:1638245306 6 | @Created on: 2021/8/9 009 20:48 7 | @Remark: 8 | """ 9 | from rest_framework import serializers 10 | 11 | from dvadmin.system.models import FileList 12 | from dvadmin.utils.serializers import CustomModelSerializer 13 | from dvadmin.utils.viewset import CustomModelViewSet 14 | 15 | 16 | class FileSerializer(CustomModelSerializer): 17 | url = serializers.SerializerMethodField(read_only=True) 18 | 19 | def get_url(self, instance): 20 | return str(instance.url) 21 | 22 | class Meta: 23 | model = FileList 24 | fields = "__all__" 25 | 26 | def create(self, validated_data): 27 | validated_data['name'] = str(self.initial_data.get('url')) 28 | validated_data['url'] = self.initial_data.get('url') 29 | return super().create(validated_data) 30 | 31 | 32 | class FileViewSet(CustomModelViewSet): 33 | """ 34 | 文件管理接口 35 | list:查询 36 | create:新增 37 | update:修改 38 | retrieve:单例 39 | destroy:删除 40 | """ 41 | queryset = FileList.objects.all() 42 | serializer_class = FileSerializer 43 | filter_fields = ['name', ] 44 | -------------------------------------------------------------------------------- /backend/dvadmin/system/views/img_list.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: 猿小天 5 | @contact: QQ:1638245306 6 | @Created on: 2021/8/9 009 20:48 7 | @Remark: 8 | """ 9 | from rest_framework import serializers 10 | 11 | from dvadmin.system.models import ImgList 12 | from dvadmin.utils.serializers import CustomModelSerializer 13 | from dvadmin.utils.viewset import CustomModelViewSet 14 | 15 | 16 | class ImgSerializer(CustomModelSerializer): 17 | img = serializers.SerializerMethodField(read_only=True) 18 | 19 | def get_img(self, instance): 20 | return str(instance.url) 21 | 22 | class Meta: 23 | model = ImgList 24 | fields = "__all__" 25 | 26 | def create(self, validated_data): 27 | validated_data['name'] = str(validated_data.get('url')) 28 | return super().create(validated_data) 29 | 30 | 31 | class ImgViewSet(CustomModelViewSet): 32 | """ 33 | 图片管理接口 34 | list:查询 35 | create:新增 36 | update:修改 37 | retrieve:单例 38 | destroy:删除 39 | """ 40 | queryset = ImgList.objects.all() 41 | serializer_class = ImgSerializer 42 | filter_fields = ['name', ] 43 | -------------------------------------------------------------------------------- /backend/dvadmin/system/views/menu_button.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: 猿小天 5 | @contact: QQ:1638245306 6 | @Created on: 2021/6/3 003 0:30 7 | @Remark: 菜单按钮管理 8 | """ 9 | from dvadmin.system.models import MenuButton 10 | from dvadmin.utils.serializers import CustomModelSerializer 11 | from dvadmin.utils.viewset import CustomModelViewSet 12 | 13 | 14 | class MenuButtonSerializer(CustomModelSerializer): 15 | """ 16 | 菜单按钮-序列化器 17 | """ 18 | 19 | class Meta: 20 | model = MenuButton 21 | fields = "__all__" 22 | read_only_fields = ["id"] 23 | 24 | 25 | class MenuButtonViewSet(CustomModelViewSet): 26 | """ 27 | 菜单按钮接口 28 | list:查询 29 | create:新增 30 | update:修改 31 | retrieve:单例 32 | destroy:删除 33 | """ 34 | queryset = MenuButton.objects.all() 35 | serializer_class = MenuButtonSerializer 36 | permission_classes = [] 37 | -------------------------------------------------------------------------------- /backend/dvadmin/system/views/operation_log.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: 李强 5 | @contact: QQ:1206709430 6 | @Created on: 2021/6/8 003 0:30 7 | @Remark: 操作日志管理 8 | """ 9 | 10 | from dvadmin.system.models import OperationLog 11 | from dvadmin.utils.serializers import CustomModelSerializer 12 | from dvadmin.utils.viewset import CustomModelViewSet 13 | 14 | 15 | class OperationLogSerializer(CustomModelSerializer): 16 | """ 17 | 日志-序列化器 18 | """ 19 | 20 | class Meta: 21 | model = OperationLog 22 | fields = "__all__" 23 | read_only_fields = ["id"] 24 | 25 | 26 | class OperationLogCreateUpdateSerializer(CustomModelSerializer): 27 | """ 28 | 操作日志 创建/更新时的列化器 29 | """ 30 | 31 | class Meta: 32 | model = OperationLog 33 | fields = '__all__' 34 | 35 | 36 | class OperationLogViewSet(CustomModelViewSet): 37 | """ 38 | 操作日志接口 39 | list:查询 40 | create:新增 41 | update:修改 42 | retrieve:单例 43 | destroy:删除 44 | """ 45 | queryset = OperationLog.objects.order_by('-create_datetime') 46 | serializer_class = OperationLogSerializer 47 | permission_classes = [] 48 | -------------------------------------------------------------------------------- /backend/dvadmin/utils/backends.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from django.contrib.auth import get_user_model 4 | from django.contrib.auth.backends import ModelBackend 5 | from django.utils import timezone 6 | 7 | logger = logging.getLogger(__name__) 8 | UserModel = get_user_model() 9 | 10 | 11 | class CustomBackend(ModelBackend): 12 | """ 13 | Django原生认证方式 14 | """ 15 | 16 | def authenticate(self, request, username=None, password=None, **kwargs): 17 | msg = '%s 正在使用本地登录...' % username 18 | logger.info(msg) 19 | if username is None: 20 | username = kwargs.get(UserModel.USERNAME_FIELD) 21 | try: 22 | user = UserModel._default_manager.get_by_natural_key(username) 23 | except UserModel.DoesNotExist: 24 | UserModel().set_password(password) 25 | else: 26 | if user.check_password(password) and self.user_can_authenticate(user): 27 | user.last_login = timezone.now() 28 | user.save() 29 | return user 30 | -------------------------------------------------------------------------------- /backend/dvadmin/utils/core_initialize.py: -------------------------------------------------------------------------------- 1 | # 初始化基类 2 | from application import settings 3 | 4 | 5 | class CoreInitialize: 6 | """ 7 | 使用方法:继承此类,重写 run方法,在 run 中调用 save 进行数据初始化 8 | """ 9 | creator_id = None 10 | reset = False 11 | 12 | def __init__(self, reset=False, creator_id=None): 13 | """ 14 | reset: 是否重置初始化数据 15 | creator_id: 创建人id 16 | """ 17 | self.reset = reset or self.reset 18 | self.creator_id = creator_id or self.creator_id 19 | 20 | def save(self, obj, data: list, name=None, no_reset=False): 21 | name = name or obj._meta.verbose_name 22 | print(f"正在初始化[{obj._meta.label} => {name}]") 23 | if not no_reset and self.reset and obj not in settings.INITIALIZE_RESET_LIST: 24 | try: 25 | obj.objects.all().delete() 26 | settings.INITIALIZE_RESET_LIST.append(obj) 27 | except Exception: 28 | pass 29 | for ele in data: 30 | m2m_dict = {} 31 | new_data = {} 32 | for key, value in ele.items(): 33 | # 判断传的 value 为 list 的多对多进行抽离,使用set 进行更新 34 | if isinstance(value, list): 35 | m2m_dict[key] = value 36 | else: 37 | new_data[key] = value 38 | object, _ = obj.objects.get_or_create(id=ele.get("id"), defaults=new_data) 39 | for key, m2m in m2m_dict.items(): 40 | m2m = list(set(m2m)) 41 | if m2m and len(m2m) > 0 and m2m[0]: 42 | exec(f""" 43 | if object.{key}: 44 | values_list = object.{key}.all().values_list('id', flat=True) 45 | values_list = list(set(list(values_list) + {m2m})) 46 | object.{key}.set(values_list) 47 | """) 48 | print(f"初始化完成[{obj._meta.label} => {name}]") 49 | 50 | def run(self): 51 | raise NotImplementedError('.run() must be overridden') 52 | -------------------------------------------------------------------------------- /backend/dvadmin/utils/exception.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: 猿小天 5 | @contact: QQ:1638245306 6 | @Created on: 2021/6/2 002 16:06 7 | @Remark: 自定义异常处理 8 | """ 9 | import logging 10 | import traceback 11 | 12 | from django.db.models import ProtectedError 13 | from rest_framework import exceptions 14 | from rest_framework.exceptions import APIException as DRFAPIException, AuthenticationFailed 15 | from rest_framework.views import set_rollback 16 | 17 | from dvadmin.utils.json_response import ErrorResponse 18 | 19 | logger = logging.getLogger(__name__) 20 | 21 | 22 | def CustomExceptionHandler(ex, context): 23 | """ 24 | 统一异常拦截处理 25 | 目的:(1)取消所有的500异常响应,统一响应为标准错误返回 26 | (2)准确显示错误信息 27 | :param ex: 28 | :param context: 29 | :return: 30 | """ 31 | msg = '' 32 | code = 4000 33 | 34 | if isinstance(ex, AuthenticationFailed): 35 | code = 401 36 | msg = ex.detail 37 | elif isinstance(ex, DRFAPIException): 38 | set_rollback() 39 | msg = ex.detail 40 | elif isinstance(ex, exceptions.APIException): 41 | set_rollback() 42 | msg = ex.detail 43 | elif isinstance(ex, ProtectedError): 44 | set_rollback() 45 | msg = "删除失败:该条数据与其他数据有相关绑定" 46 | # elif isinstance(ex, DatabaseError): 47 | # set_rollback() 48 | # msg = "接口服务器异常,请联系管理员" 49 | elif isinstance(ex, Exception): 50 | logger.error(traceback.format_exc()) 51 | msg = str(ex) 52 | 53 | # errorMsg = msg 54 | # for key in errorMsg: 55 | # msg = errorMsg[key][0] 56 | 57 | return ErrorResponse(msg=msg, code=code) 58 | -------------------------------------------------------------------------------- /backend/dvadmin/utils/json_response.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: 猿小天 5 | @contact: QQ:1638245306 6 | @Created on: 2021/6/2 002 14:43 7 | @Remark: 自定义的JsonResonpse文件 8 | """ 9 | 10 | from rest_framework.response import Response 11 | 12 | 13 | class SuccessResponse(Response): 14 | """ 15 | 标准响应成功的返回, SuccessResponse(data)或者SuccessResponse(data=data) 16 | (1)默认code返回2000, 不支持指定其他返回码 17 | """ 18 | 19 | def __init__(self, data=None, msg='success', status=None, template_name=None, headers=None, exception=False, 20 | content_type=None,page=1,limit=1,total=1): 21 | std_data = { 22 | "code": 2000, 23 | "data": { 24 | "page": page, 25 | "limit": limit, 26 | "total": total, 27 | "data": data 28 | }, 29 | "msg": msg 30 | } 31 | super().__init__(std_data, status, template_name, headers, exception, content_type) 32 | 33 | 34 | class ErrorResponse(Response): 35 | """ 36 | 标准响应错误的返回,ErrorResponse(msg='xxx') 37 | (1)默认错误码返回400, 也可以指定其他返回码:ErrorResponse(code=xxx) 38 | """ 39 | 40 | def __init__(self, data=None, msg='error', code=400, status=None, template_name=None, headers=None, 41 | exception=False, content_type=None): 42 | std_data = { 43 | "code": code, 44 | "data": data, 45 | "msg": msg 46 | } 47 | super().__init__(std_data, status, template_name, headers, exception, content_type) 48 | -------------------------------------------------------------------------------- /backend/dvadmin/utils/models.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: 猿小天 5 | @contact: QQ:1638245306 6 | @Created on: 2021/5/31 031 22:08 7 | @Remark: 公共基础model类 8 | """ 9 | import uuid 10 | 11 | from django.db import models 12 | 13 | from application import settings 14 | 15 | table_prefix = settings.TABLE_PREFIX # 数据库表名前缀 16 | 17 | 18 | class CoreModel(models.Model): 19 | """ 20 | 核心标准抽象模型模型,可直接继承使用 21 | 增加审计字段, 覆盖字段时, 字段名称请勿修改, 必须统一审计字段名称 22 | """ 23 | id = models.CharField(max_length=255, primary_key=True, default=uuid.uuid4, help_text="Id", verbose_name="Id") 24 | description = models.CharField(max_length=255, verbose_name="描述", null=True, blank=True, help_text="描述") 25 | creator = models.ForeignKey(to=settings.AUTH_USER_MODEL, related_query_name='creator_query', null=True, 26 | verbose_name='创建人', help_text="创建人", on_delete=models.SET_NULL, db_constraint=False) 27 | modifier = models.CharField(max_length=255, null=True, blank=True, help_text="修改人", verbose_name="修改人") 28 | dept_belong_id = models.CharField(max_length=255, help_text="数据归属部门", null=True, blank=True, verbose_name="数据归属部门") 29 | update_datetime = models.DateTimeField(auto_now=True, null=True, blank=True, help_text="修改时间", verbose_name="修改时间") 30 | create_datetime = models.DateTimeField(auto_now_add=True, null=True, blank=True, help_text="创建时间", 31 | verbose_name="创建时间") 32 | 33 | class Meta: 34 | abstract = True 35 | verbose_name = '核心模型' 36 | verbose_name_plural = verbose_name 37 | -------------------------------------------------------------------------------- /backend/dvadmin/utils/pagination.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: 猿小天 5 | 6 | @contact: QQ:1638245306 7 | 8 | @Created on: 2020/4/16 23:35 9 | """ 10 | from collections import OrderedDict 11 | 12 | from django.core import paginator 13 | from django.core.paginator import Paginator as DjangoPaginator 14 | from rest_framework.pagination import PageNumberPagination 15 | from rest_framework.response import Response 16 | 17 | 18 | class CustomPagination(PageNumberPagination): 19 | page_size = 10 20 | page_size_query_param = "limit" 21 | max_page_size = 999 22 | django_paginator_class = DjangoPaginator 23 | 24 | def get_paginated_response(self, data): 25 | code = 2000 26 | msg = 'success' 27 | res = { 28 | "page": int(self.get_page_number(self.request, paginator)) or 1, 29 | "total": self.page.paginator.count, 30 | "limit": int(self.get_page_size(self.request)) or 10, 31 | "data": data 32 | } 33 | if not data: 34 | code = 2000 35 | msg = "暂无数据" 36 | res['data'] = [] 37 | 38 | return Response(OrderedDict([ 39 | ('code', code), 40 | ('msg', msg), 41 | # ('total',self.page.paginator.count), 42 | ('data', res), 43 | ])) 44 | -------------------------------------------------------------------------------- /backend/dvadmin/utils/permission.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: 猿小天 5 | @contact: QQ:1638245306 6 | @Created on: 2021/6/6 006 10:30 7 | @Remark: 自定义权限 8 | """ 9 | import re 10 | 11 | from rest_framework.permissions import BasePermission 12 | 13 | 14 | def ValidationApi(reqApi, validApi): 15 | """ 16 | 验证当前用户是否有接口权限 17 | :param reqApi: 当前请求的接口 18 | :param validApi: 用于验证的接口 19 | :return: True或者False 20 | """ 21 | if validApi is not None: 22 | valid_api = validApi.replace('{id}', '.*?') 23 | matchObj = re.match(valid_api, reqApi, re.M | re.I) 24 | if matchObj: 25 | return True 26 | else: 27 | return False 28 | else: 29 | return False 30 | 31 | 32 | class CustomPermission(BasePermission): 33 | """自定义权限""" 34 | 35 | def has_permission(self, request, view): 36 | 37 | # 对ViewSet下的def方法进行权限判断 38 | # 当权限为空时,则可以访问 39 | is_head = getattr(view, 'head', None) 40 | if is_head: 41 | head_kwargs = getattr(view.head, 'kwargs', None) 42 | if head_kwargs: 43 | _permission_classes = getattr(head_kwargs, 'permission_classes', None) 44 | if _permission_classes is None: 45 | return True 46 | 47 | # 判断是否是超级管理员 48 | if request.user.is_superuser: 49 | return True 50 | else: 51 | api = request.path # 当前请求接口 52 | method = request.method # 当前请求方法 53 | methodList = ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'] 54 | method = methodList.index(method) 55 | if not hasattr(request.user, "role"): 56 | return False 57 | userApiList = request.user.role.values('permission__api', 'permission__method') # 获取当前用户的角色拥有的所有接口 58 | for item in userApiList: 59 | valid = ValidationApi(api, item.get('permission__api')) 60 | if valid and (method == item.get('permission__method')): 61 | return True 62 | return True 63 | -------------------------------------------------------------------------------- /backend/dvadmin/utils/string_util.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: 猿小天 5 | @contact: QQ:1638245306 6 | @Created on: 2021/8/21 021 9:48 7 | @Remark: 8 | """ 9 | import hashlib 10 | import random 11 | 12 | CHAR_SET = ("2", "3", "4", "5", 13 | "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", 14 | "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", 15 | "W", "X", "Y", "Z") 16 | 17 | 18 | def random_str(number=16): 19 | """ 20 | 返回特定长度的随机字符串(非进制) 21 | :return: 22 | """ 23 | result = "" 24 | for i in range(0, number): 25 | inx = random.randint(0, len(CHAR_SET) - 1) 26 | result += CHAR_SET[inx] 27 | return result 28 | 29 | 30 | def has_md5(str, salt='123456'): 31 | """ 32 | md5 加密 33 | :param str: 34 | :param salt: 35 | :return: 36 | """ 37 | # satl是盐值,默认是123456 38 | str = str + salt 39 | md = hashlib.md5() # 构造一个md5对象 40 | md.update(str.encode()) 41 | res = md.hexdigest() 42 | return res 43 | -------------------------------------------------------------------------------- /backend/dvadmin/utils/swagger.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | @author: 猿小天 5 | @contact: QQ:1638245306 6 | @Created on: 2021/8/12 012 10:25 7 | @Remark: swagger配置 8 | """ 9 | from drf_yasg.generators import OpenAPISchemaGenerator 10 | from drf_yasg.inspectors import SwaggerAutoSchema 11 | 12 | from application.settings import SWAGGER_SETTINGS 13 | 14 | 15 | def get_summary(string): 16 | if string is not None: 17 | result = string.strip().replace(" ","").split("\n") 18 | return result[0] 19 | 20 | class CustomSwaggerAutoSchema(SwaggerAutoSchema): 21 | def get_tags(self, operation_keys=None): 22 | tags = super().get_tags(operation_keys) 23 | if "api" in tags and operation_keys: 24 | # `operation_keys` 内容像这样 ['v1', 'prize_join_log', 'create'] 25 | tags[0] = operation_keys[SWAGGER_SETTINGS.get('AUTO_SCHEMA_TYPE', 2)] 26 | return tags 27 | 28 | def get_summary_and_description(self): 29 | summary_and_description = super().get_summary_and_description() 30 | summary = get_summary(self.__dict__.get('view').__doc__) 31 | description = summary_and_description[1] 32 | return summary,description 33 | 34 | 35 | class CustomOpenAPISchemaGenerator(OpenAPISchemaGenerator): 36 | def get_schema(self, request=None, public=False): 37 | """Generate a :class:`.Swagger` object with custom tags""" 38 | 39 | swagger = super().get_schema(request, public) 40 | swagger.tags = [ 41 | { 42 | "name": "token", 43 | "description": "认证相关" 44 | }, 45 | ] 46 | return swagger 47 | -------------------------------------------------------------------------------- /backend/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings') 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == '__main__': 22 | main() 23 | -------------------------------------------------------------------------------- /backend/plugins/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins_market_backend": { 3 | "name": "插件市场后台", 4 | "enable": true, 5 | "git": "https://gitee.com/dvadmin/plugins_market_backend.git", 6 | "priority": 1, 7 | "tags": "v0.0.1", 8 | "type": "backend" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /backend/requirements.txt: -------------------------------------------------------------------------------- 1 | asgiref==3.3.4 2 | Django==3.2.3 3 | django-comment-migrate==0.1.2 4 | django-cors-headers==3.7.0 5 | django-filter==2.4.0 6 | djangorestframework==3.12.4 7 | djangorestframework-simplejwt==4.7.1 8 | mysqlclient==2.0.3 9 | PyJWT==2.1.0 10 | pytz==2021.1 11 | six==1.16.0 12 | sqlparse==0.4.1 13 | typing-extensions==3.10.0.0 14 | user-agents==2.2.0 15 | drf-yasg==1.20.0 16 | daphne==3.0.2 17 | django-simple-captcha==0.5.14 18 | gitpython==3.1.20 19 | pypinyin==0.42.0 20 | whitenoise==5.3.0 21 | -------------------------------------------------------------------------------- /backend/static/drf-yasg/insQ.min.js: -------------------------------------------------------------------------------- 1 | // insertion-query v1.0.3 (2016-01-20) 2 | // license:MIT 3 | // Zbyszek Tenerowicz (http://naugtur.pl/) 4 | var insertionQ=function(){"use strict";function a(a,b){var d,e="insQ_"+g++,f=function(a){(a.animationName===e||a[i]===e)&&(c(a.target)||b(a.target))};d=document.createElement("style"),d.innerHTML="@"+j+"keyframes "+e+" { from { outline: 1px solid transparent } to { outline: 0px solid transparent } }\n"+a+" { animation-duration: 0.001s; animation-name: "+e+"; "+j+"animation-duration: 0.001s; "+j+"animation-name: "+e+"; } ",document.head.appendChild(d);var h=setTimeout(function(){document.addEventListener("animationstart",f,!1),document.addEventListener("MSAnimationStart",f,!1),document.addEventListener("webkitAnimationStart",f,!1)},n.timeout);return{destroy:function(){clearTimeout(h),d&&(document.head.removeChild(d),d=null),document.removeEventListener("animationstart",f),document.removeEventListener("MSAnimationStart",f),document.removeEventListener("webkitAnimationStart",f)}}}function b(a){a.QinsQ=!0}function c(a){return n.strictlyNew&&a.QinsQ===!0}function d(a){return c(a.parentNode)?a:d(a.parentNode)}function e(a){for(b(a),a=a.firstChild;a;a=a.nextSibling)void 0!==a&&1===a.nodeType&&e(a)}function f(f,g){var h=[],i=function(){var a;return function(){clearTimeout(a),a=setTimeout(function(){h.forEach(e),g(h),h=[]},10)}}();return a(f,function(a){if(!c(a)){b(a);var e=d(a);h.indexOf(e)<0&&h.push(e),i()}})}var g=100,h=!1,i="animationName",j="",k="Webkit Moz O ms Khtml".split(" "),l="",m=document.createElement("div"),n={strictlyNew:!0,timeout:20};if(m.style.animationName&&(h=!0),h===!1)for(var o=0;o div { 27 | display: inline-block; 28 | } 29 | 30 | #django-session-auth .btn.authorize { 31 | padding: 10px 23px; 32 | } 33 | 34 | #django-session-auth .btn.authorize a { 35 | color: #49cc90; 36 | text-decoration: none; 37 | } 38 | 39 | #django-session-auth .hello { 40 | margin-right: 5px; 41 | } 42 | 43 | #django-session-auth .hello .django-session { 44 | font-weight: bold; 45 | } 46 | 47 | .label { 48 | display: inline; 49 | padding: .2em .6em .3em; 50 | font-weight: 700; 51 | line-height: 1; 52 | color: #fff; 53 | text-align: center; 54 | white-space: nowrap; 55 | vertical-align: baseline; 56 | border-radius: .25em; 57 | } 58 | 59 | .label-primary { 60 | background-color: #337ab7; 61 | } 62 | 63 | .divider { 64 | margin-right: 8px; 65 | background: #16222c44; 66 | width: 2px; 67 | } 68 | 69 | svg.swagger-defs { 70 | position: absolute; 71 | width: 0; 72 | height: 0; 73 | } 74 | -------------------------------------------------------------------------------- /backend/static/drf-yasg/swagger-ui-dist/absolute-path.js: -------------------------------------------------------------------------------- 1 | /* 2 | * getAbsoluteFSPath 3 | * @return {string} When run in NodeJS env, returns the absolute path to the current directory 4 | * When run outside of NodeJS, will return an error message 5 | */ 6 | const getAbsoluteFSPath = function () { 7 | // detect whether we are running in a browser or nodejs 8 | if (typeof module !== "undefined" && module.exports) { 9 | return require("path").resolve(__dirname) 10 | } 11 | throw new Error('getAbsoluteFSPath can only be called within a Nodejs environment'); 12 | } 13 | 14 | module.exports = getAbsoluteFSPath 15 | -------------------------------------------------------------------------------- /backend/static/drf-yasg/swagger-ui-dist/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/backend/static/drf-yasg/swagger-ui-dist/favicon-32x32.png -------------------------------------------------------------------------------- /backend/static/drf-yasg/swagger-ui-dist/index.js: -------------------------------------------------------------------------------- 1 | try { 2 | module.exports.SwaggerUIBundle = require("./swagger-ui-bundle.js") 3 | module.exports.SwaggerUIStandalonePreset = require("./swagger-ui-standalone-preset.js") 4 | } catch(e) { 5 | // swallow the error if there's a problem loading the assets. 6 | // allows this module to support providing the assets for browserish contexts, 7 | // without exploding in a Node context. 8 | // 9 | // see https://github.com/swagger-api/swagger-ui/issues/3291#issuecomment-311195388 10 | // for more information. 11 | } 12 | 13 | // `absolutePath` and `getAbsoluteFSPath` are both here because at one point, 14 | // we documented having one and actually implemented the other. 15 | // They were both retained so we don't break anyone's code. 16 | module.exports.absolutePath = require("./absolute-path.js") 17 | module.exports.getAbsoluteFSPath = require("./absolute-path.js") 18 | -------------------------------------------------------------------------------- /backend/static/rest_framework/css/default.css: -------------------------------------------------------------------------------- 1 | /* The navbar is fixed at >= 980px wide, so add padding to the body to prevent 2 | content running up underneath it. */ 3 | 4 | h1 { 5 | font-weight: 300; 6 | } 7 | 8 | h2, h3 { 9 | font-weight: 300; 10 | } 11 | 12 | .resource-description, .response-info { 13 | margin-bottom: 2em; 14 | } 15 | 16 | .version:before { 17 | content: "v"; 18 | opacity: 0.6; 19 | padding-right: 0.25em; 20 | } 21 | 22 | .version { 23 | font-size: 70%; 24 | } 25 | 26 | .format-option { 27 | font-family: Menlo, Consolas, "Andale Mono", "Lucida Console", monospace; 28 | } 29 | 30 | .button-form { 31 | float: right; 32 | margin-right: 1em; 33 | } 34 | 35 | td.nested { 36 | padding: 0 !important; 37 | } 38 | 39 | td.nested > table { 40 | margin: 0; 41 | } 42 | 43 | form select, form input:not([type=checkbox]), form textarea { 44 | width: 90%; 45 | } 46 | 47 | form select[multiple] { 48 | height: 150px; 49 | } 50 | 51 | /* To allow tooltips to work on disabled elements */ 52 | .disabled-tooltip-shield { 53 | position: absolute; 54 | top: 0; 55 | right: 0; 56 | bottom: 0; 57 | left: 0; 58 | } 59 | 60 | .errorlist { 61 | margin-top: 0.5em; 62 | } 63 | 64 | pre { 65 | overflow: auto; 66 | word-wrap: normal; 67 | white-space: pre; 68 | font-size: 12px; 69 | } 70 | 71 | .page-header { 72 | border-bottom: none; 73 | padding-bottom: 0px; 74 | } 75 | 76 | #filtersModal form input[type=submit] { 77 | width: auto; 78 | } 79 | 80 | #filtersModal .modal-body h2 { 81 | margin-top: 0 82 | } 83 | -------------------------------------------------------------------------------- /backend/static/rest_framework/css/prettify.css: -------------------------------------------------------------------------------- 1 | .com { color: #93a1a1; } 2 | .lit { color: #195f91; } 3 | .pun, .opn, .clo { color: #93a1a1; } 4 | .fun { color: #dc322f; } 5 | .str, .atv { color: #D14; } 6 | .kwd, .prettyprint .tag { color: #1e347b; } 7 | .typ, .atn, .dec, .var { color: teal; } 8 | .pln { color: #48484c; } 9 | 10 | .prettyprint { 11 | padding: 8px; 12 | background-color: #f7f7f9; 13 | border: 1px solid #e1e1e8; 14 | } 15 | .prettyprint.linenums { 16 | -webkit-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; 17 | -moz-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; 18 | box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; 19 | } 20 | 21 | /* Specify class=linenums on a pre to get line numbering */ 22 | ol.linenums { 23 | margin: 0 0 0 33px; /* IE indents via margin-left */ 24 | } 25 | ol.linenums li { 26 | padding-left: 12px; 27 | color: #bebec5; 28 | line-height: 20px; 29 | text-shadow: 0 1px 0 #fff; 30 | } -------------------------------------------------------------------------------- /backend/static/rest_framework/docs/css/jquery.json-view.min.css: -------------------------------------------------------------------------------- 1 | .json-view{position:relative} 2 | .json-view .collapser{width:20px;height:18px;display:block;position:absolute;left:-1.7em;top:-.2em;z-index:5;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAD1JREFUeNpiYGBgOADE%2F3Hgw0DM4IRHgSsDFOzFInmMAQnY49ONzZRjDFiADT7dMLALiE8y4AGW6LoBAgwAuIkf%2F%2FB7O9sAAAAASUVORK5CYII%3D);background-repeat:no-repeat;background-position:center center;opacity:.5;cursor:pointer} 3 | .json-view .collapsed{-ms-transform:rotate(-90deg);-moz-transform:rotate(-90deg);-khtml-transform:rotate(-90deg);-webkit-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg)} 4 | .json-view .bl{display:block;padding-left:20px;margin-left:-20px;position:relative} 5 | .json-view{font-family:monospace} 6 | .json-view ul{list-style-type:none;padding-left:2em;border-left:1px dotted;margin:.3em} 7 | .json-view ul li{position:relative} 8 | .json-view .comments,.json-view .dots{display:none;-moz-user-select:none;-ms-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-o-user-select:none;user-select:none} 9 | .json-view .comments{padding-left:.8em;font-style:italic;color:#888} 10 | .json-view .bool,.json-view .null,.json-view .num,.json-view .undef{font-weight:700;color:#1A01CC} 11 | .json-view .str{color:#800} -------------------------------------------------------------------------------- /backend/static/rest_framework/docs/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/backend/static/rest_framework/docs/img/favicon.ico -------------------------------------------------------------------------------- /backend/static/rest_framework/docs/img/grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/backend/static/rest_framework/docs/img/grid.png -------------------------------------------------------------------------------- /backend/static/rest_framework/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/backend/static/rest_framework/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /backend/static/rest_framework/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/backend/static/rest_framework/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /backend/static/rest_framework/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/backend/static/rest_framework/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /backend/static/rest_framework/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/backend/static/rest_framework/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /backend/static/rest_framework/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/backend/static/rest_framework/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /backend/static/rest_framework/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/backend/static/rest_framework/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /backend/static/rest_framework/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/backend/static/rest_framework/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /backend/static/rest_framework/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/backend/static/rest_framework/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /backend/static/rest_framework/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/backend/static/rest_framework/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /backend/static/rest_framework/img/grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/backend/static/rest_framework/img/grid.png -------------------------------------------------------------------------------- /backend/static/rest_framework/js/csrf.js: -------------------------------------------------------------------------------- 1 | function getCookie(name) { 2 | var cookieValue = null; 3 | 4 | if (document.cookie && document.cookie != '') { 5 | var cookies = document.cookie.split(';'); 6 | 7 | for (var i = 0; i < cookies.length; i++) { 8 | var cookie = jQuery.trim(cookies[i]); 9 | 10 | // Does this cookie string begin with the name we want? 11 | if (cookie.substring(0, name.length + 1) == (name + '=')) { 12 | cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); 13 | break; 14 | } 15 | } 16 | } 17 | 18 | return cookieValue; 19 | } 20 | 21 | function csrfSafeMethod(method) { 22 | // these HTTP methods do not require CSRF protection 23 | return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); 24 | } 25 | 26 | function sameOrigin(url) { 27 | // test that a given url is a same-origin URL 28 | // url could be relative or scheme relative or absolute 29 | var host = document.location.host; // host + port 30 | var protocol = document.location.protocol; 31 | var sr_origin = '//' + host; 32 | var origin = protocol + sr_origin; 33 | 34 | // Allow absolute or scheme relative URLs to same origin 35 | return (url == origin || url.slice(0, origin.length + 1) == origin + '/') || 36 | (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') || 37 | // or any other URL that isn't scheme relative or absolute i.e relative. 38 | !(/^(\/\/|http:|https:).*/.test(url)); 39 | } 40 | 41 | var csrftoken = window.drf.csrfToken; 42 | 43 | $.ajaxSetup({ 44 | beforeSend: function(xhr, settings) { 45 | if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) { 46 | // Send the token to same-origin, relative URLs only. 47 | // Send the token only if the method warrants CSRF protection 48 | // Using the CSRFToken value acquired earlier 49 | xhr.setRequestHeader(window.drf.csrfHeaderName, csrftoken); 50 | } 51 | } 52 | }); 53 | -------------------------------------------------------------------------------- /backend/static/rest_framework/js/default.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | // JSON highlighting. 3 | prettyPrint(); 4 | 5 | // Bootstrap tooltips. 6 | $('.js-tooltip').tooltip({ 7 | delay: 1000, 8 | container: 'body' 9 | }); 10 | 11 | // Deal with rounded tab styling after tab clicks. 12 | $('a[data-toggle="tab"]:first').on('shown', function(e) { 13 | $(e.target).parents('.tabbable').addClass('first-tab-active'); 14 | }); 15 | 16 | $('a[data-toggle="tab"]:not(:first)').on('shown', function(e) { 17 | $(e.target).parents('.tabbable').removeClass('first-tab-active'); 18 | }); 19 | 20 | $('a[data-toggle="tab"]').click(function() { 21 | document.cookie = "tabstyle=" + this.name + "; path=/"; 22 | }); 23 | 24 | // Store tab preference in cookies & display appropriate tab on load. 25 | var selectedTab = null; 26 | var selectedTabName = getCookie('tabstyle'); 27 | 28 | if (selectedTabName) { 29 | selectedTabName = selectedTabName.replace(/[^a-z-]/g, ''); 30 | } 31 | 32 | if (selectedTabName) { 33 | selectedTab = $('.form-switcher a[name=' + selectedTabName + ']'); 34 | } 35 | 36 | if (selectedTab && selectedTab.length > 0) { 37 | // Display whichever tab is selected. 38 | selectedTab.tab('show'); 39 | } else { 40 | // If no tab selected, display rightmost tab. 41 | $('.form-switcher a:first').tab('show'); 42 | } 43 | 44 | $(window).on('load', function() { 45 | $('#errorModal').modal('show'); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /docker_env/README.md: -------------------------------------------------------------------------------- 1 | # docker 镜像打包 2 | 3 | ### 打包web基础Build包 4 | 5 | ~~~sh 6 | # 编译打包到本地 7 | docker build -f ./docker_env/web/DockerfileBuild -t registry.cn-zhangjiakou.aliyuncs.com/dvadmin-pro/node12-base-web:latest . 8 | # 上传到阿里云仓库 9 | docker push registry.cn-zhangjiakou.aliyuncs.com/dvadmin-pro/node12-base-web:latest 10 | 11 | ~~~ 12 | 13 | ### 打包Backend基础Build包 14 | 15 | ~~~sh 16 | # 编译打包到本地 17 | docker build -f ./docker_env/django/DockerfileBuild -t registry.cn-zhangjiakou.aliyuncs.com/dvadmin-pro/python38-base-backend:latest . 18 | # 上传到阿里云仓库 19 | docker push registry.cn-zhangjiakou.aliyuncs.com/dvadmin-pro/python38-base-backend:latest 20 | ~~~ 21 | 22 | ### 运行前端 23 | 24 | ~~~ 25 | docker build -f ./docker_env/web/Dockerfile -t dvadmin-pro-web . 26 | ~~~ 27 | 28 | ### 运行后端 29 | 30 | ~~~ 31 | docker build -f ./docker_env/django/Dockerfile -t dvadmin-pro-django . 32 | ~~~ 33 | 34 | ### 运行celery 35 | 36 | ~~~ 37 | docker build -f ./docker_env/celery/Dockerfile -t dvadmin-pro-celery . 38 | ~~~ 39 | 40 | ## docker-compose 运行 41 | 42 | ~~~ 43 | # 先安装docker-compose (自行百度安装),执行此命令等待安装,如有使用celery插件请打开docker-compose.yml中celery 部分注释 44 | docker-compose up -d 45 | # 初始化后端数据(第一次执行即可) 46 | docker exec -ti dvadmin-django bash 47 | python manage.py makemigrations 48 | python manage.py migrate 49 | python manage.py init -y 50 | exit 51 | 52 | 前端地址:http://127.0.0.1:8080 53 | 后端地址:http://127.0.0.1:8000 54 | # 在服务器上请把127.0.0.1 换成自己公网ip 55 | 账号:superadmin 密码:admin123456 56 | 57 | # docker-compose 停止 58 | docker-compose down 59 | # docker-compose 重启 60 | docker-compose restart 61 | # docker-compose 启动时重新进行 build 62 | docker-compose up -d --build 63 | 64 | ~~~ 65 | 66 | -------------------------------------------------------------------------------- /docker_env/base-build.sh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/docker_env/base-build.sh -------------------------------------------------------------------------------- /docker_env/celery/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM registry.cn-zhangjiakou.aliyuncs.com/dvadmin-pro/python38-base-backend:latest 2 | WORKDIR /backend 3 | COPY ./backend/ . 4 | COPY ./backend/conf/env.example.py /dvadmin-backend/conf/env.py 5 | RUN python3 -m pip install -i https://mirrors.aliyun.com/pypi/simple/ -r /requirements.txt 6 | CMD ["celery", "-A", "application", "worker", "-B", "--loglevel=info"] 7 | 8 | -------------------------------------------------------------------------------- /docker_env/django/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM registry.cn-zhangjiakou.aliyuncs.com/dvadmin-pro/python38-base-backend:latest 2 | WORKDIR /backend 3 | COPY ./backend/ . 4 | COPY ./backend/conf/env.example.py /dvadmin-backend/conf/env.py 5 | RUN python3 -m pip install -i https://mirrors.aliyun.com/pypi/simple/ -r /requirements.txt 6 | CMD ["daphne","-b","0.0.0.0","-p","8000","application.asgi:application"] 7 | -------------------------------------------------------------------------------- /docker_env/django/DockerfileBuild: -------------------------------------------------------------------------------- 1 | FROM python:3.8-alpine 2 | RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories 3 | RUN apk update && apk add bash bash-doc bash-completion git freetds-dev jpeg-dev linux-headers mysql-client mariadb-dev build-base libffi-dev openssl-dev zlib-dev bzip2-dev pcre-dev ncurses-dev readline-dev tk-dev postgresql-dev 4 | WORKDIR /backend 5 | COPY ./backend/requirements.txt / 6 | COPY ./docker_env/requirements-all.txt / 7 | RUN python3 -m pip install -i https://mirrors.aliyun.com/pypi/simple/ -r /requirements.txt 8 | RUN python3 -m pip install -i https://mirrors.aliyun.com/pypi/simple/ -r /requirements-all.txt -------------------------------------------------------------------------------- /docker_env/mysql/conf.d/my.cnf: -------------------------------------------------------------------------------- 1 | [mysql] 2 | #设置mysql客户端默认字符集 3 | default-character-set=utf8 4 | socket=/var/run/mysql/mysql.sock 5 | 6 | 7 | [mysqld] 8 | # skip-grant-tables 9 | #mysql5.7以后的不兼容问题处理 10 | sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES 11 | datadir=/var/lib/mysql 12 | socket=/var/run/mysql/mysql.sock 13 | 14 | # Disabling symbolic-links is recommended to prevent assorted security risks 15 | symbolic-links=0 16 | # Settings user and group are ignored when systemd is used. 17 | # If you need to run mysqld under a different user or group, 18 | # customize your systemd unit file for mariadb according to the 19 | # instructions in http://fedoraproject.org/wiki/Systemdd 20 | #允许最大连接数 21 | max_connections=200 22 | #服务端使用的字符集默认为8比特编码的latin1字符集 23 | character-set-server=utf8 24 | #创建新表时将使用的默认存储引擎 25 | default-storage-engine=INNODB 26 | lower_case_table_names=1 27 | max_allowed_packet=16M 28 | #设置时区 29 | default-time_zone='+8:00' 30 | 31 | [mysqld_safe] 32 | log-error=/var/log/mariadb/mariadb.log 33 | pid-file=/var/run/mariadb/mariadb.pid 34 | -------------------------------------------------------------------------------- /docker_env/mysql/launch.sh: -------------------------------------------------------------------------------- 1 | cur_path=`pwd` 2 | docker rm mysql 3 | # docker pull mysql:5.7 4 | # docker pull mysql:5.5 5 | docker run -p 3306:3306 --privileged=true --name mysql -v $cur_path/logs:/logs -v $cur_path/data:/var/lib/mysql -v $cur_path/conf.d/my.cnf:/etc/mysql/mysql.conf.d/mysqld.cnf -v $cur_path/run/:/var/run/mysql -e MYSQL_ROOT_PASSWORD=q1w2e3r4 -d mysql:5.7 6 | -------------------------------------------------------------------------------- /docker_env/nginx/my.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 8080; 3 | server_name localhost; 4 | client_max_body_size 100M; 5 | location / { 6 | proxy_set_header Host $http_host; 7 | proxy_set_header X-Real-IP $remote_addr; 8 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 9 | proxy_set_header X-Forwarded-Proto https; 10 | root /usr/share/nginx/html; 11 | index index.html index.php index.htm; 12 | } 13 | 14 | location /api/ { 15 | proxy_set_header Host $http_host; 16 | proxy_set_header X-Real-IP $remote_addr; 17 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 18 | proxy_set_header X-Forwarded-Proto $scheme; 19 | rewrite ^/api/(.*)$ /$1 break; #重写 20 | proxy_pass http://177.7.0.12:8000/; # 设置代理服务器的协议和地址 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /docker_env/requirements-all.txt: -------------------------------------------------------------------------------- 1 | asgiref==3.3.4 2 | Django==3.2.3 3 | django-comment-migrate==0.1.2 4 | django-cors-headers==3.7.0 5 | django-filter==2.4.0 6 | djangorestframework==3.12.4 7 | djangorestframework-simplejwt==4.7.1 8 | mysqlclient==2.0.3 9 | PyJWT==2.1.0 10 | pytz==2021.1 11 | six==1.16.0 12 | sqlparse==0.4.1 13 | typing-extensions==3.10.0.0 14 | user-agents==2.2.0 15 | drf-yasg==1.20.0 16 | daphne==3.0.2 17 | django-simple-captcha==0.5.14 18 | gitpython==3.1.20 19 | pypinyin==0.42.0 20 | python-dateutil==2.8.2 21 | demjson==2.2.4 22 | django-fernet-fields==0.6 23 | django-celery-beat==2.2.1 24 | tenant-schemas-celery==1.0.1 25 | django-redis==5.0.0 26 | django-celery-results==2.2.0 27 | django-apscheduler==0.6.0 28 | django-tenants==3.3.2 29 | psycopg2-binary==2.9.1 30 | whitenoise==5.3.0 31 | -------------------------------------------------------------------------------- /docker_env/web/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM registry.cn-zhangjiakou.aliyuncs.com/dvadmin-pro/node12-base-web:latest 2 | WORKDIR /web/ 3 | COPY web/. . 4 | RUN npm install --registry=https://registry.npm.taobao.org 5 | RUN npm run build 6 | 7 | FROM nginx:alpine 8 | COPY ./docker_env/nginx/my.conf /etc/nginx/conf.d/my.conf 9 | COPY --from=0 /web/dist /usr/share/nginx/html 10 | -------------------------------------------------------------------------------- /docker_env/web/DockerfileBuild: -------------------------------------------------------------------------------- 1 | FROM node:14-alpine 2 | COPY ./web/package.json / 3 | RUN npm install --registry=https://registry.npm.taobao.org 4 | -------------------------------------------------------------------------------- /web/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | -------------------------------------------------------------------------------- /web/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js,jsx,ts,tsx,vue}] 2 | indent_style = space 3 | indent_size = 2 4 | trim_trailing_whitespace = true 5 | insert_final_newline = true 6 | -------------------------------------------------------------------------------- /web/.env: -------------------------------------------------------------------------------- 1 | # 所有环境默认 2 | 3 | # 页面 title 前缀 4 | VUE_APP_TITLE=D2Admin 5 | 6 | # 网络请求公用地址 7 | VUE_APP_API=/api/ 8 | 9 | # 仓库地址 10 | VUE_APP_REPO=https://github.com/d2-projects/d2-admin-start-kit 11 | 12 | # 国际化配置 13 | VUE_APP_I18N_LOCALE=zh-chs 14 | VUE_APP_I18N_FALLBACK_LOCALE=en 15 | 16 | # element 颜色 17 | VUE_APP_ELEMENT_COLOR=#409EFF 18 | -------------------------------------------------------------------------------- /web/.env.development: -------------------------------------------------------------------------------- 1 | # 开发环境 2 | 3 | # 页面 title 前缀 4 | VUE_APP_TITLE=dvAdmin 5 | # 启用权限管理 6 | VUE_APP_PM_ENABLED = true 7 | # 后端接口地址及端口(域名) 8 | VUE_APP_API = "http://127.0.0.1:8000" 9 | 10 | -------------------------------------------------------------------------------- /web/.env.preview: -------------------------------------------------------------------------------- 1 | # 构建预览页面 2 | 3 | # 指定构建模式 4 | NODE_ENV=production 5 | 6 | # 标记当前构建方式 7 | VUE_APP_BUILD_MODE=PREVIEW 8 | 9 | # 显示源码按钮 10 | VUE_APP_SCOURCE_LINK=TRUE 11 | 12 | # 部署路径 13 | VUE_APP_PUBLIC_PATH=/ 14 | -------------------------------------------------------------------------------- /web/.env.test: -------------------------------------------------------------------------------- 1 | # 测试环境 2 | 3 | # 页面 title 前缀 4 | VUE_APP_TITLE=dvAdmin 5 | # 启用权限管理 6 | VUE_APP_PM_ENABLED = true 7 | # 后端接口地址及端口(域名) 8 | VUE_APP_API = "http://117.50.22.212:8000/" 9 | 10 | -------------------------------------------------------------------------------- /web/.eslintignore: -------------------------------------------------------------------------------- 1 | # 忽略目录 2 | build/ 3 | tests/ 4 | node_modules/ 5 | 6 | # D2CRUD 演示 7 | src/views/demo/d2-crud/ 8 | 9 | # node 覆盖率文件 10 | coverage/ 11 | 12 | # 忽略文件 13 | **/*-min.js 14 | **/*.min.js 15 | -------------------------------------------------------------------------------- /web/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | 'extends': [ 7 | 'plugin:vue/essential', 8 | '@vue/standard' 9 | ], 10 | rules: { 11 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', 12 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' 13 | }, 14 | parserOptions: { 15 | parser: 'babel-eslint' 16 | }, 17 | overrides: [ 18 | { 19 | files: [ 20 | '**/__tests__/*.{j,t}s?(x)', 21 | '**/tests/unit/**/*.spec.{j,t}s?(x)' 22 | ], 23 | env: { 24 | jest: true 25 | } 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /web/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw? 22 | -------------------------------------------------------------------------------- /web/.postcssrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /web/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 李杨 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /web/README.md: -------------------------------------------------------------------------------- 1 | # d2-crud-plus与d2-admin集成启动项目 2 | 3 | ## 修改之处 4 | 1. `main.js` import `'./busienss'` 5 | 2. `business/index.js` 进行`d2-crud-plus`的初始化工作 6 | 3. 请求返回结果去掉`.data`,将`{code,msg,data}`整体传递到下层 7 | 4. `views/demo` 为示例页面 8 | 9 | 10 | ## 带权限版本 11 | 请checkout permission分支 -------------------------------------------------------------------------------- /web/README.zh.md: -------------------------------------------------------------------------------- 1 | [D2Admin](https://github.com/d2-projects/d2-admin) 是一个完全 **开源免费** 的企业中后台产品前端集成方案,使用最新的前端技术栈,小于 60kb 的本地首屏 js 加载,已经做好大部分项目前期准备工作,并且带有大量示例代码,助力管理系统敏捷开发。 2 | 3 | **中文** | [English](https://github.com/d2-projects/d2-admin-start-kit) 4 | 5 | ## 预览 6 | 7 | ![Deploy preview](https://github.com/d2-projects/d2-admin-start-kit/workflows/Deploy%20preview/badge.svg) 8 | [![Netlify Status](https://api.netlify.com/api/v1/badges/08ff8c93-f0a8-497a-a081-440b31fb3aa4/deploy-status)](https://app.netlify.com/sites/d2-admin-start-kit/deploys) 9 | 10 | 下列访问地址均由最新的 master 分支代码同时构建部署,访问效果完全一致,请根据自身网络情况选择合适的访问链接。 11 | 12 | | 位置 | 链接 | 部署位置 | 13 | | --- | --- | --- | 14 | | d2.pub | [preview](https://d2.pub/d2-admin-start-kit/preview) | 中国服务器 | 15 | | cdn.d2.pub | [preview](https://cdn.d2.pub/d2-admin-start-kit/preview) | 七牛云 CDN | 16 | | github | [preview](https://d2-projects.github.io/d2-admin-start-kit) | GitHub pages | 17 | | netlify | [preview](https://d2-admin-start-kit.netlify.com) | Netlify CDN | 18 | 19 | ## 其它同步仓库 20 | 21 | | 位置 | 链接 | 22 | | --- | --- | 23 | | 码云 | [https://gitee.com/d2-projects/d2-admin-start-kit](https://gitee.com/d2-projects/d2-admin-start-kit) | 24 | | coding | [https://d2-projects.coding.net/p/d2-projects/d/d2-admin-start-kit/git](https://d2-projects.coding.net/p/d2-projects/d/d2-admin-start-kit/git) | 25 | 26 | > 如果您在 github 仓库下载很慢,可以尝试使用我们的码云仓库克隆代码 -------------------------------------------------------------------------------- /web/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ], 5 | // 允许两种编码引入方式共存,也就是 common 规范与 es6 规范的共存处理 6 | sourceType: 'unambiguous' 7 | } 8 | -------------------------------------------------------------------------------- /web/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: '@vue/cli-plugin-unit-jest' 3 | } 4 | -------------------------------------------------------------------------------- /web/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "allowSyntheticDefaultImports": false, 5 | "baseUrl": "./", 6 | "paths": { 7 | "@/*": ["src/*"] 8 | } 9 | }, 10 | "exclude": ["node_modules", "dist"] 11 | } 12 | -------------------------------------------------------------------------------- /web/public/icon-1.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/icon-1.ico -------------------------------------------------------------------------------- /web/public/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/icon.ico -------------------------------------------------------------------------------- /web/public/image/baidu-pan-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/baidu-pan-logo.png -------------------------------------------------------------------------------- /web/public/image/bbs-go.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/bbs-go.png -------------------------------------------------------------------------------- /web/public/image/d2-pub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/d2-pub.png -------------------------------------------------------------------------------- /web/public/image/django-comment-migrate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/django-comment-migrate.png -------------------------------------------------------------------------------- /web/public/image/django-vue-admin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/django-vue-admin.png -------------------------------------------------------------------------------- /web/public/image/django.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/django.png -------------------------------------------------------------------------------- /web/public/image/gin-vue-admin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/gin-vue-admin.png -------------------------------------------------------------------------------- /web/public/image/jetbrains.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/jetbrains.jpeg -------------------------------------------------------------------------------- /web/public/image/loading/loading-spin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /web/public/image/ruoyi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/ruoyi.png -------------------------------------------------------------------------------- /web/public/image/simple-ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/simple-ui.png -------------------------------------------------------------------------------- /web/public/image/theme/chester/logo/all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/theme/chester/logo/all.png -------------------------------------------------------------------------------- /web/public/image/theme/chester/logo/icon-only.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/theme/chester/logo/icon-only.png -------------------------------------------------------------------------------- /web/public/image/theme/chester/preview@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/theme/chester/preview@2x.png -------------------------------------------------------------------------------- /web/public/image/theme/d2/logo/all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/theme/d2/logo/all.png -------------------------------------------------------------------------------- /web/public/image/theme/d2/logo/icon-only.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/theme/d2/logo/icon-only.png -------------------------------------------------------------------------------- /web/public/image/theme/d2/preview@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/theme/d2/preview@2x.png -------------------------------------------------------------------------------- /web/public/image/theme/element/logo/all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/theme/element/logo/all.png -------------------------------------------------------------------------------- /web/public/image/theme/element/logo/icon-only.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/theme/element/logo/icon-only.png -------------------------------------------------------------------------------- /web/public/image/theme/element/preview@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/theme/element/preview@2x.png -------------------------------------------------------------------------------- /web/public/image/theme/line/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/theme/line/bg.jpg -------------------------------------------------------------------------------- /web/public/image/theme/line/logo/all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/theme/line/logo/all.png -------------------------------------------------------------------------------- /web/public/image/theme/line/logo/icon-only.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/theme/line/logo/icon-only.png -------------------------------------------------------------------------------- /web/public/image/theme/line/preview@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/theme/line/preview@2x.png -------------------------------------------------------------------------------- /web/public/image/theme/star/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/theme/star/bg.jpg -------------------------------------------------------------------------------- /web/public/image/theme/star/logo/all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/theme/star/logo/all.png -------------------------------------------------------------------------------- /web/public/image/theme/star/logo/icon-only.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/theme/star/logo/icon-only.png -------------------------------------------------------------------------------- /web/public/image/theme/star/preview@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/theme/star/preview@2x.png -------------------------------------------------------------------------------- /web/public/image/theme/tomorrow-night-blue/logo/all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/theme/tomorrow-night-blue/logo/all.png -------------------------------------------------------------------------------- /web/public/image/theme/tomorrow-night-blue/logo/icon-only.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/theme/tomorrow-night-blue/logo/icon-only.png -------------------------------------------------------------------------------- /web/public/image/theme/tomorrow-night-blue/preview@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/theme/tomorrow-night-blue/preview@2x.png -------------------------------------------------------------------------------- /web/public/image/theme/violet/logo/all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/theme/violet/logo/all.png -------------------------------------------------------------------------------- /web/public/image/theme/violet/logo/icon-only.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/theme/violet/logo/icon-only.png -------------------------------------------------------------------------------- /web/public/image/theme/violet/preview@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/public/image/theme/violet/preview@2x.png -------------------------------------------------------------------------------- /web/src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 25 | 26 | 30 | -------------------------------------------------------------------------------- /web/src/api/index.js: -------------------------------------------------------------------------------- 1 | import { assign, map } from 'lodash' 2 | import faker from 'faker/locale/zh_CN' 3 | import { service, request, serviceForMock, requestForMock, mock } from './service' 4 | import * as tools from './tools' 5 | 6 | const files = require.context('./modules', true, /\.api\.js$/) 7 | const generators = files.keys().map(key => files(key).default) 8 | 9 | export default assign({}, ...map(generators, generator => generator({ 10 | service, 11 | request, 12 | serviceForMock, 13 | requestForMock, 14 | mock, 15 | faker, 16 | tools 17 | }))) 18 | -------------------------------------------------------------------------------- /web/src/api/modules/sys.user.api.js: -------------------------------------------------------------------------------- 1 | import { find, assign } from 'lodash' 2 | 3 | const users = [ 4 | { username: 'admin', password: 'admin', uuid: 'admin-uuid', name: 'Admin' }, 5 | { username: 'editor', password: 'editor', uuid: 'editor-uuid', name: 'Editor' }, 6 | { username: 'user1', password: 'user1', uuid: 'user1-uuid', name: 'User1' } 7 | ] 8 | 9 | export default ({ service, request, serviceForMock, requestForMock, mock, faker, tools }) => ({ 10 | /** 11 | * @description 登录 12 | * @param {Object} data 登录携带的信息 13 | */ 14 | SYS_USER_LOGIN (data = {}) { 15 | // 模拟数据 16 | mock 17 | .onAny('/login') 18 | .reply(config => { 19 | const user = find(users, tools.parse(config.data)) 20 | return user 21 | ? tools.responseSuccess(assign({}, user, { token: faker.random.uuid() })) 22 | : tools.responseError({}, '账号或密码不正确') 23 | }) 24 | // 接口请求 25 | return requestForMock({ 26 | url: '/login', 27 | method: 'post', 28 | data 29 | }) 30 | } 31 | }) 32 | -------------------------------------------------------------------------------- /web/src/assets/style/animate/vue-transition.scss: -------------------------------------------------------------------------------- 1 | // 过渡动画 横向渐变 2 | .fade-transverse-leave-active, 3 | .fade-transverse-enter-active { 4 | transition: all .5s; 5 | } 6 | .fade-transverse-enter { 7 | opacity: 0; 8 | transform: translateX(-30px); 9 | } 10 | .fade-transverse-leave-to { 11 | opacity: 0; 12 | transform: translateX(30px); 13 | } 14 | 15 | // 过渡动画 缩放渐变 16 | .fade-scale-leave-active, 17 | .fade-scale-enter-active { 18 | transition: all .3s; 19 | } 20 | .fade-scale-enter { 21 | opacity: 0; 22 | transform: scale(1.2); 23 | } 24 | .fade-scale-leave-to { 25 | opacity: 0; 26 | transform: scale(0.8); 27 | } 28 | -------------------------------------------------------------------------------- /web/src/assets/style/fixed/base.scss: -------------------------------------------------------------------------------- 1 | // 优化显示 2 | html, body { 3 | margin: 0px; 4 | height: 100%; 5 | font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif; 6 | #app { 7 | @extend %full; 8 | a { 9 | text-decoration: none; 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /web/src/assets/style/fixed/element.scss: -------------------------------------------------------------------------------- 1 | // element 样式补丁 2 | .el-card { 3 | &.is-always-shadow { 4 | box-shadow: 0 0 8px 0 rgba(232,237,250,.6), 0 2px 4px 0 rgba(232,237,250,.5); 5 | } 6 | &.is-hover-shadow { 7 | &:hover { 8 | box-shadow: 0 0 8px 0 rgba(232,237,250,.6), 0 2px 4px 0 rgba(232,237,250,.5); 9 | } 10 | } 11 | } 12 | 13 | .el-menu--horizontal { 14 | border-bottom: none !important; 15 | } 16 | 17 | .el-tabs__item:focus.is-active.is-focus:not(:active) { 18 | box-shadow: none !important; 19 | } 20 | 21 | // 修复IE宽度不能撑满 22 | .el-table__body, 23 | .el-table__header { 24 | width: 100% !important; 25 | } 26 | 27 | // Chrome下表格头部错位修复 28 | .el-table th.gutter, 29 | .el-table colgroup.gutter { 30 | display: table-cell !important; 31 | } 32 | -------------------------------------------------------------------------------- /web/src/assets/style/fixed/markdown.scss: -------------------------------------------------------------------------------- 1 | // markdown 样式补丁 2 | .markdown-body { 3 | ul { 4 | list-style: disc; 5 | } 6 | h1, h2 { 7 | border-bottom: none; 8 | } 9 | } -------------------------------------------------------------------------------- /web/src/assets/style/fixed/n-progress.scss: -------------------------------------------------------------------------------- 1 | #nprogress { 2 | .bar { 3 | background: $color-primary !important; 4 | } 5 | .peg { 6 | box-shadow: 0 0 10px $color-primary, 0 0 5px $color-primary !important; 7 | } 8 | } -------------------------------------------------------------------------------- /web/src/assets/style/fixed/tree-view.scss: -------------------------------------------------------------------------------- 1 | .tree-view-wrapper.tree-view-small { 2 | .tree-view-item { 3 | font-size: 10px; 4 | } 5 | } -------------------------------------------------------------------------------- /web/src/assets/style/fixed/vue-grid-layout.scss: -------------------------------------------------------------------------------- 1 | // vue-splitpane 样式补丁 2 | .vue-grid-item { 3 | &.vue-grid-placeholder { 4 | border: 1px solid $color-border-1; 5 | background-color: rgba(#FFF, .3); 6 | opacity: 1; 7 | border-radius: 4px; 8 | } 9 | } -------------------------------------------------------------------------------- /web/src/assets/style/fixed/vue-splitpane.scss: -------------------------------------------------------------------------------- 1 | // vue-splitpane 样式补丁 2 | .splitter-pane-resizer { 3 | background-color: $color-border-1 !important; 4 | opacity: 1 !important; 5 | } -------------------------------------------------------------------------------- /web/src/assets/style/public.scss: -------------------------------------------------------------------------------- 1 | @import '~@/assets/style/unit/color.scss'; 2 | 3 | // 工具类名统一前缀 4 | $prefix: d2; 5 | 6 | // 禁止用户选中 鼠标变为手形 7 | %unable-select { 8 | user-select: none; 9 | cursor: pointer; 10 | } 11 | 12 | // 填满父元素 13 | // 组要父元素 position: relative | absolute; 14 | %full { 15 | position: absolute; 16 | top: 0px; 17 | right: 0px; 18 | bottom: 0px; 19 | left: 0px; 20 | } 21 | 22 | // flex 垂直水平居中 23 | %flex-center-row { 24 | display: flex; 25 | justify-content: center; 26 | align-items: center; 27 | flex-direction: row; 28 | } 29 | %flex-center-col { 30 | display: flex; 31 | justify-content: center; 32 | align-items: center; 33 | flex-direction: column; 34 | } 35 | 36 | // 将元素模拟成卡片外观 37 | %card { 38 | border: 1px solid #dddee1; 39 | border-color: #e9eaec; 40 | background: #fff; 41 | border-radius: 4px; 42 | font-size: 14px; 43 | position: relative; 44 | } -------------------------------------------------------------------------------- /web/src/assets/style/theme/chester/index.scss: -------------------------------------------------------------------------------- 1 | @import './setting.scss'; 2 | @import '../theme.scss'; 3 | -------------------------------------------------------------------------------- /web/src/assets/style/theme/d2/index.scss: -------------------------------------------------------------------------------- 1 | @import './setting.scss'; 2 | @import '../theme.scss'; 3 | -------------------------------------------------------------------------------- /web/src/assets/style/theme/element/index.scss: -------------------------------------------------------------------------------- 1 | @import './setting.scss'; 2 | @import '../theme.scss'; 3 | -------------------------------------------------------------------------------- /web/src/assets/style/theme/line/index.scss: -------------------------------------------------------------------------------- 1 | @import './setting.scss'; 2 | @import '../theme.scss'; 3 | -------------------------------------------------------------------------------- /web/src/assets/style/theme/register.scss: -------------------------------------------------------------------------------- 1 | @import '~@/assets/style/theme/theme-base.scss'; 2 | 3 | @import '~@/assets/style/theme/d2/index.scss'; 4 | @import '~@/assets/style/theme/chester/index.scss'; 5 | @import '~@/assets/style/theme/element/index.scss'; 6 | @import '~@/assets/style/theme/line/index.scss'; 7 | @import '~@/assets/style/theme/star/index.scss'; 8 | @import '~@/assets/style/theme/tomorrow-night-blue/index.scss'; 9 | @import '~@/assets/style/theme/violet/index.scss'; -------------------------------------------------------------------------------- /web/src/assets/style/theme/star/index.scss: -------------------------------------------------------------------------------- 1 | @import './setting.scss'; 2 | @import '../theme.scss'; 3 | -------------------------------------------------------------------------------- /web/src/assets/style/theme/tomorrow-night-blue/index.scss: -------------------------------------------------------------------------------- 1 | @import './setting.scss'; 2 | @import '../theme.scss'; 3 | -------------------------------------------------------------------------------- /web/src/assets/style/theme/violet/index.scss: -------------------------------------------------------------------------------- 1 | @import './setting.scss'; 2 | @import '../theme.scss'; 3 | 4 | .theme-#{$theme-name} { 5 | .d2-layout-header-aside-group { 6 | background: #bc00e3; 7 | background: linear-gradient(120deg, #bc00e3 0%, #4EFFFB 100%); 8 | } 9 | } -------------------------------------------------------------------------------- /web/src/assets/style/unit/color.scss: -------------------------------------------------------------------------------- 1 | // 主色 2 | $color-primary: #409EFF; 3 | 4 | // 辅助色 5 | $color-info: #909399; 6 | $color-success: #67C23A; 7 | $color-warning: #E6A23C; 8 | $color-danger: #F56C6C; 9 | 10 | // 文字 11 | $color-text-main: #303133; 12 | $color-text-normal: #606266; 13 | $color-text-sub: #909399; 14 | $color-text-placehoder: #C0C4CC; 15 | 16 | // 边框 17 | $color-border-1: #DCDFE6; 18 | $color-border-2: #E4E7ED; 19 | $color-border-3: #EBEEF5; 20 | $color-border-4: #F2F6FC; 21 | 22 | // 背景 23 | $color-bg: #f8f8f9; -------------------------------------------------------------------------------- /web/src/assets/style/yxt-public.scss: -------------------------------------------------------------------------------- 1 | /*常用 flex 水平居后*/ 2 | .yxt-flex-end{ 3 | display: flex; 4 | justify-content: flex-end; 5 | } 6 | /*常用 flex 水平居前*/ 7 | .yxt-flex-start{ 8 | display: flex; 9 | justify-content: flex-start; 10 | } 11 | /*用 flex 两边对齐*/ 12 | .yxt-flex-between{ 13 | display: flex; 14 | justify-content: space-between; 15 | } 16 | /*常用 flex 水平居中*/ 17 | .yxt-flex-center{ 18 | display: flex; 19 | justify-content:center; 20 | } 21 | /* 常用 flex 垂直居中*/ 22 | .yxt-flex-align-center{ 23 | display: flex; 24 | -webkit-align-items: center; 25 | align-items: center; 26 | } 27 | /* 常用 flex 基于底部对齐*/ 28 | .yxt-flex-align-end{ 29 | display:flex; 30 | align-items:flex-end; 31 | } 32 | 33 | /**常用 flex 纵向排列**/ 34 | .yxt-flex-column{ 35 | display: -webkit-flex; 36 | display: flex; 37 | -webkit-flex-direction: column; 38 | flex-direction: column; 39 | } 40 | /**垂直竖线,常用于标题**/ 41 | .yxt-divider{ 42 | background: #409EFF; 43 | width: 8px; 44 | height: 20px; 45 | display: inline-block; 46 | margin-right: 10px; 47 | } -------------------------------------------------------------------------------- /web/src/assets/svg-icons/icons/department.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/src/assets/svg-icons/icons/home.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/src/assets/svg-icons/icons/log.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/src/assets/svg-icons/icons/menu.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/src/assets/svg-icons/icons/role.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/src/assets/svg-icons/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | const requireAll = requireContext => requireContext.keys().map(requireContext) 4 | const req = require.context('./icons', false, /\.svg$/) 5 | const iconMap = requireAll(req) 6 | 7 | Vue.prototype.$IconSvg = iconMap.map(e => e.default.id.slice(3)) 8 | -------------------------------------------------------------------------------- /web/src/components/d2-container/components/d2-container-card-bs.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 28 | -------------------------------------------------------------------------------- /web/src/components/d2-container/components/d2-container-card.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 34 | -------------------------------------------------------------------------------- /web/src/components/d2-container/components/d2-container-full-bs.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 26 | -------------------------------------------------------------------------------- /web/src/components/d2-container/components/d2-container-full.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 32 | -------------------------------------------------------------------------------- /web/src/components/d2-container/components/d2-container-ghost-bs.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 27 | -------------------------------------------------------------------------------- /web/src/components/d2-container/components/d2-container-ghost.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 32 | -------------------------------------------------------------------------------- /web/src/components/d2-container/components/d2-source.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 47 | 48 | 80 | -------------------------------------------------------------------------------- /web/src/components/d2-container/components/mixins/bs.js: -------------------------------------------------------------------------------- 1 | import BScroll from 'better-scroll' 2 | export default { 3 | props: { 4 | // 滚动优化的选项 5 | betterScrollOptions: { 6 | type: Object, 7 | required: false, 8 | default: () => ({}) 9 | } 10 | }, 11 | data () { 12 | return { 13 | BS: null 14 | } 15 | }, 16 | mounted () { 17 | this.scrollInit() 18 | }, 19 | beforeDestroy () { 20 | this.scrollDestroy() 21 | }, 22 | methods: { 23 | scrollInit () { 24 | // 初始化 bs 25 | this.BS = new BScroll(this.$refs.wrapper, Object.assign({ 26 | mouseWheel: true, 27 | click: true, 28 | scrollbar: { 29 | fade: true, 30 | interactive: false 31 | } 32 | }, this.betterScrollOptions)) 33 | // 滚动时发出事件 并且统一返回的数据格式 34 | this.BS.on('scroll', ({ x, y }) => this.$emit('scroll', { 35 | x: -x, 36 | y: -y 37 | })) 38 | }, 39 | scrollDestroy () { 40 | // https://github.com/d2-projects/d2-admin/issues/75 41 | try { 42 | this.BS.destroy() 43 | } catch (e) { 44 | delete this.BS 45 | this.BS = null 46 | } 47 | }, 48 | // 外部调用的方法 返回顶部 49 | scrollToTop () { 50 | if (this.BS) this.BS.scrollTo(0, 0, 300) 51 | }, 52 | // 手动发出滚动事件 53 | scroll () { 54 | if (this.BS) { 55 | this.$emit('scroll', { 56 | x: -this.BS.x, 57 | y: -this.BS.y 58 | }) 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /web/src/components/d2-container/components/mixins/normal.js: -------------------------------------------------------------------------------- 1 | // 提供滚动方面的功能 2 | // 非滚动优化模式通用 3 | 4 | import { throttle } from 'lodash' 5 | 6 | // 生成滚动事件的 handler 7 | function handleMaker (wait) { 8 | return throttle(e => { 9 | this.$emit('scroll', { 10 | x: e.target.scrollLeft, 11 | y: e.target.scrollTop 12 | }) 13 | }, wait) 14 | } 15 | 16 | export default { 17 | props: { 18 | // 滚动事件节流间隔 19 | scrollDelay: { 20 | type: Number, 21 | required: false, 22 | default: 10 23 | } 24 | }, 25 | data () { 26 | return { 27 | handleScroll: null 28 | } 29 | }, 30 | watch: { 31 | scrollDelay (val) { 32 | // 移除旧的监听 33 | this.removeScrollListener() 34 | // 生成新的 handle 方法 35 | this.handleScroll = handleMaker.call(this, val) 36 | // 添加新的监听 37 | this.addScrollListener() 38 | } 39 | }, 40 | methods: { 41 | // 增加滚动事件监听 42 | addScrollListener () { 43 | if (typeof this.handleScroll !== 'function') { 44 | // mounted 生命周期内调用这个方法的时候会进入这里的判断 45 | this.handleScroll = handleMaker.call(this, this.scrollDelay) 46 | } 47 | // 添加监听 48 | this.$refs.body.addEventListener('scroll', this.handleScroll) 49 | }, 50 | // 移除滚动事件监听 51 | removeScrollListener () { 52 | this.$refs.body.removeEventListener('scroll', this.handleScroll) 53 | }, 54 | // 外部调用的方法 返回顶部 55 | scrollToTop () { 56 | const smoothscroll = () => { 57 | const body = this.$refs.body 58 | const currentScroll = body.scrollTop 59 | if (currentScroll > 0) { 60 | window.requestAnimationFrame(smoothscroll) 61 | body.scrollTo(0, currentScroll - (currentScroll / 5)) 62 | } 63 | } 64 | smoothscroll() 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /web/src/components/d2-icon-svg/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 23 | -------------------------------------------------------------------------------- /web/src/components/d2-icon/font-awesome-4.7.0/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/src/components/d2-icon/font-awesome-4.7.0/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /web/src/components/d2-icon/font-awesome-4.7.0/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/src/components/d2-icon/font-awesome-4.7.0/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /web/src/components/d2-icon/font-awesome-4.7.0/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/src/components/d2-icon/font-awesome-4.7.0/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /web/src/components/d2-icon/font-awesome-4.7.0/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/src/components/d2-icon/font-awesome-4.7.0/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /web/src/components/d2-icon/font-awesome-4.7.0/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/src/components/d2-icon/font-awesome-4.7.0/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /web/src/components/d2-icon/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 18 | -------------------------------------------------------------------------------- /web/src/components/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | import d2Container from './d2-container' 4 | 5 | // 注意 有些组件使用异步加载会有影响 6 | Vue.component('d2-container', d2Container) 7 | Vue.component('d2-icon', () => import('./d2-icon')) 8 | Vue.component('d2-icon-svg', () => import('./d2-icon-svg/index.vue')) 9 | -------------------------------------------------------------------------------- /web/src/components/table-selector/group.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @创建文件时间: 2021-08-02 23:55:30 3 | * @Auther: 猿小天 4 | * @最后修改人: 猿小天 5 | * @最后修改时间: 2021-08-08 12:27:45 6 | * 联系Qq:1638245306 7 | * @文件介绍: 8 | */ 9 | export default { 10 | // 字段类型配置,注册之后即可在crud.js中使用了 11 | 'table-selector': { 12 | // 表单组件配置 13 | form: { component: { name: 'table-selector-input', props: { color: 'danger' } } }, 14 | // 行组件配置 15 | component: { name: 'values-format', props: {} }, 16 | // 行展示时居中 17 | align: 'center' 18 | // 您还可以写更多默认配置 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /web/src/components/table-selector/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @创建文件时间: 2021-08-02 23:56:15 3 | * @Auther: 猿小天 4 | * @最后修改人: 猿小天 5 | * @最后修改时间: 2021-08-09 22:15:56 6 | * 联系Qq:1638245306 7 | * @文件介绍: 8 | */ 9 | import { d2CrudPlus } from 'd2-crud-plus' 10 | import group from './group' 11 | 12 | function install (Vue, options) { 13 | Vue.component('table-selector-input', () => import('./table-selector')) 14 | // Vue.component('d2p-row-format', () => import('./row')) 15 | if (d2CrudPlus != null) { 16 | // 注册字段类型`demo-extend` 17 | d2CrudPlus.util.columnResolve.addTypes(group) 18 | } 19 | } 20 | 21 | // 导出install, 通过`vue.use(D2pDemoExtend)`安装后 ,`demo-extend` 就可以在`crud.js`中使用了 22 | export default { 23 | install 24 | } 25 | -------------------------------------------------------------------------------- /web/src/config/button.js: -------------------------------------------------------------------------------- 1 | export const BUTTON_VALUE_TO_COLOR_MAPPING = { 2 | 1: 'success', 3 | true: 'success', 4 | 0: 'danger', 5 | false: 'danger', 6 | Search: 'warning', // 查询 7 | Update: 'primary', // 编辑 8 | Create: 'success', // 新增 9 | Retrieve: 'info', // 单例 10 | Delete: 'danger' // 删除 11 | } 12 | 13 | export function getButtonSettings (objectSettings) { 14 | return objectSettings.map(item => { 15 | return { 16 | label: item.label, 17 | value: item.value, 18 | color: BUTTON_VALUE_TO_COLOR_MAPPING[item.value] 19 | } 20 | }) 21 | } 22 | 23 | // 启用 true/ 禁用 false 24 | export const BUTTON_STATUS_BOOL = getButtonSettings([{ label: '启用', value: true }, { label: '禁用', value: false }]) 25 | 26 | // 启用 1/ 禁用 0 27 | export const BUTTON_STATUS_NUMBER = getButtonSettings([{ label: '启用', value: 1 }, { label: '禁用', value: 0 }]) 28 | 29 | // 是 1/ 否 0 30 | export const BUTTON_WHETHER_NUMBER = getButtonSettings([{ label: '是', value: 1 }, { label: '否', value: 0 }]) 31 | // 是 true/ 否 false 32 | export const BUTTON_WHETHER_BOOL = getButtonSettings([{ label: '是', value: true }, { label: '否', value: false }]) 33 | -------------------------------------------------------------------------------- /web/src/i18n.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueI18n from 'vue-i18n' 3 | import util from '@/libs/util' 4 | 5 | Vue.use(VueI18n) 6 | 7 | function loadLocaleMessages () { 8 | const locales = require.context('./locales', true, /[A-Za-z0-9-_,\s]+\.json$/i) 9 | const messages = {} 10 | for (const key of locales.keys()) { 11 | const matched = key.match(/([A-Za-z0-9-_]+)\./i) 12 | if (matched && matched.length > 1) { 13 | const locale = matched[1] 14 | const localeElementUI = require(`element-ui/lib/locale/lang/${locales(key)._element}`) 15 | messages[locale] = { 16 | ...locales(key), 17 | ...localeElementUI ? localeElementUI.default : {} 18 | } 19 | } 20 | } 21 | return messages 22 | } 23 | 24 | const messages = loadLocaleMessages() 25 | 26 | Vue.prototype.$languages = Object.keys(messages).map(langlage => ({ 27 | label: messages[langlage]._name, 28 | value: langlage 29 | })) 30 | 31 | const i18n = new VueI18n({ 32 | locale: util.cookies.get('lang') || process.env.VUE_APP_I18N_LOCALE, 33 | fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE, 34 | messages 35 | }) 36 | 37 | export default i18n 38 | -------------------------------------------------------------------------------- /web/src/layout/header-aside/components/contextmenu/components/contentmenuList/index.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 32 | 33 | 51 | -------------------------------------------------------------------------------- /web/src/layout/header-aside/components/contextmenu/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 57 | 58 | 69 | -------------------------------------------------------------------------------- /web/src/layout/header-aside/components/header-color/index.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 45 | -------------------------------------------------------------------------------- /web/src/layout/header-aside/components/header-fullscreen/index.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 25 | -------------------------------------------------------------------------------- /web/src/layout/header-aside/components/header-locales/index.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 26 | -------------------------------------------------------------------------------- /web/src/layout/header-aside/components/header-log/index.vue: -------------------------------------------------------------------------------- 1 | 9 | 31 | 32 | 60 | -------------------------------------------------------------------------------- /web/src/layout/header-aside/components/header-search/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 16 | -------------------------------------------------------------------------------- /web/src/layout/header-aside/components/header-size/index.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 55 | -------------------------------------------------------------------------------- /web/src/layout/header-aside/components/header-theme/components/d2-theme-list/index.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 44 | 45 | 54 | -------------------------------------------------------------------------------- /web/src/layout/header-aside/components/header-theme/index.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 39 | -------------------------------------------------------------------------------- /web/src/layout/header-aside/components/header-user/index.vue: -------------------------------------------------------------------------------- 1 | 9 | 25 | 26 | 49 | -------------------------------------------------------------------------------- /web/src/layout/header-aside/components/libs/util.menu.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 创建菜单 3 | * @param {Function} h createElement 4 | * @param {Object} menu 菜单项 5 | */ 6 | export function elMenuItem (h, menu) { 7 | let icon = null 8 | if (menu.icon) icon = 9 | else if (menu.iconSvg) icon = 10 | else icon = 11 | return 14 | { icon } 15 | { menu.title || '未命名菜单' } 16 | 17 | } 18 | 19 | /** 20 | * @description 创建子菜单 21 | * @param {Function} h createElement 22 | * @param {Object} menu 菜单项 23 | */ 24 | export function elSubmenu (h, menu) { 25 | let icon = null 26 | if (menu.icon) icon = 27 | else if (menu.iconSvg) icon = 28 | else icon = 29 | return 32 | { icon } 33 | { menu.title || '未命名菜单' } 34 | { menu.children.map(child => createMenu.call(this, h, child)) } 35 | 36 | } 37 | 38 | /** 39 | * @description 在组件中调用此方法渲染菜单项目 40 | * @param {Function} h createElement 41 | * @param {Object} menu 菜单项 42 | */ 43 | export function createMenu (h, menu) { 44 | if (menu.children === undefined) return elMenuItem.call(this, h, menu) 45 | return elSubmenu.call(this, h, menu) 46 | } 47 | -------------------------------------------------------------------------------- /web/src/layout/header-aside/components/mixin/menu.js: -------------------------------------------------------------------------------- 1 | import util from '@/libs/util.js' 2 | 3 | export default { 4 | methods: { 5 | handleMenuSelect (index, indexPath) { 6 | if (/^d2-menu-empty-\d+$/.test(index) || index === undefined) { 7 | this.$message.warning('临时菜单') 8 | } else if (/^https:\/\/|http:\/\//.test(index)) { 9 | util.open(index) 10 | } else { 11 | this.$router.push({ 12 | path: index 13 | }) 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /web/src/layout/header-aside/index.js: -------------------------------------------------------------------------------- 1 | import layout from './layout' 2 | 3 | export default layout 4 | -------------------------------------------------------------------------------- /web/src/layout/header-aside/mixins/search.js: -------------------------------------------------------------------------------- 1 | import { mapState, mapMutations } from 'vuex' 2 | 3 | import hotkeys from 'hotkeys-js' 4 | 5 | export default { 6 | components: { 7 | 'd2-panel-search': () => import('../components/panel-search') 8 | }, 9 | mounted () { 10 | // 绑定搜索功能快捷键 [ 打开 ] 11 | hotkeys(this.searchHotkey.open, event => { 12 | event.preventDefault() 13 | this.searchPanelOpen() 14 | }) 15 | // 绑定搜索功能快捷键 [ 关闭 ] 16 | hotkeys(this.searchHotkey.close, event => { 17 | event.preventDefault() 18 | this.searchPanelClose() 19 | }) 20 | }, 21 | beforeDestroy () { 22 | hotkeys.unbind(this.searchHotkey.open) 23 | hotkeys.unbind(this.searchHotkey.close) 24 | }, 25 | computed: { 26 | ...mapState('d2admin', { 27 | searchActive: state => state.search.active, 28 | searchHotkey: state => state.search.hotkey 29 | }) 30 | }, 31 | methods: { 32 | ...mapMutations({ 33 | searchToggle: 'd2admin/search/toggle', 34 | searchSet: 'd2admin/search/set' 35 | }), 36 | /** 37 | * 接收点击搜索按钮 38 | */ 39 | handleSearchClick () { 40 | this.searchToggle() 41 | if (this.searchActive) { 42 | setTimeout(() => { 43 | if (this.$refs.panelSearch) { 44 | this.$refs.panelSearch.focus() 45 | } 46 | }, 500) 47 | } 48 | }, 49 | searchPanelOpen () { 50 | if (!this.searchActive) { 51 | this.searchSet(true) 52 | setTimeout(() => { 53 | if (this.$refs.panelSearch) { 54 | this.$refs.panelSearch.focus() 55 | } 56 | }, 500) 57 | } 58 | }, 59 | // 关闭搜索面板 60 | searchPanelClose () { 61 | if (this.searchActive) { 62 | this.searchSet(false) 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /web/src/libs/util.cookies.js: -------------------------------------------------------------------------------- 1 | import Cookies from 'js-cookie' 2 | 3 | const cookies = {} 4 | 5 | /** 6 | * @description 存储 cookie 值 7 | * @param {String} name cookie name 8 | * @param {String} value cookie value 9 | * @param {Object} setting cookie setting 10 | */ 11 | cookies.set = function (name = 'default', value = '', cookieSetting = {}) { 12 | const currentCookieSetting = { 13 | expires: 1 14 | } 15 | Object.assign(currentCookieSetting, cookieSetting) 16 | Cookies.set(`d2admin-${process.env.VUE_APP_VERSION}-${name}`, value, currentCookieSetting) 17 | } 18 | 19 | /** 20 | * @description 拿到 cookie 值 21 | * @param {String} name cookie name 22 | */ 23 | cookies.get = function (name = 'default') { 24 | return Cookies.get(`d2admin-${process.env.VUE_APP_VERSION}-${name}`) 25 | } 26 | 27 | /** 28 | * @description 拿到 cookie 全部的值 29 | */ 30 | cookies.getAll = function () { 31 | return Cookies.get() 32 | } 33 | 34 | /** 35 | * @description 删除 cookie 36 | * @param {String} name cookie name 37 | */ 38 | cookies.remove = function (name = 'default') { 39 | return Cookies.remove(`d2admin-${process.env.VUE_APP_VERSION}-${name}`) 40 | } 41 | 42 | export default cookies 43 | -------------------------------------------------------------------------------- /web/src/libs/util.import.development.js: -------------------------------------------------------------------------------- 1 | module.exports = file => require('@/views/' + file).default 2 | -------------------------------------------------------------------------------- /web/src/libs/util.import.production.js: -------------------------------------------------------------------------------- 1 | module.exports = file => () => import('@/views/' + file) 2 | -------------------------------------------------------------------------------- /web/src/libs/util.import.test.js: -------------------------------------------------------------------------------- 1 | module.exports = file => require('@/views/' + file).default 2 | -------------------------------------------------------------------------------- /web/src/libs/util.js: -------------------------------------------------------------------------------- 1 | import cookies from './util.cookies' 2 | import db from './util.db' 3 | import log from './util.log' 4 | import { plugins } from '@/views/dvadmin_plugins/index.js' 5 | const util = { 6 | cookies, 7 | db, 8 | log 9 | } 10 | 11 | /** 12 | * @description 更新标题 13 | * @param {String} titleText 标题 14 | */ 15 | util.title = function (titleText) { 16 | const processTitle = process.env.VUE_APP_TITLE || 'D2Admin' 17 | window.document.title = `${processTitle}${titleText ? ` | ${titleText}` : ''}` 18 | } 19 | 20 | /** 21 | * @description 打开新页面 22 | * @param {String} url 地址 23 | */ 24 | util.open = function (url) { 25 | var a = document.createElement('a') 26 | a.setAttribute('href', url) 27 | a.setAttribute('target', '_blank') 28 | a.setAttribute('id', 'd2admin-link-temp') 29 | document.body.appendChild(a) 30 | a.click() 31 | document.body.removeChild(document.getElementById('d2admin-link-temp')) 32 | } 33 | /** 34 | * @description 校验是否为租户模式。租户模式把域名替换成 域名 加端口 35 | */ 36 | util.baseURL = function () { 37 | var baseURL = process.env.VUE_APP_API 38 | if (plugins.dvadmin_tenant_web) { 39 | // document.domain 40 | var host = baseURL.split('/')[2] 41 | var prot = host.split(':')[1] || 80 42 | host = document.domain + ':' + prot 43 | baseURL = baseURL.split('/')[0] + '//' + baseURL.split('/')[1] + host + '/' + (baseURL.split('/')[3] || '') 44 | } 45 | if (!baseURL.endsWith('/')) { 46 | baseURL += '/' 47 | } 48 | return baseURL 49 | } 50 | 51 | export default util 52 | -------------------------------------------------------------------------------- /web/src/libs/util.log.js: -------------------------------------------------------------------------------- 1 | const log = {} 2 | 3 | /** 4 | * @description 返回这个样式的颜色值 5 | * @param {String} type 样式名称 [ primary | success | warning | danger | text ] 6 | */ 7 | function typeColor (type = 'default') { 8 | let color = '' 9 | switch (type) { 10 | case 'default': color = '#35495E'; break 11 | case 'primary': color = '#3488ff'; break 12 | case 'success': color = '#43B883'; break 13 | case 'warning': color = '#e6a23c'; break 14 | case 'danger': color = '#f56c6c'; break 15 | default:; break 16 | } 17 | return color 18 | } 19 | 20 | /** 21 | * @description 打印一个 [ title | text ] 样式的信息 22 | * @param {String} title title text 23 | * @param {String} info info text 24 | * @param {String} type style 25 | */ 26 | log.capsule = function (title, info, type = 'primary') { 27 | console.log( 28 | `%c ${title} %c ${info} %c`, 29 | 'background:#35495E; padding: 1px; border-radius: 3px 0 0 3px; color: #fff;', 30 | `background:${typeColor(type)}; padding: 1px; border-radius: 0 3px 3px 0; color: #fff;`, 31 | 'background:transparent' 32 | ) 33 | } 34 | 35 | /** 36 | * @description 打印彩色文字 37 | */ 38 | log.colorful = function (textArr) { 39 | console.log( 40 | `%c${textArr.map(t => t.text || '').join('%c')}`, 41 | ...textArr.map(t => `color: ${typeColor(t.type)};`) 42 | ) 43 | } 44 | 45 | /** 46 | * @description 打印 default 样式的文字 47 | */ 48 | log.default = function (text) { 49 | log.colorful([{ text }]) 50 | } 51 | 52 | /** 53 | * @description 打印 primary 样式的文字 54 | */ 55 | log.primary = function (text) { 56 | log.colorful([{ text, type: 'primary' }]) 57 | } 58 | 59 | /** 60 | * @description 打印 success 样式的文字 61 | */ 62 | log.success = function (text) { 63 | log.colorful([{ text, type: 'success' }]) 64 | } 65 | 66 | /** 67 | * @description 打印 warning 样式的文字 68 | */ 69 | log.warning = function (text) { 70 | log.colorful([{ text, type: 'warning' }]) 71 | } 72 | 73 | /** 74 | * @description 打印 danger 样式的文字 75 | */ 76 | log.danger = function (text) { 77 | log.colorful([{ text, type: 'danger' }]) 78 | } 79 | 80 | export default log 81 | -------------------------------------------------------------------------------- /web/src/locales/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "_element": "en", 3 | "_name": "English", 4 | "page": { 5 | "demo": { 6 | "playground": { 7 | "locales": { 8 | "text": "D2Admin is a fully open source and free enterprise back-end product front-end integration solution, using the latest front-end technology stack, has prepared most of the project preparations, and with a lot of sample code to help the management system agile development." 9 | } 10 | } 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /web/src/locales/ja.json: -------------------------------------------------------------------------------- 1 | { 2 | "_element": "ja", 3 | "_name": "日本語", 4 | "page": { 5 | "demo": { 6 | "playground": { 7 | "locales": { 8 | "text": "D2Adminは、最新のフロントエンドテクノロジースタックを使用した、完全にオープンソースの無料エンタープライズバックエンド製品フロントエンド統合ソリューションであり、プロジェクトのほとんどの準備を整えており、システムのアジャイル開発の管理に役立つ多くのサンプルコードを備えています。" 9 | } 10 | } 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /web/src/locales/mixin.js: -------------------------------------------------------------------------------- 1 | export default { 2 | methods: { 3 | onChangeLocale (command) { 4 | this.$i18n.locale = command 5 | let message = `当前语言:${this.$t('_name')} [ ${this.$i18n.locale} ]` 6 | if (process.env.VUE_APP_BUILD_MODE === 'PREVIEW') { 7 | message = [ 8 | `当前语言:${this.$t('_name')} [ ${this.$i18n.locale} ]`, 9 | '仅提供切换功能,没有配置具体的语言数据 ', 10 | '文档参考:《国际化 | D2Admin》' 11 | ].join('
') 12 | } 13 | this.$notify({ 14 | title: '语言变更', 15 | dangerouslyUseHTMLString: true, 16 | message 17 | }) 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /web/src/locales/zh-chs.json: -------------------------------------------------------------------------------- 1 | { 2 | "_element": "zh-CN", 3 | "_name": "简体中文", 4 | "page": { 5 | "demo": { 6 | "playground": { 7 | "locales": { 8 | "text": "D2Admin 是一个完全 开源免费 的企业中后台产品前端集成方案,使用最新的前端技术栈,已经做好大部分项目前期准备工作,并且带有大量示例代码,助力管理系统敏捷开发。" 9 | } 10 | } 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /web/src/locales/zh-cht.json: -------------------------------------------------------------------------------- 1 | { 2 | "_element": "zh-TW", 3 | "_name": "繁體中文", 4 | "page": { 5 | "demo": { 6 | "playground": { 7 | "locales": { 8 | "text": "D2Admin 是一個完全 開源免費 的企業中後台產品前端集成方案,使用最新的前端技術棧,已經做好大部分項目前期準備工作,並且帶有大量示例代碼,助力管理系統敏捷開發。" 9 | } 10 | } 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /web/src/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @创建文件时间: 2021-06-01 22:41:19 3 | * @Auther: 猿小天 4 | * @最后修改人: 猿小天 5 | * @最后修改时间: 2021-08-12 00:57:05 6 | * 联系Qq:1638245306 7 | * @文件介绍: 8 | */ 9 | // Vue 10 | import Vue from 'vue' 11 | import i18n from './i18n' 12 | import App from './App' 13 | // 核心插件 14 | import d2Admin from '@/plugin/d2admin' 15 | // store 16 | import store from '@/store/index' 17 | 18 | // 菜单和路由设置 19 | import router from './router' 20 | import { menuHeader } from '@/menu' 21 | 22 | // 按钮权限 23 | import '@/plugin/permission' // 加载permission 24 | 25 | // d2-crud-plus 安装与初始化 26 | import './install' 27 | // 配置vxe-table 28 | import 'xe-utils' 29 | import VXETable from 'vxe-table' 30 | import 'vxe-table/lib/style.css' 31 | 32 | // md5加密 33 | import md5 from 'js-md5' 34 | 35 | // 核心插件 36 | Vue.use(d2Admin) 37 | Vue.use(VXETable) 38 | Vue.prototype.$md5 = md5 39 | 40 | new Vue({ 41 | router, 42 | store, 43 | i18n, 44 | render: h => h(App), 45 | created () { 46 | 47 | // 处理路由 得到每一级的路由设置 48 | // this.$store.commit('d2admin/page/init', frameInRoutes) 49 | // 设置顶栏菜单 50 | // this.$store.commit('d2admin/menu/headerSet', menuHeader) 51 | // 设置侧边栏菜单 52 | // this.$store.commit('d2admin/menu/asideSet', menuAside) 53 | // 初始化菜单搜索功能 54 | // this.$store.commit('d2admin/search/init', menuAside) 55 | }, 56 | mounted () { 57 | // 展示系统信息 58 | this.$store.commit('d2admin/releases/versionShow') 59 | // 用户登录后从数据库加载一系列的设置 60 | this.$store.dispatch('d2admin/account/load') 61 | // 获取并记录用户 UA 62 | this.$store.commit('d2admin/ua/get') 63 | // 初始化全屏监听 64 | this.$store.dispatch('d2admin/fullscreen/listen') 65 | }, 66 | watch: { 67 | // 检测路由变化切换侧边栏内容 68 | '$route.matched': { 69 | handler (matched) { 70 | if (matched.length > 0) { 71 | const _side = menuHeader.filter(menu => menu.path === matched[0].path) 72 | if (_side.length > 0) { 73 | this.$store.commit('d2admin/menu/asideSet', _side[0].children) 74 | } 75 | } 76 | }, 77 | immediate: true 78 | } 79 | } 80 | }).$mount('#app') 81 | -------------------------------------------------------------------------------- /web/src/plugin/api/index.js: -------------------------------------------------------------------------------- 1 | import api from '@/api' 2 | 3 | export default { 4 | install (Vue) { 5 | Vue.prototype.$api = api 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /web/src/plugin/d2admin/index.js: -------------------------------------------------------------------------------- 1 | // Element 2 | import ElementUI from 'element-ui' 3 | import 'element-ui/lib/theme-chalk/index.css' 4 | // flex 布局库 5 | import 'flex.css' 6 | // 组件 7 | import '@/components' 8 | // svg 图标 9 | import '@/assets/svg-icons' 10 | // 国际化 11 | import i18n from '@/i18n.js' 12 | 13 | // 功能插件 14 | import pluginApi from '@/plugin/api' 15 | import pluginError from '@/plugin/error' 16 | import pluginLog from '@/plugin/log' 17 | import pluginOpen from '@/plugin/open' 18 | import tableSelector from '@/components/table-selector/index' 19 | import { dvadminPlugins } from '@/views/dvadmin_plugins/index' 20 | export default { 21 | async install (Vue, options) { 22 | // 设置为 false 以阻止 vue 在启动时生成生产提示 23 | // https://cn.vuejs.org/v2/api/#productionTip 24 | Vue.config.productionTip = false 25 | // 当前环境 26 | Vue.prototype.$env = process.env.NODE_ENV 27 | // 当前的 baseUrl 28 | Vue.prototype.$baseUrl = process.env.BASE_URL 29 | // 当前版本 30 | Vue.prototype.$version = process.env.VUE_APP_VERSION 31 | // 构建时间 32 | Vue.prototype.$buildTime = process.env.VUE_APP_BUILD_TIME 33 | // Element 34 | Vue.use(ElementUI, { 35 | i18n: (key, value) => i18n.t(key, value) 36 | }) 37 | // 插件 38 | Vue.use(pluginApi) 39 | Vue.use(pluginError) 40 | Vue.use(pluginLog) 41 | Vue.use(pluginOpen) 42 | Vue.use(tableSelector) 43 | Vue.use(dvadminPlugins) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /web/src/plugin/error/index.js: -------------------------------------------------------------------------------- 1 | import { get, isObject } from 'lodash' 2 | import store from '@/store' 3 | import util from '@/libs/util' 4 | 5 | export default { 6 | install (Vue, options) { 7 | function writeLog (logType) { 8 | return (error, vm, info = '') => { 9 | Vue.nextTick(() => { 10 | store.dispatch('d2admin/log/push', { 11 | message: `${info}: ${isObject(error) ? error.message : error}`, 12 | type: logType, 13 | meta: { 14 | error, 15 | vm 16 | } 17 | }) 18 | if (process.env.NODE_ENV !== 'development') return 19 | util.log.capsule('D2Admin', 'ErrorHandler', logType) 20 | util.log.danger('>>>>>> 错误信息 >>>>>>') 21 | console.log(info) 22 | util.log.danger('>>>>>> Vue 实例 >>>>>>') 23 | console.log(vm) 24 | util.log.danger('>>>>>> Error >>>>>>') 25 | console.log(error) 26 | }) 27 | } 28 | } 29 | if (process.env.NODE_ENV === 'development') { 30 | Vue.config.warnHandler = writeLog('warning') 31 | } 32 | Vue.config.errorHandler = writeLog('danger') 33 | window.onunhandledrejection = error => { 34 | store.dispatch('d2admin/log/push', { 35 | message: get(error, 'reason.message', 'Unknown error'), 36 | type: 'danger', 37 | meta: { 38 | error: get(error, 'reason'), 39 | trace: get(error, 'reason.stack') 40 | } 41 | }) 42 | } 43 | window.onerror = (event, source, lineno, colno, error) => { 44 | store.dispatch('d2admin/log/push', { 45 | message: get(error, 'message', 'Unknown error'), 46 | type: 'danger', 47 | meta: { 48 | error, 49 | trace: get(error, 'stack'), 50 | source: `${source}@${lineno}:${colno}`, 51 | event: event 52 | } 53 | }) 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /web/src/plugin/log/index.js: -------------------------------------------------------------------------------- 1 | import store from '@/store' 2 | import util from '@/libs/util' 3 | 4 | export default { 5 | install (Vue, options) { 6 | // 快速打印 log 7 | Vue.prototype.$log = { 8 | ...util.log, 9 | push (data) { 10 | if (typeof data === 'string') { 11 | // 如果传递来的数据是字符串 12 | // 赋值给 message 字段 13 | // 为了方便使用 14 | // eg: this.$log.push('foo text') 15 | store.dispatch('d2admin/log/push', { 16 | message: data 17 | }) 18 | } else if (typeof data === 'object') { 19 | // 如果传递来的数据是对象 20 | store.dispatch('d2admin/log/push', data) 21 | } 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /web/src/plugin/open/index.js: -------------------------------------------------------------------------------- 1 | import util from '@/libs/util' 2 | 3 | export default { 4 | install (Vue, options) { 5 | Vue.prototype.$open = util.open 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /web/src/plugin/permission/directive/permission/index.js: -------------------------------------------------------------------------------- 1 | import permission from './permission' 2 | import permissionUtil from './util.permission' 3 | const install = function (Vue) { 4 | Vue.directive('permission', permission) 5 | Vue.prototype.hasPermissions = permissionUtil.hasPermissions 6 | } 7 | 8 | if (window.Vue) { 9 | window.permission = permission 10 | Vue.use(install); // eslint-disable-line 11 | } 12 | 13 | permission.install = install 14 | export default permission 15 | -------------------------------------------------------------------------------- /web/src/plugin/permission/directive/permission/permission.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @创建文件时间: 2021-06-27 10:14:26 3 | * @Auther: 猿小天 4 | * @最后修改人: 猿小天 5 | * @最后修改时间: 2021-07-27 23:00:10 6 | * 联系Qq:1638245306 7 | * @文件介绍: 自定义指令-权限控制 8 | */ 9 | import permissionUtil from './util.permission' 10 | export default { 11 | inserted (el, binding, vnode) { 12 | const { value } = binding 13 | const hasPermission = permissionUtil.hasPermissions(value) 14 | if (process.env.VUE_APP_PM_ENABLED) { 15 | if (!hasPermission) { 16 | el.parentNode && el.parentNode.removeChild(el) 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /web/src/plugin/permission/directive/permission/util.permission.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @创建文件时间: 2021-06-27 10:14:26 3 | * @Auther: 猿小天 4 | * @最后修改人: 猿小天 5 | * @最后修改时间: 2021-08-09 21:51:29 6 | * 联系Qq:1638245306 7 | * @文件介绍: 权限控制 8 | */ 9 | import XEUtils from 'xe-utils' 10 | import router from '@/router' 11 | export default { 12 | hasPermissions (value) { 13 | if (process.env.VUE_APP_PM_ENABLED) { 14 | const path = router.history.current.path// 当前路由 15 | let need = [] 16 | if (typeof value === 'string') { 17 | need.push(value) 18 | } else if (value && value instanceof Array && value.length > 0) { 19 | need = need.concat(value) 20 | } 21 | if (need.length === 0) { 22 | throw new Error('need permissions! Like v-permission="usersphere:user:view" ') 23 | } 24 | // 获取所有的菜单路由(包含权限) 25 | let menuTree = sessionStorage.getItem('menuData') 26 | menuTree = JSON.parse(menuTree) 27 | const userPermissionList = XEUtils.toTreeArray(menuTree) 28 | const permissionList = [] 29 | for (const item of userPermissionList) { 30 | if (item.menuPermission) { 31 | for (const per of item.menuPermission) { 32 | permissionList.push(item.path + ':' + per) 33 | } 34 | } 35 | } 36 | return permissionList.includes(path + ':' + value) 37 | } 38 | return true 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /web/src/plugin/permission/index.js: -------------------------------------------------------------------------------- 1 | import store from '@/store' 2 | 3 | import Vue from 'vue' 4 | import permissionDirective from './directive/permission' 5 | 6 | function isInited () { 7 | if (!isEnabled) { 8 | console.warn('PM is disabled') 9 | return true 10 | } 11 | return store.getters['permission/inited'] 12 | } 13 | 14 | const isEnabled = process.env.VUE_APP_PM_ENABLED === 'true' 15 | // 开启权限模块 16 | if (isEnabled) { 17 | // 注册v-permission指令, 用于控制按钮权限 18 | Vue.use(permissionDirective) 19 | } 20 | 21 | export default { 22 | isEnabled, 23 | isInited 24 | } 25 | -------------------------------------------------------------------------------- /web/src/setting.js: -------------------------------------------------------------------------------- 1 | export default { 2 | // 快捷键 3 | // 支持快捷键 例如 ctrl+shift+s 4 | hotkey: { 5 | search: { 6 | open: 's', 7 | close: 'esc' 8 | } 9 | }, 10 | // 侧边栏默认配置 11 | menu: { 12 | asideCollapse: false, 13 | asideTransition: true 14 | }, 15 | // 在读取持久化数据失败时默认页面 16 | page: { 17 | opened: [ 18 | { 19 | name: 'index', 20 | fullPath: '/index', 21 | meta: { 22 | title: '首页', 23 | auth: false 24 | } 25 | } 26 | ] 27 | }, 28 | // 菜单搜索 29 | search: { 30 | enable: true 31 | }, 32 | // 注册的主题 33 | theme: { 34 | list: [ 35 | { 36 | title: 'd2admin 经典', 37 | name: 'd2', 38 | preview: 'image/theme/d2/preview@2x.png' 39 | }, 40 | { 41 | title: 'Chester', 42 | name: 'chester', 43 | preview: 'image/theme/chester/preview@2x.png' 44 | }, 45 | { 46 | title: 'Element', 47 | name: 'element', 48 | preview: 'image/theme/element/preview@2x.png' 49 | }, 50 | { 51 | title: '紫罗兰', 52 | name: 'violet', 53 | preview: 'image/theme/violet/preview@2x.png' 54 | }, 55 | { 56 | title: '简约线条', 57 | name: 'line', 58 | backgroundImage: 'image/theme/line/bg.jpg', 59 | preview: 'image/theme/line/preview@2x.png' 60 | }, 61 | { 62 | title: '流星', 63 | name: 'star', 64 | backgroundImage: 'image/theme/star/bg.jpg', 65 | preview: 'image/theme/star/preview@2x.png' 66 | }, 67 | { 68 | title: 'Tomorrow Night Blue (vsCode)', 69 | name: 'tomorrow-night-blue', 70 | preview: 'image/theme/tomorrow-night-blue/preview@2x.png' 71 | } 72 | ] 73 | }, 74 | // 是否默认开启页面切换动画 75 | transition: { 76 | active: true 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /web/src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | import d2admin from './modules/d2admin' 5 | 6 | Vue.use(Vuex) 7 | 8 | export default new Vuex.Store({ 9 | modules: { 10 | d2admin 11 | } 12 | }) 13 | -------------------------------------------------------------------------------- /web/src/store/modules/d2admin/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The file enables `@/store/index.js` to import all vuex modules 3 | * in a one-shot manner. There should not be any reason to edit this file. 4 | */ 5 | 6 | const files = require.context('./modules', false, /\.js$/) 7 | const modules = {} 8 | 9 | files.keys().forEach(key => { 10 | modules[key.replace(/(\.\/|\.js)/g, '')] = files(key).default 11 | }) 12 | 13 | export default { 14 | namespaced: true, 15 | modules 16 | } 17 | -------------------------------------------------------------------------------- /web/src/store/modules/d2admin/modules/color.js: -------------------------------------------------------------------------------- 1 | import { cloneDeep } from 'lodash' 2 | import client from 'webpack-theme-color-replacer/client' 3 | import forElementUI from 'webpack-theme-color-replacer/forElementUI' 4 | 5 | export default { 6 | namespaced: true, 7 | state: { 8 | // 颜色 9 | value: process.env.VUE_APP_ELEMENT_COLOR 10 | }, 11 | actions: { 12 | /** 13 | * @description 设置颜色 14 | * @param {Object} context 15 | * @param {String} color 尺寸 16 | */ 17 | async set ({ state, dispatch, commit }, color) { 18 | // 记录上个值 19 | const old = state.value 20 | // store 赋值 21 | state.value = color || process.env.VUE_APP_ELEMENT_COLOR 22 | // 持久化 23 | await dispatch('d2admin/db/set', { 24 | dbName: 'sys', 25 | path: 'color.value', 26 | value: state.value, 27 | user: true 28 | }, { root: true }) 29 | // 应用 30 | commit('apply', { 31 | oldColor: old, 32 | newColor: state.value 33 | }) 34 | }, 35 | /** 36 | * @description 从持久化数据读取颜色设置 37 | * @param {Object} context 38 | */ 39 | async load ({ state, dispatch, commit }) { 40 | // 记录上个值 41 | const old = state.value 42 | // store 赋值 43 | state.value = await dispatch('d2admin/db/get', { 44 | dbName: 'sys', 45 | path: 'color.value', 46 | defaultValue: process.env.VUE_APP_ELEMENT_COLOR, 47 | user: true 48 | }, { root: true }) 49 | // 应用 50 | commit('apply', { 51 | oldColor: old, 52 | newColor: state.value 53 | }) 54 | } 55 | }, 56 | mutations: { 57 | /** 58 | * @description 将 vuex 中的主题颜色设置应用到系统中 59 | * @param {Object} context 60 | * @param {Object} payload oldColor {String} 旧的颜色 61 | * @param {Object} payload newColor {String} 新颜色 62 | */ 63 | apply (state, { oldColor, newColor }) { 64 | var options = { 65 | oldColors: cloneDeep(forElementUI.getElementUISeries(oldColor)), 66 | newColors: cloneDeep(forElementUI.getElementUISeries(newColor)) 67 | } 68 | client.changer.changeColor(options) 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /web/src/store/modules/d2admin/modules/fullscreen.js: -------------------------------------------------------------------------------- 1 | import screenfull from 'screenfull' 2 | 3 | export default { 4 | namespaced: true, 5 | state: { 6 | // 全屏激活 7 | active: false 8 | }, 9 | actions: { 10 | /** 11 | * @description 初始化监听 12 | * @param {Object} context 13 | */ 14 | listen ({ commit }) { 15 | if (screenfull.isEnabled) { 16 | screenfull.on('change', () => { 17 | if (!screenfull.isFullscreen) commit('set', false) 18 | }) 19 | } 20 | }, 21 | /** 22 | * @description 切换全屏 23 | * @param {Object} context 24 | */ 25 | toggle ({ commit }) { 26 | if (screenfull.isFullscreen) { 27 | screenfull.exit() 28 | commit('set', false) 29 | } else { 30 | screenfull.request() 31 | commit('set', true) 32 | } 33 | } 34 | }, 35 | mutations: { 36 | /** 37 | * @description 设置 store 里的全屏状态 38 | * @param {Object} state state 39 | * @param {Boolean} active active 40 | */ 41 | set (state, active) { 42 | state.active = active 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /web/src/store/modules/d2admin/modules/gray.js: -------------------------------------------------------------------------------- 1 | export default { 2 | namespaced: true, 3 | state: { 4 | // 灰度 5 | active: false 6 | }, 7 | mutations: { 8 | /** 9 | * @description 切换灰度状态 10 | * @param {Object} state state 11 | */ 12 | toggle (state) { 13 | state.active = !state.active 14 | }, 15 | /** 16 | * @description 设置灰度模式 17 | * @param {Object} state state 18 | * @param {Boolean} active active 19 | */ 20 | set (state, active) { 21 | state.active = active 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /web/src/store/modules/d2admin/modules/log.js: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs' 2 | import { get } from 'lodash' 3 | import util from '@/libs/util.js' 4 | 5 | export default { 6 | namespaced: true, 7 | state: { 8 | // 错误日志 9 | // + 日志条目的属性 10 | // - message 必须 日志信息 11 | // - type 非必须 类型 success | warning | info(默认) | danger 12 | // - time 必须 日志记录时间 13 | // - meta 非必须 其它携带信息 14 | log: [] 15 | }, 16 | getters: { 17 | /** 18 | * @description 返回现存 log (all) 的条数 19 | * @param {*} state vuex state 20 | */ 21 | length (state) { 22 | return state.log.length 23 | }, 24 | /** 25 | * @description 返回现存 log (error) 的条数 26 | * @param {*} state vuex state 27 | */ 28 | lengthError (state) { 29 | return state.log.filter(log => log.type === 'danger').length 30 | } 31 | }, 32 | actions: { 33 | /** 34 | * @description 添加一个日志 35 | * @param {Object} context 36 | * @param {String} param message {String} 信息 37 | * @param {String} param type {String} 类型 38 | * @param {Object} payload meta {Object} 附带的信息 39 | */ 40 | push ({ rootState, commit }, { message, type = 'info', meta }) { 41 | commit('push', { 42 | message, 43 | type, 44 | time: dayjs().format('YYYY-MM-DD HH:mm:ss'), 45 | meta: { 46 | // 当前用户信息 47 | user: rootState.d2admin.user.info, 48 | // 当前用户的 uuid 49 | uuid: util.cookies.get('uuid'), 50 | // 当前的 token 51 | token: util.cookies.get('token'), 52 | // 当前地址 53 | url: get(window, 'location.href', ''), 54 | // 用户设置 55 | ...meta 56 | } 57 | }) 58 | } 59 | }, 60 | mutations: { 61 | /** 62 | * @description 添加日志 63 | * @param {Object} state state 64 | * @param {Object} log data 65 | */ 66 | push (state, log) { 67 | state.log.push(log) 68 | }, 69 | /** 70 | * @description 清空日志 71 | * @param {Object} state state 72 | */ 73 | clean (state) { 74 | // store 赋值 75 | state.log = [] 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /web/src/store/modules/d2admin/modules/releases.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @创建文件时间: 2021-06-01 22:41:21 3 | * @Auther: 猿小天 4 | * @最后修改人: 猿小天 5 | * @最后修改时间: 2021-07-04 00:54:41 6 | * 联系Qq:1638245306 7 | * @文件介绍: 版本介绍 8 | */ 9 | import util from '@/libs/util.js' 10 | 11 | export default { 12 | namespaced: true, 13 | mutations: { 14 | /** 15 | * @description 显示版本信息 16 | * @param {Object} state state 17 | */ 18 | versionShow () { 19 | util.log.capsule('D2Admin', `v${process.env.VUE_APP_VERSION}`) 20 | console.log('dvAdmin(Gitee) https://gitee.com/liqianglog/django-vue-admin-pro') 21 | console.log('演示地址 http://dvadmin.django.icu/') 22 | console.log('文档地址 暂无') 23 | console.log('请不要吝啬您的 star,谢谢 ~') 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /web/src/store/modules/d2admin/modules/search.js: -------------------------------------------------------------------------------- 1 | import setting from '@/setting.js' 2 | 3 | export default { 4 | namespaced: true, 5 | state: { 6 | // 搜索面板激活状态 7 | active: false, 8 | // 快捷键 9 | hotkey: { 10 | open: setting.hotkey.search.open, 11 | close: setting.hotkey.search.close 12 | }, 13 | // 所有可以搜索的页面 14 | pool: [] 15 | }, 16 | mutations: { 17 | /** 18 | * @description 切换激活状态 19 | * @param {Object} state state 20 | */ 21 | toggle (state) { 22 | state.active = !state.active 23 | }, 24 | /** 25 | * @description 设置激活模式 26 | * @param {Object} state state 27 | * @param {Boolean} active active 28 | */ 29 | set (state, active) { 30 | state.active = active 31 | }, 32 | /** 33 | * @description 初始化 34 | * @param {Object} state state 35 | * @param {Array} menu menu 36 | */ 37 | init (state, menu) { 38 | const pool = [] 39 | const push = function (menu, titlePrefix = []) { 40 | menu.forEach(m => { 41 | if (m.children) { 42 | push(m.children, [...titlePrefix, m.title]) 43 | } else { 44 | pool.push({ 45 | ...m, 46 | fullTitle: [...titlePrefix, m.title].join(' / ') 47 | }) 48 | } 49 | }) 50 | } 51 | push(menu) 52 | state.pool = pool 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /web/src/store/modules/d2admin/modules/size.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import router from '@/router' 3 | 4 | export default { 5 | namespaced: true, 6 | state: { 7 | // 尺寸 8 | value: '' // medium small mini 9 | }, 10 | actions: { 11 | /** 12 | * @description 将当前的设置应用到 element 13 | * @param {Object} context 14 | * @param {Boolean} refresh 是否在设置之后刷新页面 15 | */ 16 | apply ({ state, commit }, refresh) { 17 | Vue.prototype.$ELEMENT.size = state.value 18 | if (refresh) { 19 | commit('d2admin/page/keepAliveClean', null, { root: true }) 20 | router.replace('/refresh') 21 | } 22 | }, 23 | /** 24 | * @description 确认已经加载组件尺寸设置 https://github.com/d2-projects/d2-admin/issues/198 25 | * @param {Object} context 26 | */ 27 | isLoaded ({ state }) { 28 | if (state.value) return Promise.resolve() 29 | return new Promise(resolve => { 30 | const timer = setInterval(() => { 31 | if (state.value) resolve(clearInterval(timer)) 32 | }, 10) 33 | }) 34 | }, 35 | /** 36 | * @description 设置尺寸 37 | * @param {Object} context 38 | * @param {String} size 尺寸 39 | */ 40 | async set ({ state, dispatch }, size) { 41 | // store 赋值 42 | state.value = size 43 | // 应用 44 | dispatch('apply', true) 45 | // 持久化 46 | await dispatch('d2admin/db/set', { 47 | dbName: 'sys', 48 | path: 'size.value', 49 | value: state.value, 50 | user: true 51 | }, { root: true }) 52 | }, 53 | /** 54 | * @description 从持久化数据读取尺寸设置 55 | * @param {Object} context 56 | */ 57 | async load ({ state, dispatch }) { 58 | // store 赋值 59 | state.value = await dispatch('d2admin/db/get', { 60 | dbName: 'sys', 61 | path: 'size.value', 62 | defaultValue: 'default', 63 | user: true 64 | }, { root: true }) 65 | // 应用 66 | dispatch('apply') 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /web/src/store/modules/d2admin/modules/transition.js: -------------------------------------------------------------------------------- 1 | // 设置文件 2 | import setting from '@/setting.js' 3 | 4 | export default { 5 | namespaced: true, 6 | state: { 7 | // 是否开启页面过度动画 8 | active: setting.transition.active 9 | }, 10 | actions: { 11 | /** 12 | * @description 设置开启状态 13 | * @param {Object} context 14 | * @param {Boolean} active 新的状态 15 | */ 16 | async set ({ state, dispatch }, active) { 17 | // store 赋值 18 | state.active = active 19 | // 持久化 20 | await dispatch('d2admin/db/set', { 21 | dbName: 'sys', 22 | path: 'transition.active', 23 | value: state.active, 24 | user: true 25 | }, { root: true }) 26 | }, 27 | /** 28 | * 从数据库读取页面过渡动画设置 29 | * @param {Object} context 30 | */ 31 | async load ({ state, dispatch }) { 32 | // store 赋值 33 | state.active = await dispatch('d2admin/db/get', { 34 | dbName: 'sys', 35 | path: 'transition.active', 36 | defaultValue: setting.transition.active, 37 | user: true 38 | }, { root: true }) 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /web/src/store/modules/d2admin/modules/ua.js: -------------------------------------------------------------------------------- 1 | import UaParser from 'ua-parser-js' 2 | 3 | export default { 4 | namespaced: true, 5 | state: { 6 | // 用户 UA 7 | data: {} 8 | }, 9 | mutations: { 10 | /** 11 | * @description 记录 UA 12 | * @param {Object} state state 13 | */ 14 | get (state) { 15 | state.data = new UaParser().getResult() 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /web/src/store/modules/d2admin/modules/user.js: -------------------------------------------------------------------------------- 1 | export default { 2 | namespaced: true, 3 | state: { 4 | // 用户信息 5 | info: {} 6 | }, 7 | actions: { 8 | /** 9 | * @description 设置用户数据 10 | * @param {Object} context 11 | * @param {*} info info 12 | */ 13 | async set ({ state, dispatch }, info) { 14 | // store 赋值 15 | state.info = info 16 | // 持久化 17 | await dispatch('d2admin/db/set', { 18 | dbName: 'sys', 19 | path: 'user.info', 20 | value: info, 21 | user: true 22 | }, { root: true }) 23 | }, 24 | /** 25 | * @description 从数据库取用户数据 26 | * @param {Object} context 27 | */ 28 | async load ({ state, dispatch }) { 29 | // store 赋值 30 | state.info = await dispatch('d2admin/db/get', { 31 | dbName: 'sys', 32 | path: 'user.info', 33 | defaultValue: {}, 34 | user: true 35 | }, { root: true }) 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /web/src/views/demo/page1/api.js: -------------------------------------------------------------------------------- 1 | import { request } from '@/api/service' 2 | 3 | export function GetList (query) { 4 | return new Promise((resolve) => { 5 | setTimeout(() => { 6 | resolve({ 7 | code: 0, 8 | msg: 'success', 9 | data: { 10 | total: 99, 11 | current: query.current, 12 | size: 20, 13 | records: [ 14 | { id: 1, select1: '1', select2: 'sz,wh' }, 15 | { id: 2, select1: '1', select2: 'sz,sh' }, 16 | { id: 3, select1: '0', select2: 'sz,gz' }, 17 | { id: 4, select1: '1', select2: 'sz' }, 18 | { id: 5, select1: '1', select2: 'sz,sh' }, 19 | { id: 6, select1: '1', select2: 'sz' } 20 | ] 21 | } 22 | }) 23 | }) 24 | }) 25 | } 26 | export function AddObj (obj) { 27 | return request({ 28 | url: '/select/add', 29 | method: 'post', 30 | data: obj 31 | }) 32 | } 33 | 34 | export function UpdateObj (obj) { 35 | return request({ 36 | url: '/select/update', 37 | method: 'post', 38 | data: obj 39 | }) 40 | } 41 | export function DelObj (id) { 42 | return request({ 43 | url: '/select/delete', 44 | method: 'post', 45 | data: { id } 46 | }) 47 | } 48 | export function GetCascadeData () { 49 | return request({ 50 | url: '/select/cascadeData', 51 | method: 'get' 52 | }) 53 | } 54 | -------------------------------------------------------------------------------- /web/src/views/demo/page1/index.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 59 | -------------------------------------------------------------------------------- /web/src/views/demo/page2/api.js: -------------------------------------------------------------------------------- 1 | import { request } from '@/api/service' 2 | 3 | export function GetList (query) { 4 | return new Promise((resolve) => { 5 | setTimeout(() => { 6 | resolve({ 7 | code: 0, 8 | msg: 'success', 9 | data: { 10 | total: 99, 11 | current: query.current, 12 | size: 20, 13 | records: [ 14 | { id: 1, select1: '1', select2: 'sz,wh' }, 15 | { id: 2, select1: '1', select2: 'sz,sh' }, 16 | { id: 3, select1: '0', select2: 'sz,gz' }, 17 | { id: 4, select1: '1', select2: 'sz' }, 18 | { id: 5, select1: '1', select2: 'sz,sh' }, 19 | { id: 6, select1: '1', select2: 'sz' } 20 | ] 21 | } 22 | }) 23 | }) 24 | }) 25 | } 26 | export function AddObj (obj) { 27 | return request({ 28 | url: '/select/add', 29 | method: 'post', 30 | data: obj 31 | }) 32 | } 33 | 34 | export function UpdateObj (obj) { 35 | return request({ 36 | url: '/select/update', 37 | method: 'post', 38 | data: obj 39 | }) 40 | } 41 | export function DelObj (id) { 42 | return request({ 43 | url: '/select/delete', 44 | method: 'post', 45 | data: { id } 46 | }) 47 | } 48 | export function GetCascadeData () { 49 | return request({ 50 | url: '/select/cascadeData', 51 | method: 'get' 52 | }) 53 | } 54 | -------------------------------------------------------------------------------- /web/src/views/demo/page2/crud.js: -------------------------------------------------------------------------------- 1 | export const crudOptions = (vm) => { 2 | return { 3 | pageOptions: { 4 | compact: true 5 | }, 6 | options: { 7 | height: '100%' 8 | }, 9 | viewOptions: { 10 | componentType: 'row' 11 | }, 12 | formOptions: { 13 | defaultSpan: 12 // 默认的表单 span 14 | }, 15 | columns: [ 16 | { 17 | title: 'ID', 18 | key: 'id', 19 | width: 90, 20 | form: { 21 | disabled: true 22 | } 23 | }, 24 | { 25 | title: '单选本地', 26 | key: 'select1', 27 | sortable: true, 28 | search: { 29 | disabled: true 30 | }, 31 | type: 'select', 32 | dict: { 33 | data: [{ value: '1', label: '开启', color: 'success' }, { value: '0', label: '关闭', color: 'danger' }, { value: '2', label: '停止', color: 'info' }] 34 | } 35 | }, 36 | { 37 | title: '多选,本地,自动染色', 38 | key: 'select2', 39 | sortable: true, 40 | width: 180, 41 | search: { 42 | disabled: false, 43 | title: '多选' 44 | }, 45 | type: 'select', 46 | form: { 47 | title: '多选本地', 48 | component: { 49 | props: { 50 | filterable: true, 51 | multiple: true, 52 | clearable: true 53 | } 54 | } 55 | }, 56 | dict: { 57 | data: [{ value: 'sz', label: '深圳' }, { value: 'gz', label: '广州' }, { value: 'wh', label: '武汉' }, { value: 'sh', label: '上海' }] 58 | } 59 | // component: { props: { color: 'auto' } } // install.js 有配置自动染色 60 | } 61 | ] 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /web/src/views/demo/page2/index.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 58 | -------------------------------------------------------------------------------- /web/src/views/demo/page3/api.js: -------------------------------------------------------------------------------- 1 | import { request } from '@/api/service' 2 | 3 | export function GetList (query) { 4 | return new Promise((resolve) => { 5 | setTimeout(() => { 6 | resolve({ 7 | code: 0, 8 | msg: 'success', 9 | data: { 10 | total: 99, 11 | current: query.current, 12 | size: 20, 13 | records: [ 14 | { id: 1, select1: '1', select2: 'sz,wh' }, 15 | { id: 2, select1: '1', select2: 'sz,sh' }, 16 | { id: 3, select1: '0', select2: 'sz,gz' }, 17 | { id: 4, select1: '1', select2: 'sz' }, 18 | { id: 5, select1: '1', select2: 'sz,sh' }, 19 | { id: 6, select1: '1', select2: 'sz' } 20 | ] 21 | } 22 | }) 23 | }) 24 | }) 25 | } 26 | export function AddObj (obj) { 27 | return request({ 28 | url: '/select/add', 29 | method: 'post', 30 | data: obj 31 | }) 32 | } 33 | 34 | export function UpdateObj (obj) { 35 | return request({ 36 | url: '/select/update', 37 | method: 'post', 38 | data: obj 39 | }) 40 | } 41 | export function DelObj (id) { 42 | return request({ 43 | url: '/select/delete', 44 | method: 'post', 45 | data: { id } 46 | }) 47 | } 48 | export function GetCascadeData () { 49 | return request({ 50 | url: '/select/cascadeData', 51 | method: 'get' 52 | }) 53 | } 54 | -------------------------------------------------------------------------------- /web/src/views/demo/page3/crud.js: -------------------------------------------------------------------------------- 1 | export const crudOptions = (vm) => { 2 | return { 3 | pageOptions: { 4 | compact: true 5 | }, 6 | options: { 7 | height: '100%' 8 | }, 9 | viewOptions: { 10 | componentType: 'row' 11 | }, 12 | formOptions: { 13 | defaultSpan: 12 // 默认的表单 span 14 | }, 15 | columns: [ 16 | { 17 | title: 'ID', 18 | key: 'id', 19 | width: 90, 20 | form: { 21 | disabled: true 22 | } 23 | }, 24 | { 25 | title: '单选本地', 26 | key: 'select1', 27 | sortable: true, 28 | search: { 29 | disabled: true 30 | }, 31 | type: 'select', 32 | dict: { 33 | data: [{ value: '1', label: '开启' }, { value: '0', label: '关闭' }, { value: '2', label: '停止' }] 34 | } 35 | }, 36 | { 37 | title: '多选,本地,自动染色', 38 | key: 'select2', 39 | sortable: true, 40 | width: 180, 41 | search: { 42 | disabled: false, 43 | title: '多选' 44 | }, 45 | type: 'select', 46 | form: { 47 | title: '多选本地', 48 | component: { 49 | props: { 50 | filterable: true, 51 | multiple: true, 52 | clearable: true 53 | } 54 | } 55 | }, 56 | dict: { 57 | data: [{ value: 'sz', label: '深圳' }, { value: 'gz', label: '广州' }, { value: 'wh', label: '武汉' }, { value: 'sh', label: '上海' }] 58 | }, 59 | component: { props: { color: 'auto' } } // 自动染色 60 | } 61 | ] 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /web/src/views/demo/page3/index.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 58 | -------------------------------------------------------------------------------- /web/src/views/dvadmin_plugins/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins_market_web": { 3 | "name": "插件市场前端", 4 | "enable": true, 5 | "git": "https://gitee.com/dvadmin/plugins_market_web.git", 6 | "priority": 1, 7 | "tags": "v0.0.1", 8 | "type": "web" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /web/src/views/dvadmin_plugins/index.js: -------------------------------------------------------------------------------- 1 | import PluginsConfig from './config.json' 2 | 3 | export function getPlugins () { 4 | const plugins = {} 5 | for (var key in PluginsConfig) { 6 | if (PluginsConfig[key].enable) { 7 | plugins[key] = PluginsConfig[key] 8 | } 9 | } 10 | return plugins 11 | } 12 | 13 | export const plugins = getPlugins() 14 | 15 | export const dvadminPlugins = async function install (Vue, options) { 16 | for (var key in plugins) { 17 | try { 18 | const Module = await import('@/views/dvadmin_plugins/' + key + '/component/index') 19 | // 注册组件 20 | if (Module.default) { 21 | Vue.use(Module.default) 22 | } 23 | } catch (exception) { 24 | 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /web/src/views/dvadmin_plugins/plugins_market_web/pluginsMarket/api.js: -------------------------------------------------------------------------------- 1 | import { request } from '@/api/service' 2 | export const urlPrefix = '/api/plugins_market/plugins/' 3 | 4 | /** 5 | * 列表查询 6 | */ 7 | export function GetList (query) { 8 | return request({ 9 | url: urlPrefix, 10 | method: 'get', 11 | params: query 12 | }) 13 | } 14 | /** 15 | * 新增 16 | */ 17 | export function createObj (obj) { 18 | return request({ 19 | url: urlPrefix, 20 | method: 'post', 21 | data: obj 22 | }) 23 | } 24 | 25 | /** 26 | * 修改 27 | */ 28 | export function UpdateObj (obj) { 29 | return request({ 30 | url: urlPrefix, 31 | method: 'put', 32 | data: obj 33 | }) 34 | } 35 | /** 36 | * 删除 37 | */ 38 | export function DelObj (obj) { 39 | return request({ 40 | url: urlPrefix, 41 | method: 'delete', 42 | data: obj 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /web/src/views/system/areas/api.js: -------------------------------------------------------------------------------- 1 | import { request } from '@/api/service' 2 | 3 | export const urlPrefix = '/api/system/area/' 4 | 5 | export function GetList (query) { 6 | if (query.pcode === undefined || query.pcode === null || query.pcode.length === 0) { 7 | query.level = 1 8 | } 9 | return request({ 10 | url: urlPrefix, 11 | method: 'get', 12 | params: { ...query, limit: 100 } 13 | }).then(res => { 14 | // 将列表数据转换为树形数据 15 | res.data.data.map(value => { 16 | value.hasChildren = value.pcode_count !== 0 17 | }) 18 | return res 19 | }) 20 | } 21 | 22 | export function AddObj (obj) { 23 | return request({ 24 | url: urlPrefix, 25 | method: 'post', 26 | data: obj 27 | }) 28 | } 29 | 30 | export function UpdateObj (obj) { 31 | return request({ 32 | url: urlPrefix + obj.id + '/', 33 | method: 'put', 34 | data: obj 35 | }) 36 | } 37 | 38 | export function DelObj (id) { 39 | return request({ 40 | url: urlPrefix + id + '/', 41 | method: 'delete', 42 | data: { id } 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /web/src/views/system/areas/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 38 | 39 | 72 | 73 | 80 | -------------------------------------------------------------------------------- /web/src/views/system/button/api.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @创建文件时间: 2021-06-01 22:41:21 3 | * @Auther: 猿小天 4 | * @最后修改人: 猿小天 5 | * @最后修改时间: 2021-07-04 22:39:11 6 | * 联系Qq:1638245306 7 | * @文件介绍: 权限管理接口 8 | */ 9 | import { request } from '@/api/service' 10 | 11 | export const urlPrefix = '/api/system/button/' 12 | 13 | export function GetList (query) { 14 | return request({ 15 | url: urlPrefix, 16 | method: 'get', 17 | data: query 18 | }) 19 | } 20 | export function createObj (obj) { 21 | return request({ 22 | url: urlPrefix, 23 | method: 'post', 24 | data: obj 25 | }) 26 | } 27 | 28 | export function UpdateObj (obj) { 29 | return request({ 30 | url: urlPrefix + obj.id + '/', 31 | method: 'put', 32 | data: obj 33 | }) 34 | } 35 | export function DelObj (id) { 36 | return request({ 37 | url: urlPrefix + id + '/', 38 | method: 'delete', 39 | data: { id } 40 | }) 41 | } 42 | -------------------------------------------------------------------------------- /web/src/views/system/dept/api.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @创建文件时间: 2021-06-01 22:41:21 3 | * @Auther: 猿小天 4 | * @最后修改人: 猿小天 5 | * @最后修改时间: 2021-09-26 21:17:30 6 | * 联系Qq:1638245306 7 | * @文件介绍: 部门管理接口 8 | */ 9 | import { request } from '@/api/service' 10 | import XEUtils from 'xe-utils' 11 | export const urlPrefix = '/api/system/dept/' 12 | 13 | /** 14 | * 列表查询 15 | */ 16 | export function GetList (query) { 17 | query.limit = 999 18 | return request({ 19 | url: urlPrefix, 20 | method: 'get', 21 | params: query 22 | }).then(res => { 23 | // 将列表数据转换为树形数据 24 | res.data.data = XEUtils.toArrayTree(res.data.data, { parentKey: 'parent', strict: false }) 25 | return res 26 | }) 27 | } 28 | /** 29 | * 新增 30 | */ 31 | export function createObj (obj) { 32 | return request({ 33 | url: urlPrefix, 34 | method: 'post', 35 | data: obj 36 | }) 37 | } 38 | 39 | /** 40 | * 修改 41 | */ 42 | export function UpdateObj (obj) { 43 | return request({ 44 | url: urlPrefix + obj.id + '/', 45 | method: 'put', 46 | data: obj 47 | }) 48 | } 49 | /** 50 | * 删除 51 | */ 52 | export function DelObj (id) { 53 | return request({ 54 | url: urlPrefix + id + '/', 55 | method: 'delete', 56 | data: { id } 57 | }) 58 | } 59 | -------------------------------------------------------------------------------- /web/src/views/system/dictionary/api.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @创建文件时间: 2021-06-01 22:41:21 3 | * @Auther: 猿小天 4 | * @最后修改人: 猿小天 5 | * @最后修改时间: 2021-08-09 20:21:47 6 | * 联系Qq:1638245306 7 | * @文件介绍: 字典管理接口 8 | */ 9 | import { request } from '@/api/service' 10 | import XEUtils from 'xe-utils' 11 | export const urlPrefix = '/api/system/dictionary/' 12 | 13 | /** 14 | * 列表查询 15 | */ 16 | export function GetList (query) { 17 | query.limit = 999 18 | return request({ 19 | url: urlPrefix, 20 | method: 'get', 21 | params: query 22 | }).then(res => { 23 | // 将列表数据转换为树形数据 24 | res.data.data = XEUtils.toArrayTree(res.data.data, { parentKey: 'parent' }) 25 | return res 26 | }) 27 | } 28 | /** 29 | * 新增 30 | */ 31 | export function createObj (obj) { 32 | return request({ 33 | url: urlPrefix, 34 | method: 'post', 35 | data: obj 36 | }) 37 | } 38 | 39 | /** 40 | * 修改 41 | */ 42 | export function UpdateObj (obj) { 43 | return request({ 44 | url: urlPrefix + obj.id + '/', 45 | method: 'put', 46 | data: obj 47 | }) 48 | } 49 | /** 50 | * 删除 51 | */ 52 | export function DelObj (id) { 53 | return request({ 54 | url: urlPrefix + id + '/', 55 | method: 'delete', 56 | data: { id } 57 | }) 58 | } 59 | -------------------------------------------------------------------------------- /web/src/views/system/error/404/index.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 25 | -------------------------------------------------------------------------------- /web/src/views/system/fileList/file/api.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @创建文件时间: 2021-08-14 17:37:36 3 | * @Auther: 猿小天 4 | * @最后修改人: 猿小天 5 | * @最后修改时间: 2021-08-14 21:20:16 6 | * 联系Qq:1638245306 7 | * @文件介绍: 文件管理 8 | */ 9 | 10 | import { request } from '@/api/service' 11 | 12 | export const urlPrefix = '/api/system/file/' 13 | 14 | export function GetList (query) { 15 | return request({ 16 | url: urlPrefix, 17 | method: 'get', 18 | params: query 19 | }) 20 | } 21 | 22 | export function AddObj (obj) { 23 | return request({ 24 | url: urlPrefix, 25 | method: 'post', 26 | data: obj 27 | }) 28 | } 29 | 30 | export function UpdateObj (obj) { 31 | return request({ 32 | url: urlPrefix + obj.id + '/', 33 | method: 'put', 34 | data: obj 35 | }) 36 | } 37 | 38 | export function DelObj (id) { 39 | return request({ 40 | url: urlPrefix + id + '/', 41 | method: 'delete', 42 | data: { id } 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /web/src/views/system/fileList/img/api.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @创建文件时间: 2021-08-14 17:37:36 3 | * @Auther: 猿小天 4 | * @最后修改人: 猿小天 5 | * @最后修改时间: 2021-08-14 17:42:58 6 | * 联系Qq:1638245306 7 | * @文件介绍: 图片管理 8 | */ 9 | 10 | import { request } from '@/api/service' 11 | 12 | export const urlPrefix = '/api/system/img/' 13 | 14 | export function GetList (query) { 15 | return request({ 16 | url: urlPrefix, 17 | method: 'get', 18 | params: query 19 | }) 20 | } 21 | 22 | export function AddObj (obj) { 23 | return request({ 24 | url: urlPrefix, 25 | method: 'post', 26 | data: obj 27 | }) 28 | } 29 | 30 | export function UpdateObj (obj) { 31 | return request({ 32 | url: urlPrefix + obj.id + '/', 33 | method: 'put', 34 | data: obj 35 | }) 36 | } 37 | 38 | export function DelObj (id) { 39 | return request({ 40 | url: urlPrefix + id + '/', 41 | method: 'delete', 42 | data: { id } 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /web/src/views/system/function/redirect/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | beforeRouteEnter (to, from, next) { 3 | next(instance => instance.$router.replace(JSON.parse(from.params.route))) 4 | }, 5 | render: h => h() 6 | } 7 | -------------------------------------------------------------------------------- /web/src/views/system/function/refresh/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | beforeRouteEnter (to, from, next) { 3 | from.meta[`__stamp-${from.path}`] = Date.now() 4 | next(instance => instance.$router.replace({ path: from.fullPath, meta: from.meta })) 5 | }, 6 | render: h => h() 7 | } 8 | -------------------------------------------------------------------------------- /web/src/views/system/index/components/d2-badge/index.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 38 | -------------------------------------------------------------------------------- /web/src/views/system/index/components/d2-help-btn/image/d2-help-button@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/src/views/system/index/components/d2-help-btn/image/d2-help-button@2x.png -------------------------------------------------------------------------------- /web/src/views/system/index/components/d2-help-btn/image/qq.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/src/views/system/index/components/d2-help-btn/image/qq.jpg -------------------------------------------------------------------------------- /web/src/views/system/index/components/d2-help-btn/image/we.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/src/views/system/index/components/d2-help-btn/image/we.jpg -------------------------------------------------------------------------------- /web/src/views/system/index/components/d2-help-btn/image/we.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/src/views/system/index/components/d2-help-btn/image/we.png -------------------------------------------------------------------------------- /web/src/views/system/index/components/d2-page-cover/helper.js: -------------------------------------------------------------------------------- 1 | export default { 2 | crud: ` columns: [ 3 | { 4 | title: '日期', //字段名称 5 | key: 'date', //字段key 6 | type: 'date', //字段类型,添加、修改、查询将自动生成相应表单组件 7 | }, 8 | { 9 | title: '状态', 10 | key: 'status', 11 | type: 'select', //选择框,默认单选 12 | dict: { url: '/dicts/OpenStatusEnum' }//远程数据字典 13 | }, 14 | { 15 | title: '地区', 16 | key: 'province', 17 | type: 'select', //选择框 18 | form: { //表单组件自定义配置,此处配置选择框为多选 19 | component: { //支持任何v-model组件 20 | props: { filterable: true, multiple: true, clearable: true } 21 | } 22 | }, 23 | dict: { 24 | data: [ //本地数据字典 25 | { value: 'sz', label: '深圳' }, 26 | { value: 'gz', label: '广州' }, 27 | { value: 'wh', label: '武汉' }, 28 | { value: 'sh', label: '上海' } 29 | ] 30 | } 31 | } 32 | ] 33 | ` 34 | } 35 | -------------------------------------------------------------------------------- /web/src/views/system/index/components/d2-page-cover/image/darkblue@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/src/views/system/index/components/d2-page-cover/image/darkblue@2x.png -------------------------------------------------------------------------------- /web/src/views/system/index/components/d2-page-cover/image/gif.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/src/views/system/index/components/d2-page-cover/image/gif.webp -------------------------------------------------------------------------------- /web/src/views/system/index/image/qr.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/src/views/system/index/image/qr.jpg -------------------------------------------------------------------------------- /web/src/views/system/index/image/qr@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/src/views/system/index/image/qr@2x.png -------------------------------------------------------------------------------- /web/src/views/system/index/index.js: -------------------------------------------------------------------------------- 1 | import page from './page' 2 | 3 | export default page 4 | -------------------------------------------------------------------------------- /web/src/views/system/log/loginLog/api.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @创建文件时间: 2021-06-01 22:41:21 3 | * @Auther: 猿小天 4 | * @最后修改人: 猿小天 5 | * @最后修改时间: 2021-06-06 10:14:14 6 | * 联系Qq:1638245306 7 | * @文件介绍: 用户接口 8 | */ 9 | import { request } from '@/api/service' 10 | 11 | export const urlPrefix = '/api/system/user/' 12 | 13 | export function GetList (query) { 14 | return request({ 15 | url: urlPrefix, 16 | method: 'get', 17 | params: query 18 | }) 19 | } 20 | 21 | export function AddObj (obj) { 22 | return request({ 23 | url: urlPrefix, 24 | method: 'post', 25 | data: obj 26 | }) 27 | } 28 | 29 | export function UpdateObj (obj) { 30 | return request({ 31 | url: urlPrefix + obj.id + '/', 32 | method: 'put', 33 | data: obj 34 | }) 35 | } 36 | 37 | export function DelObj (id) { 38 | return request({ 39 | url: urlPrefix + id + '/', 40 | method: 'delete', 41 | data: { id } 42 | }) 43 | } 44 | -------------------------------------------------------------------------------- /web/src/views/system/log/loginLog/index.vue: -------------------------------------------------------------------------------- 1 | 9 | 40 | 41 | 74 | 75 | 82 | -------------------------------------------------------------------------------- /web/src/views/system/log/operationLog/api.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @创建文件时间: 2021-06-08 10:40:32 3 | * @Auther: 猿小天 4 | * @最后修改人: 猿小天 5 | * @最后修改时间: 2021-06-09 10:36:20 6 | * 联系Qq:1638245306 7 | * @文件介绍: 操作日志 8 | */ 9 | import { request } from '@/api/service' 10 | 11 | export const urlPrefix = '/api/system/operation_log/' 12 | 13 | export function GetList (query) { 14 | return request({ 15 | url: urlPrefix, 16 | method: 'get', 17 | params: query 18 | }) 19 | } 20 | export function AddObj (obj) { 21 | return request({ 22 | url: urlPrefix, 23 | method: 'post', 24 | data: obj 25 | }) 26 | } 27 | 28 | export function UpdateObj (obj) { 29 | return request({ 30 | url: urlPrefix + obj.id + '/', 31 | method: 'put', 32 | data: obj 33 | }) 34 | } 35 | export function DelObj (id) { 36 | return request({ 37 | url: urlPrefix + id + '/', 38 | method: 'delete', 39 | data: { id } 40 | }) 41 | } 42 | -------------------------------------------------------------------------------- /web/src/views/system/log/operationLog/index.vue: -------------------------------------------------------------------------------- 1 | 9 | 39 | 40 | 73 | 74 | 81 | -------------------------------------------------------------------------------- /web/src/views/system/login/api.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @创建文件时间: 2021-06-02 10:33:33 3 | * @Auther: 猿小天 4 | * @最后修改人: 猿小天 5 | * @最后修改时间: 2021-08-12 22:53:38 6 | * 联系Qq:1638245306 7 | * @文件介绍: 登录的接口 8 | */ 9 | 10 | import { request } from '@/api/service' 11 | 12 | export function SYS_USER_LOGIN (data) { 13 | return request({ 14 | url: 'api/login/', 15 | method: 'post', 16 | data 17 | }) 18 | } 19 | 20 | export function getCaptcha () { 21 | return request({ 22 | url: 'api/captcha/', 23 | method: 'get' 24 | }) 25 | } 26 | -------------------------------------------------------------------------------- /web/src/views/system/login/image/dvadmin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/src/views/system/login/image/dvadmin.png -------------------------------------------------------------------------------- /web/src/views/system/login/image/login-code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/src/views/system/login/image/login-code.png -------------------------------------------------------------------------------- /web/src/views/system/login/image/logo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvadmin-pro/django-vue-admin-pro/34a8b8b63844d56a8190c3cbb7057f96f02cfd94/web/src/views/system/login/image/logo@2x.png -------------------------------------------------------------------------------- /web/src/views/system/login/index.js: -------------------------------------------------------------------------------- 1 | import page from './page' 2 | 3 | export default page 4 | -------------------------------------------------------------------------------- /web/src/views/system/menu/api.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @创建文件时间: 2021-06-01 22:41:21 3 | * @Auther: 猿小天 4 | * @最后修改人: 猿小天 5 | * @最后修改时间: 2021-07-29 19:23:33 6 | * 联系Qq:1638245306 7 | * @文件介绍: 菜单管理接口 8 | */ 9 | import { request } from '@/api/service' 10 | import XEUtils from 'xe-utils' 11 | 12 | export const urlPrefix = '/api/system/menu/' 13 | 14 | /** 15 | * 列表查询 16 | */ 17 | export function GetList (query) { 18 | query.limit = 999 19 | return request({ 20 | url: urlPrefix, 21 | method: 'get', 22 | params: { ...query, limit: 999 } 23 | }).then(res => { 24 | // 将列表数据转换为树形数据 25 | res.data.data = XEUtils.toArrayTree(res.data.data, { parentKey: 'parent', strict: false }) 26 | return res 27 | }) 28 | } 29 | 30 | /** 31 | * 新增 32 | */ 33 | export function createObj (obj) { 34 | return request({ 35 | url: urlPrefix, 36 | method: 'post', 37 | data: obj 38 | }) 39 | } 40 | 41 | /** 42 | * 修改 43 | */ 44 | export function UpdateObj (obj) { 45 | return request({ 46 | url: urlPrefix + obj.id + '/', 47 | method: 'put', 48 | data: obj 49 | }) 50 | } 51 | 52 | /** 53 | * 删除 54 | */ 55 | export function DelObj (id) { 56 | return request({ 57 | url: urlPrefix + id + '/', 58 | method: 'delete', 59 | data: { id } 60 | }) 61 | } 62 | -------------------------------------------------------------------------------- /web/src/views/system/menuButton/api.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @创建文件时间: 2021-06-01 22:41:21 3 | * @Auther: 猿小天 4 | * @最后修改人: 猿小天 5 | * @最后修改时间: 2021-06-06 12:25:38 6 | * 联系Qq:1638245306 7 | * @文件介绍: 菜单权限接口 8 | */ 9 | import { request } from '@/api/service' 10 | 11 | export const urlPrefix = '/api/system/menu_button/' 12 | 13 | export function GetList (query) { 14 | return request({ 15 | url: urlPrefix, 16 | method: 'get', 17 | params: query 18 | }) 19 | } 20 | 21 | export function createObj (obj, id) { 22 | const data = { ...obj, menu: id } 23 | return request({ 24 | url: urlPrefix, 25 | method: 'post', 26 | data: data 27 | }) 28 | } 29 | 30 | export function UpdateObj (obj) { 31 | return request({ 32 | url: urlPrefix + obj.id + '/', 33 | method: 'put', 34 | data: obj 35 | }) 36 | } 37 | 38 | export function DelObj (id) { 39 | return request({ 40 | url: urlPrefix + id + '/', 41 | method: 'delete', 42 | data: { id } 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /web/src/views/system/role/api.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @创建文件时间: 2021-06-01 22:41:21 3 | * @Auther: 猿小天 4 | * @最后修改人: 猿小天 5 | * @最后修改时间: 2021-06-05 01:03:36 6 | * 联系Qq:1638245306 7 | * @文件介绍: 角色管理接口 8 | */ 9 | import { request } from '@/api/service' 10 | 11 | export const urlPrefix = '/api/system/role/' 12 | 13 | export function GetList (query) { 14 | return request({ 15 | url: urlPrefix, 16 | method: 'get', 17 | params: query 18 | }) 19 | } 20 | 21 | export function GetObj (obj) { 22 | return request({ 23 | url: urlPrefix + obj.id + '/', 24 | method: 'get' 25 | }) 26 | } 27 | 28 | export function createObj (obj) { 29 | return request({ 30 | url: urlPrefix, 31 | method: 'post', 32 | data: obj 33 | }) 34 | } 35 | 36 | export function UpdateObj (obj) { 37 | return request({ 38 | url: urlPrefix + obj.id + '/', 39 | method: 'put', 40 | data: obj 41 | }) 42 | } 43 | 44 | export function DelObj (id) { 45 | return request({ 46 | url: urlPrefix + id + '/', 47 | method: 'delete', 48 | data: { id } 49 | }) 50 | } 51 | -------------------------------------------------------------------------------- /web/src/views/system/rolePermission/api.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @创建文件时间: 2021-06-01 22:41:21 3 | * @Auther: 猿小天 4 | * @最后修改人: 猿小天 5 | * @最后修改时间: 2021-08-12 16:29:27 6 | * 联系Qq:1638245306 7 | * @文件介绍: 角色管理接口 8 | */ 9 | import { request } from '@/api/service' 10 | 11 | export const urlPrefix = '/api/system/role/' 12 | 13 | export function GetList (query) { 14 | return request({ 15 | url: urlPrefix, 16 | method: 'get', 17 | params: query 18 | }).then(res => { 19 | return res.data.data 20 | }) 21 | } 22 | 23 | export function createObj (obj) { 24 | return request({ 25 | url: urlPrefix, 26 | method: 'post', 27 | data: obj 28 | }) 29 | } 30 | 31 | export function UpdateObj (obj) { 32 | return request({ 33 | url: urlPrefix + obj.id + '/', 34 | method: 'put', 35 | data: obj 36 | }) 37 | } 38 | 39 | export function DelObj (id) { 40 | return request({ 41 | url: urlPrefix + id + '/', 42 | method: 'delete', 43 | data: { id } 44 | }) 45 | } 46 | 47 | // 通过角色id,获取菜单数据 48 | export function GetMenuData (obj) { 49 | return request({ 50 | url: '/api/system/role/role_id_to_menu/' + obj.id + '/', 51 | method: 'get', 52 | params: {} 53 | }).then(res => { 54 | // 将列表数据转换为树形数据 55 | return res.data.data 56 | }) 57 | } 58 | -------------------------------------------------------------------------------- /web/src/views/system/user/api.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @创建文件时间: 2021-06-01 22:41:21 3 | * @Auther: 猿小天 4 | * @最后修改人: 猿小天 5 | * @最后修改时间: 2021-06-06 10:14:14 6 | * 联系Qq:1638245306 7 | * @文件介绍: 用户接口 8 | */ 9 | import { request } from '@/api/service' 10 | 11 | export const urlPrefix = '/api/system/user/' 12 | 13 | export function GetList (query) { 14 | return request({ 15 | url: urlPrefix, 16 | method: 'get', 17 | params: query 18 | }) 19 | } 20 | 21 | export function AddObj (obj) { 22 | return request({ 23 | url: urlPrefix, 24 | method: 'post', 25 | data: obj 26 | }) 27 | } 28 | 29 | export function UpdateObj (obj) { 30 | return request({ 31 | url: urlPrefix + obj.id + '/', 32 | method: 'put', 33 | data: obj 34 | }) 35 | } 36 | 37 | export function DelObj (id) { 38 | return request({ 39 | url: urlPrefix + id + '/', 40 | method: 'delete', 41 | data: { id } 42 | }) 43 | } 44 | -------------------------------------------------------------------------------- /web/tests/unit/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | jest: true 4 | }, 5 | rules: { 6 | 'import/no-extraneous-dependencies': 'off' 7 | } 8 | } --------------------------------------------------------------------------------