初始化项目

pull/22/head
小诺 2020-12-01 20:53:52 +08:00
commit ec222db6f0
707 changed files with 65800 additions and 0 deletions

4
.gitattributes vendored Normal file
View File

@ -0,0 +1,4 @@
*.js linguist-language=java
*.css linguist-language=java
*.html linguist-language=java
*.btl linguist-language=java

45
.gitignore vendored Normal file
View File

@ -0,0 +1,45 @@
# Compiled class file
*.class
*.iml
*.idea
target/
logs/
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.ear
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
*velocity.log*
# Eclipse #
.classpath
.project
.settings/
.DS_Store
_dockerCerts/
.factorypath
node_modules/
dist/
package-lock.json
yarn.lock
rebel.xml

53
LICENSE Normal file
View File

@ -0,0 +1,53 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
You must give any other recipients of the Work or Derivative Works a copy of this License; and
You must cause any modified files to carry prominent notices stating that You changed the files; and
You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

72
README.md Normal file
View File

@ -0,0 +1,72 @@
<p align="center">
<p align="center">
xiaonuo-vue为xiaonuo生态技术框架环境中的vue分离版本<br/>
前后端分离架构,开箱即用,紧随前沿技术<br/>
<br>
<a href="https://www.antdv.com/docs/vue/introduce-cn/">
<img src="https://img.shields.io/badge/vue--ant--design-2.1.0-blue.svg" alt="bootstrap">
</a>
+
<a href="http://spring.io/projects/spring-boot">
<img src="https://img.shields.io/badge/spring--boot-2.3.1-green.svg" alt="spring-boot">
</a>
<a href="http://mp.baomidou.com">
<img src="https://img.shields.io/badge/mybatis--plus-3.3.2-blue.svg" alt="mybatis-plus">
</a>
</p>
</p>
#框架说明
#### 利用空闲时间纯手研发搭建框架脚手架,在自己用的时候,也为各位小伙伴打下坚固的接私活利器。后续我们会发多个版本,并且根据多年经验会出相关系统中用到的案例,提供给大家使用!
#### 当然、如需了解我们更多请移步官网https://xiaonuo.vip
### 在线演示
* 账号密码superAdmin/123456地址https://www.xiaonuo.vip:81
* 注意:因服务器数量暂少,演示环境必须加端口访问
### 框架优势
1. 模块化架构设计,层次清晰,业务层推荐写到单独模块,方便升级。
2. 前后端分离架构,分离开发,分离部署,前后端互不影响。
3. 前端技术采用vue + antdvPro + axios。
3. 后端采用spring boot + mybatis-plus + hutool等开源可靠。
4. 基于spring security(jwt) + 用户UUID双重认证。
5. 基于AOP实现的接口粒度的鉴权最细粒度过滤权限资源。
6. 基于hibernate validator实现的校验框架支持自定义校验注解。
7. 提供Request-No的响应header快速定位线上异常问题。
8. 在线用户可查,可在线踢人,同账号登录可同时在线,可单独在线(通过系统参数配置)。
9. 支持前端 + 后端在线代码生成(后续开放)。
10. 支持jenkins一键部署另自带docker maven插件支持docker部署。
11. 文件,短信,缓存,邮件等,利用接口封装,方便拓展。
12. 文件默认使用本地文件短信默认使用阿里云sms缓存默认使用内存缓存。
### 功能介绍
1. 主控面板。控制台页面,可进行工作台,分析页,统计等功能的展示。
2. 用户管理。对企业用户和系统管理员用户的维护,可绑定用户职务,机构,角色,数据权限等。
3. 应用管理。通过应用来控制不同维度的菜单展示。
4. 机构管理。公司组织架构维护,支持多层级结构的树形结构。
5. 职位管理。用户职务管理,职务可作为用户的一个标签,职务目前没有和权限等其他功能挂钩。
6. 菜单管理。菜单目录,菜单,和按钮的维护是权限控制的基本单位。
7. 角色管理。角色绑定菜单后,可限制相关角色的人员登录系统的功能范围。角色也可以绑定数据授权范围。
8. 字典管理。系统内各种枚举类型的维护。
9. 访问日志。用户的登录和退出日志的查看和管理。
10. 操作日志。用户的操作业务的日志的查看和管理。
11. 服务监控。服务器的运行状态Java虚拟机信息jvm等数据的查看。
12. 在线用户。当前系统在线用户的查看。
13. 数据监控。druid控制台功能可查看sql的运行信息。
14. 公告管理。系统的公告的管理。
15. 文件管理。文件的上传下载查看等操作文件可使用本地存储阿里云oss腾讯cos接入支持拓展。
16. 定时任务。定时任务的维护通过cron表达式控制任务的执行频率。
17. 系统配置。系统运行的参数的维护,参数的配置与系统运行机制息息相关。
18. 邮件发送。发送邮件功能。
19. 短信发送。短信发送功能可使用阿里云sms腾讯云sms支持拓展。
### XiaoNuo技术团队荣誉作品
| 成员组成 | 负责内容 |
| :---: | :---: |
| 俞宝山 | 全栈 |
| 徐玉祥 | 全栈 |

1296
_sql/xiaonuo-vue-pub.sql Normal file

File diff suppressed because one or more lines are too long

3
_web/.browserslistrc Normal file
View File

@ -0,0 +1,3 @@
> 1%
last 2 versions
not ie <= 10

39
_web/.editorconfig Normal file
View File

@ -0,0 +1,39 @@
[*]
charset=utf-8
end_of_line=lf
insert_final_newline=false
indent_style=space
indent_size=2
[{*.ng,*.sht,*.html,*.shtm,*.shtml,*.htm}]
indent_style=space
indent_size=2
[{*.jhm,*.xslt,*.xul,*.rng,*.xsl,*.xsd,*.ant,*.tld,*.fxml,*.jrxml,*.xml,*.jnlp,*.wsdl}]
indent_style=space
indent_size=2
[{.babelrc,.stylelintrc,jest.config,.eslintrc,.prettierrc,*.json,*.jsb3,*.jsb2,*.bowerrc}]
indent_style=space
indent_size=2
[*.svg]
indent_style=space
indent_size=2
[*.js.map]
indent_style=space
indent_size=2
[*.less]
indent_style=space
indent_size=2
[*.vue]
indent_style=space
indent_size=2
[{.analysis_options,*.yml,*.yaml}]
indent_style=space
indent_size=2

3
_web/.env Normal file
View File

@ -0,0 +1,3 @@
NODE_ENV=production
VUE_APP_PREVIEW=true
VUE_APP_API_BASE_URL=http://www.xiaonuo.vip:82

3
_web/.env.development Normal file
View File

@ -0,0 +1,3 @@
NODE_ENV=development
VUE_APP_PREVIEW=true
VUE_APP_API_BASE_URL=http://www.xiaonuo.vip:82

3
_web/.env.preview Normal file
View File

@ -0,0 +1,3 @@
NODE_ENV=production
VUE_APP_PREVIEW=false
VUE_APP_API_BASE_URL=http://www.xiaonuo.vip:82

75
_web/.eslintrc.js Normal file
View File

@ -0,0 +1,75 @@
module.exports = {
root: true,
env: {
node: true
},
'extends': [
'plugin:vue/strongly-recommended',
'@vue/standard'
],
rules: {
'no-console': 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'generator-star-spacing': 'off',
'no-mixed-operators': 0,
'vue/max-attributes-per-line': [
2,
{
'singleline': 5,
'multiline': {
'max': 1,
'allowFirstLine': false
}
}
],
'vue/attribute-hyphenation': 0,
'vue/html-self-closing': 0,
'vue/component-name-in-template-casing': 0,
'vue/html-closing-bracket-spacing': 0,
'vue/singleline-html-element-content-newline': 0,
'vue/no-unused-components': 0,
'vue/multiline-html-element-content-newline': 0,
'vue/no-use-v-if-with-v-for': 0,
'vue/html-closing-bracket-newline': 0,
'vue/no-parsing-error': 0,
'no-tabs': 0,
'quotes': [
2,
'single',
{
'avoidEscape': true,
'allowTemplateLiterals': true
}
],
'semi': [
2,
'never',
{
'beforeStatementContinuationChars': 'never'
}
],
'no-delete-var': 2,
'prefer-const': [
2,
{
'ignoreReadBeforeAssign': false
}
],
'template-curly-spacing': 'off',
'indent': 'off'
},
parserOptions: {
parser: 'babel-eslint'
},
overrides: [
{
files: [
'**/__tests__/*.{j,t}s?(x)',
'**/tests/unit/**/*.spec.{j,t}s?(x)'
],
env: {
jest: true
}
}
]
}

3
_web/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
node_modules/
dist/
.idea/

5
_web/.prettierrc Normal file
View File

@ -0,0 +1,5 @@
{
"printWidth": 120,
"semi": false,
"singleQuote": true
}

7
_web/.travis.yml Normal file
View File

@ -0,0 +1,7 @@
language: node_js
node_js:
- 10.15.0
cache: yarn
script:
- yarn
- yarn run lint --no-fix && yarn run build

21
_web/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Anan Yang
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

28
_web/babel.config.js Normal file
View File

@ -0,0 +1,28 @@
const IS_PROD = ['production', 'prod'].includes(process.env.NODE_ENV)
const plugins = []
if (IS_PROD) {
plugins.push('transform-remove-console')
}
// lazy load ant-design-vue
// if your use import on Demand, Use this code
plugins.push(['import', {
'libraryName': 'ant-design-vue',
'libraryDirectory': 'es',
'style': true // `style: true` 会加载 less 文件
}])
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset',
[
'@babel/preset-env',
{
'useBuiltIns': 'entry',
'corejs': 3
}
]
],
plugins
}

View File

@ -0,0 +1,46 @@
const ThemeColorReplacer = require('webpack-theme-color-replacer')
const generate = require('@ant-design/colors/lib/generate').default
const getAntdSerials = (color) => {
// 淡化即less的tint
const lightens = new Array(9).fill().map((t, i) => {
return ThemeColorReplacer.varyColor.lighten(color, i / 10)
})
const colorPalettes = generate(color)
const rgb = ThemeColorReplacer.varyColor.toNum3(color.replace('#', '')).join(',')
return lightens.concat(colorPalettes).concat(rgb)
}
const themePluginOption = {
fileName: 'css/theme-colors-[contenthash:8].css',
matchColors: getAntdSerials('#1890ff'), // 主色系列
// 改变样式选择器,解决样式覆盖问题
changeSelector (selector) {
switch (selector) {
case '.ant-calendar-today .ant-calendar-date':
return ':not(.ant-calendar-selected-date):not(.ant-calendar-selected-day)' + selector
case '.ant-btn:focus,.ant-btn:hover':
return '.ant-btn:focus:not(.ant-btn-primary):not(.ant-btn-danger),.ant-btn:hover:not(.ant-btn-primary):not(.ant-btn-danger)'
case '.ant-btn.active,.ant-btn:active':
return '.ant-btn.active:not(.ant-btn-primary):not(.ant-btn-danger),.ant-btn:active:not(.ant-btn-primary):not(.ant-btn-danger)'
case '.ant-steps-item-process .ant-steps-item-icon > .ant-steps-icon':
case '.ant-steps-item-process .ant-steps-item-icon>.ant-steps-icon':
return ':not(.ant-steps-item-process)' + selector
case '.ant-menu-horizontal>.ant-menu-item-active,.ant-menu-horizontal>.ant-menu-item-open,.ant-menu-horizontal>.ant-menu-item-selected,.ant-menu-horizontal>.ant-menu-item:hover,.ant-menu-horizontal>.ant-menu-submenu-active,.ant-menu-horizontal>.ant-menu-submenu-open,.ant-menu-horizontal>.ant-menu-submenu-selected,.ant-menu-horizontal>.ant-menu-submenu:hover':
case '.ant-menu-horizontal > .ant-menu-item-active,.ant-menu-horizontal > .ant-menu-item-open,.ant-menu-horizontal > .ant-menu-item-selected,.ant-menu-horizontal > .ant-menu-item:hover,.ant-menu-horizontal > .ant-menu-submenu-active,.ant-menu-horizontal > .ant-menu-submenu-open,.ant-menu-horizontal > .ant-menu-submenu-selected,.ant-menu-horizontal > .ant-menu-submenu:hover':
return '.ant-menu-horizontal > .ant-menu-item-active,.ant-menu-horizontal > .ant-menu-item-open,.ant-menu-horizontal > .ant-menu-item-selected,.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-item:hover,.ant-menu-horizontal > .ant-menu-submenu-active,.ant-menu-horizontal > .ant-menu-submenu-open,.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-submenu-selected,.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-submenu:hover'
case '.ant-menu-horizontal > .ant-menu-item-selected > a':
case '.ant-menu-horizontal>.ant-menu-item-selected>a':
return '.ant-menu-horizontal:not(ant-menu-light):not(.ant-menu-dark) > .ant-menu-item-selected > a'
case '.ant-menu-horizontal > .ant-menu-item > a:hover':
case '.ant-menu-horizontal>.ant-menu-item>a:hover':
return '.ant-menu-horizontal:not(ant-menu-light):not(.ant-menu-dark) > .ant-menu-item > a:hover'
default :
return selector
}
}
}
const createThemeColorReplacerPlugin = () => new ThemeColorReplacer(themePluginOption)
module.exports = createThemeColorReplacerPlugin

23
_web/jest.config.js Normal file
View File

