初次提交

master
15128022404 3 years ago
parent 00096b4b0c
commit 4926c55755

@ -0,0 +1,23 @@
docs
public
src
.dockerignore
.editorconfig
.eslintignore
.gitattributes
.gitignore
.prettierrc
babel.config.js
Dockerfile
idea.config.js
LICENSE
package.json
package-lock.json
README.md
vue.config.js
yarn
yarn.lock
yarn-error.log
.idea
.svn
node_modules

@ -0,0 +1,39 @@
[*]
charset=utf-8
end_of_line=crlf
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

@ -0,0 +1,3 @@
NODE_ENV=production
VUE_APP_PLATFORM_NAME=中国恩菲访客系统
VUE_APP_SSO=false

@ -0,0 +1,6 @@
NODE_ENV=development
#VUE_APP_API_BASE_URL=https://enfi.guest.dink.xyz/enfi-visitor
#VUE_APP_API_BASE_URL=https://openapi.enfi.com.cn:52601/enfi-visitor
VUE_APP_API_BASE_URL=http://172.28.17.88:52601/enfi-visitor
VUE_APP_CAS_BASE_URL=http://cas.example.org:8443/cas
VUE_APP_ONLINE_BASE_URL=http://fileview.jeecg.com/onlinePreview

@ -0,0 +1,5 @@
NODE_ENV=production
#VUE_APP_API_BASE_URL=https://enfi.guest.dink.xyz/enfi-visitor
VUE_APP_API_BASE_URL=https://openapi.enfi.com.cn:52601/enfi-visitor
VUE_APP_CAS_BASE_URL=http://localhost:8888/cas
VUE_APP_ONLINE_BASE_URL=http://fileview.jeecg.com/onlinePreview

@ -0,0 +1,4 @@
NODE_ENV=production
VUE_APP_API_BASE_URL=http://boot.jeecg.com:8080/jeecg-boot
VUE_APP_CAS_BASE_URL=http://cas.example.org:8443/cas
VUE_APP_ONLINE_BASE_URL=http://fileview.jeecg.com/onlinePreview

1
.gitattributes vendored