@ -0,0 +1,23 @@
module.exports = {
moduleFileExtensions: [
'js',
'jsx',
'json',
'vue'
],
transform: {
'^.+\\.vue$': 'vue-jest',
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',
'^.+\\.jsx?$': 'babel-jest'
},
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1'
},
snapshotSerializers: [
'jest-serializer-vue'
],
testMatch: [
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
],
testURL: 'http://localhost/'
}

11
_web/jsconfig.json Normal file
View File

@ -0,0 +1,11 @@
{
"compilerOptions": {
"target": "es6",
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"exclude": ["node_modules", "dist"],
"include": ["src/**/*"]
}

84
_web/package.json Normal file
View File

@ -0,0 +1,84 @@
{
"name": "vue-antd-pro",
"version": "2.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"test:unit": "vue-cli-service test:unit",
"build:preview": "vue-cli-service build --mode preview",
"postinstall": "opencollective-postinstall"
},
"dependencies": {
"@antv/data-set": "^0.10.2",
"ant-design-vue": "1.5.0-rc.6",
"axios": "^0.19.0",
"babel-polyfill": "^6.26.0",
"clipboard": "^2.0.6",
"core-js": "^3.1.2",
"default-passive-events": "^1.0.10",
"enquire.js": "^2.1.6",
"font-awesome": "^4.7.0",
"jquery": "^3.5.1",
"lodash.clonedeep": "^4.5.0",
"lodash.get": "^4.4.2",
"lodash.pick": "^4.4.0",
"md5": "^2.2.1",
"mockjs2": "1.0.8",
"moment": "^2.24.0",
"nprogress": "^0.2.0",
"print-js": "^1.0.63",
"raphael": "^2.3.0",
"viser-vue": "^2.4.6",
"vue": "^2.6.10",
"vue-clipboard2": "^0.2.1",
"vue-codemirror-lite": "^1.0.4",
"vue-cropper": "0.4.9",
"vue-ls": "^3.2.1",
"vue-quill-editor": "^3.0.6",
"vue-router": "^3.1.2",
"vue-svg-component-runtime": "^1.0.1",
"vuedraggable": "^2.23.2",
"vuex": "^3.1.1",
"wangeditor": "^3.1.1"
},
"devDependencies": {
"@ant-design/colors": "^3.2.1",
"@vue/cli-plugin-babel": "^4.0.4",
"@vue/cli-plugin-eslint": "^4.0.4",
"@vue/cli-plugin-router": "^4.0.4",
"@vue/cli-plugin-unit-jest": "^4.0.4",
"@vue/cli-plugin-vuex": "^4.0.4",
"@vue/cli-service": "^4.0.4",
"@vue/eslint-config-prettier": "^5.0.0",
"@vue/eslint-config-standard": "^4.0.0",
"@vue/test-utils": "^1.0.0-beta.29",
"babel-eslint": "^10.0.1",
"babel-plugin-import": "^1.13.0",
"babel-plugin-transform-remove-console": "^6.9.4",
"eslint": "^6.8.0",
"eslint-plugin-html": "^5.0.0",
"eslint-plugin-prettier": "^3.1.0",
"eslint-plugin-vue": "^5.2.3",
"less": "^3.0.4",
"less-loader": "^5.0.0",
"opencollective": "^1.0.3",
"opencollective-postinstall": "^2.0.2",
"prettier": "^1.18.2",
"vue-svg-icon-loader": "^2.1.1",
"vue-template-compiler": "^2.6.10",
"webpack-theme-color-replacer": "^1.2.17"
},
"collective": {
"type": "opencollective",
"url": "https://opencollective.com/ant-design-pro-vue"
},
"main": ".eslintrc.js",
"directories": {
"test": "tests"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": ""
}

5
_web/postcss.config.js Normal file
View File

@ -0,0 +1,5 @@
module.exports = {
plugins: {
autoprefixer: {}
}
}

BIN
_web/public/avatar2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

34
_web/public/index.html Normal file
View File

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>logo.png">
<title>XiaoNuo</title>
<style>.first-loading-wrp{display:flex;justify-content:center;align-items:center;flex-direction:column;min-height:420px;height:100%}.first-loading-wrp>h1{font-size:128px}.first-loading-wrp .loading-wrp{padding:98px;display:flex;justify-content:center;align-items:center}.dot{animation:antRotate 1.2s infinite linear;transform:rotate(45deg);position:relative;display:inline-block;font-size:32px;width:32px;height:32px;box-sizing:border-box}.dot i{width:14px;height:14px;position:absolute;display:block;background-color:#1890ff;border-radius:100%;transform:scale(.75);transform-origin:50% 50%;opacity:.3;animation:antSpinMove 1s infinite linear alternate}.dot i:nth-child(1){top:0;left:0}.dot i:nth-child(2){top:0;right:0;-webkit-animation-delay:.4s;animation-delay:.4s}.dot i:nth-child(3){right:0;bottom:0;-webkit-animation-delay:.8s;animation-delay:.8s}.dot i:nth-child(4){bottom:0;left:0;-webkit-animation-delay:1.2s;animation-delay:1.2s}@keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@-webkit-keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@keyframes antSpinMove{to{opacity:1}}@-webkit-keyframes antSpinMove{to{opacity:1}}</style>
<!-- require cdn assets css -->
<% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %>
<link rel="stylesheet" href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" />
<% } %>
</head>
<body>
<noscript>
<strong>We're sorry but vue-antd-pro doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app">
<div class="first-loading-wrp">
<h1>XiaoNuo</h1>
<div class="loading-wrp">
<span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
</div>
<div style="display: flex; justify-content: center; align-items: center;">XiaoNuo</div>
</div>
</div>
<!-- require cdn assets js -->
<% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>
<script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
<% } %>
<!-- built files will be auto injected -->
</body>
</html>

View File

@ -0,0 +1 @@
#preloadingAnimation{position:fixed;left:0;top:0;height:100%;width:100%;background:#ffffff;user-select:none;z-index: 9999;overflow: hidden}.lds-roller{display:inline-block;position:relative;left:50%;top:50%;transform:translate(-50%,-50%);width:64px;height:64px;}.lds-roller div{animation:lds-roller 1.2s cubic-bezier(0.5,0,0.5,1) infinite;transform-origin:32px 32px;}.lds-roller div:after{content:" ";display:block;position:absolute;width:6px;height:6px;border-radius:50%;background:#13c2c2;margin:-3px 0 0 -3px;}.lds-roller div:nth-child(1){animation-delay:-0.036s;}.lds-roller div:nth-child(1):after{top:50px;left:50px;}.lds-roller div:nth-child(2){animation-delay:-0.072s;}.lds-roller div:nth-child(2):after{top:54px;left:45px;}.lds-roller div:nth-child(3){animation-delay:-0.108s;}.lds-roller div:nth-child(3):after{top:57px;left:39px;}.lds-roller div:nth-child(4){animation-delay:-0.144s;}.lds-roller div:nth-child(4):after{top:58px;left:32px;}.lds-roller div:nth-child(5){animation-delay:-0.18s;}.lds-roller div:nth-child(5):after{top:57px;left:25px;}.lds-roller div:nth-child(6){animation-delay:-0.216s;}.lds-roller div:nth-child(6):after{top:54px;left:19px;}.lds-roller div:nth-child(7){animation-delay:-0.252s;}.lds-roller div:nth-child(7):after{top:50px;left:14px;}.lds-roller div:nth-child(8){animation-delay:-0.288s;}.lds-roller div:nth-child(8):after{top:45px;left:10px;}#preloadingAnimation .load-tips{color: #13c2c2;font-size:2rem;position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);margin-top:80px;text-align:center;width:400px;height:64px;} @keyframes lds-roller{0%{transform:rotate(0deg);} 100%{transform:rotate(360deg);}}

View File

@ -0,0 +1 @@
<div id="preloadingAnimation"><div class=lds-roller><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div></div><div class=load-tips>Loading</div></div>

View File

@ -0,0 +1,5 @@
<div class="preloading-animate">
<div class="preloading-wrapper">
<svg class="preloading-balls" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid"><circle cx="67.802" cy="59.907" r="6" fill="#51CACC"><animate attributeName="cx" values="75;57.72542485937369" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="cy" values="50;73.77641290737884" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="fill" values="#51CACC;#9DF871" keyTimes="0;1" dur="1s" repeatCount="indefinite"/></circle><circle cx="46.079" cy="69.992" r="6" fill="#9DF871"><animate attributeName="cx" values="57.72542485937369;29.774575140626318" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="cy" values="73.77641290737884;64.69463130731182" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="fill" values="#9DF871;#E0FF77" keyTimes="0;1" dur="1s" repeatCount="indefinite"/></circle><circle cx="29.775" cy="52.449" r="6" fill="#E0FF77"><animate attributeName="cx" values="29.774575140626318;29.774575140626315" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="cy" values="64.69463130731182;35.30536869268818" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="fill" values="#E0FF77;#DE9DD6" keyTimes="0;1" dur="1s" repeatCount="indefinite"/></circle><circle cx="41.421" cy="31.521" r="6" fill="#DE9DD6"><animate attributeName="cx" values="29.774575140626315;57.72542485937368" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="cy" values="35.30536869268818;26.22358709262116" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="fill" values="#DE9DD6;#FF708E" keyTimes="0;1" dur="1s" repeatCount="indefinite"/></circle><circle cx="64.923" cy="36.13" r="6" fill="#FF708E"><animate attributeName="cx" values="57.72542485937368;75" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="cy" values="26.22358709262116;49.99999999999999" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="fill" values="#FF708E;#51CACC" keyTimes="0;1" dur="1s" repeatCount="indefinite"/></circle></svg>
</div>
</div>

View File

@ -0,0 +1 @@
.preloading-animate{background:#ffffff;width:100%;height:100%;position:fixed;left:0;top:0;z-index:299;}.preloading-animate .preloading-wrapper{position:absolute;width:5rem;height:5rem;left:50%;top:50%;transform:translate(-50%,-50%);}.preloading-animate .preloading-wrapper .preloading-balls{font-size:5rem;}

View File

@ -0,0 +1 @@
<svg class="preloading-balls" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid"><circle cx="67.802" cy="59.907" r="6" fill="#51CACC"><animate attributeName="cx" values="75;57.72542485937369" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="cy" values="50;73.77641290737884" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="fill" values="#51CACC;#9DF871" keyTimes="0;1" dur="1s" repeatCount="indefinite"/></circle><circle cx="46.079" cy="69.992" r="6" fill="#9DF871"><animate attributeName="cx" values="57.72542485937369;29.774575140626318" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="cy" values="73.77641290737884;64.69463130731182" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="fill" values="#9DF871;#E0FF77" keyTimes="0;1" dur="1s" repeatCount="indefinite"/></circle><circle cx="29.775" cy="52.449" r="6" fill="#E0FF77"><animate attributeName="cx" values="29.774575140626318;29.774575140626315" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="cy" values="64.69463130731182;35.30536869268818" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="fill" values="#E0FF77;#DE9DD6" keyTimes="0;1" dur="1s" repeatCount="indefinite"/></circle><circle cx="41.421" cy="31.521" r="6" fill="#DE9DD6"><animate attributeName="cx" values="29.774575140626315;57.72542485937368" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="cy" values="35.30536869268818;26.22358709262116" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="fill" values="#DE9DD6;#FF708E" keyTimes="0;1" dur="1s" repeatCount="indefinite"/></circle><circle cx="64.923" cy="36.13" r="6" fill="#FF708E"><animate attributeName="cx" values="57.72542485937368;75" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="cy" values="26.22358709262116;49.99999999999999" keyTimes="0;1" dur="1s" repeatCount="indefinite"/><animate attributeName="fill" values="#FF708E;#51CACC" keyTimes="0;1" dur="1s" repeatCount="indefinite"/></circle></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
_web/public/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

24
_web/src/App.vue Normal file
View File

@ -0,0 +1,24 @@
<template>
<a-config-provider :locale="locale">
<div id="app">
<router-view/>
</div>
</a-config-provider>
</template>
<script>
import zhCN from 'ant-design-vue/lib/locale-provider/zh_CN'
import { AppDeviceEnquire } from '@/utils/mixin'
export default {
mixins: [AppDeviceEnquire],
data () {
return {
locale: zhCN
}
},
mounted () {
}
}
</script>

View File

@ -0,0 +1 @@
/** 您的业务接口文件全写在此文件夹下面,升级底座直接迁移代码即可 **/

View File

@ -0,0 +1 @@
/** 此文件夹下代码尽量不要动,底座升级直接覆盖替换 **/

View File

@ -0,0 +1,92 @@
/**
*
*
* @author yubaoshan
* @date 202042312:10:57
*/
import { axios } from '@/utils/request'
/**
*
*
* @author yubaoshan
* @date 20207915:05:01
*/
export function getAppPage (parameter) {
return axios({
url: '/sysApp/page',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 20207915:05:01
*/
export function getAppList (parameter) {
return axios({
url: '/sysApp/list',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 20207915:05:01
*/
export function sysAppAdd (parameter) {
return axios({
url: '/sysApp/add',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @param parameter
* @returns {*}
*/
export function sysAppEdit (parameter) {
return axios({
url: '/sysApp/edit',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 20207915:05:01
*/
export function sysAppDelete (parameter) {
return axios({
url: '/sysApp/delete',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 20207915:05:01
*/
export function sysAppSetAsDefault (parameter) {
return axios({
url: '/sysApp/setAsDefault',
method: 'post',
data: parameter
})
}

View File

@ -0,0 +1,85 @@
import { axios } from '@/utils/request'
/**
*
*
* @author yubaoshan
* @date 2020/5/25 01:57
*/
export function sysConfigPage (parameter) {
return axios({
url: '/sysConfig/page',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/25 01:57
*/
export function sysConfigAdd (parameter) {
return axios({
url: '/sysConfig/add',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/25 01:57
*/
export function sysConfigEdit (parameter) {
return axios({
url: '/sysConfig/edit',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/25 01:57
*/
export function sysConfigDelete (parameter) {
return axios({
url: '/sysConfig/delete',
method: 'post',
data: parameter
})
}
/**
* [{code:"M",value:"男"},{code:"F",value:"女"}]
*
* @author yubaoshan
* @date 2020/5/25 02:06
*/
export function sysDictTypeDropDown (parameter) {
return axios({
url: '/sysDictType/dropDown',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/7/8 20:46
*/
export function sysTimersGetActionClasses (parameter) {
return axios({
url: '/sysTimers/getActionClasses',
method: 'get',
params: parameter
})
}

View File

@ -0,0 +1,57 @@
import { axios } from '@/utils/request'
/**
*
*
* @author yubaoshan
* @date 2020/5/17 02:24
*/
export function sysDictDataPage (parameter) {
return axios({
url: '/sysDictData/page',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/17 02:24
*/
export function sysDictDataAdd (parameter) {
return axios({
url: '/sysDictData/add',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/17 02:25
*/
export function sysDictDataEdit (parameter) {
return axios({
url: '/sysDictData/edit',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/17 02:25
*/
export function sysDictDataDelete (parameter) {
return axios({
url: '/sysDictData/delete',
method: 'post',
data: parameter
})
}

View File

@ -0,0 +1,85 @@
import { axios } from '@/utils/request'
/**
*
*
* @author yubaoshan
* @date 2020/5/17 01:46
*/
export function sysDictTypePage (parameter) {
return axios({
url: '/sysDictType/page',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/17 01:46
*/
export function sysDictTypeAdd (parameter) {
return axios({
url: '/sysDictType/add',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/17 01:50
*/
export function sysDictTypeEdit (parameter) {
return axios({
url: '/sysDictType/edit',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/17 01:50
*/
export function sysDictTypeDelete (parameter) {
return axios({
url: '/sysDictType/delete',
method: 'post',
data: parameter
})
}
/**
* [{code:"M",value:"男"},{code:"F",value:"女"}]
*
* @author yubaoshan
* @date 2020/6/10 00:10
*/
export function sysDictTypeDropDown (parameter) {
return axios({
url: '/sysDictType/dropDown',
method: 'get',
params: parameter
})
}
/**
* 使
*
* @author yubaoshan
* @date 2020/6/10 00:10
*/
export function sysDictTypeTree (parameter) {
return axios({
url: '/sysDictType/tree',
method: 'get',
params: parameter
})
}

View File

@ -0,0 +1,29 @@
import { axios } from '@/utils/request'
/**
*
*
* @author yubaoshan
* @date 2020/7/3 23:22
*/
export function emailSendEmail (parameter) {
return axios({
url: '/email/sendEmail',
method: 'post',
data: parameter
})
}
/**
* html
*
* @author yubaoshan
* @date 2020/7/3 23:23
*/
export function emailSendEmailHtml (parameter) {
return axios({
url: '/email/sendEmailHtml',
method: 'post',
data: parameter
})
}

View File

@ -0,0 +1,101 @@
import { axios } from '@/utils/request'
/**
*
*
* @author yubaoshan
* @date 2020/6/30 00:20
*/
export function sysFileInfoPage (parameter) {
return axios({
url: '/sysFileInfo/page',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/6/30 00:20
*/
export function sysFileInfoList (parameter) {
return axios({
url: '/sysFileInfo/list',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/6/30 00:20
*/
export function sysFileInfoUpload (parameter) {
return axios({
url: '/sysFileInfo/upload',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/6/30 00:20
*/
export function sysFileInfoDownload (parameter) {
return axios({
url: '/sysFileInfo/download',
method: 'get',
params: parameter,
responseType: 'blob'
})
}
/**
*
*
* @author yubaoshan
* @date 2020/6/30 00:20
*/
export function sysFileInfoPreview (parameter) {
return axios({
url: '/sysFileInfo/preview',
method: 'get',
params: parameter,
responseType: 'arraybuffer'
})
}
/**
*
*
* @author yubaoshan
* @date 2020/6/30 00:20
*/
export function sysFileInfoDetail (parameter) {
return axios({
url: '/sysFileInfo/detail',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/6/30 00:20
*/
export function sysFileInfoDelete (parameter) {
return axios({
url: '/sysFileInfo/delete',
method: 'post',
data: parameter
})
}

View File

@ -0,0 +1,57 @@
import { axios } from '@/utils/request'
/**
* 访
*
* @author yubaoshan
* @date 2020/5/19 11:57
*/
export function sysVisLogPage (parameter) {
return axios({
url: '/sysVisLog/page',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/19 11:57
*/
export function sysOpLogPage (parameter) {
return axios({
url: '/sysOpLog/page',
method: 'get',
params: parameter
})
}
/**
* 访
*
* @author yubaoshan
* @date 2020/6/23 23:09
*/
export function sysVisLogDelete (parameter) {
return axios({
url: '/sysVisLog/delete',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/6/23 23:09
*/
export function sysOpLogDelete (parameter) {
return axios({
url: '/sysOpLog/delete',
method: 'post',
data: parameter
})
}

View File

@ -0,0 +1,77 @@
/**
*
*
* @author yubaoshan
* @date 2020/5/26 19:06
*/
import { axios } from '@/utils/request'
/**
*
*
* @author yubaoshan
* @date 2020/5/26 19:06
*/
export function login (parameter) {
return axios({
url: '/login',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/26 19:07
*/
export function logout (parameter) {
return axios({
url: '/logout',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/26 19:08
*/
export function getLoginUser (parameter) {
return axios({
url: '/getLoginUser',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/9/5 1:24
*/
export function getTenantOpen (parameter) {
return axios({
url: '/getTenantOpen',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/26 19:29
*/
export function getSmsCaptcha (parameter) {
return axios({
url: '/getSmsCaptcha',
method: 'get',
params: parameter
})
}

View File

@ -0,0 +1,15 @@
import { axios } from '@/utils/request'
/**
*
*
* @author yubaoshan
* @date 2020/6/8 19:47
*/
export function sysMachineQuery (parameter) {
return axios({
url: '/sysMachine/query',
method: 'get',
params: parameter
})
}

View File

@ -0,0 +1,114 @@
import { axios } from '@/utils/request'
/**
*
*
* @author yubaoshan
* @param parameter
* @returns {*}
*/
export function getMenuList (parameter) {
return axios({
url: '/sysMenu/list',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/4/23 12:22
*/
export function getMenuTree (parameter) {
return axios({
url: '/sysMenu/tree',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/4/24 23:23
*/
export function sysMenuAdd (parameter) {
return axios({
url: '/sysMenu/add',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/4/24 23:23
*/
export function sysMenuDelete (parameter) {
return axios({
url: '/sysMenu/delete',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/4/25 01:11
*/
export function sysMenuDetail (parameter) {
return axios({
url: '/sysMenu/detail',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/4/25 01:11
*/
export function sysMenuEdit (parameter) {
return axios({
url: '/sysMenu/edit',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/6/2 17:30
*/
export function SysMenuTreeForGrant (parameter) {
return axios({
url: '/sysMenu/treeForGrant',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/6/28 15:25
*/
export function sysMenuChange (parameter) {
return axios({
url: '/sysMenu/change',
method: 'post',
data: parameter
})
}

View File

@ -0,0 +1,85 @@
import { axios } from '@/utils/request'
/**
*
*
* @author yubaoshan
* @date 2020/6/30 01:56
*/
export function sysNoticePage (parameter) {
return axios({
url: '/sysNotice/page',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/6/30 01:56
*/
export function sysNoticeAdd (parameter) {
return axios({
url: '/sysNotice/add',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/6/30 01:56
*/
export function sysNoticeEdit (parameter) {
return axios({
url: '/sysNotice/edit',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/6/30 01:56
*/
export function sysNoticeDelete (parameter) {
return axios({
url: '/sysNotice/delete',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/6/30 01:56
*/
export function sysNoticeDetail (parameter) {
return axios({
url: '/sysNotice/detail',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/7/30 02:23
*/
export function sysNoticeChangeStatus (parameter) {
return axios({
url: '/sysNotice/changeStatus',
method: 'post',
data: parameter
})
}

View File

@ -0,0 +1,15 @@
import { axios } from '@/utils/request'
/**
*
*
* @author yubaoshan
* @date 2020/7/3 03:02
*/
export function sysNoticeReceived (parameter) {
return axios({
url: '/sysNotice/received',
method: 'get',
params: parameter
})
}

View File

@ -0,0 +1,29 @@
import { axios } from '@/utils/request'
/**
* 线
*
* @author yubaoshan
* @date 2020/6/8 11:11
*/
export function sysOnlineUserList (parameter) {
return axios({
url: '/sysOnlineUser/list',
method: 'get',
params: parameter
})
}
/**
* 线
*
* @author yubaoshan
* @date 2020/6/8 11:11
*/
export function sysOnlineUserForceExist (parameter) {
return axios({
url: '/sysOnlineUser/forceExist',
method: 'post',
data: parameter
})
}

View File

@ -0,0 +1,85 @@
import { axios } from '@/utils/request'
/**
*
*
* @author yubaoshan
* @date 2020/4/26 12:08
*/
export function getOrgTree (parameter) {
return axios({
url: '/sysOrg/tree',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/11 12:59
*/
export function getOrgList (parameter) {
return axios({
url: '/sysOrg/list',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/11 16:17
*/
export function getOrgPage (parameter) {
return axios({
url: '/sysOrg/page',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/11 13:56
*/
export function sysOrgAdd (parameter) {
return axios({
url: '/sysOrg/add',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/11 13:56
*/
export function sysOrgEdit (parameter) {
return axios({
url: '/sysOrg/edit',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/11 12:59
*/
export function sysOrgDelete (parameter) {
return axios({
url: '/sysOrg/delete',
method: 'post',
data: parameter
})
}

View File

@ -0,0 +1,71 @@
import { axios } from '@/utils/request'
/**
*
*
* @author yubaoshan
* @date 2020/5/25 01:31
*/
export function sysPosPage (parameter) {
return axios({
url: '/sysPos/page',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/6/21 23:50
*/
export function sysPosList (parameter) {
return axios({
url: '/sysPos/list',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/25 01:31
*/
export function sysPosAdd (parameter) {
return axios({
url: '/sysPos/add',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/25 01:31
*/
export function sysPosEdit (parameter) {
return axios({
url: '/sysPos/edit',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/25 01:31
*/
export function sysPosDelete (parameter) {
return axios({
url: '/sysPos/delete',
method: 'post',
data: parameter
})
}

View File

@ -0,0 +1,141 @@
import { axios } from '@/utils/request'
/**
*
*
* @author yubaoshan
* @date 2020/5/6 11:44
*/
export function getRolePage (parameter) {
return axios({
url: '/sysRole/page',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/6 11:44
*/
export function sysRoleAdd (parameter) {
return axios({
url: '/sysRole/add',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/6 11:44
*/
export function sysRoleEdit (parameter) {
return axios({
url: '/sysRole/edit',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/6 17:51
*/
export function sysRoleDelete (parameter) {
return axios({
url: '/sysRole/delete',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/7 11:28
*/
export function sysRoleDeteil (parameter) {
return axios({
url: '/sysRole/detail',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/26 23:59
*/
export function sysRoleDropDown (parameter) {
return axios({
url: '/sysRole/dropDown',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/6/02 19:02
*/
export function sysRoleOwnMenu (parameter) {
return axios({
url: '/sysRole/ownMenu',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/6/2 21:10
*/
export function sysRoleGrantMenu (parameter) {
return axios({
url: '/sysRole/grantMenu',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/6/02 21:40
*/
export function sysRoleOwnData (parameter) {
return axios({
url: '/sysRole/ownData',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/6/2 21:50
*/
export function sysRoleGrantData (parameter) {
return axios({
url: '/sysRole/grantData',
method: 'post',
data: parameter
})
}

View File

@ -0,0 +1,43 @@
import { axios } from '@/utils/request'
/**
*
*
* @author yubaoshan
* @date 2020/7/3 22:11
*/
export function smsPage (parameter) {
return axios({
url: '/sms/page',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/7/3 22:12
*/
export function sysSendLoginMessage (parameter) {
return axios({
url: '/sms/sendLoginMessage',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/7/3 22:12
*/
export function sysValidateMessage (parameter) {
return axios({
url: '/sms/validateMessage',
method: 'post',
data: parameter
})
}

View File

@ -0,0 +1,127 @@
import { axios } from '@/utils/request'
/**
*
*
* @author yubaoshan
* @date 2020/7/3 03:13
*/
export function sysTimersPage (parameter) {
return axios({
url: '/sysTimers/page',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/7/3 03:23
*/
export function sysTimersList (parameter) {
return axios({
url: '/sysTimers/list',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/7/3 03:23
*/
export function sysTimersDetail (parameter) {
return axios({
url: '/sysTimers/detail',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/7/3 03:23
*/
export function sysTimersAdd (parameter) {
return axios({
url: '/sysTimers/add',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/7/3 03:23
*/
export function sysTimersDelete (parameter) {
return axios({
url: '/sysTimers/delete',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/7/3 03:23
*/
export function sysTimersEdit (parameter) {
return axios({
url: '/sysTimers/edit',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/7/3 03:23
*/
export function sysTimersGetActionClasses (parameter) {
return axios({
url: '/sysTimers/getActionClasses',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/7/3 03:23
*/
export function sysTimersStart (parameter) {
return axios({
url: '/sysTimers/start',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/7/3 03:23
*/
export function sysTimersStop (parameter) {
return axios({
url: '/sysTimers/stop',
method: 'post',
data: parameter
})
}

View File

@ -0,0 +1,211 @@
import { axios } from '@/utils/request'
/**
*
*
* @author yubaoshan
* @date 2020/4/26 12:08
*/
export function getUserPage (parameter) {
return axios({
url: '/sysUser/page',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/5 02:08
*/
export function sysUserAdd (parameter) {
return axios({
url: '/sysUser/add',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/5 02:08
*/
export function sysUserEdit (parameter) {
return axios({
url: '/sysUser/edit',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/5 19:55
*/
export function sysUserDetail (parameter) {
return axios({
url: '/sysUser/detail',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/7 19:31
*/
export function sysUserDelete (parameter) {
return axios({
url: '/sysUser/delete',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/6/3 11:58
*/
export function sysUserOwnRole (parameter) {
return axios({
url: '/sysUser/ownRole',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/5/26 23:59
*/
export function sysUserGrantRole (parameter) {
return axios({
url: '/sysUser/grantRole',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/6/2 23:14
*/
export function sysUserOwnData (parameter) {
return axios({
url: '/sysUser/ownData',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/6/2 23:15
*/
export function sysUserGrantData (parameter) {
return axios({
url: '/sysUser/grantData',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/6/23 21:36
*/
export function sysUserChangeStatus (parameter) {
return axios({
url: '/sysUser/changeStatus',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/6/23 22:04
*/
export function sysUserResetPwd (parameter) {
return axios({
url: '/sysUser/resetPwd',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/6/25 00:25
*/
export function sysUserUpdatePwd (parameter) {
return axios({
url: '/sysUser/updatePwd',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/6/25 00:25
*/
export function sysUserSelector (parameter) {
return axios({
url: '/sysUser/selector',
method: 'get',
params: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/9/20 2:21
*/
export function sysUserUpdateAvatar (parameter) {
return axios({
url: '/sysUser/updateAvatar',
method: 'post',
data: parameter
})
}
/**
*
*
* @author yubaoshan
* @date 2020/9/20 03:12
*/
export function sysUserUpdateInfo (parameter) {
return axios({
url: '/sysUser/updateInfo',
method: 'post',
data: parameter
})
}

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="1361px" height="609px" viewBox="0 0 1361 609" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
<title>Group 21</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Ant-Design-Pro-3.0" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="账户密码登录-校验" transform="translate(-79.000000, -82.000000)">
<g id="Group-21" transform="translate(77.000000, 73.000000)">
<g id="Group-18" opacity="0.8" transform="translate(74.901416, 569.699158) rotate(-7.000000) translate(-74.901416, -569.699158) translate(4.901416, 525.199158)">
<ellipse id="Oval-11" fill="#CFDAE6" opacity="0.25" cx="63.5748792" cy="32.468367" rx="21.7830479" ry="21.766008"></ellipse>
<ellipse id="Oval-3" fill="#CFDAE6" opacity="0.599999964" cx="5.98746479" cy="13.8668601" rx="5.2173913" ry="5.21330997"></ellipse>
<path d="M38.1354514,88.3520215 C43.8984227,88.3520215 48.570234,83.6838647 48.570234,77.9254015 C48.570234,72.1669383 43.8984227,67.4987816 38.1354514,67.4987816 C32.3724801,67.4987816 27.7006688,72.1669383 27.7006688,77.9254015 C27.7006688,83.6838647 32.3724801,88.3520215 38.1354514,88.3520215 Z" id="Oval-3-Copy" fill="#CFDAE6" opacity="0.45"></path>
<path d="M64.2775582,33.1704963 L119.185836,16.5654915" id="Path-12" stroke="#CFDAE6" stroke-width="1.73913043" stroke-linecap="round" stroke-linejoin="round"></path>
<path d="M42.1431708,26.5002681 L7.71190162,14.5640702" id="Path-16" stroke="#E0B4B7" stroke-width="0.702678964" opacity="0.7" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="1.405357899873153,2.108036953469981"></path>
<path d="M63.9262187,33.521561 L43.6721326,69.3250951" id="Path-15" stroke="#BACAD9" stroke-width="0.702678964" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="1.405357899873153,2.108036953469981"></path>
<g id="Group-17" transform="translate(126.850922, 13.543654) rotate(30.000000) translate(-126.850922, -13.543654) translate(117.285705, 4.381889)" fill="#CFDAE6">
<ellipse id="Oval-4" opacity="0.45" cx="9.13482653" cy="9.12768076" rx="9.13482653" ry="9.12768076"></ellipse>
<path d="M18.2696531,18.2553615 C18.2696531,13.2142826 14.1798519,9.12768076 9.13482653,9.12768076 C4.08980114,9.12768076 0,13.2142826 0,18.2553615 L18.2696531,18.2553615 Z" id="Oval-4" transform="translate(9.134827, 13.691521) scale(-1, -1) translate(-9.134827, -13.691521) "></path>
</g>
</g>
<g id="Group-14" transform="translate(216.294700, 123.725600) rotate(-5.000000) translate(-216.294700, -123.725600) translate(106.294700, 35.225600)">
<ellipse id="Oval-2" fill="#CFDAE6" opacity="0.25" cx="29.1176471" cy="29.1402439" rx="29.1176471" ry="29.1402439"></ellipse>
<ellipse id="Oval-2" fill="#CFDAE6" opacity="0.3" cx="29.1176471" cy="29.1402439" rx="21.5686275" ry="21.5853659"></ellipse>
<ellipse id="Oval-2-Copy" stroke="#CFDAE6" opacity="0.4" cx="179.019608" cy="138.146341" rx="23.7254902" ry="23.7439024"></ellipse>
<ellipse id="Oval-2" fill="#BACAD9" opacity="0.5" cx="29.1176471" cy="29.1402439" rx="10.7843137" ry="10.7926829"></ellipse>
<path d="M29.1176471,39.9329268 L29.1176471,18.347561 C23.1616351,18.347561 18.3333333,23.1796097 18.3333333,29.1402439 C18.3333333,35.1008781 23.1616351,39.9329268 29.1176471,39.9329268 Z" id="Oval-2" fill="#BACAD9"></path>
<g id="Group-9" opacity="0.45" transform="translate(172.000000, 131.000000)" fill="#E6A1A6">
<ellipse id="Oval-2-Copy-2" cx="7.01960784" cy="7.14634146" rx="6.47058824" ry="6.47560976"></ellipse>
<path d="M0.549019608,13.6219512 C4.12262681,13.6219512 7.01960784,10.722722 7.01960784,7.14634146 C7.01960784,3.56996095 4.12262681,0.670731707 0.549019608,0.670731707 L0.549019608,13.6219512 Z" id="Oval-2-Copy-2" transform="translate(3.784314, 7.146341) scale(-1, 1) translate(-3.784314, -7.146341) "></path>
</g>
<ellipse id="Oval-10" fill="#CFDAE6" cx="218.382353" cy="138.685976" rx="1.61764706" ry="1.61890244"></ellipse>
<ellipse id="Oval-10-Copy-2" fill="#E0B4B7" opacity="0.35" cx="179.558824" cy="175.381098" rx="1.61764706" ry="1.61890244"></ellipse>
<ellipse id="Oval-10-Copy" fill="#E0B4B7" opacity="0.35" cx="180.098039" cy="102.530488" rx="2.15686275" ry="2.15853659"></ellipse>
<path d="M28.9985381,29.9671598 L171.151018,132.876024" id="Path-11" stroke="#CFDAE6" opacity="0.8"></path>
</g>
<g id="Group-10" opacity="0.799999952" transform="translate(1054.100635, 36.659317) rotate(-11.000000) translate(-1054.100635, -36.659317) translate(1026.600635, 4.659317)">
<ellipse id="Oval-7" stroke="#CFDAE6" stroke-width="0.941176471" cx="43.8135593" cy="32" rx="11.1864407" ry="11.2941176"></ellipse>
<g id="Group-12" transform="translate(34.596774, 23.111111)" fill="#BACAD9">
<ellipse id="Oval-7" opacity="0.45" cx="9.18534718" cy="8.88888889" rx="8.47457627" ry="8.55614973"></ellipse>
<path d="M9.18534718,17.4450386 C13.8657264,17.4450386 17.6599235,13.6143199 17.6599235,8.88888889 C17.6599235,4.16345787 13.8657264,0.332739156 9.18534718,0.332739156 L9.18534718,17.4450386 Z" id="Oval-7"></path>
</g>
<path d="M34.6597385,24.809694 L5.71666084,4.76878945" id="Path-2" stroke="#CFDAE6" stroke-width="0.941176471"></path>
<ellipse id="Oval" stroke="#CFDAE6" stroke-width="0.941176471" cx="3.26271186" cy="3.29411765" rx="3.26271186" ry="3.29411765"></ellipse>
<ellipse id="Oval-Copy" fill="#F7E1AD" cx="2.79661017" cy="61.1764706" rx="2.79661017" ry="2.82352941"></ellipse>
<path d="M34.6312443,39.2922712 L5.06366663,59.785082" id="Path-10" stroke="#CFDAE6" stroke-width="0.941176471"></path>
</g>
<g id="Group-19" opacity="0.33" transform="translate(1282.537219, 446.502867) rotate(-10.000000) translate(-1282.537219, -446.502867) translate(1142.537219, 327.502867)">
<g id="Group-17" transform="translate(141.333539, 104.502742) rotate(275.000000) translate(-141.333539, -104.502742) translate(129.333539, 92.502742)" fill="#BACAD9">
<circle id="Oval-4" opacity="0.45" cx="11.6666667" cy="11.6666667" r="11.6666667"></circle>
<path d="M23.3333333,23.3333333 C23.3333333,16.8900113 18.1099887,11.6666667 11.6666667,11.6666667 C5.22334459,11.6666667 0,16.8900113 0,23.3333333 L23.3333333,23.3333333 Z" id="Oval-4" transform="translate(11.666667, 17.500000) scale(-1, -1) translate(-11.666667, -17.500000) "></path>
</g>
<circle id="Oval-5-Copy-6" fill="#CFDAE6" cx="201.833333" cy="87.5" r="5.83333333"></circle>
<path d="M143.5,88.8126685 L155.070501,17.6038544" id="Path-17" stroke="#BACAD9" stroke-width="1.16666667"></path>
<path d="M17.5,37.3333333 L127.466252,97.6449735" id="Path-18" stroke="#BACAD9" stroke-width="1.16666667"></path>
<polyline id="Path-19" stroke="#CFDAE6" stroke-width="1.16666667" points="143.902597 120.302281 174.935455 231.571342 38.5 147.510847 126.366941 110.833333"></polyline>
<path d="M159.833333,99.7453842 L195.416667,89.25" id="Path-20" stroke="#E0B4B7" stroke-width="1.16666667" opacity="0.6"></path>
<path d="M205.333333,82.1372105 L238.719406,36.1666667" id="Path-24" stroke="#BACAD9" stroke-width="1.16666667"></path>
<path d="M266.723424,132.231988 L207.083333,90.4166667" id="Path-25" stroke="#CFDAE6" stroke-width="1.16666667"></path>
<circle id="Oval-5" fill="#C1D1E0" cx="156.916667" cy="8.75" r="8.75"></circle>
<circle id="Oval-5-Copy-3" fill="#C1D1E0" cx="39.0833333" cy="148.75" r="5.25"></circle>
<circle id="Oval-5-Copy-2" fill-opacity="0.6" fill="#D1DEED" cx="8.75" cy="33.25" r="8.75"></circle>
<circle id="Oval-5-Copy-4" fill-opacity="0.6" fill="#D1DEED" cx="243.833333" cy="30.3333333" r="5.83333333"></circle>
<circle id="Oval-5-Copy-5" fill="#E0B4B7" cx="175.583333" cy="232.75" r="5.25"></circle>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.7 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1551058675966" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7872" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M85.333333 512h85.333334a340.736 340.736 0 0 1 99.712-241.621333 337.493333 337.493333 0 0 1 108.458666-72.96 346.453333 346.453333 0 0 1 261.546667-1.749334A106.154667 106.154667 0 0 0 746.666667 298.666667C805.802667 298.666667 853.333333 251.136 853.333333 192S805.802667 85.333333 746.666667 85.333333c-29.397333 0-55.978667 11.776-75.221334 30.933334-103.722667-41.514667-222.848-40.874667-325.76 2.517333a423.594667 423.594667 0 0 0-135.68 91.264 423.253333 423.253333 0 0 0-91.306666 135.637333A426.88 426.88 0 0 0 85.333333 512z m741.248 133.205333c-17.109333 40.618667-41.685333 77.141333-72.96 108.416s-67.797333 55.850667-108.458666 72.96a346.453333 346.453333 0 0 1-261.546667 1.749334A106.154667 106.154667 0 0 0 277.333333 725.333333C218.197333 725.333333 170.666667 772.864 170.666667 832S218.197333 938.666667 277.333333 938.666667c29.397333 0 55.978667-11.776 75.221334-30.933334A425.173333 425.173333 0 0 0 512 938.666667a425.941333 425.941333 0 0 0 393.258667-260.352A426.325333 426.325333 0 0 0 938.666667 512h-85.333334a341.034667 341.034667 0 0 1-26.752 133.205333z" p-id="7873"></path><path d="M512 318.378667c-106.752 0-193.621333 86.869333-193.621333 193.621333S405.248 705.621333 512 705.621333s193.621333-86.869333 193.621333-193.621333S618.752 318.378667 512 318.378667z m0 301.909333c-59.690667 0-108.288-48.597333-108.288-108.288S452.309333 403.712 512 403.712s108.288 48.597333 108.288 108.288-48.597333 108.288-108.288 108.288z" p-id="7874"></path></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
_web/src/assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

376
_web/src/assets/logo.svg Normal file
View File

@ -0,0 +1,376 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="244px" height="180px" viewBox="0 0 244 180" enable-background="new 0 0 244 180" xml:space="preserve"> <image id="image0" width="244" height="180" x="0" y="0"
href="data:image/png;base64,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
zx/BE51u1AgMe7gEwwWQZ8rplbIFzPufwBVnf334+G774BD0l39NlwiriFCJsdOAf7bwKLATcMLz
R/BOpxs0AsMfJq3ATITTRHjE+VB0bljt+W8Mo62SIfA59KoQHwTYgH92jwgXANs9fwTXPH/E8J31
RmDwweQVeRI4FRImElrKwnm2wM0Y3ut03fsTXIIWNhJh0Rwhp89khP0/4Ahg9xeOHH7+sCMwNEDg
0qrlcqPF7GJD2VvAdWcvN7wZT0bQXzqG2QV1bhiF2x8fBHZ+4UiOfeFIPux0A0bgkwvnrcz7tspp
1R6e9E8DJf/4Igz/20hrHFoYL8JqhaeJWARhCrDdC0dyXacrPgIjAIDw8KxZnNrby/v6oniPwAW4
iJhLD2vICFpgJYQFAidvIvAfYF/gJy8cOTRvth+B4Qnnr4ZYy/kff8SVtgqVEKc2VIHbh7u4DQlB
L/VL5hFh9YKzwO5H2OGFozjlhSP5oNMVHoER8OGStfigdxYnzvqQpyTgvw3cAbzS6XoOBEQAIiyH
sE76MlmqmgmcDnz3xaO4udMVHYERKIM/r8fDMz/klI8/pupcNRvDpWcvxxudruNAQCpyLwPMqY4K
eo1YxN77xaNGjtIdgaEB1nLx+29zRbUXoppT80fAY52u20BBtOTRzA1spRxI/gps++JRnPniUfR2
uoIjMAKNwhUb8s6smRzz3pu8qpawpgJPdbpuAwWRxDdirJ1w5xOB77549MhRuiMwNOG6TXnsw/c4
7oP3oBL7O/71T1/75HgwdiF8V+KDxvd66WimdLpCIzACrYIVznrjdb49egyrdHV/sk7IiUSYB1h3
hJhHYLjA9Zvz8axZHPPqS9z4/js80On6DCT8P9ednZxrfdkhAAAAJXRFWHRkYXRlOmNyZWF0ZQAy
MDIwLTEyLTAxVDIwOjA2OjE3KzA4OjAwk+5owQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMC0xMi0w
MVQyMDowNjoxNyswODowMOKz0H0AAAAgdEVYdHNvZnR3YXJlAGh0dHBzOi8vaW1hZ2VtYWdpY2su
b3JnvM8dnQAAABh0RVh0VGh1bWI6OkRvY3VtZW50OjpQYWdlcwAxp/+7LwAAABh0RVh0VGh1bWI6
OkltYWdlOjpIZWlnaHQAMTgwt0ghOAAAABd0RVh0VGh1bWI6OkltYWdlOjpXaWR0aAAyNDSNJ0Qp
AAAAGXRFWHRUaHVtYjo6TWltZXR5cGUAaW1hZ2UvcG5nP7JWTgAAABd0RVh0VGh1bWI6Ok1UaW1l
ADE2MDY4MjQzNzerTbE+AAAAE3RFWHRUaHVtYjo6U2l6ZQAyMjY0NUJCb9B/YQAAAEZ0RVh0VGh1
bWI6OlVSSQBmaWxlOi8vL2FwcC90bXAvaW1hZ2VsYy9pbWd2aWV3Ml85XzE2MDY3MjkwNjAzODUx
ODcxXzI4X1swXV5WmREAAAAASUVORK5CYII=" ></image>
</svg>

After

Width:  |  Height:  |  Size: 29 KiB

BIN
_web/src/assets/welcome.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -0,0 +1,89 @@
<template>
<div class="antd-pro-components-article-list-content-index-listContent">
<div class="description">
<slot>
{{ description }}
</slot>
</div>
<div class="extra">
<a-avatar :src="avatar" size="small" />
<a :href="href">{{ owner }}</a> 发布在 <a :href="href">{{ href }}</a>
<em>{{ updateAt | moment }}</em>
</div>
</div>
</template>
<script>
export default {
name: 'ArticleListContent',
props: {
prefixCls: {
type: String,
default: 'antd-pro-components-article-list-content-index-listContent'
},
description: {
type: String,
default: ''
},
owner: {
type: String,
required: true
},
avatar: {
type: String,
required: true
},
href: {
type: String,
required: true
},
updateAt: {
type: String,
required: true
}
}
}
</script>
<style lang="less" scoped>
@import '../index.less';
.antd-pro-components-article-list-content-index-listContent {
.description {
max-width: 720px;
line-height: 22px;
}
.extra {
margin-top: 16px;
color: @text-color-secondary;
line-height: 22px;
& /deep/ .ant-avatar {
position: relative;
top: 1px;
width: 20px;
height: 20px;
margin-right: 8px;
vertical-align: top;
}
& > em {
margin-left: 16px;
color: @disabled-color;
font-style: normal;
}
}
}
@media screen and (max-width: @screen-xs) {
.antd-pro-components-article-list-content-index-listContent {
.extra {
& > em {
display: block;
margin-top: 8px;
margin-left: 0;
}
}
}
}
</style>

View File

@ -0,0 +1,3 @@
import ArticleListContent from './ArticleListContent'
export default ArticleListContent

View File

@ -0,0 +1,46 @@
<template>
<tooltip v-if="tips !== ''">
<template slot="title">{{ tips }}</template>
<avatar :size="avatarSize" :src="src" />
</tooltip>
<avatar v-else :size="avatarSize" :src="src" />
</template>
<script>
import Avatar from 'ant-design-vue/es/avatar'
import Tooltip from 'ant-design-vue/es/tooltip'
export default {
name: 'AvatarItem',
components: {
Avatar,
Tooltip
},
props: {
tips: {
type: String,
default: '',
required: false
},
src: {
type: String,
default: ''
}
},
data () {
return {
size: this.$parent.size
}
},
computed: {
avatarSize () {
return this.size !== 'mini' && this.size || 20
}
},
watch: {
'$parent.size' (val) {
this.size = val
}
}
}
</script>

View File

@ -0,0 +1,99 @@
<!--
<template>
<div :class="[prefixCls]">
<ul>
<slot></slot>
<template v-for="item in filterEmpty($slots.default).slice(0, 3)"></template>
<template v-if="maxLength > 0 && filterEmpty($slots.default).length > maxLength">
<avatar-item :size="size">
<avatar :size="size !== 'mini' && size || 20" :style="excessItemsStyle">{{ `+${maxLength}` }}</avatar>
</avatar-item>
</template>
</ul>
</div>
</template>
-->
<script>
import Avatar from 'ant-design-vue/es/avatar'
import AvatarItem from './Item'
import { filterEmpty } from '@/components/_util/util'
export default {
AvatarItem,
name: 'AvatarList',
components: {
Avatar,
AvatarItem
},
props: {
prefixCls: {
type: String,
default: 'ant-pro-avatar-list'
},
/**
* 头像大小 类型: largesmall mini, default
* 默认值: default
*/
size: {
type: [String, Number],
default: 'default'
},
/**
* 要显示的最大项目
*/
maxLength: {
type: Number,
default: 0
},
/**
* 多余的项目风格
*/
excessItemsStyle: {
type: Object,
default: () => {
return {
color: '#f56a00',
backgroundColor: '#fde3cf'
}
}
}
},
data () {
return {}
},
methods: {
getItems (items) {
const classString = {
[`${this.prefixCls}-item`]: true,
[`${this.size}`]: true
}
if (this.maxLength > 0) {
items = items.slice(0, this.maxLength)
items.push((<Avatar size={ this.size } style={ this.excessItemsStyle }>{`+${this.maxLength}`}</Avatar>))
}
const itemList = items.map((item) => (
<li class={ classString }>{ item }</li>
))
return itemList
}
},
render () {
const { prefixCls, size } = this.$props
const classString = {
[`${prefixCls}`]: true,
[`${size}`]: true
}
const items = filterEmpty(this.$slots.default)
const itemsDom = items && items.length ? <ul class={`${prefixCls}-items`}>{ this.getItems(items) }</ul> : null
return (
<div class={ classString }>
{ itemsDom }
</div>
)
}
}
</script>

View File

@ -0,0 +1,4 @@
import AvatarList from './List'
import './index.less'
export default AvatarList

View File

@ -0,0 +1,60 @@
@import "../index";
@avatar-list-prefix-cls: ~"@{ant-pro-prefix}-avatar-list";
@avatar-list-item-prefix-cls: ~"@{ant-pro-prefix}-avatar-list-item";
.@{avatar-list-prefix-cls} {
display: inline-block;
ul {
list-style: none;
display: inline-block;
padding: 0;
margin: 0 0 0 8px;
font-size: 0;
}
}
.@{avatar-list-item-prefix-cls} {
display: inline-block;
font-size: @font-size-base;
margin-left: -8px;
width: @avatar-size-base;
height: @avatar-size-base;
:global {
.ant-avatar {
border: 1px solid #fff;
cursor: pointer;
}
}
&.large {
width: @avatar-size-lg;
height: @avatar-size-lg;
}
&.small {
width: @avatar-size-sm;
height: @avatar-size-sm;
}
&.mini {
width: 20px;
height: 20px;
:global {
.ant-avatar {
width: 20px;
height: 20px;
line-height: 20px;
.ant-avatar-string {
font-size: 12px;
line-height: 18px;
}
}
}
}
}

View File

@ -0,0 +1,64 @@
# AvatarList 用户头像列表
一组用户头像,常用在项目/团队成员列表。可通过设置 `size` 属性来指定头像大小。
引用方式:
```javascript
import AvatarList from '@/components/AvatarList'
const AvatarListItem = AvatarList.AvatarItem
export default {
components: {
AvatarList,
AvatarListItem
}
}
```
## 代码演示 [demo](https://pro.loacg.com/test/home)
```html
<avatar-list size="mini">
<avatar-list-item tips="Jake" src="https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png" />
<avatar-list-item tips="Andy" src="https://gw.alipayobjects.com/zos/rmsportal/sfjbOqnsXXJgNCjCzDBL.png" />
<avatar-list-item tips="Niko" src="https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png" />
</avatar-list>
```
```html
<avatar-list :max-length="3">
<avatar-list-item tips="Jake" src="https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png" />
<avatar-list-item tips="Andy" src="https://gw.alipayobjects.com/zos/rmsportal/sfjbOqnsXXJgNCjCzDBL.png" />
<avatar-list-item tips="Niko" src="https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png" />
<avatar-list-item tips="Niko" src="https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png" />
<avatar-list-item tips="Niko" src="https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png" />
<avatar-list-item tips="Niko" src="https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png" />
<avatar-list-item tips="Niko" src="https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png" />
</avatar-list>
```
## API
### AvatarList
| 参数 | 说明 | 类型 | 默认值 |
| ---------------- | -------- | ---------------------------------- | --------- |
| size | 头像大小 | `large`、`small` 、`mini`, `default` | `default` |
| maxLength | 要显示的最大项目 | number | - |
| excessItemsStyle | 多余的项目风格 | CSSProperties | - |
### AvatarList.Item
| 参数 | 说明 | 类型 | 默认值 |
| ---- | ------ | --------- | --- |
| tips | 头像展示文案 | string | - |
| src | 头像图片连接 | string | - |

View File

@ -0,0 +1,62 @@
<template>
<div :style="{ padding: '0 0 32px 32px' }">
<h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
<v-chart
height="254"
:data="data"
:forceFit="true"
:padding="['auto', 'auto', '40', '50']">
<v-tooltip />
<v-axis />
<v-bar position="x*y"/>
</v-chart>
</div>
</template>
<script>
export default {
name: 'Bar',
props: {
title: {
type: String,
default: ''
},
data: {
type: Array,
default: () => {
return []
}
},
scale: {
type: Array,
default: () => {
return [{
dataKey: 'x',
min: 2
}, {
dataKey: 'y',
title: '时间',
min: 1,
max: 22
}]
}
},
tooltip: {
type: Array,
default: () => {
return [
'x*y',
(x, y) => ({
name: x,
value: y
})
]
}
}
},
data () {
return {
}
}
}
</script>

View File

@ -0,0 +1,120 @@
<template>
<a-card :loading="loading" :body-style="{ padding: '20px 24px 8px' }" :bordered="false">
<div class="chart-card-header">
<div class="meta">
<span class="chart-card-title">
<slot name="title">
{{ title }}
</slot>
</span>
<span class="chart-card-action">
<slot name="action"></slot>
</span>
</div>
<div class="total">
<slot name="total">
<span>{{ typeof total === 'function' && total() || total }}</span>
</slot>
</div>
</div>
<div class="chart-card-content">
<div class="content-fix">
<slot></slot>
</div>
</div>
<div class="chart-card-footer">
<div class="field">
<slot name="footer"></slot>
</div>
</div>
</a-card>
</template>
<script>
export default {
name: 'ChartCard',
props: {
title: {
type: String,
default: ''
},
total: {
type: [Function, Number, String],
required: false,
default: null
},
loading: {
type: Boolean,
default: false
}
}
}
</script>
<style lang="less" scoped>
.chart-card-header {
position: relative;
overflow: hidden;
width: 100%;
.meta {
position: relative;
overflow: hidden;
width: 100%;
color: rgba(0, 0, 0, .45);
font-size: 14px;
line-height: 22px;
}
}
.chart-card-action {
cursor: pointer;
position: absolute;
top: 0;
right: 0;
}
.chart-card-footer {
border-top: 1px solid #e8e8e8;
padding-top: 9px;
margin-top: 8px;
> * {
position: relative;
}
.field {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin: 0;
}
}
.chart-card-content {
margin-bottom: 12px;
position: relative;
height: 46px;
width: 100%;
.content-fix {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
}
}
.total {
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
white-space: nowrap;
color: #000;
margin-top: 4px;
margin-bottom: 0;
font-size: 30px;
line-height: 38px;
height: 38px;
}
</style>

View File

@ -0,0 +1,67 @@
<template>
<div>
<v-chart
:forceFit="true"
:height="height"
:width="width"
:data="data"
:scale="scale"
:padding="0">
<v-tooltip />
<v-interval
:shape="['liquid-fill-gauge']"
position="transfer*value"
color=""
:v-style="{
lineWidth: 10,
opacity: 0.75
}"
:tooltip="[
'transfer*value',
(transfer, value) => {
return {
name: transfer,
value,
};
},
]"
></v-interval>
<v-guide
v-for="(row, index) in data"
:key="index"
type="text"
:top="true"
:position="{
gender: row.transfer,
value: 45
}"
:content="row.value + '%'"
:v-style="{
fontSize: 100,
textAlign: 'center',
opacity: 0.75,
}"
/>
</v-chart>
</div>
</template>
<script>
export default {
name: 'Liquid',
props: {
height: {
type: Number,
default: 0
},
width: {
type: Number,
default: 0
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,56 @@
<template>
<div class="antv-chart-mini">
<div class="chart-wrapper" :style="{ height: 46 }">
<v-chart :force-fit="true" :height="height" :data="data" :padding="[36, 0, 18, 0]">
<v-tooltip />
<v-smooth-area position="x*y" />
</v-chart>
</div>
</div>
</template>
<script>
import moment from 'moment'
const data = []
const beginDay = new Date().getTime()
for (let i = 0; i < 10; i++) {
data.push({
x: moment(new Date(beginDay + 1000 * 60 * 60 * 24 * i)).format('YYYY-MM-DD'),
y: Math.round(Math.random() * 10)
})
}
const tooltip = [
'x*y',
(x, y) => ({
name: x,
value: y
})
]
const scale = [{
dataKey: 'x',
min: 2
}, {
dataKey: 'y',
title: '时间',
min: 1,
max: 22
}]
export default {
name: 'MiniArea',
data () {
return {
data,
tooltip,
scale,
height: 100
}
}
}
</script>
<style lang="less" scoped>
@import "chart";
</style>

View File

@ -0,0 +1,57 @@
<template>
<div class="antv-chart-mini">
<div class="chart-wrapper" :style="{ height: 46 }">
<v-chart :force-fit="true" :height="height" :data="data" :padding="[36, 5, 18, 5]">
<v-tooltip />
<v-bar position="x*y" />
</v-chart>
</div>
</div>
</template>
<script>
import moment from 'moment'
const data = []
const beginDay = new Date().getTime()
for (let i = 0; i < 10; i++) {
data.push({
x: moment(new Date(beginDay + 1000 * 60 * 60 * 24 * i)).format('YYYY-MM-DD'),
y: Math.round(Math.random() * 10)
})
}
const tooltip = [
'x*y',
(x, y) => ({
name: x,
value: y
})
]
const scale = [{
dataKey: 'x',
min: 2
}, {
dataKey: 'y',
title: '时间',
min: 1,
max: 30
}]
export default {
name: 'MiniBar',
data () {
return {
data,
tooltip,
scale,
height: 100
}
}
}
</script>
<style lang="less" scoped>
@import "chart";
</style>

View File

@ -0,0 +1,75 @@
<template>
<div class="chart-mini-progress">
<div class="target" :style="{ left: target + '%'}">
<span :style="{ backgroundColor: color }" />
<span :style="{ backgroundColor: color }"/>
</div>
<div class="progress-wrapper">
<div class="progress" :style="{ backgroundColor: color, width: percentage + '%', height: height }"></div>
</div>
</div>
</template>
<script>
export default {
name: 'MiniProgress',
props: {
target: {
type: Number,
default: 0
},
height: {
type: String,
default: '10px'
},
color: {
type: String,
default: '#13C2C2'
},
percentage: {
type: Number,
default: 0
}
}
}
</script>
<style lang="less" scoped>
.chart-mini-progress {
padding: 5px 0;
position: relative;
width: 100%;
.target {
position: absolute;
top: 0;
bottom: 0;
span {
border-radius: 100px;
position: absolute;
top: 0;
left: 0;
height: 4px;
width: 2px;
&:last-child {
top: auto;
bottom: 0;
}
}
}
.progress-wrapper {
background-color: #f5f5f5;
position: relative;
.progress {
transition: all .4s cubic-bezier(.08,.82,.17,1) 0s;
border-radius: 1px 0 0 1px;
background-color: #1890ff;
width: 0;
height: 100%;
}
}
}
</style>

View File

@ -0,0 +1,40 @@
<template>
<div :class="prefixCls">
<div class="chart-wrapper" :style="{ height: 46 }">
<v-chart :force-fit="true" :height="100" :data="dataSource" :scale="scale" :padding="[36, 0, 18, 0]">
<v-tooltip />
<v-smooth-line position="x*y" :size="2" />
<v-smooth-area position="x*y" />
</v-chart>
</div>
</div>
</template>
<script>
export default {
name: 'MiniSmoothArea',
props: {
prefixCls: {
type: String,
default: 'ant-pro-smooth-area'
},
scale: {
type: [Object, Array],
required: true
},
dataSource: {
type: Array,
required: true
}
},
data () {
return {
height: 100
}
}
}
</script>
<style lang="less" scoped>
@import "smooth.area.less";
</style>

View File

@ -0,0 +1,68 @@
<template>
<v-chart :forceFit="true" height="400" :data="data" :padding="[20, 20, 95, 20]" :scale="scale">
<v-tooltip></v-tooltip>
<v-axis :dataKey="axis1Opts.dataKey" :line="axis1Opts.line" :tickLine="axis1Opts.tickLine" :grid="axis1Opts.grid" />
<v-axis :dataKey="axis2Opts.dataKey" :line="axis2Opts.line" :tickLine="axis2Opts.tickLine" :grid="axis2Opts.grid" />
<v-legend dataKey="user" marker="circle" :offset="30" />
<v-coord type="polar" radius="0.8" />
<v-line position="item*score" color="user" :size="2" />
<v-point position="item*score" color="user" :size="4" shape="circle" />
</v-chart>
</template>
<script>
const axis1Opts = {
dataKey: 'item',
line: null,
tickLine: null,
grid: {
lineStyle: {
lineDash: null
},
hideFirstLine: false
}
}
const axis2Opts = {
dataKey: 'score',
line: null,
tickLine: null,
grid: {
type: 'polygon',
lineStyle: {
lineDash: null
}
}
}
const scale = [
{
dataKey: 'score',
min: 0,
max: 80
}, {
dataKey: 'user',
alias: '类型'
}
]
export default {
name: 'Radar',
props: {
data: {
type: Array,
default: null
}
},
data () {
return {
axis1Opts,
axis2Opts,
scale
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,77 @@
<template>
<div class="rank">
<h4 class="title">{{ title }}</h4>
<ul class="list">
<li :key="index" v-for="(item, index) in list">
<span :class="index < 3 ? 'active' : null">{{ index + 1 }}</span>
<span>{{ item.name }}</span>
<span>{{ item.total }}</span>
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'RankList',
// ['title', 'list']
props: {
title: {
type: String,
default: ''
},
list: {
type: Array,
default: null
}
}
}
</script>
<style lang="less" scoped>
.rank {
padding: 0 32px 32px 72px;
.list {
margin: 25px 0 0;
padding: 0;
list-style: none;
li {
margin-top: 16px;
span {
color: rgba(0, 0, 0, .65);
font-size: 14px;
line-height: 22px;
&:first-child {
background-color: #f5f5f5;
border-radius: 20px;
display: inline-block;
font-size: 12px;
font-weight: 600;
margin-right: 24px;
height: 20px;
line-height: 20px;
width: 20px;
text-align: center;
}
&.active {
background-color: #314659;
color: #fff;
}
&:last-child {
float: right;
}
}
}
}
}
.mobile .rank {
padding: 0 32px 32px 32px;
}
</style>

View File

@ -0,0 +1,113 @@
<template>
<v-chart :width="width" :height="height" :padding="[0]" :data="data" :scale="scale">
<v-tooltip :show-title="false" />
<v-coord type="rect" direction="TL" />
<v-point position="x*y" color="category" shape="cloud" tooltip="value*category" />
</v-chart>
</template>
<script>
import { registerShape } from 'viser-vue'
const DataSet = require('@antv/data-set')
const imgUrl = 'https://gw.alipayobjects.com/zos/rmsportal/gWyeGLCdFFRavBGIDzWk.png'
const scale = [
{ dataKey: 'x', nice: false },
{ dataKey: 'y', nice: false }
]
registerShape('point', 'cloud', {
draw (cfg, container) {
return container.addShape('text', {
attrs: {
fillOpacity: cfg.opacity,
fontSize: cfg.origin._origin.size,
rotate: cfg.origin._origin.rotate,
text: cfg.origin._origin.text,
textAlign: 'center',
fontFamily: cfg.origin._origin.font,
fill: cfg.color,
textBaseline: 'Alphabetic',
...cfg.style,
x: cfg.x,
y: cfg.y
}
})
}
})
export default {
name: 'TagCloud',
props: {
tagList: {
type: Array,
required: true
},
height: {
type: Number,
default: 400
},
width: {
type: Number,
default: 640
}
},
data () {
return {
data: [],
scale
}
},
watch: {
tagList: function (val) {
if (val.length > 0) {
this.initTagCloud(val)
}
}
},
mounted () {
if (this.tagList.length > 0) {
this.initTagCloud(this.tagList)
}
},
methods: {
initTagCloud (dataSource) {
const { height, width } = this
const dv = new DataSet.View().source(dataSource)
const range = dv.range('value')
const min = range[0]
const max = range[1]
const imageMask = new Image()
imageMask.crossOrigin = ''
imageMask.src = imgUrl
imageMask.onload = () => {
dv.transform({
type: 'tag-cloud',
fields: ['name', 'value'],
size: [width, height],
imageMask,
font: 'Verdana',
padding: 0,
timeInterval: 5000, // max execute time
rotate () {
let random = ~~(Math.random() * 4) % 4
if (random === 2) {
random = 0
}
return random * 90 // 0, 90, 270
},
fontSize (d) {
if (d.value) {
return ((d.value - min) / (max - min)) * (32 - 8) + 8
}
return 0
}
})
this.data = dv.rows
}
}
}
}
</script>

View File

@ -0,0 +1,64 @@
<template>
<div :style="{ padding: '0 0 32px 32px' }">
<h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
<v-chart
height="254"
:data="data"
:scale="scale"
:forceFit="true"
:padding="['auto', 'auto', '40', '50']">
<v-tooltip />
<v-axis />
<v-bar position="x*y"/>
</v-chart>
</div>
</template>
<script>
const tooltip = [
'x*y',
(x, y) => ({
name: x,
value: y
})
]
const scale = [{
dataKey: 'x',
title: '日期(天)',
alias: '日期(天)',
min: 2
}, {
dataKey: 'y',
title: '流量(Gb)',
alias: '流量(Gb)',
min: 1
}]
export default {
name: 'Bar',
props: {
title: {
type: String,
default: ''
}
},
data () {
return {
data: [],
scale,
tooltip
}
},
created () {
this.getMonthBar()
},
methods: {
getMonthBar () {
this.$http.get('/analysis/month-bar')
.then(res => {
this.data = res.result
})
}
}
}
</script>

View File

@ -0,0 +1,82 @@
<template>
<div class="chart-trend">
{{ term }}
<span>{{ rate }}%</span>
<span :class="['trend-icon', trend]"><a-icon :type="'caret-' + trend"/></span>
</div>
</template>
<script>
export default {
name: 'Trend',
props: {
term: {
type: String,
default: '',
required: true
},
percentage: {
type: Number,
default: null
},
type: {
type: Boolean,
default: null
},
target: {
type: Number,
default: 0
},
value: {
type: Number,
default: 0
},
fixed: {
type: Number,
default: 2
}
},
data () {
return {
trend: this.type && 'up' || 'down',
rate: this.percentage
}
},
created () {
const type = this.type === null ? this.value >= this.target : this.type
this.trend = type ? 'up' : 'down'
this.rate = (this.percentage === null ? Math.abs(this.value - this.target) * 100 / this.target : this.percentage).toFixed(this.fixed)
}
}
</script>
<style lang="less" scoped>
.chart-trend {
display: inline-block;
font-size: 14px;
line-height: 22px;
.trend-icon {
font-size: 12px;
&.up, &.down {
margin-left: 4px;
position: relative;
top: 1px;
i {
font-size: 12px;
transform: scale(.83);
}
}
&.up {
color: #f5222d;
}
&.down {
color: #52c41a;
top: -1px;
}
}
}
</style>

View File

@ -0,0 +1,13 @@
.antv-chart-mini {
position: relative;
width: 100%;
.chart-wrapper {
position: absolute;
bottom: -28px;
width: 100%;
/* margin: 0 -5px;
overflow: hidden;*/
}
}

View File

@ -0,0 +1,14 @@
@import "../index";
@smoothArea-prefix-cls: ~"@{ant-pro-prefix}-smooth-area";
.@{smoothArea-prefix-cls} {
position: relative;
width: 100%;
.chart-wrapper {
position: absolute;
bottom: -28px;
width: 100%;
}
}

View File

@ -0,0 +1,102 @@
<template>
<span>
{{ lastTime | format }}
</span>
</template>
<script>
function fixedZero (val) {
return val * 1 < 10 ? `0${val}` : val
}
export default {
name: 'CountDown',
props: {
format: {
type: Function,
default: undefined
},
target: {
type: [Date, Number],
required: true
},
onEnd: {
type: Function,
default: () => ({})
}
},
data () {
return {
dateTime: '0',
originTargetTime: 0,
lastTime: 0,
timer: 0,
interval: 1000
}
},
filters: {
format (time) {
const hours = 60 * 60 * 1000
const minutes = 60 * 1000
const h = Math.floor(time / hours)
const m = Math.floor((time - h * hours) / minutes)
const s = Math.floor((time - h * hours - m * minutes) / 1000)
return `${fixedZero(h)}:${fixedZero(m)}:${fixedZero(s)}`
}
},
created () {
this.initTime()
this.tick()
},
methods: {
initTime () {
let lastTime = 0
let targetTime = 0
this.originTargetTime = this.target
try {
if (Object.prototype.toString.call(this.target) === '[object Date]') {
targetTime = this.target
} else {
targetTime = new Date(this.target).getTime()
}
} catch (e) {
throw new Error('invalid target prop')
}
lastTime = targetTime - new Date().getTime()
this.lastTime = lastTime < 0 ? 0 : lastTime
},
tick () {
const { onEnd } = this
this.timer = setTimeout(() => {
if (this.lastTime < this.interval) {
clearTimeout(this.timer)
this.lastTime = 0
if (typeof onEnd === 'function') {
onEnd()
}
} else {
this.lastTime -= this.interval
this.tick()
}
}, this.interval)
}
},
beforeUpdate () {
if (this.originTargetTime !== this.target) {
this.initTime()
}
},
beforeDestroy () {
clearTimeout(this.timer)
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,3 @@
import CountDown from './CountDown'
export default CountDown

View File

@ -0,0 +1,34 @@
# CountDown 倒计时
倒计时组件。
引用方式:
```javascript
import CountDown from '@/components/CountDown/CountDown'
export default {
components: {
CountDown
}
}
```
## 代码演示 [demo](https://pro.loacg.com/test/home)
```html
<count-down :target="new Date().getTime() + 3000000" :on-end="onEndHandle" />
```
## API
| 参数 | 说明 | 类型 | 默认值 |
|----------|------------------------------------------|-------------|-------|
| target | 目标时间 | Date | - |
| onEnd | 倒计时结束回调 | funtion | -|

View File

@ -0,0 +1,153 @@
<template>
<div :class="['description-list', size, layout === 'vertical' ? 'vertical': 'horizontal']">
<div v-if="title" class="title">{{ title }}</div>
<a-row>
<slot></slot>
</a-row>
</div>
</template>
<script>
import { Col } from 'ant-design-vue/es/grid/'
const Item = {
name: 'DetailListItem',
props: {
term: {
type: String,
default: '',
required: false
}
},
inject: {
col: {
type: Number
}
},
render () {
return (
<Col {...{ props: responsive[this.col] }}>
<div class="term">{this.$props.term}</div>
<div class="content">{this.$slots.default}</div>
</Col>
)
}
}
const responsive = {
1: { xs: 24 },
2: { xs: 24, sm: 12 },
3: { xs: 24, sm: 12, md: 8 },
4: { xs: 24, sm: 12, md: 6 }
}
export default {
name: 'DetailList',
Item: Item,
components: {
Col
},
props: {
title: {
type: String,
default: '',
required: false
},
col: {
type: Number,
required: false,
default: 3
},
size: {
type: String,
required: false,
default: 'large'
},
layout: {
type: String,
required: false,
default: 'horizontal'
}
},
provide () {
return {
col: this.col > 4 ? 4 : this.col
}
}
}
</script>
<style lang="less" scoped>
.description-list {
.title {
color: rgba(0,0,0,.85);
font-size: 14px;
font-weight: 500;
margin-bottom: 16px;
}
/deep/ .term {
color: rgba(0,0,0,.85);
display: table-cell;
line-height: 20px;
margin-right: 8px;
padding-bottom: 16px;
white-space: nowrap;
&:not(:empty):after {
content: ":";
margin: 0 8px 0 2px;
position: relative;
top: -.5px;
}
}
/deep/ .content {
color: rgba(0,0,0,.65);
display: table-cell;
min-height: 22px;
line-height: 22px;
padding-bottom: 16px;
width: 100%;
&:empty {
content: ' ';
height: 38px;
padding-bottom: 16px;
}
}
&.small {
.title {
font-size: 14px;
color: rgba(0, 0, 0, .65);
font-weight: normal;
margin-bottom: 12px;
}
/deep/ .term, .content {
padding-bottom: 8px;
}
}
&.large {
/deep/ .term, .content {
padding-bottom: 16px;
}
.title {
font-size: 16px;
}
}
&.vertical {
.term {
padding-bottom: 8px;
}
/deep/ .term, .content {
display: block;
}
}
}
</style>

View File

@ -0,0 +1,2 @@
import DescriptionList from './DescriptionList'
export default DescriptionList

View File

@ -0,0 +1,113 @@
import Modal from 'ant-design-vue/es/modal'
export default (Vue) => {
function dialog (component, componentProps, modalProps) {
const _vm = this
modalProps = modalProps || {}
if (!_vm || !_vm._isVue) {
return
}
let dialogDiv = document.querySelector('body>div[type=dialog]')
if (!dialogDiv) {
dialogDiv = document.createElement('div')
dialogDiv.setAttribute('type', 'dialog')
document.body.appendChild(dialogDiv)
}
const handle = function (checkFunction, afterHandel) {
if (checkFunction instanceof Function) {
const res = checkFunction()
if (res instanceof Promise) {
res.then(c => {
c && afterHandel()
})
} else {
res && afterHandel()
}
} else {
// checkFunction && afterHandel()
checkFunction || afterHandel()
}
}
const dialogInstance = new Vue({
data () {
return {
visible: true
}
},
router: _vm.$router,
store: _vm.$store,
mounted () {
this.$on('close', (v) => {
this.handleClose()
})
},
methods: {
handleClose () {
handle(this.$refs._component.onCancel, () => {
this.visible = false
this.$refs._component.$emit('close')
this.$refs._component.$emit('cancel')
dialogInstance.$destroy()
})
},
handleOk () {
handle(this.$refs._component.onOK || this.$refs._component.onOk, () => {
this.visible = false
this.$refs._component.$emit('close')
this.$refs._component.$emit('ok')
dialogInstance.$destroy()
})
}
},
render: function (h) {
const that = this
const modalModel = modalProps && modalProps.model
if (modalModel) {
delete modalProps.model
}
const ModalProps = Object.assign({}, modalModel && { model: modalModel } || {}, {
attrs: Object.assign({}, {
...(modalProps.attrs || modalProps)
}, {
visible: this.visible
}),
on: Object.assign({}, {
...(modalProps.on || modalProps)
}, {
ok: () => {
that.handleOk()
},
cancel: () => {
that.handleClose()
}
})
})
const componentModel = componentProps && componentProps.model
if (componentModel) {
delete componentProps.model
}
const ComponentProps = Object.assign({}, componentModel && { model: componentModel } || {}, {
ref: '_component',
attrs: Object.assign({}, {
...((componentProps && componentProps.attrs) || componentProps)
}),
on: Object.assign({}, {
...((componentProps && componentProps.on) || componentProps)
})
})
return h(Modal, ModalProps, [h(component, ComponentProps)])
}
}).$mount(dialogDiv)
}
Object.defineProperty(Vue.prototype, '$dialog', {
get: () => {
return function () {
dialog.apply(this, arguments)
}
}
})
}

View File

@ -0,0 +1,82 @@
<template>
<div :class="prefixCls">
<quill-editor
v-model="content"
ref="myQuillEditor"
:options="editorOption"
@blur="onEditorBlur($event)"
@focus="onEditorFocus($event)"
@ready="onEditorReady($event)"
@change="onEditorChange($event)">
</quill-editor>
</div>
</template>
<script>
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
import { quillEditor } from 'vue-quill-editor'
export default {
name: 'QuillEditor',
components: {
quillEditor
},
props: {
prefixCls: {
type: String,
default: 'ant-editor-quill'
},
//
// eslint-disable-next-line
value: {
type: String
}
},
data () {
return {
content: null,
editorOption: {
// some quill options
}
}
},
methods: {
onEditorBlur (quill) {
console.log('editor blur!', quill)
},
onEditorFocus (quill) {
console.log('editor focus!', quill)
},
onEditorReady (quill) {
console.log('editor ready!', quill)
},
onEditorChange ({ quill, html, text }) {
console.log('editor change!', quill, html, text)
this.$emit('change', html)
}
},
watch: {
value (val) {
this.content = val
}
}
}
</script>
<style lang="less" scoped>
@import url('../index.less');
/* 覆盖 quill 默认边框圆角为 ant 默认圆角,用于统一 ant 组件风格 */
.ant-editor-quill {
/deep/ .ql-toolbar.ql-snow {
border-radius: @border-radius-base @border-radius-base 0 0;
}
/deep/ .ql-container.ql-snow {
border-radius: 0 0 @border-radius-base @border-radius-base;
}
}
</style>

View File

@ -0,0 +1,126 @@
<template>
<div>
<div id="editor" ref="myEditor"></div>
<slot></slot>
</div>
</template>
<script>
import WangEditor from 'wangeditor'
export default {
name: 'ComponentWangeditor',
data () {
return {
edit: ''
}
},
props: {
value: {
type: String,
default: ''
},
config: {
type: Object,
default: () => {
return {}
}
},
uploadConfig: {
type: Object,
default: () => {
return {
method: 'http', // custom(objurl)http()base64
url: '/'
}
}
}
},
computed: {
customConfig () {
return {
pasteFilterStyle: false, //
pasteIgnoreImg: false, //
...this.config
}
}
},
watch: {
},
components: {
},
methods: {
readBlobAsDataURL (blob, callback) {
var a = new FileReader()
a.onload = function (e) { callback(e.target.result) }
a.readAsDataURL(blob)
},
initEditor () {
var self = this
this.editor = new WangEditor(this.$refs.myEditor)
// onchange
this.editor.customConfig = this.customConfig
this.editor.customConfig.uploadImgMaxLength = 5
this.editor.change = function () { //
self.$emit('input', this.txt.html())
self.$emit('onchange', this.txt.html(), this.txt)
// editor.txt.html('.....') //
// editor.txt.clear() //
// editor.txt.append('<p></p>')//
// editor.txt.text() // text
// editor.txt.getJSON() // JSON
}
this.editor.customConfig.customUploadImg = function (files, insert) {
if (self.uploadConfig.method === 'custom') {
files.forEach(file => {
var fileUrl = URL.createObjectURL(file)
insert(fileUrl)
})
}
if (self.uploadConfig.method === 'base64') {
files.forEach(file => {
self.readBlobAsDataURL(file, function (dataurl) {
insert(dataurl)
})
})
}
if (self.uploadConfig.method === 'http') {
if (self.uploadConfig.callback) {
self.uploadConfig.callback(files, insert)
} else {
var formData = new FormData()
files.forEach(file => {
formData.append('file', file)
})
self.$axios.post(self.uploadConfig.url, formData).then(({ data }) => {
if (data.status === 'success') {
insert(data.url)
}
})
}
}
}
this.editor.create() //
this.editor.txt.text(this.value) //
this.$emit('oninit', this.editor)
}
},
beforeCreate () {
},
created () {
},
beforeMount () {
},
mounted () {
this.initEditor()
}
}
</script>
<style >
.w-e-toolbar{
flex-wrap:wrap;
}
</style>

View File

@ -0,0 +1,64 @@
<script>
import Tooltip from 'ant-design-vue/es/tooltip'
import { cutStrByFullLength, getStrFullLength } from '@/components/_util/util'
/*
const isSupportLineClamp = document.body.style.webkitLineClamp !== undefined;
const TooltipOverlayStyle = {
overflowWrap: 'break-word',
wordWrap: 'break-word',
};
*/
export default {
name: 'Ellipsis',
components: {
Tooltip
},
props: {
prefixCls: {
type: String,
default: 'ant-pro-ellipsis'
},
tooltip: {
type: Boolean
},
length: {
type: Number,
required: true
},
lines: {
type: Number,
default: 1
},
fullWidthRecognition: {
type: Boolean,
default: false
}
},
methods: {
getStrDom (str, fullLength) {
return (
<span>{ cutStrByFullLength(str, this.length) + (fullLength > this.length ? '...' : '') }</span>
)
},
getTooltip (fullStr, fullLength) {
return (
<Tooltip>
<template slot="title">{ fullStr }</template>
{ this.getStrDom(fullStr, fullLength) }
</Tooltip>
)
}
},
render () {
const { tooltip, length } = this.$props
const str = this.$slots.default.map(vNode => vNode.text).join('')
const fullLength = getStrFullLength(str)
const strDom = tooltip && fullLength > length ? this.getTooltip(str, fullLength) : this.getStrDom(str, fullLength)
return (
strDom
)
}
}
</script>

View File

@ -0,0 +1,3 @@
import Ellipsis from './Ellipsis'
export default Ellipsis

View File

@ -0,0 +1,38 @@
# Ellipsis 文本自动省略号
文本过长自动处理省略号,支持按照文本长度和最大行数两种方式截取。
引用方式:
```javascript
import Ellipsis from '@/components/Ellipsis'
export default {
components: {
Ellipsis
}
}
```
## 代码演示 [demo](https://pro.loacg.com/test/home)
```html
<ellipsis :length="100" tooltip>
There were injuries alleged in three cases in 2015, and a
fourth incident in September, according to the safety recall report. After meeting with US regulators in October, the firm decided to issue a voluntary recall.
</ellipsis>
```
## API
参数 | 说明 | 类型 | 默认值
----|------|-----|------
tooltip | 移动到文本展示完整内容的提示 | boolean | -
length | 在按照长度截取下的文本最大字符数,超过则截取省略 | number | -

View File

@ -0,0 +1,130 @@
<template>
<div class="exception">
<div class="imgBlock">
<div class="imgEle" :style="{backgroundImage: `url(${config[type].img})`}">
</div>
</div>
<div class="content">
<h1>{{ config[type].title }}</h1>
<div class="desc">{{ config[type].desc }}</div>
<div class="actions">
<a-button type="primary" @click="handleToHome"></a-button>
</div>
</div>
</div>
</template>
<script>
import types from './type'
export default {
name: 'Exception',
props: {
type: {
type: String,
default: '404'
}
},
data () {
return {
config: types
}
},
methods: {
handleToHome () {
this.$router.push({ name: 'Console' })
}
}
}
</script>
<style lang="less">
@import "~ant-design-vue/lib/style/index";
.exception {
display: flex;
align-items: center;
height: 80%;
min-height: 500px;
.imgBlock {
flex: 0 0 62.5%;
width: 62.5%;
padding-right: 152px;
zoom: 1;
&::before,
&::after {
content: ' ';
display: table;
}
&::after {
clear: both;
height: 0;
font-size: 0;
visibility: hidden;
}
}
.imgEle {
float: right;
width: 100%;
max-width: 430px;
height: 360px;
background-repeat: no-repeat;
background-position: 50% 50%;
background-size: contain;
}
.content {
flex: auto;
h1 {
margin-bottom: 24px;
color: #434e59;
font-weight: 600;
font-size: 72px;
line-height: 72px;
}
.desc {
margin-bottom: 16px;
color: @text-color-secondary;
font-size: 20px;
line-height: 28px;
}
.actions {
button:not(:last-child) {
margin-right: 8px;
}
}
}
}
@media screen and (max-width: @screen-xl) {
.exception {
.imgBlock {
padding-right: 88px;
}
}
}
@media screen and (max-width: @screen-sm) {
.exception {
display: block;
text-align: center;
.imgBlock {
margin: 0 auto 24px;
padding-right: 0;
}
}
}
@media screen and (max-width: @screen-xs) {
.exception {
.imgBlock {
margin-bottom: -24px;
overflow: hidden;
}
}
}
</style>

View File

@ -0,0 +1,2 @@
import ExceptionPage from './ExceptionPage.vue'
export default ExceptionPage

View File

@ -0,0 +1,19 @@
const types = {
403: {
img: 'https://gw.alipayobjects.com/zos/rmsportal/wZcnGqRDyhPOEYFcZDnb.svg',
title: '403',
desc: '访'
},
404: {
img: 'https://gw.alipayobjects.com/zos/rmsportal/KpnpchXsobRgLElEozzI.svg',
title: '404',
desc: '访'
},
500: {
img: 'https://gw.alipayobjects.com/zos/rmsportal/RVRUAYdCGeYNBWoKiIwB.svg',
title: '500',
desc: ''
}
}
export default types

View File

@ -0,0 +1,30 @@
<template>
<div :class="prefixCls">
<div style="float: left">
<slot name="extra">{{ extra }}</slot>
</div>
<div style="float: right">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
name: 'FooterToolBar',
props: {
prefixCls: {
type: String,
default: 'ant-pro-footer-toolbar'
},
extra: {
type: [String, Object],
default: ''
}
}
}
</script>
<style lang="less" scoped>
</style>

View File

@ -0,0 +1,4 @@
import FooterToolBar from './FooterToolBar'
import './index.less'
export default FooterToolBar

View File

@ -0,0 +1,23 @@
@import "../index";
@footer-toolbar-prefix-cls: ~"@{ant-pro-prefix}-footer-toolbar";
.@{footer-toolbar-prefix-cls} {
position: fixed;
width: 100%;
bottom: 0;
right: 0;
height: 56px;
line-height: 56px;
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.03);
background: #fff;
border-top: 1px solid #e8e8e8;
padding: 0 24px;
z-index: 9;
&:after {
content: "";
display: block;
clear: both;
}
}

View File

@ -0,0 +1,48 @@
# FooterToolbar 底部工具栏
固定在底部的工具栏。
## 何时使用
固定在内容区域的底部,不随滚动条移动,常用于长页面的数据搜集和提交工作。
引用方式:
```javascript
import FooterToolBar from '@/components/FooterToolbar'
export default {
components: {
FooterToolBar
}
}
```
## 代码演示
```html
<footer-tool-bar>
<a-button type="primary" @click="validate" :loading="loading">提交</a-button>
</footer-tool-bar>
```
```html
<footer-tool-bar extra="扩展信息提示">
<a-button type="primary" @click="validate" :loading="loading">提交</a-button>
</footer-tool-bar>
```
## API
参数 | 说明 | 类型 | 默认值
----|------|-----|------
children (slot) | 工具栏内容,向右对齐 | - | -
extra | 额外信息,向左对齐 | String, Object | -

View File

@ -0,0 +1,46 @@
<template>
<div class="footer">
<div class="links">
</div>
<div class="copyright">
Copyright © 2020 <a target="_blank" href="https://www.xiaonuo.vip/">XiaoNuo</a> All rights reserved. xiaonuo-vue 1.0
</div>
</div>
</template>
<script>
export default {
name: 'GlobalFooter',
data () {
return {}
}
}
</script>
<style lang="less" scoped>
.footer {
padding: 0 16px;
margin: 48px 0 24px;
text-align: center;
.links {
margin-bottom: 8px;
a {
color: rgba(0, 0, 0, 0.45);
&:hover {
color: rgba(0, 0, 0, 0.65);
}
&:not(:last-child) {
margin-right: 40px;
}
}
}
.copyright {
color: rgba(0, 0, 0, 0.45);
font-size: 14px;
}
}
</style>

View File

@ -0,0 +1,2 @@
import GlobalFooter from './GlobalFooter'
export default GlobalFooter

View File

@ -0,0 +1,165 @@
<template>
<transition name="showHeader">
<div v-if="visible" class="header-animat">
<a-layout-header
v-if="visible"
:class="[fixedHeader && 'ant-header-fixedHeader', sidebarOpened ? 'ant-header-side-opened' : 'ant-header-side-closed', ]"
:style="{ padding: '0' }">
<div v-if="mode === 'sidemenu'" class="header">
<a-menu
mode="horizontal"
:default-selected-keys="this.defApp"
style="border-bottom:0px;lineHeight:62px;"
>
<a-icon v-if="device==='mobile'" class="trigger" :type="collapsed ? 'menu-fold' : 'menu-unfold'" @click="toggle"/>
<a-icon v-else class="trigger" :type="collapsed ? 'menu-unfold' : 'menu-fold'" @click="toggle"/>
<a-menu-item v-for="(item) in userInfo.apps" :key="item.code" style="top:0px;" @click="switchApp(item.code)">
{{ item.name }}
</a-menu-item>
<user-menu></user-menu>
</a-menu>
</div>
<div v-else :class="['top-nav-header-index', theme]">
<div class="header-index-wide">
<div class="header-index-left">
<logo class="top-nav-header" :show-title="device !== 'mobile'"/>
<s-menu v-if="device !== 'mobile'" mode="horizontal" :menu="menus" :theme="theme" />
<a-icon v-else class="trigger" :type="collapsed ? 'menu-fold' : 'menu-unfold'" @click="toggle" />
</div>
<user-menu class="header-index-right"></user-menu>
</div>
</div>
</a-layout-header>
</div>
</transition>
</template>
<script>
import UserMenu from '../tools/UserMenu'
import SMenu from '../Menu/'
import Logo from '../tools/Logo'
import { mixin } from '@/utils/mixin'
import { mapActions, mapGetters } from 'vuex'
import { ALL_APPS_MENU } from '@/store/mutation-types'
import Vue from 'vue'
import { message } from 'ant-design-vue/es'
export default {
name: 'GlobalHeader',
components: {
UserMenu,
SMenu,
Logo
},
computed: {
...mapGetters(['userInfo'])
},
created () {
this.defApp.push(Vue.ls.get(ALL_APPS_MENU)[0].code)
},
mixins: [mixin],
props: {
mode: {
type: String,
// sidemenu, topmenu
default: 'sidemenu'
},
menus: {
type: Array,
required: true
},
theme: {
type: String,
required: false,
default: 'dark'
},
collapsed: {
type: Boolean,
required: false,
default: false
},
device: {
type: String,
required: false,
default: 'desktop'
}
},
data () {
return {
visible: true,
oldScrollTop: 0,
defApp: []
}
},
mounted () {
document.addEventListener('scroll', this.handleScroll, { passive: true })
},
methods: {
...mapActions(['MenuChange']),
/**
* 应用切换
*/
switchApp (appCode) {
this.defApp = []
const applicationData = this.userInfo.apps.filter(item => item.code === appCode)
const hideMessage = message.loading('正在切换应用!', 0)
this.MenuChange(applicationData[0]).then((res) => {
hideMessage()
// eslint-disable-next-line handle-callback-err
}).catch((err) => {
message.error('应用切换异常')
})
},
handleScroll () {
if (!this.autoHideHeader) {
return
}
const scrollTop = document.body.scrollTop + document.documentElement.scrollTop
if (!this.ticking) {
this.ticking = true
requestAnimationFrame(() => {
if (this.oldScrollTop > scrollTop) {
this.visible = true
} else if (scrollTop > 300 && this.visible) {
this.visible = false
} else if (scrollTop < 300 && !this.visible) {
this.visible = true
}
this.oldScrollTop = scrollTop
this.ticking = false
})
}
},
toggle () {
this.$emit('toggle')
}
},
beforeDestroy () {
document.body.removeEventListener('scroll', this.handleScroll, true)
}
}
</script>
<style lang="less">
@import '../index.less';
.header-animat{
position: relative;
z-index: @ant-global-header-zindex;
}
.showHeader-enter-active {
transition: all 0.25s ease;
}
.showHeader-leave-active {
transition: all 0.5s ease;
}
.showHeader-enter, .showHeader-leave-to {
opacity: 0;
}
</style>

View File

@ -0,0 +1,2 @@
import GlobalHeader from './GlobalHeader'
export default GlobalHeader

View File

@ -0,0 +1,86 @@
<template>
<div :class="prefixCls">
<a-tabs v-model="currentTab" @change="handleTabChange">
<a-tab-pane v-for="v in icons" :tab="v.title" :key="v.key">
<ul>
<li v-for="(icon, key) in v.icons" :key="`${v.key}-${key}`" :class="{ 'active': selectedIcon==icon }" @click="handleSelectedIcon(icon)" >
<a-icon :type="icon" :style="{ fontSize: '36px' }" />
</li>
</ul>
</a-tab-pane>
</a-tabs>
</div>
</template>
<script>
import icons from './icons'
export default {
name: 'IconSelect',
props: {
prefixCls: {
type: String,
default: 'ant-pro-icon-selector'
},
// eslint-disable-next-line
value: {
type: String
}
},
data () {
return {
selectedIcon: this.value || '',
currentTab: 'directional',
icons
}
},
watch: {
value (val) {
this.selectedIcon = val
this.autoSwitchTab()
}
},
created () {
if (this.value) {
this.autoSwitchTab()
}
},
methods: {
handleSelectedIcon (icon) {
this.selectedIcon = icon
this.$emit('change', icon)
},
handleTabChange (activeKey) {
this.currentTab = activeKey
},
autoSwitchTab () {
icons.some(item => item.icons.some(icon => icon === this.value) && (this.currentTab = item.key))
}
}
}
</script>
<style lang="less" scoped>
@import "../index.less";
ul{
list-style: none;
padding: 0;
overflow-y: scroll;
height: 250px;
li{
display: inline-block;
padding: @padding-sm;
margin: 3px 0;
border-radius: @border-radius-base;
&:hover, &.active{
// box-shadow: 0px 0px 5px 2px @primary-color;
cursor: pointer;
color: @white;
background-color: @primary-color;
}
}
}
</style>

Some files were not shown because too many files have changed in this diff Show More