@ -0,0 +1 @@
public/* linguist-vendored

33
.gitignore vendored

@ -1,18 +1,21 @@
# Build and Release Folders .DS_Store
bin-debug/ node_modules
bin-release/ /dist
[Oo]bj/
[Bb]in/
# Other files and folders # local env files
.settings/ .env.local
.env.*.local
# Executables # Log files
*.swf npm-debug.log*
*.air yarn-debug.log*
*.ipa yarn-error.log*
*.apk
# Project files, i.e. `.project`, `.actionScriptProperties` and `.flexProperties` # Editor directories and files
# should NOT be excluded as they contain compiler settings and other important .idea
# information for Eclipse / Flash Builder. .vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*

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

@ -0,0 +1,29 @@
FROM nginx
MAINTAINER jeecgos@163.com
VOLUME /tmp
ENV LANG en_US.UTF-8
RUN echo "server { \
listen 80; \
location ^~ /jeecg-boot { \
proxy_pass http://jeecg-boot-system:8080/jeecg-boot/; \
proxy_set_header Host jeecg-boot-system; \
proxy_set_header X-Real-IP \$remote_addr; \
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; \
} \
#解决Router(mode: 'history')模式下,刷新路由地址不能找到页面的问题 \
location / { \
root /var/www/html/; \
index index.html index.htm; \
if (!-e \$request_filename) { \
rewrite ^(.*)\$ /index.html?s=\$1 last; \
break; \
} \
} \
access_log /var/log/nginx/access.log ; \
} " > /etc/nginx/conf.d/default.conf \
&& mkdir -p /var/www \
&& mkdir -p /var/www/html
ADD dist/ /var/www/html/
EXPOSE 80
EXPOSE 443

@ -1,201 +1,21 @@
Apache License MIT License
Version 2.0, January 2004
http://www.apache.org/licenses/ Copyright (c) 2019 DaiHao Zhang
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
1. Definitions. in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
"License" shall mean the terms and conditions for use, reproduction, copies of the Software, and to permit persons to whom the Software is
and distribution as defined by Sections 1 through 9 of this document. furnished to do so, subject to the following conditions:
"Licensor" shall mean the copyright owner or entity authorized by The above copyright notice and this permission notice shall be included in all
the copyright owner that is granting the License. copies or substantial portions of the Software.
"Legal Entity" shall mean the union of the acting entity and all THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
other entities that control, are controlled by, or are under common IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
control with that entity. For the purposes of this definition, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
"control" means (i) the power, direct or indirect, to cause the AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
direction or management of such entity, whether by contract or LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
otherwise, or (ii) ownership of fifty percent (50%) or more of the OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
outstanding shares, or (iii) beneficial ownership of such entity. SOFTWARE.
"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:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) 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
(d) 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
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

@ -1,36 +0,0 @@
# jeecg-boot-vue
#### Description
{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**}
#### Software Architecture
Software architecture description
#### Installation
1. xxxx
2. xxxx
3. xxxx
#### Instructions
1. xxxx
2. xxxx
3. xxxx
#### Contribution
1. Fork the repository
2. Create Feat_xxx branch
3. Commit your code
4. Create Pull Request
#### Gitee Feature
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

@ -1,39 +1,135 @@
# jeecg-boot-vue Ant Design Jeecg Vue
====
#### 介绍 当前最新版本: 3.0.0发布日期2021-11-01
{**以下是 Gitee 平台说明,您可以替换此简介**
Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN。专为开发者提供稳定、高效、安全的云端软件开发协作平台
无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)}
#### 软件架构 Overview
软件架构说明 ----
基于 [Ant Design of Vue](https://vuecomponent.github.io/ant-design-vue/docs/vue/introduce-cn/) 实现的 Ant Design Pro Vue 版
Jeecg-boot 的前端UI框架采用前后端分离方案提供强大代码生成器的低代码平台。
前端页面代码和后端功能代码一键生成不需要写任何代码保持jeecg一贯的强大
#### 安装教程
1. xxxx
2. xxxx
3. xxxx
#### 使用说明 #### 前端技术
1. xxxx - 基础框架:[ant-design-vue](https://github.com/vueComponent/ant-design-vue) - Ant Design Of Vue 实现
2. xxxx - JavaScript框架Vue
3. xxxx - Webpack
- node
- yarn
- eslint
- @vue/cli 3.2.1
- [vue-cropper](https://github.com/xyxiao001/vue-cropper) - 头像裁剪组件
- [@antv/g2](https://antv.alipay.com/zh-cn/index.html) - Alipay AntV 数据可视化图表
- [Viser-vue](https://viserjs.github.io/docs.html#/viser/guide/installation) - antv/g2 封装实现
#### 参与贡献
1. Fork 本仓库
2. 新建 Feat_xxx 分支
3. 提交代码
4. 新建 Pull Request
项目下载和运行
----
#### 特技 - 拉取项目代码
```bash
git clone https://github.com/zhangdaiscott/jeecg-boot.git
cd jeecg-boot/ant-design-vue-jeecg
```
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md - 安装依赖
2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) ```
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 yarn install
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 ```
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) - 开发模式运行
```
yarn run serve
```
- 编译项目
```
yarn run build
```
- Lints and fixes files
```
yarn run lint
```
其他说明
----
- 项目使用的 [vue-cli3](https://cli.vuejs.org/guide/), 请更新您的 cli
- 关闭 Eslint (不推荐) 移除 `package.json``eslintConfig` 整个节点代码
- 修改 Ant Design 配色,在文件 `vue.config.js` 中,其他 less 变量覆盖参考 [ant design](https://ant.design/docs/react/customize-theme-cn) 官方说明
```ecmascript 6
css: {
loaderOptions: {
less: {
modifyVars: {
/* less 变量覆盖,用于自定义 ant design 主题 */
'primary-color': '#F5222D',
'link-color': '#F5222D',
'border-radius-base': '4px',
},
javascriptEnabled: true,
}
}
}
```
附属文档
----
- [Ant Design Vue](https://vuecomponent.github.io/ant-design-vue/docs/vue/introduce-cn)
- [报表 viser-vue](https://viserjs.github.io/demo.html#/viser/bar/basic-bar)
- [Vue](https://cn.vuejs.org/v2/guide)
- [路由/菜单说明](https://github.com/zhangdaiscott/jeecg-boot/tree/master/ant-design-vue-jeecg/src/router/README.md)
- [ANTD 默认配置项](https://github.com/zhangdaiscott/jeecg-boot/tree/master/ant-design-vue-jeecg/src/defaultSettings.js)
- 其他待补充...
备注
----
> @vue/cli 升级后eslint 规则更新了。由于影响到全部 .vue 文件,需要逐个验证。既暂时关闭部分原本不验证的规则,后期维护时,在逐步修正这些 rules
Docker 镜像使用
----
```
# 1.修改前端项目的后台域名
.env.development
域名改成: http://jeecg-boot-system:8080/jeecg-boot
# 2.先进入打包前端项目
yarn run build
# 3.构建镜像
docker build -t nginx:jeecgboot .
# 4.启动镜像
docker run --name jeecg-boot-nginx -p 80:80 -d nginx:jeecgboot
# 5.配置host
# jeecgboot
127.0.0.1 jeecg-boot-redis
127.0.0.1 jeecg-boot-mysql
127.0.0.1 jeecg-boot-system
# 6.访问前台项目
http://localhost:80
```

@ -0,0 +1,6 @@
module.exports = {
presets: [
['@vue/app',
{ useBuiltIns: 'entry' }]
]
}

@ -0,0 +1,24 @@
'use strict'
const path = require('path')
function resolve (dir) {
return path.join(__dirname, '.', dir)
}
module.exports = {
context: path.resolve(__dirname, './'),
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'config': resolve('config'),
'@': resolve('src'),
'@views': resolve('src/views'),
'@comp': resolve('src/components'),
'@core': resolve('src/core'),
'@utils': resolve('src/utils'),
'@entry': resolve('src/entry'),
'@router': resolve('src/router'),
'@store': resolve('src/store')
}
},
}

18282
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,116 @@
{
"name": "vue-antd-jeecg",
"version": "3.0.0",
"private": true,
"scripts": {
"pre": "cnpm install || yarn --registry https://registry.npm.taobao.org || npm install --registry https://registry.npm.taobao.org ",
"serve": "vue-cli-service serve",
"dev": "vue-cli-service serve --mode development",
"build:test": "vue-cli-service build --mode test",
"build": "vue-cli-service build --mode production",
"lint": "vue-cli-service lint"
},
"dependencies": {
"ant-design-vue": "^1.7.2",
"@jeecg/antd-online-mini": "3.0.0-beta",
"@antv/data-set": "^0.11.4",
"viser-vue": "^2.4.8",
"axios": "^0.18.0",
"dayjs": "^1.8.0",
"enquire.js": "^2.1.6",
"js-cookie": "^2.2.0",
"lodash.get": "^4.4.2",
"lodash.pick": "^4.4.0",
"md5": "^2.2.1",
"nprogress": "^0.2.0",
"vue": "^2.6.10",
"vue-cropper": "^0.5.4",
"vue-i18n": "^8.7.0",
"vue-loader": "^15.7.0",
"vue-ls": "^3.2.0",
"vue-router": "^3.0.1",
"vuex": "^3.1.0",
"vue-print-nb-jeecg": "^1.0.9",
"clipboard": "^2.0.4",
"vue-photo-preview": "^1.1.3",
"vue-splitpane": "^1.0.4",
"vuedraggable": "^2.20.0",
"codemirror": "^5.46.0",
"@tinymce/tinymce-vue": "^2.1.0",
"tinymce": "^5.3.2",
"@toast-ui/editor": "^2.1.2",
"vue-area-linkage": "^5.1.0",
"china-area-data": "^5.0.1",
"dom-align": "1.12.0",
"xe-utils": "2.4.8",
"vxe-table": "2.9.13",
"vxe-table-plugin-antd": "1.8.10",
"cron-parser": "^2.10.0"
},
"devDependencies": {
"@babel/polyfill": "^7.2.5",
"@vue/cli-plugin-babel": "^3.3.0",
"@vue/cli-plugin-eslint": "^3.3.0",
"@vue/cli-service": "^3.3.0",
"@vue/eslint-config-standard": "^4.0.0",
"babel-eslint": "7.2.3",
"eslint": "^5.16.0",
"eslint-plugin-vue": "^5.1.0",
"less": "^3.9.0",
"less-loader": "^4.1.0",
"vue-template-compiler": "^2.6.10",
"html-webpack-plugin": "^4.2.0",
"compression-webpack-plugin": "^3.1.0"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/strongly-recommended",
"@vue/standard"
],
"parserOptions": {
"parser": "babel-eslint"
},
"rules": {
"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,
"indent": ["off", 2],
"no-console": 0,
"space-before-function-paren": 0
}
},
"postcss": {
"plugins": {
"autoprefixer": {}
}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 10"
]
}

BIN
public/avatar2.jpg vendored

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

7720
public/color.less vendored

File diff suppressed because it is too large Load Diff

BIN
public/enfi_logo.png vendored

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
public/goright.png vendored

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

262
public/index.html vendored

@ -0,0 +1,262 @@
<!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">
<title>中国恩菲访客系统</title>
<link rel="icon" href="<%= BASE_URL %>enfi_logo.png">
<script src="<%= BASE_URL %>cdn/babel-polyfill/polyfill_7_2_5.js"></script>
<style>
html,
body,
#app {
height: 100%;
margin: 0px;
padding: 0px;
}
.chromeframe {
margin: 0.2em 0;
background: #ccc;
color: #000;
padding: 0.2em 0;
}
#loader-wrapper {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 999999;
}
#loader {
display: block;
position: relative;
left: 50%;
top: 50%;
width: 120px;
height: 120px;
margin: -75px 0 0 -75px;
border-radius: 50%;
border: 3px solid transparent;
/* COLOR 1 */
border-top-color: #FFF;
-webkit-animation: spin 2s linear infinite;
/* Chrome, Opera 15+, Safari 5+ */
-ms-animation: spin 2s linear infinite;
/* Chrome, Opera 15+, Safari 5+ */
-moz-animation: spin 2s linear infinite;
/* Chrome, Opera 15+, Safari 5+ */
-o-animation: spin 2s linear infinite;
/* Chrome, Opera 15+, Safari 5+ */
animation: spin 2s linear infinite;
/* Chrome, Firefox 16+, IE 10+, Opera */
z-index: 1001;
}
#loader:before {
content: "";
position: absolute;
top: 5px;
left: 5px;
right: 5px;
bottom: 5px;
border-radius: 50%;
border: 3px solid transparent;
/* COLOR 2 */
border-top-color: #FFF;
-webkit-animation: spin 3s linear infinite;
/* Chrome, Opera 15+, Safari 5+ */
-moz-animation: spin 3s linear infinite;
/* Chrome, Opera 15+, Safari 5+ */
-o-animation: spin 3s linear infinite;
/* Chrome, Opera 15+, Safari 5+ */
-ms-animation: spin 3s linear infinite;
/* Chrome, Opera 15+, Safari 5+ */
animation: spin 3s linear infinite;
/* Chrome, Firefox 16+, IE 10+, Opera */
}
#loader:after {
content: "";
position: absolute;
top: 15px;
left: 15px;
right: 15px;
bottom: 15px;
border-radius: 50%;
border: 3px solid transparent;
border-top-color: #FFF;
/* COLOR 3 */
-moz-animation: spin 1.5s linear infinite;
/* Chrome, Opera 15+, Safari 5+ */
-o-animation: spin 1.5s linear infinite;
/* Chrome, Opera 15+, Safari 5+ */
-ms-animation: spin 1.5s linear infinite;
/* Chrome, Opera 15+, Safari 5+ */
-webkit-animation: spin 1.5s linear infinite;
/* Chrome, Opera 15+, Safari 5+ */
animation: spin 1.5s linear infinite;
/* Chrome, Firefox 16+, IE 10+, Opera */
}
@-webkit-keyframes spin {
0% {
-webkit-transform: rotate(0deg);
/* Chrome, Opera 15+, Safari 3.1+ */
-ms-transform: rotate(0deg);
/* IE 9 */
transform: rotate(0deg);
/* Firefox 16+, IE 10+, Opera */
}
100% {
-webkit-transform: rotate(360deg);
/* Chrome, Opera 15+, Safari 3.1+ */
-ms-transform: rotate(360deg);
/* IE 9 */
transform: rotate(360deg);
/* Firefox 16+, IE 10+, Opera */
}
}
@keyframes spin {
0% {
-webkit-transform: rotate(0deg);
/* Chrome, Opera 15+, Safari 3.1+ */
-ms-transform: rotate(0deg);
/* IE 9 */
transform: rotate(0deg);
/* Firefox 16+, IE 10+, Opera */
}
100% {
-webkit-transform: rotate(360deg);
/* Chrome, Opera 15+, Safari 3.1+ */
-ms-transform: rotate(360deg);
/* IE 9 */
transform: rotate(360deg);
/* Firefox 16+, IE 10+, Opera */
}
}
#loader-wrapper .loader-section {
position: fixed;
top: 0;
width: 51%;
height: 100%;
background: #49a9ee;
/* Old browsers */
z-index: 1000;
-webkit-transform: translateX(0);
/* Chrome, Opera 15+, Safari 3.1+ */
-ms-transform: translateX(0);
/* IE 9 */
transform: translateX(0);
/* Firefox 16+, IE 10+, Opera */
}
#loader-wrapper .loader-section.section-left {
left: 0;
}
#loader-wrapper .loader-section.section-right {
right: 0;
}
/* Loaded */
.loaded #loader-wrapper .loader-section.section-left {
-webkit-transform: translateX(-100%);
/* Chrome, Opera 15+, Safari 3.1+ */
-ms-transform: translateX(-100%);
/* IE 9 */
transform: translateX(-100%);
/* Firefox 16+, IE 10+, Opera */
-webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
}
.loaded #loader-wrapper .loader-section.section-right {
-webkit-transform: translateX(100%);
/* Chrome, Opera 15+, Safari 3.1+ */
-ms-transform: translateX(100%);
/* IE 9 */
transform: translateX(100%);
/* Firefox 16+, IE 10+, Opera */
-webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
}
.loaded #loader {
opacity: 0;
-webkit-transition: all 0.3s ease-out;
transition: all 0.3s ease-out;
}
.loaded #loader-wrapper {
visibility: hidden;
-webkit-transform: translateY(-100%);
/* Chrome, Opera 15+, Safari 3.1+ */
-ms-transform: translateY(-100%);
/* IE 9 */
transform: translateY(-100%);
/* Firefox 16+, IE 10+, Opera */
-webkit-transition: all 0.3s 1s ease-out;
transition: all 0.3s 1s ease-out;
}
/* JavaScript Turned Off */
.no-js #loader-wrapper {
display: none;
}
.no-js h1 {
color: #222222;
}
#loader-wrapper .load_title {
font-family: 'Open Sans';
color: #FFF;
font-size: 14px;
width: 100%;
text-align: center;
z-index: 9999999999999;
position: absolute;
top: 60%;
opacity: 1;
line-height: 30px;
}
#loader-wrapper .load_title span {
font-weight: normal;
font-style: italic;
font-size: 14px;
color: #FFF;
opacity: 0.5;
}
/* 滚动条优化 start */
::-webkit-scrollbar{
width:8px;
height:8px;
}
::-webkit-scrollbar-track{
background: #f6f6f6;
border-radius:2px;
}
::-webkit-scrollbar-thumb{
background: #cdcdcd;
border-radius:2px;
}
::-webkit-scrollbar-thumb:hover{
background: #747474;
}
::-webkit-scrollbar-corner {
background: #f6f6f6;
}
/* 滚动条优化 end */
</style>
<!-- 全局配置 -->
<script>
window._CONFIG = {};
</script>
</head>
<body>
<div id="app">
<div id="loader-wrapper">
<div id="loader"></div>
<div class="loader-section section-left"></div>
<div class="loader-section section-right"></div>
<div class="load_title">正在加载 中国恩菲访客系统,请耐心等待
</div>
</div>
</div>
</body>
</html>

BIN
public/logo.png vendored

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

@ -0,0 +1,261 @@
tinymce.addI18n('zh_CN',{
"Redo": "\u91cd\u590d",
"Undo": "\u64a4\u6d88",
"Cut": "\u526a\u5207",
"Copy": "\u590d\u5236",
"Paste": "\u7c98\u8d34",
"Select all": "\u5168\u9009",
"New document": "\u65b0\u6587\u6863",
"Ok": "\u786e\u5b9a",
"Cancel": "\u53d6\u6d88",
"Visual aids": "\u7f51\u683c\u7ebf",
"Bold": "\u7c97\u4f53",
"Italic": "\u659c\u4f53",
"Underline": "\u4e0b\u5212\u7ebf",
"Strikethrough": "\u5220\u9664\u7ebf",
"Superscript": "\u4e0a\u6807",
"Subscript": "\u4e0b\u6807",
"Clear formatting": "\u6e05\u9664\u683c\u5f0f",
"Align left": "\u5de6\u5bf9\u9f50",
"Align center": "\u5c45\u4e2d",
"Align right": "\u53f3\u5bf9\u9f50",
"Justify": "\u4e24\u7aef\u5bf9\u9f50",
"Bullet list": "\u9879\u76ee\u7b26\u53f7",
"Numbered list": "\u7f16\u53f7\u5217\u8868",
"Decrease indent": "\u51cf\u5c11\u7f29\u8fdb",
"Increase indent": "\u589e\u52a0\u7f29\u8fdb",
"Close": "\u5173\u95ed",
"Formats": "\u683c\u5f0f",
"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u4f60\u7684\u6d4f\u89c8\u5668\u4e0d\u652f\u6301\u5bf9\u526a\u8d34\u677f\u7684\u8bbf\u95ee\uff0c\u8bf7\u4f7f\u7528Ctrl+X\/C\/V\u952e\u8fdb\u884c\u590d\u5236\u7c98\u8d34\u3002",
"Headers": "\u6807\u9898",
"Header 1": "\u6807\u98981",
"Header 2": "\u6807\u98982",
"Header 3": "\u6807\u98983",
"Header 4": "\u6807\u98984",
"Header 5": "\u6807\u98985",
"Header 6": "\u6807\u98986",
"Headings": "\u6807\u9898",
"Heading 1": "\u6807\u98981",
"Heading 2": "\u6807\u98982",
"Heading 3": "\u6807\u98983",
"Heading 4": "\u6807\u98984",
"Heading 5": "\u6807\u98985",
"Heading 6": "\u6807\u98986",
"Preformatted": "\u9884\u683c\u5f0f\u5316",
"Div": "Div\u533a\u5757",
"Pre": "\u9884\u683c\u5f0f\u6587\u672c",
"Code": "\u4ee3\u7801",
"Paragraph": "\u6bb5\u843d",
"Blockquote": "\u5f15\u7528",
"Inline": "\u6587\u672c",
"Blocks": "\u533a\u5757",
"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\u5f53\u524d\u4e3a\u7eaf\u6587\u672c\u7c98\u8d34\u6a21\u5f0f\uff0c\u518d\u6b21\u70b9\u51fb\u53ef\u4ee5\u56de\u5230\u666e\u901a\u7c98\u8d34\u6a21\u5f0f\u3002",
"Font Family": "\u5b57\u4f53",
"Font Sizes": "\u5b57\u53f7",
"Class": "Class",
"Browse for an image": "\u6d4f\u89c8\u56fe\u50cf",
"OR": "\u6216",
"Drop an image here": "\u62d6\u653e\u4e00\u5f20\u56fe\u50cf\u81f3\u6b64",
"Upload": "\u4e0a\u4f20",
"Block": "\u5757",
"Align": "\u5bf9\u9f50",
"Default": "\u9ed8\u8ba4",
"Circle": "\u7a7a\u5fc3\u5706",
"Disc": "\u5b9e\u5fc3\u5706",
"Square": "\u65b9\u5757",
"Lower Alpha": "\u5c0f\u5199\u82f1\u6587\u5b57\u6bcd",
"Lower Greek": "\u5c0f\u5199\u5e0c\u814a\u5b57\u6bcd",
"Lower Roman": "\u5c0f\u5199\u7f57\u9a6c\u5b57\u6bcd",
"Upper Alpha": "\u5927\u5199\u82f1\u6587\u5b57\u6bcd",
"Upper Roman": "\u5927\u5199\u7f57\u9a6c\u5b57\u6bcd",
"Anchor": "\u951a\u70b9",
"Name": "\u540d\u79f0",
"Id": "\u6807\u8bc6\u7b26",
"Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.": "\u6807\u8bc6\u7b26\u5e94\u8be5\u4ee5\u5b57\u6bcd\u5f00\u5934\uff0c\u540e\u8ddf\u5b57\u6bcd\u3001\u6570\u5b57\u3001\u7834\u6298\u53f7\u3001\u70b9\u3001\u5192\u53f7\u6216\u4e0b\u5212\u7ebf\u3002",
"You have unsaved changes are you sure you want to navigate away?": "\u4f60\u8fd8\u6709\u6587\u6863\u5c1a\u672a\u4fdd\u5b58\uff0c\u786e\u5b9a\u8981\u79bb\u5f00\uff1f",
"Restore last draft": "\u6062\u590d\u4e0a\u6b21\u7684\u8349\u7a3f",
"Special character": "\u7279\u6b8a\u7b26\u53f7",
"Source code": "\u6e90\u4ee3\u7801",
"Insert\/Edit code sample": "\u63d2\u5165\/\u7f16\u8f91\u4ee3\u7801\u793a\u4f8b",
"Language": "\u8bed\u8a00",
"Code sample": "\u4ee3\u7801\u793a\u4f8b",
"Color": "\u989c\u8272",
"R": "R",
"G": "G",
"B": "B",
"Left to right": "\u4ece\u5de6\u5230\u53f3",
"Right to left": "\u4ece\u53f3\u5230\u5de6",
"Emoticons": "\u8868\u60c5",
"Document properties": "\u6587\u6863\u5c5e\u6027",
"Title": "\u6807\u9898",
"Keywords": "\u5173\u952e\u8bcd",
"Description": "\u63cf\u8ff0",
"Robots": "\u673a\u5668\u4eba",
"Author": "\u4f5c\u8005",
"Encoding": "\u7f16\u7801",
"Fullscreen": "\u5168\u5c4f",
"Action": "\u64cd\u4f5c",
"Shortcut": "\u5feb\u6377\u952e",
"Help": "\u5e2e\u52a9",
"Address": "\u5730\u5740",
"Focus to menubar": "\u79fb\u52a8\u7126\u70b9\u5230\u83dc\u5355\u680f",
"Focus to toolbar": "\u79fb\u52a8\u7126\u70b9\u5230\u5de5\u5177\u680f",
"Focus to element path": "\u79fb\u52a8\u7126\u70b9\u5230\u5143\u7d20\u8def\u5f84",
"Focus to contextual toolbar": "\u79fb\u52a8\u7126\u70b9\u5230\u4e0a\u4e0b\u6587\u83dc\u5355",
"Insert link (if link plugin activated)": "\u63d2\u5165\u94fe\u63a5 (\u5982\u679c\u94fe\u63a5\u63d2\u4ef6\u5df2\u6fc0\u6d3b)",
"Save (if save plugin activated)": "\u4fdd\u5b58(\u5982\u679c\u4fdd\u5b58\u63d2\u4ef6\u5df2\u6fc0\u6d3b)",
"Find (if searchreplace plugin activated)": "\u67e5\u627e(\u5982\u679c\u67e5\u627e\u66ff\u6362\u63d2\u4ef6\u5df2\u6fc0\u6d3b)",
"Plugins installed ({0}):": "\u5df2\u5b89\u88c5\u63d2\u4ef6 ({0}):",
"Premium plugins:": "\u4f18\u79c0\u63d2\u4ef6\uff1a",
"Learn more...": "\u4e86\u89e3\u66f4\u591a...",
"You are using {0}": "\u4f60\u6b63\u5728\u4f7f\u7528 {0}",
"Plugins": "\u63d2\u4ef6",
"Handy Shortcuts": "\u5feb\u6377\u952e",
"Horizontal line": "\u6c34\u5e73\u5206\u5272\u7ebf",
"Insert\/edit image": "\u63d2\u5165\/\u7f16\u8f91\u56fe\u7247",
"Image description": "\u56fe\u7247\u63cf\u8ff0",
"Source": "\u5730\u5740",
"Dimensions": "\u5927\u5c0f",
"Constrain proportions": "\u4fdd\u6301\u7eb5\u6a2a\u6bd4",
"General": "\u666e\u901a",
"Advanced": "\u9ad8\u7ea7",
"Style": "\u6837\u5f0f",
"Vertical space": "\u5782\u76f4\u8fb9\u8ddd",
"Horizontal space": "\u6c34\u5e73\u8fb9\u8ddd",
"Border": "\u8fb9\u6846",
"Insert image": "\u63d2\u5165\u56fe\u7247",
"Image": "\u56fe\u7247",
"Image list": "\u56fe\u7247\u5217\u8868",
"Rotate counterclockwise": "\u9006\u65f6\u9488\u65cb\u8f6c",
"Rotate clockwise": "\u987a\u65f6\u9488\u65cb\u8f6c",
"Flip vertically": "\u5782\u76f4\u7ffb\u8f6c",
"Flip horizontally": "\u6c34\u5e73\u7ffb\u8f6c",
"Edit image": "\u7f16\u8f91\u56fe\u7247",
"Image options": "\u56fe\u7247\u9009\u9879",
"Zoom in": "\u653e\u5927",
"Zoom out": "\u7f29\u5c0f",
"Crop": "\u88c1\u526a",
"Resize": "\u8c03\u6574\u5927\u5c0f",
"Orientation": "\u65b9\u5411",
"Brightness": "\u4eae\u5ea6",
"Sharpen": "\u9510\u5316",
"Contrast": "\u5bf9\u6bd4\u5ea6",
"Color levels": "\u989c\u8272\u5c42\u6b21",
"Gamma": "\u4f3d\u9a6c\u503c",
"Invert": "\u53cd\u8f6c",
"Apply": "\u5e94\u7528",
"Back": "\u540e\u9000",
"Insert date\/time": "\u63d2\u5165\u65e5\u671f\/\u65f6\u95f4",
"Date\/time": "\u65e5\u671f\/\u65f6\u95f4",
"Insert link": "\u63d2\u5165\u94fe\u63a5",
"Insert\/edit link": "\u63d2\u5165\/\u7f16\u8f91\u94fe\u63a5",
"Text to display": "\u663e\u793a\u6587\u5b57",
"Url": "\u5730\u5740",
"Target": "\u6253\u5f00\u65b9\u5f0f",
"None": "\u65e0",
"New window": "\u5728\u65b0\u7a97\u53e3\u6253\u5f00",
"Remove link": "\u5220\u9664\u94fe\u63a5",
"Anchors": "\u951a\u70b9",
"Link": "\u94fe\u63a5",
"Paste or type a link": "\u7c98\u8d34\u6216\u8f93\u5165\u94fe\u63a5",
"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "\u4f60\u6240\u586b\u5199\u7684URL\u5730\u5740\u4e3a\u90ae\u4ef6\u5730\u5740\uff0c\u9700\u8981\u52a0\u4e0amailto:\u524d\u7f00\u5417\uff1f",
"The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": "\u4f60\u6240\u586b\u5199\u7684URL\u5730\u5740\u5c5e\u4e8e\u5916\u90e8\u94fe\u63a5\uff0c\u9700\u8981\u52a0\u4e0ahttp:\/\/:\u524d\u7f00\u5417\uff1f",
"Link list": "\u94fe\u63a5\u5217\u8868",
"Insert video": "\u63d2\u5165\u89c6\u9891",
"Insert\/edit video": "\u63d2\u5165\/\u7f16\u8f91\u89c6\u9891",
"Insert\/edit media": "\u63d2\u5165\/\u7f16\u8f91\u5a92\u4f53",
"Alternative source": "\u955c\u50cf",
"Poster": "\u5c01\u9762",
"Paste your embed code below:": "\u5c06\u5185\u5d4c\u4ee3\u7801\u7c98\u8d34\u5728\u4e0b\u9762:",
"Embed": "\u5185\u5d4c",
"Media": "\u5a92\u4f53",
"Nonbreaking space": "\u4e0d\u95f4\u65ad\u7a7a\u683c",
"Page break": "\u5206\u9875\u7b26",
"Paste as text": "\u7c98\u8d34\u4e3a\u6587\u672c",
"Preview": "\u9884\u89c8",
"Print": "\u6253\u5370",
"Save": "\u4fdd\u5b58",
"Find": "\u67e5\u627e",
"Replace with": "\u66ff\u6362\u4e3a",
"Replace": "\u66ff\u6362",
"Replace all": "\u5168\u90e8\u66ff\u6362",
"Prev": "\u4e0a\u4e00\u4e2a",
"Next": "\u4e0b\u4e00\u4e2a",
"Find and replace": "\u67e5\u627e\u548c\u66ff\u6362",
"Could not find the specified string.": "\u672a\u627e\u5230\u641c\u7d22\u5185\u5bb9.",
"Match case": "\u533a\u5206\u5927\u5c0f\u5199",
"Whole words": "\u5168\u5b57\u5339\u914d",
"Spellcheck": "\u62fc\u5199\u68c0\u67e5",
"Ignore": "\u5ffd\u7565",
"Ignore all": "\u5168\u90e8\u5ffd\u7565",
"Finish": "\u5b8c\u6210",
"Add to Dictionary": "\u6dfb\u52a0\u5230\u5b57\u5178",
"Insert table": "\u63d2\u5165\u8868\u683c",
"Table properties": "\u8868\u683c\u5c5e\u6027",
"Delete table": "\u5220\u9664\u8868\u683c",
"Cell": "\u5355\u5143\u683c",
"Row": "\u884c",
"Column": "\u5217",
"Cell properties": "\u5355\u5143\u683c\u5c5e\u6027",
"Merge cells": "\u5408\u5e76\u5355\u5143\u683c",
"Split cell": "\u62c6\u5206\u5355\u5143\u683c",
"Insert row before": "\u5728\u4e0a\u65b9\u63d2\u5165",
"Insert row after": "\u5728\u4e0b\u65b9\u63d2\u5165",
"Delete row": "\u5220\u9664\u884c",
"Row properties": "\u884c\u5c5e\u6027",
"Cut row": "\u526a\u5207\u884c",
"Copy row": "\u590d\u5236\u884c",
"Paste row before": "\u7c98\u8d34\u5230\u4e0a\u65b9",
"Paste row after": "\u7c98\u8d34\u5230\u4e0b\u65b9",
"Insert column before": "\u5728\u5de6\u4fa7\u63d2\u5165",
"Insert column after": "\u5728\u53f3\u4fa7\u63d2\u5165",
"Delete column": "\u5220\u9664\u5217",
"Cols": "\u5217",
"Rows": "\u884c",
"Width": "\u5bbd",
"Height": "\u9ad8",
"Cell spacing": "\u5355\u5143\u683c\u5916\u95f4\u8ddd",
"Cell padding": "\u5355\u5143\u683c\u5185\u8fb9\u8ddd",
"Caption": "\u6807\u9898",
"Left": "\u5de6\u5bf9\u9f50",
"Center": "\u5c45\u4e2d",
"Right": "\u53f3\u5bf9\u9f50",
"Cell type": "\u5355\u5143\u683c\u7c7b\u578b",
"Scope": "\u8303\u56f4",
"Alignment": "\u5bf9\u9f50\u65b9\u5f0f",
"H Align": "\u6c34\u5e73\u5bf9\u9f50",
"V Align": "\u5782\u76f4\u5bf9\u9f50",
"Top": "\u9876\u90e8\u5bf9\u9f50",
"Middle": "\u5782\u76f4\u5c45\u4e2d",
"Bottom": "\u5e95\u90e8\u5bf9\u9f50",
"Header cell": "\u8868\u5934\u5355\u5143\u683c",
"Row group": "\u884c\u7ec4",
"Column group": "\u5217\u7ec4",
"Row type": "\u884c\u7c7b\u578b",
"Header": "\u8868\u5934",
"Body": "\u8868\u4f53",
"Footer": "\u8868\u5c3e",
"Border color": "\u8fb9\u6846\u989c\u8272",
"Insert template": "\u63d2\u5165\u6a21\u677f",
"Templates": "\u6a21\u677f",
"Template": "\u6a21\u677f",
"Text color": "\u6587\u5b57\u989c\u8272",
"Background color": "\u80cc\u666f\u8272",
"Custom...": "\u81ea\u5b9a\u4e49...",
"Custom color": "\u81ea\u5b9a\u4e49\u989c\u8272",
"No color": "\u65e0",
"Table of Contents": "\u5185\u5bb9\u5217\u8868",
"Show blocks": "\u663e\u793a\u533a\u5757\u8fb9\u6846",
"Show invisible characters": "\u663e\u793a\u4e0d\u53ef\u89c1\u5b57\u7b26",
"Words: {0}": "\u5b57\u6570\uff1a{0}",
"{0} words": "{0} \u5b57",
"File": "\u6587\u4ef6",
"Edit": "\u7f16\u8f91",
"Insert": "\u63d2\u5165",
"View": "\u89c6\u56fe",
"Format": "\u683c\u5f0f",
"Table": "\u8868\u683c",
"Tools": "\u5de5\u5177",
"Powered by {0}": "\u7531{0}\u9a71\u52a8",
"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u5728\u7f16\u8f91\u533a\u6309ALT-F9\u6253\u5f00\u83dc\u5355\uff0c\u6309ALT-F10\u6253\u5f00\u5de5\u5177\u680f\uff0c\u6309ALT-0\u67e5\u770b\u5e2e\u52a9"
});

@ -0,0 +1,554 @@
/**
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
* Licensed under the LGPL or a commercial license.
* For LGPL see License.txt in the project root for license information.
* For commercial licenses see https://www.tiny.cloud/
*/
.mce-content-body .mce-item-anchor {
background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center;
cursor: default;
display: inline-block;
height: 12px !important;
padding: 0 2px;
-webkit-user-modify: read-only;
-moz-user-modify: read-only;
-webkit-user-select: all;
-moz-user-select: all;
-ms-user-select: all;
user-select: all;
width: 8px !important;
}
.mce-content-body .mce-item-anchor[data-mce-selected] {
outline-offset: 1px;
}
.tox-comments-visible .tox-comment {
background-color: #fff0b7;
}
.tox-comments-visible .tox-comment--active {
background-color: #ffe168;
}
.tox-checklist > li:not(.tox-checklist--hidden) {
list-style: none;
margin: .25em 0;
position: relative;
}
.tox-checklist > li:not(.tox-checklist--hidden)::before {
background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A");
background-size: 100%;
content: '';
cursor: pointer;
height: 1em;
left: -1.5em;
position: absolute;
top: .125em;
width: 1em;
}
.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before {
background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A");
}
/* stylelint-disable */
/* http://prismjs.com/ */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
font-size: .875rem;
direction: ltr;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection,
pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: transparent !important;
border: 1px solid #ccc;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #a67f59;
background: rgba(255, 255, 255, 0.5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
/* stylelint-enable */
.mce-content-body .mce-visual-caret {
background-color: black;
background-color: currentcolor;
position: absolute;
}
.mce-content-body .mce-visual-caret-hidden {
display: none;
}
.mce-content-body *[data-mce-caret] {
left: -1000px;
margin: 0;
padding: 0;
position: absolute;
right: auto;
top: 0;
}
.mce-content-body .mce-offscreen-selection {
left: -9999999999px;
max-width: 1000000px;
position: absolute;
}
.mce-content-body *[contentEditable=false] {
cursor: default;
}
.mce-content-body *[contentEditable=true] {
cursor: text;
}
.tox-cursor-format-painter {
cursor: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"), default;
}
.mce-content-body figure.align-left {
float: left;
}
.mce-content-body figure.align-right {
float: right;
}
.mce-content-body figure.image.align-center {
display: table;
margin-left: auto;
margin-right: auto;
}
.mce-preview-object {
border: 1px solid gray;
display: inline-block;
line-height: 0;
margin: 0 2px 0 2px;
position: relative;
}
.mce-preview-object .mce-shim {
background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
}
.mce-preview-object[data-mce-selected="2"] .mce-shim {
display: none;
}
.mce-object {
background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center;
border: 1px dashed #aaa;
}
.mce-pagebreak {
border: 1px dashed #aaa;
cursor: default;
display: block;
height: 5px;
margin-top: 15px;
page-break-before: always;
width: 100%;
}
@media print {
.mce-pagebreak {
border: 0;
}
}
.tiny-pageembed .mce-shim {
background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
}
.tiny-pageembed[data-mce-selected="2"] .mce-shim {
display: none;
}
.tiny-pageembed {
display: inline-block;
position: relative;
}
.tiny-pageembed--21by9,
.tiny-pageembed--16by9,
.tiny-pageembed--4by3,
.tiny-pageembed--1by1 {
display: block;
overflow: hidden;
padding: 0;
position: relative;
width: 100%;
}
.tiny-pageembed--21by9::before,
.tiny-pageembed--16by9::before,
.tiny-pageembed--4by3::before,
.tiny-pageembed--1by1::before {
content: "";
display: block;
}
.tiny-pageembed--21by9::before {
padding-top: 42.857143%;
}
.tiny-pageembed--16by9::before {
padding-top: 56.25%;
}
.tiny-pageembed--4by3::before {
padding-top: 75%;
}
.tiny-pageembed--1by1::before {
padding-top: 100%;
}
.tiny-pageembed--21by9 iframe,
.tiny-pageembed--16by9 iframe,
.tiny-pageembed--4by3 iframe,
.tiny-pageembed--1by1 iframe {
border: 0;
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
}
.mce-content-body div.mce-resizehandle {
background-color: #4099ff;
border-color: #4099ff;
border-style: solid;
border-width: 1px;
box-sizing: border-box;
height: 10px;
position: absolute;
width: 10px;
z-index: 10000;
}
.mce-content-body div.mce-resizehandle:hover {
background-color: #4099ff;
}
.mce-content-body div.mce-resizehandle:nth-of-type(1) {
cursor: nwse-resize;
}
.mce-content-body div.mce-resizehandle:nth-of-type(2) {
cursor: nesw-resize;
}
.mce-content-body div.mce-resizehandle:nth-of-type(3) {
cursor: nwse-resize;
}
.mce-content-body div.mce-resizehandle:nth-of-type(4) {
cursor: nesw-resize;
}
.mce-content-body .mce-clonedresizable {
opacity: .5;
outline: 1px dashed black;
position: absolute;
z-index: 10000;
}
.mce-content-body .mce-resize-helper {
background: #555;
background: rgba(0, 0, 0, 0.75);
border: 1px;
border-radius: 3px;
color: white;
display: none;
font-family: sans-serif;
font-size: 12px;
line-height: 14px;
margin: 5px 10px;
padding: 5px;
position: absolute;
white-space: nowrap;
z-index: 10001;
}
.mce-match-marker {
background: #aaa;
color: #fff;
}
.mce-match-marker-selected {
background: #39f;
color: #fff;
}
.mce-content-body img[data-mce-selected],
.mce-content-body table[data-mce-selected] {
outline: 3px solid #b4d7ff;
}
.mce-content-body hr[data-mce-selected] {
outline: 3px solid #b4d7ff;
outline-offset: 1px;
}
.mce-content-body *[contentEditable=false] *[contentEditable=true]:focus {
outline: 3px solid #b4d7ff;
}
.mce-content-body *[contentEditable=false] *[contentEditable=true]:hover {
outline: 3px solid #b4d7ff;
}
.mce-content-body *[contentEditable=false][data-mce-selected] {
cursor: not-allowed;
outline: 3px solid #b4d7ff;
}
.mce-content-body.mce-content-readonly *[contentEditable=true]:focus,
.mce-content-body.mce-content-readonly *[contentEditable=true]:hover {
outline: none;
}
.mce-content-body *[data-mce-selected="inline-boundary"] {
background-color: #b4d7ff;
}
.mce-content-body .mce-edit-focus {
outline: 3px solid #b4d7ff;
}
.mce-content-body td[data-mce-selected],
.mce-content-body th[data-mce-selected] {
background-color: #b4d7ff !important;
}
.mce-content-body td[data-mce-selected]::-moz-selection,
.mce-content-body th[data-mce-selected]::-moz-selection {
background: none;
}
.mce-content-body td[data-mce-selected]::selection,
.mce-content-body th[data-mce-selected]::selection {
background: none;
}
.mce-content-body td[data-mce-selected] *,
.mce-content-body th[data-mce-selected] * {
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.mce-content-body img::-moz-selection {
background: none;
}
.mce-content-body img::selection {
background: none;
}
.ephox-snooker-resizer-bar {
background-color: #b4d7ff;
opacity: 0;
}
.ephox-snooker-resizer-cols {
cursor: col-resize;
}
.ephox-snooker-resizer-rows {
cursor: row-resize;
}
.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging {
opacity: 1;
}
.mce-spellchecker-word {
background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.5'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");
background-position: 0 calc(100% + 1px);
background-repeat: repeat-x;
background-size: auto 6px;
cursor: default;
height: 2rem;
}
.mce-spellchecker-grammar {
background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23008800'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");
background-position: 0 calc(100% + 1px);
background-repeat: repeat-x;
background-size: auto 6px;
cursor: default;
}
.mce-toc {
border: 1px solid gray;
}
.mce-toc h2 {
margin: 4px;
}
.mce-toc li {
list-style-type: none;
}
.mce-item-table,
.mce-item-table td,
.mce-item-table th,
.mce-item-table caption {
border: 1px dashed #bbb;
}
.mce-visualblocks p,
.mce-visualblocks h1,
.mce-visualblocks h2,
.mce-visualblocks h3,
.mce-visualblocks h4,
.mce-visualblocks h5,
.mce-visualblocks h6,
.mce-visualblocks div:not([data-mce-bogus]),
.mce-visualblocks section,
.mce-visualblocks article,
.mce-visualblocks blockquote,
.mce-visualblocks address,
.mce-visualblocks pre,
.mce-visualblocks figure,
.mce-visualblocks figcaption,
.mce-visualblocks hgroup,
.mce-visualblocks aside,
.mce-visualblocks ul,
.mce-visualblocks ol,
.mce-visualblocks dl {
background-repeat: no-repeat;
border: 1px dashed #bbb;
margin-left: 3px;
padding-top: 10px;
}
.mce-visualblocks p {
background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7);
}
.mce-visualblocks h1 {
background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==);
}
.mce-visualblocks h2 {
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==);
}
.mce-visualblocks h3 {
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7);
}
.mce-visualblocks h4 {
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==);
}
.mce-visualblocks h5 {
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==);
}
.mce-visualblocks h6 {
background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==);
}
.mce-visualblocks div:not([data-mce-bogus]) {
background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7);
}
.mce-visualblocks section {
background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=);
}
.mce-visualblocks article {
background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7);
}
.mce-visualblocks blockquote {
background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7);
}
.mce-visualblocks address {
background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=);
}
.mce-visualblocks pre {
background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==);
}
.mce-visualblocks figure {
background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7);
}
.mce-visualblocks figcaption {
border: 1px dashed #bbb;
}
.mce-visualblocks hgroup {
background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7);
}
.mce-visualblocks aside {
background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=);
}
.mce-visualblocks ul {
background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==);
}
.mce-visualblocks ol {
background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==);
}
.mce-visualblocks dl {
background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==);
}
.mce-nbsp,
.mce-shy {
background: #aaa;
}
.mce-shy::after {
content: '-';
}
body {
font-family: sans-serif;
}
table {
border-collapse: collapse;
}

File diff suppressed because it is too large Load Diff

1
public/v2.js vendored

File diff suppressed because one or more lines are too long

@ -0,0 +1,44 @@
<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 enquireScreen from '@/utils/device'
export default {
data () {
return {
locale: zhCN,
}
},
created () {
let that = this
enquireScreen(deviceType => {
// tablet
if (deviceType === 0) {
that.$store.commit('TOGGLE_DEVICE', 'mobile')
that.$store.dispatch('setSidebar', false)
}
// mobile
else if (deviceType === 1) {
that.$store.commit('TOGGLE_DEVICE', 'mobile')
that.$store.dispatch('setSidebar', false)
}
else {
that.$store.commit('TOGGLE_DEVICE', 'desktop')
that.$store.dispatch('setSidebar', true)
}
})
}
}
</script>
<style>
#app {
height: 100%;
}
</style>

@ -0,0 +1,30 @@
import Vue from 'vue'
/**
* 将一个请求分组
*
* @param getPromise 传入一个可以获取到Promise对象的方法
* @param groupId 分组ID如果不传或者为空则不分组
* @param expire 过期时间默认 半分钟
*/
export function httpGroupRequest(getPromise, groupId, expire = 1000 * 30) {
if (groupId == null || groupId === '') {
console.log("--------popup----------getFrom DB-------with---no--groupId ")
return getPromise()
}
if (Vue.ls.get(groupId)) {
console.log("---------popup--------getFrom Cache--------groupId = " + groupId)
return Promise.resolve(Vue.ls.get(groupId));
} else {
console.log("--------popup----------getFrom DB---------groupId = " + groupId)
}
// 还没有发出请求,就发出第一次的请求
return getPromise().then(res => {
Vue.ls.set(groupId, res, expire);
return Promise.resolve(res);
})
}

@ -0,0 +1,164 @@
import { getAction, deleteAction, putAction, postAction, httpAction } from '@/api/manage'
import Vue from 'vue'
import {UI_CACHE_DB_DICT_DATA } from "@/store/mutation-types"
//角色管理
const addRole = (params)=>postAction("/sys/role/add",params);
const editRole = (params)=>putAction("/sys/role/edit",params);
const checkRoleCode = (params)=>getAction("/sys/role/checkRoleCode",params);
const queryall = (params)=>getAction("/sys/role/queryall",params);
//用户管理
const addUser = (params)=>postAction("/sys/user/add",params);
const editUser = (params)=>putAction("/sys/user/edit",params);
const queryUserRole = (params)=>getAction("/sys/user/queryUserRole",params);
const getUserList = (params)=>getAction("/sys/user/list",params);
const frozenBatch = (params)=>putAction("/sys/user/frozenBatch",params);
//验证用户是否存在
const checkOnlyUser = (params)=>getAction("/sys/user/checkOnlyUser",params);
//改变密码
const changePassword = (params)=>putAction("/sys/user/changePassword",params);
//权限管理
const addPermission= (params)=>postAction("/sys/permission/add",params);
const editPermission= (params)=>putAction("/sys/permission/edit",params);
const getPermissionList = (params)=>getAction("/sys/permission/list",params);
const getSystemMenuList = (params)=>getAction("/sys/permission/getSystemMenuList",params);
const getSystemSubmenu = (params)=>getAction("/sys/permission/getSystemSubmenu",params);
const getSystemSubmenuBatch = (params) => getAction('/sys/permission/getSystemSubmenuBatch', params)
const queryTreeList = (params)=>getAction("/sys/permission/queryTreeList",params);
const queryTreeListForRole = (params)=>getAction("/sys/role/queryTreeList",params);
const queryListAsync = (params)=>getAction("/sys/permission/queryListAsync",params);
const queryRolePermission = (params)=>getAction("/sys/permission/queryRolePermission",params);
const saveRolePermission = (params)=>postAction("/sys/permission/saveRolePermission",params);
const queryPermissionsByUser = ()=>getAction("/sys/permission/getUserPermissionByToken");
const loadAllRoleIds = (params)=>getAction("/sys/permission/loadAllRoleIds",params);
const getPermissionRuleList = (params)=>getAction("/sys/permission/getPermRuleListByPermId",params);
const queryPermissionRule = (params)=>getAction("/sys/permission/queryPermissionRule",params);
// 部门管理
const queryDepartTreeList = (params)=>getAction("/sys/sysDepart/queryTreeList",params);
const queryDepartTreeSync = (params)=>getAction("/sys/sysDepart/queryDepartTreeSync",params);
const queryIdTree = (params)=>getAction("/sys/sysDepart/queryIdTree",params);
const queryParentName = (params)=>getAction("/sys/sysDepart/queryParentName",params);
const searchByKeywords = (params)=>getAction("/sys/sysDepart/searchBy",params);
const deleteByDepartId = (params)=>deleteAction("/sys/sysDepart/delete",params);
//二级部门管理
const queryDepartPermission = (params)=>getAction("/sys/permission/queryDepartPermission",params);
const saveDepartPermission = (params)=>postAction("/sys/permission/saveDepartPermission",params);
const queryTreeListForDeptRole = (params)=>getAction("/sys/sysDepartPermission/queryTreeListForDeptRole",params);
const queryDeptRolePermission = (params)=>getAction("/sys/sysDepartPermission/queryDeptRolePermission",params);
const saveDeptRolePermission = (params)=>postAction("/sys/sysDepartPermission/saveDeptRolePermission",params);
const queryMyDepartTreeList = (params)=>getAction("/sys/sysDepart/queryMyDeptTreeList",params);
//日志管理
const deleteLog = (params)=>deleteAction("/sys/log/delete",params);
const deleteLogList = (params)=>deleteAction("/sys/log/deleteBatch",params);
//数据字典
const addDict = (params)=>postAction("/sys/dict/add",params);
const editDict = (params)=>putAction("/sys/dict/edit",params);
const treeList = (params)=>getAction("/sys/dict/treeList",params);
const addDictItem = (params)=>postAction("/sys/dictItem/add",params);
const editDictItem = (params)=>putAction("/sys/dictItem/edit",params);
//字典标签专用通过code获取字典数组
export const ajaxGetDictItems = (code, params)=>getAction(`/sys/dict/getDictItems/${code}`,params);
//从缓存中获取字典配置
function getDictItemsFromCache(dictCode) {
if (Vue.ls.get(UI_CACHE_DB_DICT_DATA) && Vue.ls.get(UI_CACHE_DB_DICT_DATA)[dictCode]) {
let dictItems = Vue.ls.get(UI_CACHE_DB_DICT_DATA)[dictCode];
//console.log("-----------getDictItemsFromCache----------dictCode="+dictCode+"---- dictItems=",dictItems)
return dictItems;
}
}
//系统通告
const doReleaseData = (params)=>getAction("/sys/annountCement/doReleaseData",params);
const doReovkeData = (params)=>getAction("/sys/annountCement/doReovkeData",params);
//获取系统访问量
const getLoginfo = (params)=>getAction("/sys/loginfo",params);
const getVisitInfo = (params)=>getAction("/sys/visitInfo",params);
// 根据部门主键查询用户信息
const queryUserByDepId = (params)=>getAction("/sys/user/queryUserByDepId",params);
// 重复校验
const duplicateCheck = (params)=>getAction("/sys/duplicate/check",params);
// 加载分类字典
const loadCategoryData = (params)=>getAction("/sys/category/loadAllData",params);
const checkRuleByCode = (params) => getAction('/sys/checkRule/checkByCode', params)
//加载我的通告信息
const getUserNoticeInfo= (params)=>getAction("/sys/sysAnnouncementSend/getMyAnnouncementSend",params);
const getTransitURL = url => `/sys/common/transitRESTful?url=${encodeURIComponent(url)}`
// 中转HTTP请求
export const transitRESTful = {
get: (url, parameter) => getAction(getTransitURL(url), parameter),
post: (url, parameter) => postAction(getTransitURL(url), parameter),
put: (url, parameter) => putAction(getTransitURL(url), parameter),
http: (url, parameter) => httpAction(getTransitURL(url), parameter),
}
export {
// imgView,
// doMian,
addRole,
editRole,
checkRoleCode,
addUser,
editUser,
queryUserRole,
getUserList,
queryall,
frozenBatch,
checkOnlyUser,
changePassword,
getPermissionList,
addPermission,
editPermission,
queryTreeList,
queryListAsync,
queryRolePermission,
saveRolePermission,
queryPermissionsByUser,
loadAllRoleIds,
getPermissionRuleList,
queryPermissionRule,
queryDepartTreeList,
queryDepartTreeSync,
queryIdTree,
queryParentName,
searchByKeywords,
deleteByDepartId,
deleteLog,
deleteLogList,
addDict,
editDict,
treeList,
addDictItem,
editDictItem,
doReleaseData,
doReovkeData,
getLoginfo,
getVisitInfo,
queryUserByDepId,
duplicateCheck,
queryTreeListForRole,
getSystemMenuList,
getSystemSubmenu,
getSystemSubmenuBatch,
loadCategoryData,
checkRuleByCode,
queryDepartPermission,
saveDepartPermission,
queryTreeListForDeptRole,
queryDeptRolePermission,
saveDeptRolePermission,
queryMyDepartTreeList,
getUserNoticeInfo,
getDictItemsFromCache
}

@ -0,0 +1,10 @@
const api = {
Login: '/sys/login',
Logout: '/sys/logout',
ForgePassword: '/auth/forge-password',
Register: '/auth/register',
SendSms: '/account/sms',
// get my info
UserInfo: '/user/info'
}
export default api

@ -0,0 +1,87 @@
import api from './index'
import { axios } from '@/utils/request'
/**
* login func
* parameter: {
* username: '',
* password: '',
* remember_me: true,
* captcha: '12345'
* }
* @param parameter
* @returns {*}
*/
export function login(parameter) {
return axios({
url: '/sys/login',
method: 'post',
data: parameter
})
}
export function phoneLogin(parameter) {
return axios({
url: '/sys/phoneLogin',
method: 'post',
data: parameter
})
}
export function getSmsCaptcha(parameter) {
return axios({
url: api.SendSms,
method: 'post',
data: parameter
})
}
// export function getInfo() {
// return axios({
// url: '/api/user/info',
// method: 'get',
// headers: {
// 'Content-Type': 'application/json;charset=UTF-8'
// }
// })
// }
export function logout(logoutToken) {
return axios({
url: '/sys/logout',
method: 'post',
headers: {
'Content-Type': 'application/json;charset=UTF-8',
'X-Access-Token': logoutToken
}
})
}
/**
* 第三方登录
* @param token
* @param thirdType
* @returns {*}
*/
export function thirdLogin(token,thirdType) {
return axios({
url: `/sys/thirdLogin/getLoginUser/${token}/${thirdType}`,
method: 'get',
headers: {
'Content-Type': 'application/json;charset=UTF-8'
}
})
}
/**
* 强退其他账号
* @param token
* @returns {*}
*/
export function forceLogout(parameter) {
return axios({
url: '/sys/online/forceLogout',
method: 'post',
data: parameter
})
}

@ -0,0 +1,197 @@
import Vue from 'vue'
import { axios } from '@/utils/request'
import signMd5Utils from '@/utils/encryption/signMd5Utils'
const api = {
user: '/mock/api/user',
role: '/mock/api/role',
service: '/mock/api/service',
permission: '/mock/api/permission',
permissionNoPager: '/mock/api/permission/no-pager'
}
export default api
//post
export function postAction(url,parameter) {
let sign = signMd5Utils.getSign(url, parameter);
//将签名和时间戳,添加在请求接口 Header
let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getDateTimeToString()};
return axios({
url: url,
method:'post' ,
data: parameter,
headers: signHeader
})
}
//post method= {post | put}
export function httpAction(url,parameter,method) {
let sign = signMd5Utils.getSign(url, parameter);
//将签名和时间戳,添加在请求接口 Header
let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getDateTimeToString()};
return axios({
url: url,
method:method ,
data: parameter,
headers: signHeader
})
}
//put
export function putAction(url,parameter) {
return axios({
url: url,
method:'put',
data: parameter
})
}
//get
export function getAction(url,parameter) {
let sign = signMd5Utils.getSign(url, parameter);
//将签名和时间戳,添加在请求接口 Header
let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getDateTimeToString()};
return axios({
url: url,
method: 'get',
params: parameter,
headers: signHeader
})
}
//deleteAction
export function deleteAction(url,parameter) {
return axios({
url: url,
method: 'delete',
params: parameter
})
}
export function getUserList(parameter) {
return axios({
url: api.user,
method: 'get',
params: parameter
})
}
export function getRoleList(parameter) {
return axios({
url: api.role,
method: 'get',
params: parameter
})
}
export function getServiceList(parameter) {
return axios({
url: api.service,
method: 'get',
params: parameter
})
}
export function getPermissions(parameter) {
return axios({
url: api.permissionNoPager,
method: 'get',
params: parameter
})
}
// id == 0 add post
// id != 0 update put
export function saveService(parameter) {
return axios({
url: api.service,
method: parameter.id == 0 ? 'post' : 'put',
data: parameter
})
}
/**
* 下载文件 用于excel导出
* @param url
* @param parameter
* @returns {*}
*/
export function downFile(url,parameter){
return axios({
url: url,
params: parameter,
method:'get' ,
responseType: 'blob'
})
}
/**
* 下载文件
* @param url 文件路径
* @param fileName 文件名
* @param parameter
* @returns {*}
*/
export function downloadFile(url, fileName, parameter) {
return downFile(url, parameter).then((data) => {
if (!data || data.size === 0) {
Vue.prototype['$message'].warning('文件下载失败')
return
}
if (typeof window.navigator.msSaveBlob !== 'undefined') {
window.navigator.msSaveBlob(new Blob([data]), fileName)
} else {
let url = window.URL.createObjectURL(new Blob([data]))
let link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', fileName)
document.body.appendChild(link)
link.click()
document.body.removeChild(link) //下载完成移除元素
window.URL.revokeObjectURL(url) //释放掉blob对象
}
})
}
/**
* 文件上传 用于富文本上传图片
* @param url
* @param parameter
* @returns {*}
*/
export function uploadAction(url,parameter){
return axios({
url: url,
data: parameter,
method:'post' ,
headers: {
'Content-Type': 'multipart/form-data', // 文件上传
},
})
}
/**
* 获取文件服务访问路径
* @param avatar
* @param subStr
* @returns {*}
*/
export function getFileAccessHttpUrl(avatar,subStr) {
if(!subStr) subStr = 'http'
try {
if(avatar && avatar.startsWith(subStr)){
return avatar;
}else{
if(avatar && avatar.length>0 && avatar.indexOf('[')==-1){
return window._CONFIG['staticDomainURL'] + "/" + avatar;
}
}
}catch(err){
return;
}
}

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

@ -0,0 +1,259 @@
.area-zoom-in-top-enter-active,
.area-zoom-in-top-leave-active {
opacity: 1;
transform: scaleY(1);
}
.area-zoom-in-top-enter,
.area-zoom-in-top-leave-active {
opacity: 0;
transform: scaleY(0);
}
.area-select {
box-sizing: border-box;
margin: 0;
padding: 0;
color: rgba(0, 0, 0, 0.65);
font-size: 14px;
font-variant: tabular-nums;
line-height: 1.5;
list-style: none;
font-feature-settings: 'tnum';
position: relative;
outline: 0;
display: block;
background-color: #fff;
border: 1px solid #d9d9d9;
border-top-width: 1.02px;
border-radius: 4px;
outline: none;
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}
.area-select-wrap .area-select {
display: inline-block;
}
.area-select * {
box-sizing: border-box;
}
.area-select:hover {
border-color: #40a9ff;
border-right-width: 1px !important;
outline: 0;
}
.area-select:active {
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
}
.area-select.small {
width: 126px;
}
.area-select.medium {
width: 160px;
}
.area-select.large {
width: 194px;
}
.area-select.is-disabled {
background: #eceff5;
cursor: not-allowed;
}
.area-select.is-disabled:hover {
border-color: #e1e2e6;
}
.area-select.is-disabled .area-selected-trigger {
cursor: not-allowed;
}
.area-select .area-selected-trigger {
position: relative;
display: block;
font-size: 14px;
cursor: pointer;
margin: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
height: 100%;
padding: 8px 20px 7px 12px;
}
.area-select .area-select-icon {
position: absolute;
top: 50%;
margin-top: -2px;
right: 6px;
content: "";
width: 0;
height: 0;
border: 6px solid transparent;
border-top-color: rgba(0, 0, 0, 0.25);
transition: all .3s linear;
transform-origin: center;
}
.area-select .area-select-icon.active {
margin-top: -8px;
transform: rotate(180deg);
}
.area-selectable-list-wrap {
position: absolute;
width: 100%;
max-height: 275px;
z-index: 15000;
background-color: #fff;
box-sizing: border-box;
overflow-x: auto;
margin: 2px 0;
border-radius: 4px;
outline: none;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
transition: opacity 0.15s, transform 0.3s !important;
transform-origin: center top !important;
}
.area-selectable-list {
position: relative;
margin: 0;
padding: 6px 0;
width: 100%;
font-size: 14px;
color: #565656;
list-style: none;
}
.area-selectable-list .area-select-option {
position: relative;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
cursor: pointer;
padding: 0 15px 0 10px;
height: 32px;
line-height: 32px;
}
.area-selectable-list .area-select-option.hover {
background-color: #e6f7ff;
}
.area-selectable-list .area-select-option.selected {
color: rgba(0, 0, 0, 0.65);
font-weight: 600;
background-color: #efefef;
}
.cascader-menu-list-wrap {
position: absolute;
white-space: nowrap;
z-index: 15000;
background-color: #fff;
box-sizing: border-box;
overflow: hidden;
font-size: 0;
margin: 2px 0;
border-radius: 4px;
outline: none;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
transition: opacity 0.15s, transform 0.3s !important;
transform-origin: center top !important;
}
.cascader-menu-list {
position: relative;
margin: 0;
font-size: 14px;
color: #565656;
padding: 6px 0;
list-style: none;
display: inline-block;
height: 204px;
overflow-x: hidden;
overflow-y: auto;
min-width: 160px;
vertical-align: top;
background-color: #fff;
border-right: 1px solid #e4e7ed;
}
.cascader-menu-list:last-child {
border-right: none;
}
.cascader-menu-list .cascader-menu-option {
position: relative;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
cursor: pointer;
padding: 0 15px 0 10px;
height: 32px;
line-height: 32px;
}
.cascader-menu-list .cascader-menu-option.hover,
.cascader-menu-list .cascader-menu-option:hover {
background-color: #e6f7ff;
}
.cascader-menu-list .cascader-menu-option.selected {
color: rgba(0, 0, 0, 0.65);
font-weight: 600;
background-color: #efefef;
}
.cascader-menu-list .cascader-menu-option.cascader-menu-extensible:after {
position: absolute;
top: 50%;
margin-top: -4px;
right: 5px;
content: "";
width: 0;
height: 0;
border: 4px solid transparent;
border-left-color: #a1a4ad;
}
.cascader-menu-list::-webkit-scrollbar,
.area-selectable-list-wrap::-webkit-scrollbar {
width: 8px;
background: transparent;
}
.area-selectable-list-wrap::-webkit-scrollbar-button:vertical:decremen,
.area-selectable-list-wrap::-webkit-scrollbar-button:vertical:end:decrement,
.area-selectable-list-wrap::-webkit-scrollbar-button:vertical:increment,
.area-selectable-list-wrap::-webkit-scrollbar-button:vertical:start:increment,
.cascader-menu-list::-webkit-scrollbar-button:vertical:decremen,
.cascader-menu-list::-webkit-scrollbar-button:vertical:end:decrement,
.cascader-menu-list::-webkit-scrollbar-button:vertical:increment,
.cascader-menu-list::-webkit-scrollbar-button:vertical:start:increment {
display: none;
}
.cascader-menu-list::-webkit-scrollbar-thumb:vertical,
.area-selectable-list-wrap::-webkit-scrollbar-thumb:vertical {
background-color: #b8b8b8;
border-radius: 4px;
}
.cascader-menu-list::-webkit-scrollbar-thumb:vertical:hover,
.area-selectable-list-wrap::-webkit-scrollbar-thumb:vertical:hover {
background-color: #777;
}

@ -0,0 +1,15 @@
/** [表格主题样式一] 表格强制列不换行 */
.j-table-force-nowrap {
td, th {
white-space: nowrap;
}
.ant-table-selection-column {
padding: 12px 22px !important;
}
/** 列自适应,弊端会导致列宽失效 */
&.ant-table-wrapper .ant-table-content {
overflow-x: auto;
}
}

@ -0,0 +1 @@
.cm-s-idea span.cm-meta{color:olive}.cm-s-idea span.cm-number{color:#00f}.cm-s-idea span.cm-keyword{line-height:1em;font-weight:700;color:navy}.cm-s-idea span.cm-atom{font-weight:700;color:navy}.cm-s-idea span.cm-def{color:#000}.cm-s-idea span.cm-variable{color:#000}.cm-s-idea span.cm-variable-2{color:#000}.cm-s-idea span.cm-type,.cm-s-idea span.cm-variable-3{color:#000}.cm-s-idea span.cm-property{color:#000}.cm-s-idea span.cm-operator{color:#000}.cm-s-idea span.cm-comment{color:grey}.cm-s-idea span.cm-string{color:green}.cm-s-idea span.cm-string-2{color:green}.cm-s-idea span.cm-qualifier{color:#555}.cm-s-idea span.cm-error{color:red}.cm-s-idea span.cm-attribute{color:#00f}.cm-s-idea span.cm-tag{color:navy}.cm-s-idea span.cm-link{color:#00f}.cm-s-idea .CodeMirror-activeline-background{background:#fffae3}.cm-s-idea span.cm-builtin{color:#30a}.cm-s-idea span.cm-bracket{color:#cc7}.cm-s-idea{font-family:Consolas,Menlo,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New,monospace,serif}.cm-s-idea .CodeMirror-matchingbracket{outline:1px solid grey;color:#000!important}.CodeMirror-hints.idea{font-family:Menlo,Monaco,Consolas,'Courier New',monospace;color:#616569;background-color:#ebf3fd!important}.CodeMirror-hints.idea .CodeMirror-hint-active{background-color:#a2b8c9!important;color:#5c6065!important}

@ -0,0 +1,61 @@
/*列表上方操作按钮区域*/
.ant-card-body .table-operator {
margin-bottom: 8px;
}
/** Button按钮间距 */
.table-operator .ant-btn {
margin: 0 8px 8px 0;
}
.table-operator .ant-btn-group .ant-btn {
margin: 0;
}
.table-operator .ant-btn-group .ant-btn:last-child {
margin: 0 8px 8px 0;
}
/*列表td的padding设置 可以控制列表大小*/
.ant-table-tbody .ant-table-row td {
padding-top: 15px;
padding-bottom: 15px;
}
/*列表页面弹出modal*/
.ant-modal-cust-warp {
height: 100%
}
/*弹出modal Y轴滚动条*/
.ant-modal-cust-warp .ant-modal-body {
height: calc(100% - 110px) !important;
overflow-y: auto
}
/*弹出modal 先有content后有body 故滚动条控制在body上*/
.ant-modal-cust-warp .ant-modal-content {
height: 90% !important;
overflow-y: hidden
}
/*列表中有图片的加这个样式 参考用户管理*/
.anty-img-wrap {
height: 25px;
position: relative;
}
.anty-img-wrap > img {
max-height: 100%;
}
/*列表中范围查询样式*/
.query-group-cust{width: calc(50% - 10px)}
.query-group-split-cust:before{content:"~";width: 20px;display: inline-block;text-align: center}
/*erp风格子表外框padding设置*/
.ant-card-wider-padding.cust-erp-sub-tab>.ant-card-body{padding:5px 12px}
/* 内嵌子表背景颜色 */
.j-inner-table-wrapper /deep/ .ant-table-expanded-row .ant-table-wrapper .ant-table-tbody .ant-table-row {
background-color: #FFFFFF;
}
/**隐藏样式-modal确定按钮 */
.jee-hidden{display: none}

@ -0,0 +1,28 @@
/**
* 列表查询通用样式,移动端自适应
*/
.search{
margin-bottom: 54px;
}
.fold{
width: calc(100% - 216px);
display: inline-block
}
.operator{
margin-bottom: 18px;
}
@media screen and (max-width: 900px) {
.fold {
width: 100%;
}
}
.operator button {
margin-right: 5px;
}
i {
cursor: pointer;
}
.trcolor{
background-color: rgba(255, 192, 203, 0.31);
color:red;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

@ -0,0 +1,172 @@
<?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="293px" height="293px" viewBox="0 0 293 293" enable-background="new 0 0 293 293" xml:space="preserve"> <image id="image0" width="293" height="293" x="0" y="0"
href="data:image/png;base64,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
OjAwP26CAAAAAABJRU5ErkJggg==" />
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

@ -0,0 +1,77 @@
import Vue from 'vue'
import { ACCESS_TOKEN } from "@/store/mutation-types"
import store from '@/store'
/**
* 单点登录
*/
const init = (callback) => {
if (process.env.VUE_APP_SSO == 'true') {
console.log("-------单点登录开始-------");
let token = Vue.ls.get(ACCESS_TOKEN);
let st = getUrlParam("ticket");
let sevice = "http://" + window.location.host + "/";
if (token) {
loginSuccess(callback);
} else {
if (st) {
validateSt(st, sevice, callback);
} else {
let serviceUrl = encodeURIComponent(sevice);
window.location.href = window._CONFIG['casPrefixUrl'] + "/login?service=" + serviceUrl;
}
}
console.log("-------单点登录结束-------");
}else{
callback && callback()
}
};
const SSO = {
init: init
};
function getUrlParam(paraName) {
let url = document.location.toString();
let arrObj = url.split("?");
if (arrObj.length > 1) {
let arrPara = arrObj[1].split("&");
let arr;
for (let i = 0; i < arrPara.length; i++) {
arr = arrPara[i].split("=");
if (arr != null && arr[0] == paraName) {
return arr[1];
}
}
return "";
}
else {
return "";
}
}
function validateSt(ticket,service,callback){
let params = {
ticket: ticket,
service:service
};
store.dispatch('ValidateLogin',params).then(res => {
//this.departConfirm(res)
if(res.success){
loginSuccess(callback);
}else{
let sevice = "http://"+window.location.host+"/";
let serviceUrl = encodeURIComponent(sevice);
window.location.href = window._CONFIG['casPrefixUrl']+"/login?service="+serviceUrl;
}
}).catch((err) => {
console.log(err);
//that.requestFailed(err);
});
}
function loginSuccess (callback) {
callback();
}
export default SSO;

@ -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>

@ -0,0 +1,100 @@
<!--
<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>

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

@ -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;
}
}
}
}
}

@ -0,0 +1,111 @@
<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">{{ title }}</span>
<span class="chart-card-action">
<slot name="action"></slot>
</span>
</div>
<div class="total"><span>{{ total }}</span></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: String,
default: ''
},
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>

@ -0,0 +1,103 @@
<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>

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

@ -0,0 +1,49 @@
<script>
import { cutStrByFullLength, getStrFullLength } from '@/components/_util/StringUtil'
export default {
name: 'Ellipsis',
props: {
prefixCls: {
type: String,
default: 'ant-pro-ellipsis'
},
tooltip: {
type: Boolean,
default: true,
},
length: {
type: Number,
default: 25,
},
lines: {
type: Number,
default: 1
},
fullWidthRecognition: {
type: Boolean,
default: false
}
},
methods: {},
render() {
const { tooltip, length } = this.$props
let text = ''
// default
if (this.$slots.default) {
text = this.$slots.default.map(vNode => vNode.text).join('')
}
// tooltip
if (tooltip && getStrFullLength(text) > length) {
return (
<a-tooltip>
<template slot="title">{text}</template>
<span>{cutStrByFullLength(text, this.length) + '…'}</span>
</a-tooltip>
)
} else {
return (<span>{text}</span>)
}
}
}
</script>

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

@ -0,0 +1,228 @@
<template>
<div>
<template v-if="hasFile" v-for="(file, fileKey) of [innerFile || {}]">
<div :key="fileKey" style="position: relative;">
<a-tooltip v-if="file.status==='uploading'" :title="`上传中(${Math.floor(file.percent)}%)`">
<a-icon type="loading"/>
<span style="margin-left:5px">上传中</span>
</a-tooltip>
<a-tooltip v-else-if="file.status==='done'" :title="file.name">
<a-icon type="paper-clip"/>
<span style="margin-left:5px">{{ ellipsisFileName }}</span>
</a-tooltip>
<a-tooltip v-else :title="file.message||'上传失败'">
<a-icon type="exclamation-circle" style="color:red;"/>
<span style="margin-left:5px">{{ ellipsisFileName }}</span>
</a-tooltip>
<template style="width: 30px">
<a-dropdown :trigger="['click']" placement="bottomRight" style="margin-left: 10px;">
<a-tooltip title="操作">
<a-icon
v-if="file.status!=='uploading'"
type="setting"
style="cursor: pointer;"/>
</a-tooltip>
<a-menu slot="overlay">
<a-menu-item v-if="originColumn.allowDownload !== false" @click="handleClickDownloadFile">
<span><a-icon type="download"/>&nbsp;下载</span>
</a-menu-item>
<a-menu-item v-if="originColumn.allowRemove !== false" @click="handleClickDeleteFile">
<span><a-icon type="delete"/>&nbsp;删除</span>
</a-menu-item>
<a-menu-item @click="handleMoreOperation(originColumn)">
<span><a-icon type="bars"/> 更多</span>
</a-menu-item>
</a-menu>
</a-dropdown>
</template>
</div>
</template>
<a-upload
v-show="!hasFile"
name="file"
:data="{'isup': 1}"
:multiple="false"
:action="uploadAction"
:headers="uploadHeaders"
:showUploadList="false"
v-bind="cellProps"
@change="handleChangeUpload"
>
<a-button icon="upload">{{originColumn.btnText || '上传文件'}}</a-button>
</a-upload>
<j-file-pop ref="filePop" @ok="handleFileSuccess" :number="number"/>
</div>
</template>
<script>
import { getFileAccessHttpUrl } from '@api/manage'
import JVxeCellMixins from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
import { ACCESS_TOKEN } from '@/store/mutation-types'
import JFilePop from '@/components/jeecg/minipop/JFilePop'
import JVxeUploadCell from '@/components/jeecg/JVxeTable/components/cells/JVxeUploadCell'
export default {
name: 'JVxeFileCell',
mixins: [JVxeCellMixins],
components: {JFilePop},
props: {},
data() {
return {
innerFile: null,
number:0,
}
},
computed: {
/** upload headers */
uploadHeaders() {
let {originColumn: col} = this
let headers = {}
if (col.token === true) {
headers['X-Access-Token'] = this.$ls.get(ACCESS_TOKEN)
}
return headers
},
/** 上传请求地址 */
uploadAction() {
if (!this.originColumn.action) {
return window._CONFIG['domianURL'] + '/sys/common/upload'
} else {
return this.originColumn.action
}
},
hasFile() {
return this.innerFile != null
},
ellipsisFileName() {
let length = 5
let file = this.innerFile
if (!file || !file.name) {
return ''
}
if (file.name.length > length) {
return file.name.substr(0, length) + '…'
}
return file.name
},
responseName() {
if (this.originColumn.responseName) {
return this.originColumn.responseName
} else {
return 'message'
}
},
},
watch: {
innerValue: {
immediate: true,
handler() {
if (this.innerValue) {
this.innerFile = this.innerValue
} else {
this.innerFile = null
}
},
},
},
methods: {
//
handleMoreOperation(originColumn) {
//update-begin-author:wangshuai date:20201021 for:LOWCOD-969 number
if (originColumn.number) {
this.number = originColumn.number
} else {
this.number = 0
}
//update-end-author:wangshuai date:20201021 for:LOWCOD-969 number
if(originColumn && originColumn.fieldExtendJson){
let json = JSON.parse(originColumn.fieldExtendJson);
this.number = json.uploadnum?json.uploadnum:0;
}
let path = ''
if (this.innerFile) {
path = this.innerFile.path
}
this.$refs.filePop.show('', path)
},
//
handleFileSuccess(file) {
if (file) {
this.innerFile.path = file.path
this.handleChangeCommon(this.innerFile)
}
},
handleChangeUpload(info) {
let {originColumn: col} = this
let {file} = info
let value = {
name: file.name,
type: file.type,
size: file.size,
status: file.status,
percent: file.percent
}
if (file.response) {
value['responseName'] = file.response[this.responseName]
}
if (file.status === 'done') {
if (typeof file.response.success === 'boolean') {
if (file.response.success) {
value['path'] = file.response[this.responseName]
this.handleChangeCommon(value)
} else {
value['status'] = 'error'
value['message'] = file.response.message || '未知错误'
}
} else {
// actionjeecg-boot success
value['path'] = file.response[this.responseName]
this.handleChangeCommon(value)
}
} else if (file.status === 'error') {
value['message'] = file.response.message || '未知错误'
}
this.innerFile = value
},
handleClickDownloadFile() {
let {url, path} = this.innerFile || {}
if (!url || url.length === 0) {
if (path && path.length > 0) {
url = getFileAccessHttpUrl(path.split(',')[0])
}
}
if (url) {
window.open(url)
}
},
handleClickDeleteFile() {
this.handleChangeCommon(null)
},
},
// JVxeCellMixins.js
enhanced: {
switches: {visible: true},
getValue: value => JVxeUploadCell.enhanced.getValue(value),
setValue: value => JVxeUploadCell.enhanced.setValue(value),
}
}
</script>
<style scoped lang="less">
</style>

@ -0,0 +1,242 @@
<template>
<div>
<template v-if="hasFile" v-for="(file, fileKey) of [innerFile || {}]">
<div :key="fileKey" style="position: relative;">
<template v-if="!file || !(file['url'] || file['path'] || file['message'])">
<a-tooltip :title="'请稍后: ' + JSON.stringify (file) + ((file['url'] || file['path'] || file['message']))">
<a-icon type="loading"/>
</a-tooltip>
</template>
<template v-else-if="file['path']">
<img class="j-editable-image" :src="imgSrc" alt="无图片" @click="handleMoreOperation"/>
</template>
<a-tooltip v-else :title="file.message||'上传失败'" @click="handleClickShowImageError">
<a-icon type="exclamation-circle" style="color:red;"/>
</a-tooltip>
<template style="width: 30px">
<a-dropdown :trigger="['click']" placement="bottomRight" style="margin-left: 10px;">
<a-tooltip title="操作">
<a-icon
v-if="file.status!=='uploading'"
type="setting"
style="cursor: pointer;"/>
</a-tooltip>
<a-menu slot="overlay">
<a-menu-item v-if="originColumn.allowDownload !== false" @click="handleClickDownloadFile">
<span><a-icon type="download"/>&nbsp;下载</span>
</a-menu-item>
<a-menu-item v-if="originColumn.allowRemove !== false" @click="handleClickDeleteFile">
<span><a-icon type="delete"/>&nbsp;删除</span>
</a-menu-item>
<a-menu-item @click="handleMoreOperation(originColumn)">
<span><a-icon type="bars"/> 更多</span>
</a-menu-item>
</a-menu>
</a-dropdown>
</template>
</div>
</template>
<a-upload
v-show="!hasFile"
name="file"
:data="{'isup': 1}"
:multiple="false"
:action="uploadAction"
:headers="uploadHeaders"
:showUploadList="false"
v-bind="cellProps"
@change="handleChangeUpload"
>
<a-button icon="upload">{{originColumn.btnText || '上传图片'}}</a-button>
</a-upload>
<j-file-pop ref="filePop" @ok="handleFileSuccess" :number="number"/>
</div>
</template>
<script>
import { getFileAccessHttpUrl } from '@api/manage'
import JVxeCellMixins from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
import { ACCESS_TOKEN } from '@/store/mutation-types'
import JFilePop from '@/components/jeecg/minipop/JFilePop'
import JVxeUploadCell from '@/components/jeecg/JVxeTable/components/cells/JVxeUploadCell'
export default {
name: 'JVxeImageCell',
mixins: [JVxeCellMixins],
components: {JFilePop},
props: {},
data() {
return {
innerFile: null,
number:0
}
},
computed: {
/** upload headers */
uploadHeaders() {
let {originColumn: col} = this
let headers = {}
if (col.token === true) {
headers['X-Access-Token'] = this.$ls.get(ACCESS_TOKEN)
}
return headers
},
/** 上传请求地址 */
uploadAction() {
if (!this.originColumn.action) {
return window._CONFIG['domianURL'] + '/sys/common/upload'
} else {
return this.originColumn.action
}
},
hasFile() {
return this.innerFile != null
},
/** 预览图片地址 */
imgSrc() {
if (this.innerFile) {
if (this.innerFile['url']) {
return this.innerFile['url']
} else if (this.innerFile['path']) {
let path = this.innerFile['path'].split(',')[0]
return getFileAccessHttpUrl(path)
}
}
return ''
},
responseName() {
if (this.originColumn.responseName) {
return this.originColumn.responseName
} else {
return 'message'
}
},
},
watch: {
innerValue: {
immediate: true,
handler() {
if (this.innerValue) {
this.innerFile = this.innerValue
} else {
this.innerFile = null
}
},
},
},
methods: {
//
handleMoreOperation(originColumn) {
//update-begin-author:wangshuai date:20201021 for:LOWCOD-969 number
if (originColumn.number) {
this.number = originColumn.number
} else {
this.number = 0
}
//update-end-author:wangshuai date:20201021 for:LOWCOD-969 number
if(originColumn && originColumn.fieldExtendJson){
let json = JSON.parse(originColumn.fieldExtendJson);
this.number = json.uploadnum?json.uploadnum:0;
}
let path = ''
if (this.innerFile) {
path = this.innerFile.path
}
this.$refs.filePop.show('', path, 'img')
},
//
handleFileSuccess(file) {
if (file) {
this.innerFile.path = file.path
this.handleChangeCommon(this.innerFile)
}
},
//
handleClickShowImageError() {
let file = this.innerFile || null
if (file && file['message']) {
this.$error({title: '上传出错', content: '错误信息:' + file['message'], maskClosable: true})
}
},
handleChangeUpload(info) {
let {originColumn: col} = this
let {file} = info
let value = {
name: file.name,
type: file.type,
size: file.size,
status: file.status,
percent: file.percent
}
if (file.response) {
value['responseName'] = file.response[this.responseName]
}
if (file.status === 'done') {
if (typeof file.response.success === 'boolean') {
if (file.response.success) {
value['path'] = file.response[this.responseName]
this.handleChangeCommon(value)
} else {
value['status'] = 'error'
value['message'] = file.response.message || '未知错误'
}
} else {
// actionjeecg-boot success
value['path'] = file.response[this.responseName]
this.handleChangeCommon(value)
}
} else if (file.status === 'error') {
value['message'] = file.response.message || '未知错误'
}
this.innerFile = value
},
handleClickDownloadFile() {
if (this.imgSrc) {
window.open(this.imgSrc)
}
},
handleClickDeleteFile() {
this.handleChangeCommon(null)
},
},
// JVxeCellMixins.js
enhanced: {
switches: {visible: true},
getValue: value => JVxeUploadCell.enhanced.getValue(value),
setValue: value => JVxeUploadCell.enhanced.setValue(value),
}
}
</script>
<style scoped lang="less">
.j-editable-image {
height: 32px;
max-width: 100px !important;
cursor: pointer;
&:hover {
opacity: 0.8;
}
&:active {
opacity: 0.6;
}
}
</style>

@ -0,0 +1,63 @@
<template>
<j-popup
v-bind="popupProps"
@input="handlePopupInput"
/>
</template>
<script>
import JVxeCellMixins, { dispatchEvent, vModel } from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
export default {
name: 'JVxePopupCell',
mixins: [JVxeCellMixins],
computed: {
popupProps() {
const {innerValue, originColumn: col, caseId, cellProps} = this
return {
...cellProps,
value: innerValue,
field: col.field || col.key,
code: col.popupCode,
orgFields: col.orgFields,
destFields: col.destFields,
groupId: caseId,
param: col.param,
sorter: col.sorter,
}
},
},
methods: {
/** popup回调 */
handlePopupInput(value, others) {
const {row, originColumn: col} = this
//
let popupValue = value
if (others && Object.keys(others).length > 0) {
Object.keys(others).forEach(key => {
let currentValue = others[key]
// vModel
if (key === col.key) {
popupValue = currentValue
} else {
vModel.call(this, currentValue, row, key)
}
})
}
this.handleChangeCommon(popupValue)
},
},
// JVxeCellMixins.js
enhanced: {
aopEvents: {
editActived(event) {
dispatchEvent.call(this, event, 'ant-input')
},
},
},
}
</script>
<style scoped>
</style>

@ -0,0 +1,60 @@
<template>
<a-radio-group
:class="clazz"
:value="innerValue"
v-bind="cellProps"
@change="(e)=>handleChangeCommon(e.target.value)"
>
<a-radio
v-for="item of originColumn.options"
:key="item.value"
:value="item.value"
@click="$event=>handleRadioClick(item,$event)"
>{{ item.text }}
</a-radio>
</a-radio-group>
</template>
<script>
import JVxeCellMixins from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
export default {
name: 'JVxeRadioCell',
mixins: [JVxeCellMixins],
computed: {
scrolling() {
return !!this.renderOptions.scrolling
},
clazz() {
return {
'j-vxe-radio': true,
'no-animation': this.scrolling
}
},
},
methods: {
handleRadioClick(item) {
if (this.originColumn.allowClear === true) {
//
if (item.value === this.innerValue) {
this.handleChangeCommon(null)
}
}
},
},
// JVxeCellMixins.js
enhanced: {
switches: {visible: true},
}
}
</script>
<style lang="less">
//
.j-vxe-radio.no-animation {
.ant-radio-inner,
.ant-radio-inner::after {
transition: none !important;
}
}
</style>

@ -0,0 +1,262 @@
import debounce from 'lodash/debounce'
import { getAction } from '@/api/manage'
import { cloneObject } from '@/utils/util'
import { filterDictText } from '@/components/dict/JDictSelectUtil'
import { ajaxGetDictItems, getDictItemsFromCache } from '@/api/api'
import JVxeCellMixins, { dispatchEvent } from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
/** 公共资源 */
const common = {
/** value - label map防止重复查询刷新清空缓存 */
labelMap: new Map(),
/** 公共data */
data() {
return {
loading: false,
innerSelectValue: null,
innerOptions: [],
}
},
/** 公共计算属性 */
computed: {
dict() {
return this.originColumn.dict
},
options() {
if (this.isAsync) {
return this.innerOptions
} else {
return this.originColumn.options || []
}
},
// 是否是异步模式
isAsync() {
let isAsync = this.originColumn.async
return (isAsync != null && isAsync !== '') ? !!isAsync : true
},
},
/** 公共属性监听 */
watch: {
innerValue: {
immediate: true,
handler(value) {
if (value == null || value === '') {
this.innerSelectValue = null
} else {
this.loadDataByValue(value)
}
}
},
dict() {
this.loadDataByDict()
}
},
/** 公共方法 */
methods: {
// 根据 value 查询数据,用于回显
async loadDataByValue(value) {
if (this.isAsync) {
if (this.innerSelectValue !== value) {
if (common.labelMap.has(value)) {
this.innerOptions = cloneObject(common.labelMap.get(value))
} else {
let {success, result} = await getAction(`/sys/dict/loadDictItem/${this.dict}`, {key: value})
if (success && result && result.length > 0) {
this.innerOptions = [{value: value, text: result[0]}]
common.labelMap.set(value, cloneObject(this.innerOptions))
}
}
}
}
this.innerSelectValue = (value || '').toString()
},
// 初始化字典
async loadDataByDict() {
if (!this.isAsync) {
// 如果字典项集合有数据
if (!this.originColumn.options || this.originColumn.options.length === 0) {
// 根据字典Code, 初始化字典数组
let dictStr = ''
if (this.dict) {
let arr = this.dict.split(',')
if (arr[0].indexOf('where') > 0) {
let tbInfo = arr[0].split('where')
dictStr = tbInfo[0].trim() + ',' + arr[1] + ',' + arr[2] + ',' + encodeURIComponent(tbInfo[1])
} else {
dictStr = this.dict
}
if (this.dict.indexOf(',') === -1) {
//优先从缓存中读取字典配置
let cache = getDictItemsFromCache(this.dict)
if (cache) {
this.innerOptions = cache
return
}
}
let {success, result} = await ajaxGetDictItems(dictStr, null)
if (success) {
this.innerOptions = result
}
}
}
}
},
},
}
// 显示组件,自带翻译
export const DictSearchSpanCell = {
name: 'JVxeSelectSearchSpanCell',
mixins: [JVxeCellMixins],
data() {
return {
...common.data.apply(this),
}
},
computed: {
...common.computed,
},
watch: {
...common.watch,
},
methods: {
...common.methods,
},
render(h) {
return h('span', {}, [
filterDictText(this.innerOptions, this.innerSelectValue || this.innerValue)
])
},
}
// 请求id
let requestId = 0
// 输入选择组件
export const DictSearchInputCell = {
name: 'JVxeSelectSearchInputCell',
mixins: [JVxeCellMixins],
data() {
return {
...common.data.apply(this),
hasRequest: false,
scopedSlots: {
notFoundContent: () => {
if (this.loading) {
return <a-spin size="small"/>
} else if (this.hasRequest) {
return <div>没有查询到任何数据</div>
} else {
return <div>{this.tipsContent}</div>
}
}
}
}
},
computed: {
...common.computed,
tipsContent() {
return this.originColumn.tipsContent || '请输入搜索内容'
},
filterOption() {
if (this.isAsync) {
return null
}
return (input, option) => option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
},
},
watch: {
...common.watch,
},
created() {
this.loadData = debounce(this.loadData, 300)//消抖
},
methods: {
...common.methods,
loadData(value) {
const currentRequestId = ++requestId
this.loading = true
this.innerOptions = []
if (value == null || value.trim() === '') {
this.loading = false
this.hasRequest = false
return
}
// 字典code格式table,text,code
this.hasRequest = true
getAction(`/sys/dict/loadDict/${this.dict}`, {keyword: value}).then(res => {
if (currentRequestId !== requestId) {
return
}
let {success, result, message} = res
if (success) {
this.innerOptions = result
result.forEach((item) => {
common.labelMap.set(item.value, [item])
})
} else {
this.$message.warning(message)
}
}).finally(() => {
this.loading = false
})
},
handleChange(selectedValue) {
this.innerSelectValue = selectedValue
this.handleChangeCommon(this.innerSelectValue)
},
handleSearch(value) {
if (this.isAsync) {
// 在输入时也应该开启加载因为loadData加了消抖所以会有800ms的用户主观上认为的卡顿时间
this.loading = true
if (this.innerOptions.length > 0) {
this.innerOptions = []
}
this.loadData(value)
}
},
renderOptionItem() {
let options = []
this.options.forEach(({value, text, label, title, disabled}) => {
options.push(
<a-select-option key={value} value={value} disabled={disabled}>{text || label || title}</a-select-option>
)
})
return options
},
},
render() {
return (
<a-select
showSearch
allowClear
value={this.innerSelectValue}
filterOption={this.filterOption}
style="width: 100%"
{...this.cellProps}
onSearch={this.handleSearch}
onChange={this.handleChange}
scopedSlots={this.scopedSlots}
>
{this.renderOptionItem()}
</a-select>
)
},
// 【组件增强】注释详见JVxeCellMixins.js
enhanced: {
aopEvents: {
editActived(event) {
dispatchEvent.call(this, event, 'ant-select')
},
},
}
}

@ -0,0 +1,36 @@
import { installCell, JVXETypes } from '@/components/jeecg/JVxeTable'
import JVxePopupCell from './JVxePopupCell'
import { DictSearchInputCell, DictSearchSpanCell } from './JVxeSelectDictSearchCell'
import JVxeFileCell from './JVxeFileCell'
import JVxeImageCell from './JVxeImageCell'
import JVxeRadioCell from './JVxeRadioCell'
import JVxeSelectCell from '@comp/jeecg/JVxeTable/components/cells/JVxeSelectCell'
import JVxeTextareaCell from '@comp/jeecg/JVxeTable/components/cells/JVxeTextareaCell'
// 注册online组件
JVXETypes.input_pop = 'input_pop'
JVXETypes.list_multi = 'list_multi'
JVXETypes.sel_search = 'sel_search'
installCell(JVXETypes.input_pop, JVxeTextareaCell)
installCell(JVXETypes.list_multi, JVxeSelectCell)
installCell(JVXETypes.sel_search, JVxeSelectCell)
// 注册【popup】组件普通封装方式
JVXETypes.popup = 'popup'
installCell(JVXETypes.popup, JVxePopupCell)
// 注册【字典搜索下拉】组件(高级封装方式)
JVXETypes.selectDictSearch = 'select-dict-search'
installCell(JVXETypes.selectDictSearch, DictSearchInputCell, DictSearchSpanCell)
// 注册【文件上传】组件
JVXETypes.file = 'file'
installCell(JVXETypes.file, JVxeFileCell)
// 注册【图片上传】组件
JVXETypes.image = 'image'
installCell(JVXETypes.image, JVxeImageCell)
// 注册【单选框】组件
JVXETypes.radio = 'radio'
installCell(JVXETypes.radio, JVxeRadioCell)

@ -0,0 +1,54 @@
<template>
<div :class="[prefixCls]">
<slot name="subtitle">
<div :class="[`${prefixCls}-subtitle`]">{{ typeof subTitle === 'string' ? subTitle : subTitle() }}</div>
</slot>
<div class="number-info-value">
<span>{{ total }}</span>
<span class="sub-total">
{{ subTotal }}
<icon :type="`caret-${status}`" />
</span>
</div>
</div>
</template>
<script>
import Icon from 'ant-design-vue/es/icon'
export default {
name: 'NumberInfo',
props: {
prefixCls: {
type: String,
default: 'ant-pro-number-info'
},
total: {
type: Number,
required: true
},
subTotal: {
type: Number,
required: true
},
subTitle: {
type: [String, Function],
default: ''
},
status: {
type: String,
default: 'up'
}
},
components: {
Icon
},
data () {
return {}
}
}
</script>
<style lang="less" scoped>
@import "index";
</style>

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

@ -0,0 +1,55 @@
@import "../index";
@numberInfo-prefix-cls: ~"@{ant-pro-prefix}-number-info";
.@{numberInfo-prefix-cls} {
.ant-pro-number-info-subtitle {
color: @text-color-secondary;
font-size: @font-size-base;
height: 22px;
line-height: 22px;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
white-space: nowrap;
}
.number-info-value {
margin-top: 4px;
font-size: 0;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
white-space: nowrap;
& > span {
color: @heading-color;
display: inline-block;
line-height: 32px;
height: 32px;
font-size: 24px;
margin-right: 32px;
}
.sub-total {
color: @text-color-secondary;
font-size: @font-size-lg;
vertical-align: top;
margin-right: 0;
i {
font-size: 12px;
transform: scale(0.82);
margin-left: 4px;
}
:global {
.anticon-caret-up {
color: @red-6;
}
.anticon-caret-down {
color: @green-6;
}
}
}
}
}

@ -0,0 +1,43 @@
####1._util包:存放自定义函数 详细见代码注释
####2.AvatarList:显示头像群并支持tip用法参考src\views\Home.vue如下图
![输入图片说明](https://static.oschina.net/uploads/img/201904/12181253_O0Xi.png "在这里输入图片标题")
####3.chart包:存放各种图表相关的组件,条形图柱形图折线图等等 具体用法参考首页
####4.countDown包:一个倒计时组件用法参考home页,简单描述,该组件有3个属性,
target(时间/毫秒数)必填,
format(function,该方法接收一个毫秒数的参数,用于格式化显示当前倒计时时间)非必填,
onEnd倒计时结束触发函数
![输入图片说明](https://static.oschina.net/uploads/img/201904/12182046_mwqJ.png "在这里输入图片标题")
####5.dict包数据字典专用用法参考文件夹下readme文件
####6.Ellipsis包字符串截取组件,可以指定字符串的显示长度,并将全部内容显示到tip中,简单使用参考src\views\system\PermissionList.vue
####7.jeecg包该包下自定义了很多列表/表单中用到的组件 参考包下readme文件
####8.jeecgbiz包该包下定义了一些业务相关的组件比如选择用户弹框,根据部门选择用户等等
####9.layouts+page包系统页面布局相关组件比如登陆进去之后页面顶部显示什么底部显示什么菜单点击触发多个tab的布局等等 一般情况不需要修改
####10.menun包菜单组件俩个一个折叠菜单一个正常显示的菜单
####11.NumberInfo:数字信息显示组件 如下图
![输入图片说明](https://static.oschina.net/uploads/img/201904/12185858_uvJ5.png "在这里输入图片标题")
####12.online包该包下封装了online表单的相关组件,用于展示表单各种控件,验证表单等等,相关用法参考readme
####13.setting包该包下封装了首页风格切换等功能如下图
![输入图片说明](https://static.oschina.net/uploads/img/201904/12190520_jySG.png "在这里输入图片标题")
####14.table包一个二次封装的table组件,用于展示列表参考readme
####15.tools包
Breadcrumb.vue面包屑二次封装,支持路由跳转
DetailList.vue详情展示用法参考src\views\profile\advanced\Advanced.vue(效果如下图)
![输入图片说明](https://static.oschina.net/uploads/img/201904/12193954_Uar6.png "在这里输入图片标题")
````
个人认为该页面代码有两点值得学习:
1.vue provide/inject的使用
2.该页面css定义方式,只定义一个顶层class,其余样式都定义在其下,这样只要顶层class不和别的页面冲突,整个页面的样式都是唯一生效的
````
FooterToolBar.vue:fixed定位的底部通过是否定义内部控件的属性slot="extra"决定是左浮动或是右浮动
HeaderNotice.vue:首页通知(如下图)
![输入图片说明](https://static.oschina.net/uploads/img/201904/12195340_fPe0.png "在这里输入图片标题")
HeaderInfo.vue:上下文字布局(如下图)
![输入图片说明](https://static.oschina.net/uploads/img/201904/12195638_dG5o.png "在这里输入图片标题")
Logo.vue:首页左上侧的log图
![输入图片说明](https://static.oschina.net/uploads/img/201904/12200908_ihv3.png "在这里输入图片标题")
UserMenu.vue:首页右上侧的内容
![输入图片说明](https://static.oschina.net/uploads/img/201904/12201226_laQK.png "在这里输入图片标题")
####16.trend包 趋势显示组件(如下图)
![输入图片说明](https://static.oschina.net/uploads/img/201904/12201600_Wo8K.png "在这里输入图片标题")
![cron表达式](https://oscimg.oschina.net/oscnet/661f9ac09016395f9f49286143af3241623.jpg)
![cron控件添加清除按钮](https://oscimg.oschina.net/oscnet/15096e49f2e29bd829e304d56770025d03c.jpg)

@ -0,0 +1,41 @@
<template>
<div :class="[prefixCls, reverseColor && 'reverse-color' ]">
<span>
<slot name="term"></slot>
<span class="item-text">
<slot></slot>
</span>
</span>
<span :class="[flag]"><a-icon :type="`caret-${flag}`"/></span>
</div>
</template>
<script>
export default {
name: "Trend",
props: {
prefixCls: {
type: String,
default: 'ant-pro-trend'
},
/**
* 上升下降标识up|down
*/
flag: {
type: String,
required: true
},
/**
* 颜色反转
*/
reverseColor: {
type: Boolean,
default: false
}
}
}
</script>
<style lang="less" scoped>
@import "index";
</style>

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

@ -0,0 +1,42 @@
@import "../index";
@trend-prefix-cls: ~"@{ant-pro-prefix}-trend";
.@{trend-prefix-cls} {
display: inline-block;
font-size: @font-size-base;
line-height: 22px;
.up,
.down {
margin-left: 4px;
position: relative;
top: 1px;
i {
font-size: 12px;
transform: scale(0.83);
}
}
.item-text {
display: inline-block;
margin-left: 8px;
color: rgba(0,0,0,.85);
}
.up {
color: @red-6;
}
.down {
color: @green-6;
top: -1px;
}
&.reverse-color .up {
color: @green-6;
}
&.reverse-color .down {
color: @red-6;
}
}

@ -0,0 +1,85 @@
import Vue from 'vue'
/**
* 省市区
*/
export default class Area {
/**
* 构造器
* @param express
*/
constructor(pcaa) {
if(!pcaa){
pcaa = Vue.prototype.$Jpcaa;
}
let arr = []
const province = pcaa['86']
Object.keys(province).map(key=>{
arr.push({id:key, text:province[key], pid:'86', index:1});
const city = pcaa[key];
Object.keys(city).map(key2=>{
arr.push({id:key2, text:city[key2], pid:key, index:2});
const qu = pcaa[key2];
if(qu){
Object.keys(qu).map(key3=>{
arr.push({id:key3, text:qu[key3], pid:key2, index:3});
})
}
})
})
this.all = arr;
}
get pca(){
return this.all;
}
getCode(text){
if(!text || text.length==0){
return ''
}
for(let item of this.all){
if(item.text === text){
return item.id;
}
}
}
getText(code){
if(!code || code.length==0){
return ''
}
let arr = []
this.getAreaBycode(code, arr, 3);
return arr.join('/')
}
getRealCode(code){
let arr = []
this.getPcode(code, arr, 3)
return arr;
}
getPcode(id, arr, index){
for(let item of this.all){
if(item.id === id && item.index == index){
arr.unshift(id)
if(item.pid != '86'){
this.getPcode(item.pid, arr, --index)
}
}
}
}
getAreaBycode(code, arr, index){
for(let item of this.all){
if(item.id === code && item.index == index){
arr.unshift(item.text);
if(item.pid != '86'){
this.getAreaBycode(item.pid, arr, --index)
}
}
}
}
}

@ -0,0 +1,46 @@
/**
* 获取字符串的长度ascii长度为1 中文长度为2
* @param str
* @returns {number}
*/
export const getStrFullLength = (str = '') =>
str.split('').reduce((pre, cur) => {
const charCode = cur.charCodeAt(0)
if (charCode >= 0 && charCode <= 128) {
return pre + 1
}
return pre + 2
}, 0)
/**
* 给定一个字符串和一个长度,将此字符串按指定长度截取
* @param str
* @param maxLength
* @returns {string}
*/
export const cutStrByFullLength = (str = '', maxLength) => {
let showLength = 0
return str.split('').reduce((pre, cur) => {
const charCode = cur.charCodeAt(0)
if (charCode >= 0 && charCode <= 128) {
showLength += 1
} else {
showLength += 2
}
if (showLength <= maxLength) {
return pre + cur
}
return pre
}, '')
}
// 下划线转换驼峰
export function underLinetoHump(name) {
return name.replace(/\_(\w)/g, function(all, letter){
return letter.toUpperCase();
});
}
// 驼峰转换下划线
export function humptoUnderLine(name) {
return name.replace(/([A-Z])/g,"_$1").toLowerCase();
}

@ -0,0 +1,12 @@
/**
* components util
*/
/**
* 清理空值对象
* @param children
* @returns {*[]}
*/
export function filterEmpty (children = []) {
return children.filter(c => c.tag || (c.text && c.text.trim() !== ''))
}

@ -0,0 +1,88 @@
<template>
<div :style="{ padding: '0' }">
<h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
<v-chart ref="chart" :forceFit="true" :height="height" :data="dataSource" :scale="scale">
<v-tooltip :shared="false"/>
<v-axis/>
<v-line position="x*y" :size="lineSize" :color="lineColor"/>
<v-area position="x*y" :color="color"/>
</v-chart>
</div>
</template>
<script>
import { triggerWindowResizeEvent } from '@/utils/util'
export default {
name: 'AreaChartTy',
props: {
//
dataSource: {
type: Array,
required: true
},
//
title: {
type: String,
default: ''
},
// x
x: {
type: String,
default: 'x'
},
// y
y: {
type: String,
default: 'y'
},
// Y
min: {
type: Number,
default: 0
},
// Y
max: {
type: Number,
default: null
},
//
height: {
type: Number,
default: 254
},
// 线
lineSize: {
type: Number,
default: 2
},
//
color: {
type: String,
default: ''
},
// 线
lineColor: {
type: String,
default: ''
}
},
computed: {
scale() {
return [
{ dataKey: 'x', title: this.x, alias: this.x },
{ dataKey: 'y', title: this.y, alias: this.y, min: this.min, max: this.max }
]
}
},
mounted() {
triggerWindowResizeEvent()
}
}
</script>
<style lang="less" scoped>
@import "chart";
</style>

@ -0,0 +1,50 @@
<template>
<div :style="{ padding: '0 0 32px 32px' }">
<h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
<v-chart :forceFit="true" :height="height" :data="dataSource" :scale="scale" :padding="padding">
<v-tooltip/>
<v-axis/>
<v-bar position="x*y"/>
</v-chart>
</div>
</template>
<script>
import { triggerWindowResizeEvent } from '@/utils/util'
export default {
name: 'Bar',
props: {
dataSource: {
type: Array,
required: true
},
yaxisText: {
type: String,
default: 'y'
},
title: {
type: String,
default: ''
},
height: {
type: Number,
default: 254
}
},
data() {
return { padding: ['auto', 'auto', '40', '50'] }
},
computed: {
scale() {
return [{
dataKey: 'y',
alias: this.yaxisText
}]
}
},
mounted() {
triggerWindowResizeEvent()
}
}
</script>

@ -0,0 +1,60 @@
<template>
<div :style="{ padding: '0 50px 32px 0' }">
<h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
<v-chart :forceFit="true" :height="height" :data="data" :scale="scale" :padding=" padding" :onClick="handleClick">
<v-tooltip/>
<v-legend/>
<v-axis/>
<v-bar position="type*bar"/>
<v-line position="type*line" color="#2fc25b" :size="3"/>
</v-chart>
</div>
</template>
<script>
import { ChartEventMixins } from './mixins/ChartMixins'
export default {
name: 'BarAndLine',
mixins: [ChartEventMixins],
props: {
title: {
type: String,
default: ''
},
dataSource: {
type: Array,
default: () => [
{ type: '10:10', bar: 200, line: 1000 },
{ type: '10:15', bar: 600, line: 1000},
{ type: '10:20', bar: 200, line: 1000},
{ type: '10:25', bar: 900, line: 1000},
{ type: '10:30', bar: 200, line: 1000},
{ type: '10:35', bar: 200, line: 1000},
{ type: '10:40', bar: 100, line: 1000}
]
},
height: {
type: Number,
default: 400
}
},
data() {
return {
padding: { top:50, right:50, bottom:100, left:50 },
scale: [{
dataKey: 'bar',
min: 0
}, {
dataKey: 'line',
min: 0
}]
}
},
computed: {
data() {
return this.dataSource
}
}
}
</script>

@ -0,0 +1,96 @@
<template>
<div :style="{ padding: '0 0 32px 32px' }">
<h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
<v-chart :data="data" :height="height" :force-fit="true" :scale="scale" :onClick="handleClick">
<v-tooltip/>
<v-axis/>
<v-legend/>
<v-bar position="x*y" color="type" :adjust="adjust"/>
</v-chart>
</div>
</template>
<script>
import { DataSet } from '@antv/data-set'
import { ChartEventMixins } from './mixins/ChartMixins'
export default {
name: 'BarMultid',
mixins: [ChartEventMixins],
props: {
title: {
type: String,
default: ''
},
dataSource: {
type: Array,
default: () => [
{ type: 'Jeecg', 'Jan.': 18.9, 'Feb.': 28.8, 'Mar.': 39.3, 'Apr.': 81.4, 'May': 47, 'Jun.': 20.3, 'Jul.': 24, 'Aug.': 35.6 },
{ type: 'Jeebt', 'Jan.': 12.4, 'Feb.': 23.2, 'Mar.': 34.5, 'Apr.': 99.7, 'May': 52.6, 'Jun.': 35.5, 'Jul.': 37.4, 'Aug.': 42.4 }
]
},
fields: {
type: Array,
default: () => ['Jan.', 'Feb.', 'Mar.', 'Apr.', 'May', 'Jun.', 'Jul.', 'Aug.']
},
// [{field:'name',alias:''}, {field:'sex',alias:''}]
aliases: {
type: Array,
default: () => []
},
height: {
type: Number,
default: 254
}
},
data() {
return {
adjust: [{
type: 'dodge',
marginRatio: 1 / 32
}]
}
},
computed: {
data() {
const dv = new DataSet.View().source(this.dataSource)
dv.transform({
type: 'fold',
fields: this.fields,
key: 'x',
value: 'y'
})
// bar 使 - /
let rows = dv.rows.map(row => {
if (typeof row.x === 'string') {
row.x = row.x.replace(/[-/]/g, '_')
}
return row
})
//
rows.forEach(row => {
for (let item of this.aliases) {
if (item.field === row.type) {
row.type = item.alias
break
}
}
})
return rows
},
scale() {
return [
{
type: 'cat',
dataKey: 'x'
}
]
}
}
}
</script>
<style scoped>
</style>

@ -0,0 +1,187 @@
<template>
<div :style="{ padding: '0 0 32px 32px' }">
<v-chart :forceFit="true" :height="300" :data="chartData" :scale="scale">
<v-coord type="polar" :startAngle="-202.5" :endAngle="22.5" :radius="0.75"></v-coord>
<v-axis
dataKey="value"
:zIndex="2"
:line="null"
:label="axisLabel"
:subTickCount="4"
:subTickLine="axisSubTickLine"
:tickLine="axisTickLine"
:grid="null"
></v-axis>
<v-axis dataKey="1" :show="false"></v-axis>
<v-series
gemo="point"
position="value*1"
shape="pointer"
color="#1890FF"
:active="false"
></v-series>
<v-guide
type="arc"
:zIndex="0"
:top="false"
:start="arcGuide1Start"
:end="arcGuide1End"
:vStyle="arcGuide1Style"
></v-guide>
<v-guide
type="arc"
:zIndex="1"
:start="arcGuide2Start"
:end="getArcGuide2End"
:vStyle="arcGuide2Style"
></v-guide>
<v-guide
type="html"
:position="htmlGuidePosition"
:html="getHtmlGuideHtml()"
></v-guide>
</v-chart>
</div>
</template>
<script>
import { registerShape } from 'viser-vue';
registerShape('point', 'pointer', {
draw(cfg, container) {
let point = cfg.points[0];
point = this.parsePoint(point);
const center = this.parsePoint({
x: 0,
y: 0,
});
container.addShape('line', {
attrs: {
x1: center.x,
y1: center.y,
x2: point.x,
y2: point.y + 15,
stroke: cfg.color,
lineWidth: 5,
lineCap: 'round',
}
});
return container.addShape('circle', {
attrs: {
x: center.x,
y: center.y,
r: 9.75,
stroke: cfg.color,
lineWidth: 4.5,
fill: '#fff',
}
});
}
});
const scale = [{
dataKey: 'value',
min: 0,
max: 9,
tickInterval: 1,
nice: false,
}];
const data = [
{ value: 7.0 },
];
export default {
name:"DashChartDemo",
props:{
datasource:{
type: Number,
default:7
},
title: {
type: String,
default: ''
}
},
created(){
if(!this.datasource){
this.chartData = data;
}else{
this.chartData = [
{ value: this.datasource },
];
}
this.getChartData()
},
watch: {
'datasource': function (val) {
this.chartData = [
{ value: val},
];
this.getChartData();
}
},
methods:{
getChartData(){
if(this.chartData && this.chartData.length>0){
this.abcd = this.chartData[0].value * 10
}else{
this.abcd = 70
}
},
getHtmlGuideHtml(){
return '<div style="width: 300px;text-align: center;">\n' +
'<p style="font-size: 14px;color: #545454;margin: 0;">'+this.title+'</p>\n' +
'<p style="font-size: 36px;color: #545454;margin: 0;">'+this.abcd+'%</p>\n' +
'</div>'
},
getArcGuide2End(){
return [this.chartData[0].value, 0.945]
}
},
data() {
return {
chartData:[],
height: 400,
scale: scale,
abcd:70,
axisLabel: {
offset: -16,
textStyle: {
fontSize: 18,
textAlign: 'center',
textBaseline: 'middle'
}
},
axisSubTickLine: {
length: -8,
stroke: '#fff',
strokeOpacity: 1,
},
axisTickLine: {
length: -17,
stroke: '#fff',
strokeOpacity: 1,
},
arcGuide1Start: [0, 0.945],
arcGuide1End: [9, 0.945],
arcGuide1Style: {
stroke: '#CBCBCB',
lineWidth: 18,
},
arcGuide2Start: [0, 0.945],
arcGuide2Style: {
stroke: '#1890FF',
lineWidth: 18,
},
htmlGuidePosition: ['50%', '100%'],
htmlGuideHtml: `
<div style="width: 300px;text-align: center;">
<p style="font-size: 14px;color: #545454;margin: 0;">${this.title}</p>
<p style="font-size: 36px;color: #545454;margin: 0;">${this.abcd}%</p>
</div>
`,
};
},
};
</script>

@ -0,0 +1,61 @@
<template>
<div :style="{ padding: '0 0 32px 32px' }">
<h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
<v-chart
height="254"
:data="datasource"
:forceFit="true"
:padding="['auto', 'auto', '40', '50']">
<v-tooltip />
<v-axis />
<v-bar position="x*y"/>
</v-chart>
</div>
</template>
<script>
const data = []
for (let i = 0; i < 12; i += 1) {
data.push({
x: `${i + 1}`,
y: Math.floor(Math.random() * 1000) + 200
})
}
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: "Bar",
props: {
title: {
type: String,
default: ''
}
},
mounted(){
this.datasource = data
},
data () {
return {
datasource:[],
scale,
tooltip
}
}
}
</script>

@ -0,0 +1,95 @@
<template>
<div :style="{ padding: '0 0 32px 32px' }">
<h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
<v-chart :force-fit="true" :height="height" :data="data" :scale="scale" :onClick="handleClick">
<v-tooltip/>
<v-axis/>
<v-legend/>
<v-line position="type*y" color="x"/>
<v-point position="type*y" color="x" :size="4" :v-style="style" :shape="'circle'"/>
</v-chart>
</div>
</template>
<script>
import { DataSet } from '@antv/data-set'
import { ChartEventMixins } from './mixins/ChartMixins'
export default {
name: 'LineChartMultid',
mixins: [ChartEventMixins],
props: {
title: {
type: String,
default: ''
},
dataSource: {
type: Array,
default: () => [
{ type: 'Jan', jeecg: 7.0, jeebt: 3.9 },
{ type: 'Feb', jeecg: 6.9, jeebt: 4.2 },
{ type: 'Mar', jeecg: 9.5, jeebt: 5.7 },
{ type: 'Apr', jeecg: 14.5, jeebt: 8.5 },
{ type: 'May', jeecg: 18.4, jeebt: 11.9 },
{ type: 'Jun', jeecg: 21.5, jeebt: 15.2 },
{ type: 'Jul', jeecg: 25.2, jeebt: 17.0 },
{ type: 'Aug', jeecg: 26.5, jeebt: 16.6 },
{ type: 'Sep', jeecg: 23.3, jeebt: 14.2 },
{ type: 'Oct', jeecg: 18.3, jeebt: 10.3 },
{ type: 'Nov', jeecg: 13.9, jeebt: 6.6 },
{ type: 'Dec', jeecg: 9.6, jeebt: 4.8 }
]
},
fields: {
type: Array,
default: () => ['jeecg', 'jeebt']
},
// [{field:'name',alias:''}, {field:'sex',alias:''}]
aliases:{
type: Array,
default: () => []
},
height: {
type: Number,
default: 254
}
},
data() {
return {
scale: [{
type: 'cat',
dataKey: 'x',
min: 0,
max: 1
}],
style: { stroke: '#fff', lineWidth: 1 }
}
},
computed: {
data() {
const dv = new DataSet.View().source(this.dataSource)
dv.transform({
type: 'fold',
fields: this.fields,
key: 'x',
value: 'y'
})
let rows = dv.rows
//
rows.forEach(row => {
for (let item of this.aliases) {
if (item.field === row.x) {
row.x = item.alias
break
}
}
})
return rows
}
}
}
</script>
<style scoped>
</style>

@ -0,0 +1,80 @@
<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: 8,
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>
const sourceDataConst = [
{ transfer: '一月', value: 813 },
{ transfer: '二月', value: 233 },
{ transfer: '三月', value: 561 }
]
export default {
name: 'Liquid',
props: {
height: {
type: Number,
default: 0
},
width: {
type: Number,
default: 0
}
},
data() {
return {
data: sourceDataConst,
scale: []
}
}
}
</script>
<style scoped>
</style>

@ -0,0 +1,69 @@
<template>
<div class="antv-chart-mini">
<div class="chart-wrapper" :style="{ height: 46 }">
<v-chart :force-fit="true" :height="height" :data="data" :scale="scale" :padding="[36, 0, 18, 0]">
<v-tooltip/>
<v-smooth-area position="x*y"/>
</v-chart>
</div>
</div>
</template>
<script>
import moment from 'dayjs'
const sourceData = []
const beginDay = new Date().getTime()
for (let i = 0; i < 10; i++) {
sourceData.push({
x: moment(new Date(beginDay + 1000 * 60 * 60 * 24 * i)).format('YYYY-MM-DD'),
y: Math.round(Math.random() * 10)
})
}
export default {
name: 'MiniArea',
props: {
dataSource: {
type: Array,
default: () => []
},
// x
x: {
type: String,
default: 'x'
},
// y
y: {
type: String,
default: 'y'
}
},
data() {
return {
data: [],
height: 100
}
},
computed: {
scale() {
return [
{ dataKey: 'x', title: this.x, alias: this.x },
{ dataKey: 'y', title: this.y, alias: this.y }
]
}
},
created() {
if (this.dataSource.length === 0) {
this.data = sourceData
} else {
this.data = this.dataSource
}
}
}
</script>
<style lang="less" scoped>
@import "chart";
</style>

@ -0,0 +1,76 @@
<template>
<div :style="{'width':width==null?'auto':width+'px'}">
<v-chart :forceFit="width==null" :height="height" :data="data" padding="0">
<v-tooltip/>
<v-bar position="x*y"/>
</v-chart>
</div>
</template>
<script>
import moment from 'dayjs'
const sourceData = []
const beginDay = new Date().getTime()
for (let i = 0; i < 10; i++) {
sourceData.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',
props: {
dataSource: {
type: Array,
default: () => []
},
width: {
type: Number,
default: null
},
height: {
type: Number,
default: 200
}
},
created() {
if (this.dataSource.length === 0) {
this.data = sourceData
} else {
this.data = this.dataSource
}
},
data() {
return {
tooltip,
data: [],
scale
}
}
}
</script>
<style lang="less" scoped>
@import "chart";
</style>

@ -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+'px' }"></div>
</div>
</div>
</template>
<script>
export default {
name: 'MiniProgress',
props: {
target: {
type: Number,
default: 0
},
height: {
type: Number,
default: 10
},
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>

@ -0,0 +1,70 @@
<template>
<v-chart :forceFit="true" :height="height" :data="data" :scale="scale" :onClick="handleClick">
<v-tooltip :showTitle="false" dataKey="item*percent"/>
<v-axis/>
<v-legend dataKey="item"/>
<v-pie position="percent" color="item" :v-style="pieStyle" :label="labelConfig"/>
<v-coord type="theta"/>
</v-chart>
</template>
<script>
const DataSet = require('@antv/data-set')
import { ChartEventMixins } from './mixins/ChartMixins'
export default {
name: 'Pie',
mixins: [ChartEventMixins],
props: {
title: {
type: String,
default: ''
},
height: {
type: Number,
default: 254
},
dataSource: {
type: Array,
default: () => [
{ item: '示例一', count: 40 },
{ item: '示例二', count: 21 },
{ item: '示例三', count: 17 },
{ item: '示例四', count: 13 },
{ item: '示例五', count: 9 }
]
}
},
data() {
return {
scale: [{
dataKey: 'percent',
min: 0,
formatter: '.0%'
}],
pieStyle: {
stroke: '#fff',
lineWidth: 1
},
labelConfig: ['percent', {
formatter: (val, item) => {
return item.point.item + ': ' + val
}
}]
}
},
computed: {
data() {
let dv = new DataSet.View().source(this.dataSource)
//
dv.transform({
type: 'percent',
field: 'count',
dimension: 'item',
as: 'percent'
})
return dv.rows
}
}
}
</script>

@ -0,0 +1,367 @@
# 报表组件文档
## 柱状图
##### 引用方式
```js
import Bar from '@/components/chart/Bar'
```
##### 参数列表
| 参数名 | 类型 | 必填 | 说明 |
|------------|--------|----|------------|
| title | string | | 报表标题 |
| dataSource | array | ✔️ | 报表数据源 |
| height | number | | 报表高度默认254 |
##### dataSource 示例
```json
[
{
"x": "1月",
"y": 320
},
{
"x": "2月",
"y": 457
},
{
"x": "3月",
"y": 182
}
]
```
##### 代码示例
```html
<template>
<bar title="柱状图" :dataSource="dataSource" :height="420"/>
</template>
<script>
import Bar from '@/components/chart/Bar'
export default {
name: 'ChartDemo',
components: {
Bar
},
data() {
return {
dataSource: [
{
"x": "1月",
"y": 320
},
{
"x": "2月",
"y": 457
},
{
"x": "3月",
"y": 182
}
]
}
}
}
</script>
<style></style>
```
## 多列柱状图
##### 引用方式
```js
import BarMultid from '@/components/chart/BarMultid'
```
##### 参数列表
| 参数名 | 类型 | 必填 | 说明 |
|------------|--------|----|------------|
| title | string | | 报表标题 |
| fields | array | | 主列字段列表 |
| dataSource | array | | 报表数据源 |
| height | number | | 报表高度默认254 |
##### fields 示例
```json
["Jan.", "Feb.", "Mar.", "Apr.", "May", "Jun.", "Jul.", "Aug."]
```
##### dataSource 示例
```json
[
{
"type": "Jeecg", // 列名
"Jan.": 18.9,
"Feb.": 28.8,
"Mar.": 39.3,
"Apr.": 81.4,
"May": 47,
"Jun.": 20.3,
"Jul.": 24,
"Aug.": 35.6
},
{
"type": "Jeebt",
"Jan.": 12.4,
"Feb.": 23.2,
"Mar.": 34.5,
"Apr.": 99.7,
"May": 52.6,
"Jun.": 35.5,
"Jul.": 37.4,
"Aug.": 42.4
}
]
```
## 迷你柱状图
不带标题和数据轴的柱状图
##### 引用方式
```js
import MiniBar from '@/components/chart/MiniBar'
```
##### 参数列表
| 参数名 | 类型 | 必填 | 说明 |
|------------|--------|----|---------------|
| width | number | | 报表宽度度,默认自适应宽度 |
| height | number | | 报表高度默认200 |
| dataSource | array | | 报表数据源 |
##### dataSource 示例
```json
[
{
"x": "1月",
"y": 320
},
{
"x": "2月",
"y": 457
},
{
"x": "3月",
"y": 182
}
]
```
## 面积图
##### 引用方式
```js
import AreaChartTy from '@/components/chart/AreaChartTy'
```
##### 参数列表
| 参数名 | 类型 | 必填 | 说明 |
|------------|--------|----|------------|
| title | string | | 报表标题 |
| dataSource | array | ✔️ | 报表数据源 |
| height | number | | 报表高度默认254 |
| lineSize | number | | 线的粗细默认2 |
##### dataSource 示例
```json
[
{
"x": "1月",
"y": 320
},
{
"x": "2月",
"y": 457
},
{
"x": "3月",
"y": 182
}
]
```
## 多行折线图
##### 引用方式
```js
import LineChartMultid from '@/components/chart/LineChartMultid'
```
##### 参数列表
| 参数名 | 类型 | 必填 | 说明 |
|------------|--------|----|------------|
| title | string | | 报表标题 |
| fields | array | | 主列字段列表 |
| dataSource | array | | 报表数据源 |
| height | number | | 报表高度默认254 |
##### fields 示例
```json
["jeecg", "jeebt"]
```
##### dataSource 示例
```json
[
{
"type": "Jan", // 列名
"jeecg": 7,
"jeebt": 3.9
},
{ "type": "Feb", "jeecg": 6.9, "jeebt": 4.2 },
{ "type": "Mar", "jeecg": 9.5, "jeebt": 5.7 },
{ "type": "Apr", "jeecg": 14.5, "jeebt": 8.5 },
{ "type": "May", "jeecg": 18.4, "jeebt": 11.9 },
{ "type": "Jun", "jeecg": 21.5, "jeebt": 15.2 },
{ "type": "Jul", "jeecg": 25.2, "jeebt": 17 },
{ "type": "Aug", "jeecg": 26.5, "jeebt": 16.6 },
{ "type": "Sep", "jeecg": 23.3, "jeebt": 14.2 },
{ "type": "Oct", "jeecg": 18.3, "jeebt": 10.3 },
{ "type": "Nov", "jeecg": 13.9, "jeebt": 6.6 },
{ "type": "Dec", "jeecg": 9.6, "jeebt": 4.8 }
]
```
## 饼状图
##### 引用方式
```js
import Pie from '@/components/chart/Pie'
```
##### 参数列表
| 参数名 | 类型 | 必填 | 说明 |
|------------|--------|----|------------|
| dataSource | array | | 报表数据源 |
| height | number | | 报表高度默认254 |
##### dataSource 示例
```json
[
// 所有的 percent 相加等于 100
{ "item": "一月", "percent": 40 },
{ "item": "二月", "percent": 21 },
{ "item": "三月", "percent": 17 },
{ "item": "四月", "percent": 13 },
{ "item": "五月", "percent": 9 }
]
```
## 雷达图
##### 引用方式
```js
import Radar from '@/components/chart/Radar'
```
##### 参数列表
| 参数名 | 类型 | 必填 | 说明 |
|------------|--------|----|------------|
| dataSource | array | | 报表数据源 |
| height | number | | 报表高度默认254 |
##### dataSource 示例
```json
[
// score 最小值为 0最大值为 100
{ "item": "一月", "score": 40 },
{ "item": "二月", "score": 20 },
{ "item": "三月", "score": 67 },
{ "item": "四月", "score": 43 },
{ "item": "五月", "score": 90 }
]
```
## 进度条
##### 引用方式
```js
import MiniProgress from '@/components/chart/MiniProgress'
```
##### 参数列表
| 参数名 | 类型 | 必填 | 说明 |
|------------|--------|----|-------------------|
| percentage | number | | 当前进度百分比默认0最高100 |
| target | number | | 目标值默认10 |
| height | number | | 进度条高度默认10 |
| color | string | | 进度条颜色,默认 #13C2C2 |
## 仪表盘
##### 引用方式
```js
import DashChartDemo from '@/components/chart/DashChartDemo'
```
##### 参数列表
| 参数名 | 类型 | 必填 | 说明 |
|--------|--------|----|----------------|
| title | string | | 报表标题 |
| value | number | | 当前值默认6.7最大为9 |
| height | number | | 报表高度默认254 |
## 排名列表
##### 引用方式
```js
import RankList from '@/components/chart/RankList'
```
##### 参数列表
| 参数名 | 类型 | 必填 | 说明 |
|--------|--------|----|--------------|
| title | string | | 报表标题 |
| list | array | | 排名列表数据 |
| height | number | | 报表高度,默认自适应高度 |
##### list 示例
```json
[
{
"name": "北京朝阳 1 号店",
"total": 1981
},
{ "name": "北京朝阳 2 号店", "total": 1359 },
{ "name": "北京朝阳 3 号店", "total": 1354 },
{ "name": "北京朝阳 4 号店", "total": 263 },
{ "name": "北京朝阳 5 号店", "total": 446 },
{ "name": "北京朝阳 6 号店", "total": 796 }
]
```

@ -0,0 +1,90 @@
<template>
<v-chart :forceFit="true" :height="height" :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: 100
}, {
dataKey: 'user',
alias: '类型'
}
]
const sourceData = [
{ item: '示例一', score: 40 },
{ item: '示例二', score: 20 },
{ item: '示例三', score: 67 },
{ item: '示例四', score: 43 },
{ item: '示例五', score: 90 }
]
export default {
name: 'Radar',
props: {
height: {
type: Number,
default: 254
},
dataSource: {
type: Array,
default: () => []
}
},
data() {
return {
axis1Opts,
axis2Opts,
scale,
data: sourceData
}
},
watch: {
dataSource(newVal) {
if (newVal.length === 0) {
this.data = sourceData
} else {
this.data = newVal
}
}
}
}
</script>
<style scoped>
</style>

@ -0,0 +1,81 @@
<template>
<div class="rank">
<h4 class="title">{{ title }}</h4>
<ul class="list" :style="{height:height?`${height}px`:'auto',overflow:'auto'}">
<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
},
height: {
type: Number,
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>

@ -0,0 +1,54 @@
<template>
<div>
<v-chart :forceFit="true" :height="height" :data="data">
<v-coord type="rect" direction="LB" />
<v-tooltip />
<v-legend />
<v-axis dataKey="State" :label="label" />
<v-stack-bar position="State*流程数量" color="流程状态" />
</v-chart>
</div>
</template>
<script>
const DataSet = require('@antv/data-set');
export default {
name: 'StackBar',
props: {
dataSource: {
type: Array,
required: true,
default: () => [
{ 'State': '请假', '流转中': 25, '已归档': 18 },
{ 'State': '出差', '流转中': 30, '已归档': 20 },
{ 'State': '加班', '流转中': 38, '已归档': 42},
{ 'State': '用车', '流转中': 51, '已归档': 67}
]
},
height: {
type: Number,
default: 254
}
},
data() {
return {
label: { offset: 12 }
}
},
computed: {
data() {
const dv = new DataSet.View().source(this.dataSource);
dv.transform({
type: 'fold',
fields: ['流转中', '已归档'],
key: '流程状态',
value: '流程数量',
retains: ['State'],
});
return dv.rows;
}
}
}
</script>

@ -0,0 +1,66 @@
<template>
<div :style="{ padding: '0 0 32px 32px' }">
<h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
<v-chart
:height="height"
: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>
export default {
name: 'Bar',
props: {
title: {
type: String,
default: ''
},
x: {
type: String,
default: 'x'
},
y: {
type: String,
default: 'y'
},
data: {
type: Array,
default: () => []
},
height: {
type: Number,
default: 254
}
},
data() {
return {}
},
computed: {
scale() {
return [
{ dataKey: 'x', title: this.x, alias: this.x },
{ dataKey: 'y', title: this.y, alias: this.y }
]
}
},
created() {
// this.getMonthBar()
},
methods: {
// getMonthBar() {
// this.$http.get('/analysis/month-bar')
// .then(res => {
// this.data = res.result
// })
// }
}
}
</script>

@ -0,0 +1,84 @@
<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: {
// title
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 () {
let 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>

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

@ -0,0 +1,10 @@
export const ChartEventMixins = {
methods: {
handleClick(event, chart) {
this.handleEvent('click', event, chart)
},
handleEvent(eventName, event, chart) {
this.$emit(eventName, event, chart)
},
}
}

@ -0,0 +1,111 @@
<template>
<a-radio-group v-if="tagType=='radio'" @change="handleInput" :value="getValueSting" :disabled="disabled">
<a-radio v-for="(item, key) in dictOptions" :key="key" :value="item.value">{{ item.text }}</a-radio>
</a-radio-group>
<a-radio-group v-else-if="tagType=='radioButton'" buttonStyle="solid" @change="handleInput" :value="getValueSting" :disabled="disabled">
<a-radio-button v-for="(item, key) in dictOptions" :key="key" :value="item.value">{{ item.text }}</a-radio-button>
</a-radio-group>
<a-select v-else-if="tagType=='select'" :getPopupContainer = "getPopupContainer" :placeholder="placeholder" :disabled="disabled" :value="getValueSting" @change="handleInput">
<a-select-option :value="undefined">请选择</a-select-option>
<a-select-option v-for="(item, key) in dictOptions" :key="key" :value="item.value">
<span style="display: inline-block;width: 100%" :title=" item.text || item.label ">
{{ item.text || item.label }}
</span>
</a-select-option>
</a-select>
</template>
<script>
import {ajaxGetDictItems,getDictItemsFromCache} from '@/api/api'
export default {
name: "JDictSelectTag",
props: {
dictCode: String,
placeholder: String,
disabled: Boolean,
value: [String, Number],
type: String,
getPopupContainer:{
type: Function,
default: (node) => node.parentNode
}
},
data() {
return {
dictOptions: [],
tagType:""
}
},
watch:{
dictCode:{
immediate:true,
handler() {
this.initDictData()
},
}
},
created() {
// console.log(this.dictCode);
if(!this.type || this.type==="list"){
this.tagType = "select"
}else{
this.tagType = this.type
}
//
// this.initDictData();
},
computed: {
getValueSting(){
// update-begin author:wangshuai date:20200601 for: placeholder ------
// null placeholder
return this.value != null ? this.value.toString() : undefined;
// update-end author:wangshuai date:20200601 for: placeholder ------
},
},
methods: {
initDictData() {
//
if(getDictItemsFromCache(this.dictCode)){
this.dictOptions = getDictItemsFromCache(this.dictCode);
return
}
//Code,
ajaxGetDictItems(this.dictCode, null).then((res) => {
if (res.success) {
// console.log(res.result);
this.dictOptions = res.result;
}
})
},
handleInput(e='') {
let val;
if(Object.keys(e).includes('target')){
val = e.target.value
}else{
val = e
}
console.log(val);
this.$emit('change', val);
//LOWCOD-2146 SQL
this.$emit('input', val);
},
setCurrentDictOptions(dictOptions){
this.dictOptions = dictOptions
},
getCurrentDictOptions(){
return this.dictOptions
}
},
model:{
prop: 'value',
event: 'change'
}
}
</script>
<style scoped>
</style>

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

Loading…
Cancel
Save