Showing preview only (920K chars total). Download the full file or copy to clipboard to get everything.
Repository: RKQF-JVS/jvs-knowledge-ui
Branch: main
Commit: 8e8e742249ab
Files: 139
Total size: 829.6 KB
Directory structure:
gitextract_eh24v6ax/
├── .browserslistrc
├── .editorconfig
├── .eslintrc.js
├── .gitignore
├── .postcssrc.js
├── CHANGELOG.sh
├── LICENSE
├── README.en.md
├── README.md
├── babel.config.js
├── docker/
│ ├── Dockerfile
│ ├── docker-compose.yml
│ └── my.conf
├── expendPlugins/
│ └── chart/
│ └── chartmix.css
├── package.json
├── public/
│ ├── index.html
│ └── jvs-ui-public/
│ ├── cdn/
│ │ ├── animate/
│ │ │ └── 3.5.2/
│ │ │ └── animate.css
│ │ ├── iconfont/
│ │ │ └── 1.0.0/
│ │ │ └── index.css
│ │ ├── jvs/
│ │ │ └── jvs.css
│ │ └── store/
│ │ └── 1.3.20/
│ │ └── store.js
│ ├── icon.js
│ └── svg/
│ └── favicon.ico1
├── src/
│ ├── App.vue
│ ├── api/
│ │ ├── common.js
│ │ ├── index.js
│ │ ├── login.js
│ │ └── newDesign.js
│ ├── components/
│ │ ├── QRcode/
│ │ │ └── index.vue
│ │ ├── api.js
│ │ ├── basic-assembly/
│ │ │ ├── button.vue
│ │ │ ├── form.vue
│ │ │ ├── formcard.vue
│ │ │ ├── formitem.vue
│ │ │ ├── levelForm.vue
│ │ │ ├── stepForm.vue
│ │ │ ├── tab.vue
│ │ │ ├── table.vue
│ │ │ ├── userForm.vue
│ │ │ └── userSelector.vue
│ │ ├── basic-container/
│ │ │ ├── loading.vue
│ │ │ ├── login/
│ │ │ │ └── loginForm.vue
│ │ │ └── main.vue
│ │ ├── doc-lib/
│ │ │ ├── api.js
│ │ │ ├── excel/
│ │ │ │ └── index.vue
│ │ │ ├── flow/
│ │ │ │ └── index.vue
│ │ │ ├── html/
│ │ │ │ └── index.vue
│ │ │ ├── index.vue
│ │ │ ├── map/
│ │ │ │ └── index.vue
│ │ │ └── show.vue
│ │ ├── error-page/
│ │ │ └── 404.vue
│ │ ├── iframe/
│ │ │ └── main.vue
│ │ ├── index.js
│ │ ├── page-footer/
│ │ │ └── FooterContent.vue
│ │ └── page-header/
│ │ ├── PageHeader.vue
│ │ └── titlePageHeader.vue
│ ├── config/
│ │ └── env.js
│ ├── const/
│ │ ├── chinaArea.js
│ │ ├── columnTypeList.js
│ │ ├── const.js
│ │ ├── errorCode.js
│ │ ├── iconList.js
│ │ ├── iconfont.js
│ │ ├── systemIcon.js
│ │ └── website.js
│ ├── error.js
│ ├── filters/
│ │ └── index.js
│ ├── main.js
│ ├── permission.js
│ ├── router/
│ │ ├── axios.js
│ │ ├── jvs-router.js
│ │ ├── page/
│ │ │ └── index.js
│ │ ├── router.js
│ │ └── views/
│ │ └── index.js
│ ├── store/
│ │ ├── getters.js
│ │ ├── index.js
│ │ ├── modules/
│ │ │ ├── common.js
│ │ │ ├── konwledge.js
│ │ │ ├── tags.js
│ │ │ └── user.js
│ │ └── types/
│ │ └── global.js
│ ├── styles/
│ │ ├── animate/
│ │ │ └── vue-transition.scss
│ │ ├── common.scss
│ │ ├── element-ui.scss
│ │ ├── login.scss
│ │ ├── media.scss
│ │ ├── mixin.scss
│ │ ├── normalize.scss
│ │ ├── reset2.0.scss
│ │ ├── resetAll.scss
│ │ ├── sidebar.scss
│ │ ├── tags.scss
│ │ ├── themes/
│ │ │ ├── common/
│ │ │ │ ├── mixins.scss
│ │ │ │ └── variables.scss
│ │ │ └── index.scss
│ │ ├── tiptap.scss
│ │ ├── tiptapView.scss
│ │ ├── top.scss
│ │ └── variables.scss
│ ├── util/
│ │ ├── date.js
│ │ ├── eventBus.js
│ │ ├── login.js
│ │ ├── permision.js
│ │ ├── store.js
│ │ ├── url.js
│ │ ├── util.js
│ │ └── validate.js
│ └── views/
│ ├── catalogview/
│ │ └── index.vue
│ ├── common/
│ │ ├── Comment.vue
│ │ ├── KnowSet.vue
│ │ ├── LuckySheet.vue
│ │ ├── MemberSet.vue
│ │ ├── MindElixir.vue
│ │ ├── Tiptap.vue
│ │ ├── Topology.vue
│ │ ├── api.js
│ │ ├── draw.js
│ │ ├── search.vue
│ │ ├── show.vue
│ │ ├── tiptap/
│ │ │ ├── extension.js
│ │ │ └── tiptapPlugin.js
│ │ ├── toolbar.vue
│ │ └── topbar.vue
│ ├── companyInfo/
│ │ └── index.vue
│ ├── index/
│ │ ├── api.js
│ │ ├── baseInfo.vue
│ │ ├── index.vue
│ │ └── page.vue
│ ├── info/
│ │ ├── icon/
│ │ │ ├── demo.css
│ │ │ ├── demo_index.html
│ │ │ ├── iconfont.css
│ │ │ ├── iconfont.js
│ │ │ └── iconfont.json
│ │ └── index.vue
│ ├── main/
│ │ └── wx/
│ │ └── login.vue
│ ├── my/
│ │ └── icon/
│ │ └── index.js
│ └── view/
│ ├── api.js
│ ├── diclibApi.js
│ └── index.vue
└── vue.config.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .browserslistrc
================================================
> 1%
last 2 versions
not ie <= 8
================================================
FILE: .editorconfig
================================================
# http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false
================================================
FILE: .eslintrc.js
================================================
module.exports = {
root: true,
env: {
node: true
},
'extends': [
"plugin:vue/essential"
],
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
},
parserOptions: {
parser: 'babel-eslint'
}
}
================================================
FILE: .gitignore
================================================
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
================================================
FILE: .postcssrc.js
================================================
module.exports = {
plugins: {
autoprefixer: {}
}
}
================================================
FILE: CHANGELOG.sh
================================================
#!/bin/bash
## Author LinkinStar
# solve the space by IFS
IFS=`echo -en "\n\b"`
echo -en $IFS
if [ -f "CHANGELOG.md" ];then
rm -f CHANGELOG.md
touch CHANGELOG.md
else
touch CHANGELOG.md
fi
function printFeat(){
for i in ${feat[@]}
do
echo "- "$i >> CHANGELOG.md
done
echo >> CHANGELOG.md
}
function printFix(){
for i in ${fix[@]}
do
echo "- "$i >> CHANGELOG.md
done
echo >> CHANGELOG.md
}
function printOther(){
for i in ${other[@]}
do
echo "- "$i >> CHANGELOG.md
done
echo >> CHANGELOG.md
}
function checkLog(){
if [[ $1 == "feat"* ]]
then
feat[featIndex]=$1
let featIndex++
elif [[ $1 == "fix"* ]]
then
fix[fixIndex]=$1
let fixIndex++
else
other[otherIndex]=$1
let otherIndex++
fi
}
function printLog(){
if [[ $featIndex -ne 0 ]]; then
echo "### Features" >> CHANGELOG.md
printFeat
fi
if [[ $fixIndex -ne 0 ]]; then
echo "### Bug Fixes" >> CHANGELOG.md
printFix
fi
if [[ $otherIndex -ne 0 ]]; then
echo "### Other Changes" >> CHANGELOG.md
printOther
fi
feat=()
featIndex=0
fix=()
fixIndex=0
other=()
otherIndex=0
}
curDate=""
function checkDate()
{
if [[ $curDate = $1 ]]; then
return
fi
curDate=$1
printLog
echo >> CHANGELOG.md
echo "## "$curDate >> CHANGELOG.md
}
commitMessageList=`git log --date=format:'%Y-%m-%d' --pretty=format:'%cd%n%s'`
index=0
for i in ${commitMessageList[@]}
do
if [[ $index%2 -eq 0 ]]
then
checkDate $i
else
#echo "- "$i >> CHANGELOG.md
checkLog $i
fi
let index++
done
printLog
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(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.
================================================
FILE: README.en.md
================================================

### Applicable scenarios:
*Applicable to enterprises and teams, it provides online notes, knowledge precipitation, online product manuals, knowledge bases, online electronic tutorials and other functions.
###Problems solved:
-* * problem of data capitalization * *: without appropriate document management tools, it is difficult to transform the intangible knowledge of employees into tangible assets of the enterprise, resulting in a waste of a lot of resources in training, learning and display, and the effect is not satisfactory.
-* * unified control of files * *: data files are scattered in employees' computers, so it is difficult to form effective unified control. Unstructured content needs to be managed from the whole process of file generation, use and flow
-* * problem of knowledge flow * *: the flow speed of information is an important guarantee for the efficient operation of enterprises. The deconstructed data is managed by the business system, but the unstructured information is a reliable flow channel, which basically depends on roaring, USB flash disk and inquiry
-* * information retrieval problem * *: because the file is not deconstructed, it is not easy to retrieve and find, which is the lack of an effective enterprise level "Baidu"
-* * information security problems * *: the enterprise cannot effectively manage files at different levels, and there is a risk of information disclosure on the SaaS platform on the Internet. Privatization + internal authority control is the basis
**Worry free · enterprise document = enterprise knowledge base + online editing tool set + enterprise search engine + content display platform**
### Technology stack selection
-Front end: Vue + element UI
-Back end: Spring_ cloud_ alibaba、spring boot、Mybatis plus、Nacos、RabbitMq、Xxl-job
-Data: MySQL, elasticsearch, redis, MariaDB (as appropriate)
-Operation and maintenance: k8s + docker
### Project value
*When using low-cost products with more than 30 users, the cost is lower than SaaS products, and the number of useless households is limited
*Information security, privatization deployment (physical server or private cloud). The core of privatization is data control. There is no data control and it belongs to a third party
*Technology is open, using general technology stack, supporting 100% code opening, supporting secondary development, and will not be kidnapped by any service provider
*Corporate operation. The project is a company level commercial operation project and an important guarantee for continuous iteration and support services of the project
*Technical support, the team supporting the project promotion belongs to senior personnel in the industry
*Expansibility thinking: the project is a part of the enterprise's digital transformation. It has learned a lot from the experience of nailing, flying book and other large platforms, made a lot of tailoring and adjustment to the Internet and C-end related capabilities, and absorbed a lot of ideas and experience of to B product design.
### Core functions:
*Integrate multiple file editors (rich text editor, online form, online brain map, online flow chart, etc., and the editor will continue to expand)
*Preview and analysis of various files (preview of PDF, word, PPT, Excel and other files)
*Collaborative editing of core documents (rich text and online forms)
*Support teamwork ()
*Provide enterprise search engine (title based, content-based)
*Support document content comments and document collection
*Support document sharing (password secondary verification setting)
*Support document templates
*Enterprise level organizational structure and authority management (rigid organization + flexible group)
#### Corpus (knowledge base) management
*The whole station intelligent search engine supports document level and content level retrieval
*Addition, deletion, modification and query of Anthology
*Collaboration of team members of the collection (viewable and editable)
*Directory structured management of Anthology
*Basic introduction of the anthology
*Participants and collaborators of knowledge base
*Support multi role collaboration (member, manager, owner)
#### Document management:
*Support rich text (word like), brain map (XMIND like) and flow chart (VISO like)
*Addition, deletion, modification and query of documents, online editing of documents
*Document sharing settings
#### Rich text editing:
*Text outline, subtitle navigation
*Support WYSIWYG
*Support form
*Support rich text expression plug-ins such as pictures, tables, third-party applications, audio, video, etc
*Support code block, reference
*Support source code viewing
## Project composition
Enterprise documents are divided into business foreground and management background. The project is composed of business foreground and business background:
-Business front end address: https://gitee.com/software-minister/jvs-knowledge-ui
-Business front end address: https://gitee.com/software-minister/jvs-apply-document
-Management background front end address: https://gitee.com/software-minister/jvs-ui
-Back end address of management background: https://gitee.com/software-minister/jvs
## Demo address
Demo address: http://knowledge.bctools.cn/
Trial account: you can log in by scanning the wechat code. If you need to try the account password, please contact us with QR code
Partial screenshot:


-

-

-



### Rapid deployment document
https://gitee.com/software-minister/jvs-docker-compose/blob/master/readme.md
### Use and authorization
The worry free enterprise document community version is 100% open source. Under the condition of compliance filing, it supports self-use and commercial use, and commercial use provides 100% source code.
### Version Description:
Use purpose | fee mode | use conditions | authorization time
-|-|-|-
Individual study | free | free filing | permanent
Commercial, secondary development | charge, code delivery | technical service contract + Commercial filing | permanent
### Description of commercial expenses:
>Technical service fee, required. Please contact the business department for the specific fee
>Customized development fee, optional, 1500 yuan/person day
>Deployment cost, optional, 500 yuan/time
>Long term operation and maintenance, optional, negotiation
Filing instructions: contact our business personnel for online filing. Filing content: project name, use mode (self use/commercial use), filing subject, filing contact personnel.
### Prohibited behaviors (to ensure the product goes further):
*Code distribution in any form (including but not limited to code copy, code disclosure, code open source, code sharing, etc.) is prohibited without our approval
*It is prohibited to use without filing (including self use and commercial use)
### Technical exchange and business support
![输入图片说明] (img/image20220522.png)
### Update history:
V1.3 20211202
*Modify some UI display diagrams
*Add online preview of multiple file formats
*Add software introduction page
*Add the view of personnel under the current tenant and within the organization
*Add knowledge base background replacement
*Fix some bugs
### Current version
V1.5
*Support multi person online collaborative editing at the same time
*Optimize drawing function
*Document knowledge base sharing
*Template management
*Access WPS
================================================
FILE: README.md
================================================

### 适用场景:
* 适用于企业、团队,提供在线笔记、知识沉淀、在线产品手册、知识库、在线电子教程等功能。
### 解决的问题:
- **数据资产化的问题** :没有合适的文件管理工具,很难对员工无形知识转化为企业的有形资产,导致培训、学习、展示上浪费了大量的资源,而且效果还不尽人意。
- **文件统一管控问题** :数据文件分散在员工各自的电脑中,很难形成有效的统一管控,需要从文件的生成、使用、流动整个过程对 非结构化内容进行管理
- **知识流动的问题** :信息的流动速度是企业高效运转的重要保障,解构化的数据由业务系统管理起来,但是非结构化的信息确实可靠的流动渠道,基本靠吼、靠U盘,靠问
- **信息的检索问题** :文件由于没有解构化,所以不便于检索查找,是缺乏一个有效的企业级“百度”
- **信息安全的问题** :企业内部无法有效的分级管理文件,放在互联网上的SaaS平台又存在信息泄露风险,私有化+内部权限管控是基础
**无忧·企业文档=企业级知识库+在线编辑工具集+企业搜索引擎+内容展示平台**

### 技术栈选择
- 前端:VUE+Element-ui
- 后端:spring_cloud_alibaba、spring boot、Mybatis plus、Nacos、RabbitMq、Xxl-job
- 数据:Mysql、ElasticSearch、Redis、MariaDB(根据情况)
- 运维:K8S+docker
### 项目价值
* 使用低成本,超过30个用户产品的使用时,成本低于SaaS产品,且无用户数的限制
* 信息安全,私有化部署(实体服务器或者私有云),私有化的核心是数据可控,不存在数据控制归第三方
* 技术开放,采用通用技术栈,支持100%代码开放,支持二次开发,不会被任何服务商绑架
* 公司化运作,项目是公司级商业运营项目,是项目持续化迭代与支持服务的重要保障
* 技术支持,支持项目推进的团队属于行业行业资深人员
* 扩展性思考,项目属于企业数字化转型的其中一部分,吸取钉钉、飞书、等大平台的很多经验借鉴,且对互联网、C端相关的能力做了大量裁剪与调整,吸收了大量的to B的产品设计的思路与经验。
### 核心功能:
* 集成多种文件编辑器(富文本编辑器、在线表格、在线脑图、在线流程图等,编辑器将会持续扩展)
* 多种文件的预览解析(PDF、Word、PPT、Excel等多种文件预览)
* 核心文档的协同编辑(富文本与在线表格)
* 支持团队化协同操作()
* 提供企业级搜索引擎(基于标题、基于内容)
* 支持文档内容评论与文档收藏
* 支持文档分享(密码二次校验设置)
* 支持文档模板
* 企业级组织构架与权限管理(刚性组织+柔性群组)
#### 文集(知识库)管理
* 全站智能搜索引擎,支持文档级、内容级检索
* 文集的增删改查
* 文集的团队成员协作(可查看、可编辑)
* 文集的目录结构化管理
* 文集的基础介绍
* 知识库的参与协作人员
* 支持多种角色协同(成员、管理者、所有者)
#### 文档管理:
* 支持富文本(类word)、脑图(类Xmind)、流程图(类viso)
* 文档的增删改查、文档在线编辑
* 文档的分享设置
#### 富文本编辑:
* 文本大纲,小标题导航
* 支持所见即所得
* 支持表格
* 支持图片、表格、三方应用、音频、视频、等富文本表达插件
* 支持代码块、引用、
* 支持源代码查看
## 项目组成
企业文档分为业务前台与管理后台,项目由 业务前台与业务后台组成:
- 业务前台前端地址:https://github.com/RKQF-JVS/jvs-knowledge-ui
- 业务前台后端地址:https://github.com/RKQF-JVS/jvs-apply-document
- 管理后台前端地址:https://github.com/RKQF-JVS/jvs-ui/tree/2.1.0/
- 管理后台后端地址:https://github.com/RKQF-JVS/jvs/tree/2.1.0/
## 部署视频
https://www.bilibili.com/video/BV1BN411q79Y
### **体验地址与账号说明**

账号说明:
- 普通用户端:体验者自有微信扫码登录
- 管理端(全网共享):testadmin 123456
- 管理端+应用编辑:联系运营微信号 ruanjbz,开设独立环境与独立账号
- 管理端+平台配置+应用编辑:联系运营微信号 ruanjbz,获取私有化部署文档与安装包
地址说明:

- 管理平台(含管理平台、低代码):https://frame.bctools.cn/
- 数据智仓(数据分析平台):http://bi.bctools.cn/
- 企业文档:http://knowledge.bctools.cn/
- 企业计划(项目管理):http://teamwork.bctools.cn/
- 企业邮筒(Web邮箱客户端):http://mailbox.bctools.cn/
- 规则引擎:http://rules.bctools.cn/
- 逻辑引擎:http://logic.bctools.cn/
- 视频会议:http://meeting.bctools.cn/
- APS(智能排产):https://aps.bctools.cn/
部分截图:

-

-

-

-

-

-

-

-

-
### 快速部署文档
https://github.com/RKQF-JVS/jvs-docker-compose/blob/master/readme.md
### 技术交流与商务支持
<img width="261" height="424" alt="0b3c772279ce09b82231b8bae7812a24" src="https://github.com/user-attachments/assets/aa641007-d0c1-4622-9de6-74a7f37d3f12" />
如因人数限制无法加群时,可加运营同学拉入技术交流群

### 历史更新记录:
V1.3 20211202
* 修改部分UI展示图
* 添加多种文件格式在线预览
* 添加软件介绍页
* 添加当前租户下与组织内人员查看
* 添加知识库背景替换
* 修复部分BUG
### 当前版本
V1.5
* 支持多人在线同时协同编辑
* 优化画图功能
* 文档知识库分享
* 模板管理
* 接入WPS
================================================
FILE: babel.config.js
================================================
module.exports = {
presets: [
['@vue/app', { useBuiltIns: "entry" }]
]
}
================================================
FILE: docker/Dockerfile
================================================
FROM nginx:1.15.4
VOLUME /tmp
ENV LANG en_US.UTF-8
COPY dist /usr/share/nginx/html/
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
#这个地方一定要把之前的默认给替换掉,不然使用这个默认nginx的镜像会无法替换配置
COPY my.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
EXPOSE 443
================================================
FILE: docker/docker-compose.yml
================================================
version: '3'
services:
jvs-knowledge-ui:
build:
context: .
restart: always
container_name: jvs-knowledge-ui
image: jvs-knowledge-ui
networks:
- jvs_jvs
external_links:
- gateway
ports:
- 80:80
networks:
jvs_jvs:
external: true
================================================
FILE: docker/my.conf
================================================
server {
listen 80;
server_name localhost;
add_header X-Content-Type-Options nosniff;
charset utf-8;
client_header_buffer_size 1024k;
large_client_header_buffers 4 1024k;
client_max_body_size 50m;
#前端
root /usr/share/nginx/html/;
# 跳转至登录页
location = / {
index index.html;
try_files /usr/share/nginx/html /jvs-knowledge-ui/index.html;
}
location ^~ /jvs-knowledge-ui/ {
index index.html ;
try_files $uri $uri/ /jvs-knowledge-ui/index.html;
}
#静态资源
location ^~ /static/ {
root /usr/share/nginx/html/;
}
location ^~ /jvs-ui-public/ {
root /usr/share/nginx/html/;
}
#其它路径全部代理到网关接口中
location /api/ {
proxy_cookie_path /jvs-knowledge-ui /jvs-knowledge-ui;
proxy_cookie_path / /;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-real-ip $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://gateway:10000/api/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection upgrade;
}
#其它路径全部代理到网关接口中
location / {
proxy_cookie_path /jvs-knowledge-ui /jvs-knowledge-ui;
proxy_cookie_path / /;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-real-ip $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto http;
proxy_pass http://gateway:10000/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection upgrade;
}
}
================================================
FILE: expendPlugins/chart/chartmix.css
================================================
.luckysheet-datavisual-quick-menu{width:120px;overflow:auto;margin-top:15px}.luckysheet-datavisual-quick-menu::-webkit-scrollbar{display:none}.luckysheet-datavisual-quick-menu>div{text-align:left;padding:4px 4px;border-right:3px solid #fff;color:#777;cursor:pointer;line-height:1.4em;word-wrap:break-word}.luckysheet-datavisual-quick-menu>div:hover{color:#000}.luckysheet-datavisual-quick-menu>div i{width:15px}.luckysheet-datavisual-quick-menu>div:hover i{color:#ff7e7e}.luckysheet-datavisual-quick-menu>div.luckysheet-datavisual-quick-menu-active{border-right:3px solid #ff7e7e;color:#000;font-weight:700}.luckysheet-datavisual-quick-menu>div.luckysheet-datavisual-quick-menu-active:hover i{color:#000}.luckysheet-datavisual-quick-range{padding:5px 0}.luckysheet-datavisual-range-container{background:#fff;border:1px solid #d9d9d9;border-top:1px solid silver;min-width:20px;width:100%;max-width:200px;display:inline-block}.luckysheet-datavisual-range-container-focus{border:1px solid #4d90fe;box-shadow:inset 0 1px 2px rgba(0,0,0,.3);outline:none}.luckysheet-datavisual-range-input,.luckysheet-datavisual-range-input:focus{background:transparent!important;border:none!important;box-sizing:border-box;box-shadow:none;height:25px;margin:0;outline:none!important;padding:1px 8px!important;width:100%}.luckysheet-datavisual-range-button-container{overflow:hidden;padding:0 0 0 8px;text-align:right;width:21px}.luckysheet-datavisual-range-button-container div{padding:2px 10px 0 10px;font-size:18px;cursor:pointer;color:#6598f3}.luckysheet-datavisual-range-button-container div:hover{color:#ff7e7e}.luckysheet-datavisual-quick-m{margin-top:5px;min-height:500px;top:50px;font-size:12px}.luckysheet-datavisual-quick-list{left:110px;right:0;bottom:0;top:80px;position:absolute;overflow:auto;border-top:1px solid #e5e5e5;padding:5px 3px 35px 3px}.luckysheet-datavisual-quick-list-title{padding:4px 6px;background:#e5e5e5;margin-top:10px}.luckysheet-datavisual-quick-list-ul{overflow:hidden}.luckysheet-datavisual-quick-list-item{display:inline-block;margin:5px 8px;border:1px solid #dadada;width:100px;height:80px}.luckysheet-datavisual-quick-list-item:hover{border:1px solid #ff7e7e;box-shadow:0 0 20px #ff7e7e}.luckysheet-datavisual-quick-list-item img{display:inline-block;width:100px;height:80px}.luckysheet-datavisual-quick-list-item-active{border:1px solid #6598f3;box-shadow:0 0 20px #6598f3}.chart-base-slider .el-slider__runway.show-input{margin-right:72px}.chart-base-slider .el-slider__input.el-input-number--mini{width:56px}.chart-base-slider .input_content{margin:6px 0 0 5px}.title{font-weight:700}.el-row{font-size:12px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.chartSetting{width:100%;height:100%}
================================================
FILE: package.json
================================================
{
"name": "jvs-knowledge-ui",
"version": "2020.09.24",
"private": true,
"scripts": {
"pre": "cnpm install || yarn --registry https://registry.npm.taobao.org || npm install --registry https://registry.npm.taobao.org ",
"dev": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"connect": "node server/index.js"
},
"dependencies": {
"axios": "^0.19.0",
"babel-polyfill": "^6.26.0",
"classlist-polyfill": "^1.2.0",
"crypto-js": "^3.1.9-1",
"element-tiptap": "^1.26.2",
"element-ui": "^2.13.0",
"js-cookie": "^2.2.1",
"js-base64": "^3.6.1",
"luckyexcel": "^1.0.0",
"mind-elixir": "^0.14.0",
"nprogress": "^0.2.0",
"qrcodejs2": "^0.0.2",
"script-loader": "^0.7.2",
"topology-vue": "^0.5.22",
"uuid": "^8.3.2",
"vue": "^2.6.10",
"vue-axios": "^2.1.4",
"vue-clipboard2": "^0.3.1",
"vue-router": "^3.1.3",
"vuex": "^3.1.1",
"wangeditor": "^4.5.2"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.11.0",
"@vue/cli-plugin-eslint": "^3.8.0",
"@vue/cli-service": "^3.11.0",
"chai": "^4.2.0",
"node-sass": "^4.13.1",
"sass-loader": "^8.0.0",
"sass-resources-loader": "^2.0.3",
"socket.io": "^2.3.0",
"socket.io-client": "^2.3.0",
"vue-json-viewer": "^2.2.12",
"vue-socket.io": "^2.1.1-a",
"vue-template-compiler": "^2.6.10"
},
"lint-staged": {
"*.js": [
"vue-cli-service lint",
"git add"
],
"*.vue": [
"vue-cli-service lint",
"git add"
]
}
}
================================================
FILE: public/index.html
================================================
<!DOCTYPE html>
<html>
<head>
<title>无忧 - 企业文档</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="format-detection" content="telephone=no">
<meta http-equiv="X-UA-Compatible" content="chrome=1" />
<meta name="referrer" content="no-referrer">
<link rel="stylesheet" href="<%= BASE_URL %>jvs-ui-public/cdn/animate/3.5.2/animate.css">
<link rel="stylesheet" href="<%= BASE_URL %>jvs-ui-public/cdn/iconfont/1.0.0/index.css">
<link rel="stylesheet" href="<%= BASE_URL %>jvs-ui-public/cdn/jvs/jvs.css">
<script src="<%= BASE_URL %>jvs-ui-public/jquery-3.4.1.min.js"></script>
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/css/pluginsCss.css' />
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/plugins.css' />
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/css/luckysheet.css' />
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/assets/iconfont/iconfont.css' />
<script src="https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/js/plugin.js"></script>
<script src="https://cdn.jsdelivr.net/npm/luckysheet/dist/luckysheet.umd.js"></script>
<script src="https://cdn.jsdelivr.net/npm/mind-elixir@0.6.1/dist/mind-elixir.js"></script>
<!-- 常用图标 -->
<link href="//at.alicdn.com/t/font_1331132_g7tv7fmj6c9.css" rel="stylesheet" />
<!-- 新通用图标topology-new -->
<link href="//at.alicdn.com/t/font_2030495_6tq2su2jmyx.css" rel="stylesheet" />
<!-- 老图标 -->
<link href="//at.alicdn.com/t/font_1331132_5lvbai88wkb.css" rel="stylesheet" />
<script src="http://topology.le5le.com/js/canvas2svg.js"></script>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script src="https://cdn.bootcss.com/jszip/3.2.2/jszip.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/echarts/4.8.0/echarts.min.js"></script>
</head>
<body>
<noscript>
<strong>很抱歉,如果没有 JavaScript 支持,网站将不能正常工作。请启用浏览器的 JavaScript 然后继续。</strong>
</noscript>
<div id="app">
<div class="jvs-home">
<div class="jvs-home__main">
<img class="jvs-home__loading_gif" src="<%= BASE_URL %>jvs-ui-public/img/loading.gif" alt="">
<!-- <img class="jvs-home__loading" src="<%= BASE_URL %>jvs-ui-public/img/loading.png" alt="loading"> -->
<div class="jvs-home__title">
正在加载资源
</div>
<div class="jvs-home__sub-title">
初次加载资源可能需要较多时间 请耐心等待
</div>
</div>
</div>
</div>
<!-- built files will be auto injected -->
<script src="<%= BASE_URL %>jvs-ui-public/cdn/axios/1.0.0/axios.min.js" charset="utf-8"></script>
</body>
</html>
================================================
FILE: public/jvs-ui-public/cdn/animate/3.5.2/animate.css
================================================
@charset "UTF-8";
/*!
* animate.css -http://daneden.me/animate
* Version - 3.5.1
* Licensed under the MIT license - http://opensource.org/licenses/MIT
*
* Copyright (c) 2016 Daniel Eden
*/
.animated{-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.animated.infinite{-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.animated.hinge{-webkit-animation-duration:2s;animation-duration:2s}.animated.bounceIn,.animated.bounceOut,.animated.flipOutX,.animated.flipOutY{-webkit-animation-duration:.75s;animation-duration:.75s}@-webkit-keyframes bounce{0%,20%,53%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1);-webkit-transform:translateZ(0);transform:translateZ(0)}40%,43%{-webkit-transform:translate3d(0,-30px,0);transform:translate3d(0,-30px,0)}40%,43%,70%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);animation-timing-function:cubic-bezier(.755,.05,.855,.06)}70%{-webkit-transform:translate3d(0,-15px,0);transform:translate3d(0,-15px,0)}90%{-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0)}}@keyframes bounce{0%,20%,53%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1);-webkit-transform:translateZ(0);transform:translateZ(0)}40%,43%{-webkit-transform:translate3d(0,-30px,0);transform:translate3d(0,-30px,0)}40%,43%,70%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);animation-timing-function:cubic-bezier(.755,.05,.855,.06)}70%{-webkit-transform:translate3d(0,-15px,0);transform:translate3d(0,-15px,0)}90%{-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0)}}.bounce{-webkit-animation-name:bounce;animation-name:bounce;-webkit-transform-origin:center bottom;transform-origin:center bottom}@-webkit-keyframes flash{0%,50%,to{opacity:1}25%,75%{opacity:0}}@keyframes flash{0%,50%,to{opacity:1}25%,75%{opacity:0}}.flash{-webkit-animation-name:flash;animation-name:flash}@-webkit-keyframes pulse{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}50%{-webkit-transform:scale3d(1.05,1.05,1.05);transform:scale3d(1.05,1.05,1.05)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}@keyframes pulse{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}50%{-webkit-transform:scale3d(1.05,1.05,1.05);transform:scale3d(1.05,1.05,1.05)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}.pulse{-webkit-animation-name:pulse;animation-name:pulse}@-webkit-keyframes rubberBand{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}30%{-webkit-transform:scale3d(1.25,.75,1);transform:scale3d(1.25,.75,1)}40%{-webkit-transform:scale3d(.75,1.25,1);transform:scale3d(.75,1.25,1)}50%{-webkit-transform:scale3d(1.15,.85,1);transform:scale3d(1.15,.85,1)}65%{-webkit-transform:scale3d(.95,1.05,1);transform:scale3d(.95,1.05,1)}75%{-webkit-transform:scale3d(1.05,.95,1);transform:scale3d(1.05,.95,1)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}@keyframes rubberBand{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}30%{-webkit-transform:scale3d(1.25,.75,1);transform:scale3d(1.25,.75,1)}40%{-webkit-transform:scale3d(.75,1.25,1);transform:scale3d(.75,1.25,1)}50%{-webkit-transform:scale3d(1.15,.85,1);transform:scale3d(1.15,.85,1)}65%{-webkit-transform:scale3d(.95,1.05,1);transform:scale3d(.95,1.05,1)}75%{-webkit-transform:scale3d(1.05,.95,1);transform:scale3d(1.05,.95,1)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}.rubberBand{-webkit-animation-name:rubberBand;animation-name:rubberBand}@-webkit-keyframes shake{0%,to{-webkit-transform:translateZ(0);transform:translateZ(0)}10%,30%,50%,70%,90%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}20%,40%,60%,80%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}}@keyframes shake{0%,to{-webkit-transform:translateZ(0);transform:translateZ(0)}10%,30%,50%,70%,90%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}20%,40%,60%,80%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}}.shake{-webkit-animation-name:shake;animation-name:shake}@-webkit-keyframes headShake{0%{-webkit-transform:translateX(0);transform:translateX(0)}6.5%{-webkit-transform:translateX(-6px) rotateY(-9deg);transform:translateX(-6px) rotateY(-9deg)}18.5%{-webkit-transform:translateX(5px) rotateY(7deg);transform:translateX(5px) rotateY(7deg)}31.5%{-webkit-transform:translateX(-3px) rotateY(-5deg);transform:translateX(-3px) rotateY(-5deg)}43.5%{-webkit-transform:translateX(2px) rotateY(3deg);transform:translateX(2px) rotateY(3deg)}50%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes headShake{0%{-webkit-transform:translateX(0);transform:translateX(0)}6.5%{-webkit-transform:translateX(-6px) rotateY(-9deg);transform:translateX(-6px) rotateY(-9deg)}18.5%{-webkit-transform:translateX(5px) rotateY(7deg);transform:translateX(5px) rotateY(7deg)}31.5%{-webkit-transform:translateX(-3px) rotateY(-5deg);transform:translateX(-3px) rotateY(-5deg)}43.5%{-webkit-transform:translateX(2px) rotateY(3deg);transform:translateX(2px) rotateY(3deg)}50%{-webkit-transform:translateX(0);transform:translateX(0)}}.headShake{-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-name:headShake;animation-name:headShake}@-webkit-keyframes swing{20%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}40%{-webkit-transform:rotate(-10deg);transform:rotate(-10deg)}60%{-webkit-transform:rotate(5deg);transform:rotate(5deg)}80%{-webkit-transform:rotate(-5deg);transform:rotate(-5deg)}to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}@keyframes swing{20%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}40%{-webkit-transform:rotate(-10deg);transform:rotate(-10deg)}60%{-webkit-transform:rotate(5deg);transform:rotate(5deg)}80%{-webkit-transform:rotate(-5deg);transform:rotate(-5deg)}to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}.swing{-webkit-transform-origin:top center;transform-origin:top center;-webkit-animation-name:swing;animation-name:swing}@-webkit-keyframes tada{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}10%,20%{-webkit-transform:scale3d(.9,.9,.9) rotate(-3deg);transform:scale3d(.9,.9,.9) rotate(-3deg)}30%,50%,70%,90%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate(3deg);transform:scale3d(1.1,1.1,1.1) rotate(3deg)}40%,60%,80%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate(-3deg);transform:scale3d(1.1,1.1,1.1) rotate(-3deg)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}@keyframes tada{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}10%,20%{-webkit-transform:scale3d(.9,.9,.9) rotate(-3deg);transform:scale3d(.9,.9,.9) rotate(-3deg)}30%,50%,70%,90%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate(3deg);transform:scale3d(1.1,1.1,1.1) rotate(3deg)}40%,60%,80%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate(-3deg);transform:scale3d(1.1,1.1,1.1) rotate(-3deg)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}.tada{-webkit-animation-name:tada;animation-name:tada}@-webkit-keyframes wobble{0%{-webkit-transform:none;transform:none}15%{-webkit-transform:translate3d(-25%,0,0) rotate(-5deg);transform:translate3d(-25%,0,0) rotate(-5deg)}30%{-webkit-transform:translate3d(20%,0,0) rotate(3deg);transform:translate3d(20%,0,0) rotate(3deg)}45%{-webkit-transform:translate3d(-15%,0,0) rotate(-3deg);transform:translate3d(-15%,0,0) rotate(-3deg)}60%{-webkit-transform:translate3d(10%,0,0) rotate(2deg);transform:translate3d(10%,0,0) rotate(2deg)}75%{-webkit-transform:translate3d(-5%,0,0) rotate(-1deg);transform:translate3d(-5%,0,0) rotate(-1deg)}to{-webkit-transform:none;transform:none}}@keyframes wobble{0%{-webkit-transform:none;transform:none}15%{-webkit-transform:translate3d(-25%,0,0) rotate(-5deg);transform:translate3d(-25%,0,0) rotate(-5deg)}30%{-webkit-transform:translate3d(20%,0,0) rotate(3deg);transform:translate3d(20%,0,0) rotate(3deg)}45%{-webkit-transform:translate3d(-15%,0,0) rotate(-3deg);transform:translate3d(-15%,0,0) rotate(-3deg)}60%{-webkit-transform:translate3d(10%,0,0) rotate(2deg);transform:translate3d(10%,0,0) rotate(2deg)}75%{-webkit-transform:translate3d(-5%,0,0) rotate(-1deg);transform:translate3d(-5%,0,0) rotate(-1deg)}to{-webkit-transform:none;transform:none}}.wobble{-webkit-animation-name:wobble;animation-name:wobble}@-webkit-keyframes jello{0%,11.1%,to{-webkit-transform:none;transform:none}22.2%{-webkit-transform:skewX(-12.5deg) skewY(-12.5deg);transform:skewX(-12.5deg) skewY(-12.5deg)}33.3%{-webkit-transform:skewX(6.25deg) skewY(6.25deg);transform:skewX(6.25deg) skewY(6.25deg)}44.4%{-webkit-transform:skewX(-3.125deg) skewY(-3.125deg);transform:skewX(-3.125deg) skewY(-3.125deg)}55.5%{-webkit-transform:skewX(1.5625deg) skewY(1.5625deg);transform:skewX(1.5625deg) skewY(1.5625deg)}66.6%{-webkit-transform:skewX(-.78125deg) skewY(-.78125deg);transform:skewX(-.78125deg) skewY(-.78125deg)}77.7%{-webkit-transform:skewX(.390625deg) skewY(.390625deg);transform:skewX(.390625deg) skewY(.390625deg)}88.8%{-webkit-transform:skewX(-.1953125deg) skewY(-.1953125deg);transform:skewX(-.1953125deg) skewY(-.1953125deg)}}@keyframes jello{0%,11.1%,to{-webkit-transform:none;transform:none}22.2%{-webkit-transform:skewX(-12.5deg) skewY(-12.5deg);transform:skewX(-12.5deg) skewY(-12.5deg)}33.3%{-webkit-transform:skewX(6.25deg) skewY(6.25deg);transform:skewX(6.25deg) skewY(6.25deg)}44.4%{-webkit-transform:skewX(-3.125deg) skewY(-3.125deg);transform:skewX(-3.125deg) skewY(-3.125deg)}55.5%{-webkit-transform:skewX(1.5625deg) skewY(1.5625deg);transform:skewX(1.5625deg) skewY(1.5625deg)}66.6%{-webkit-transform:skewX(-.78125deg) skewY(-.78125deg);transform:skewX(-.78125deg) skewY(-.78125deg)}77.7%{-webkit-transform:skewX(.390625deg) skewY(.390625deg);transform:skewX(.390625deg) skewY(.390625deg)}88.8%{-webkit-transform:skewX(-.1953125deg) skewY(-.1953125deg);transform:skewX(-.1953125deg) skewY(-.1953125deg)}}.jello{-webkit-animation-name:jello;animation-name:jello;-webkit-transform-origin:center;transform-origin:center}@-webkit-keyframes bounceIn{0%,20%,40%,60%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}20%{-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}40%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}60%{opacity:1;-webkit-transform:scale3d(1.03,1.03,1.03);transform:scale3d(1.03,1.03,1.03)}80%{-webkit-transform:scale3d(.97,.97,.97);transform:scale3d(.97,.97,.97)}to{opacity:1;-webkit-transform:scaleX(1);transform:scaleX(1)}}@keyframes bounceIn{0%,20%,40%,60%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}20%{-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}40%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}60%{opacity:1;-webkit-transform:scale3d(1.03,1.03,1.03);transform:scale3d(1.03,1.03,1.03)}80%{-webkit-transform:scale3d(.97,.97,.97);transform:scale3d(.97,.97,.97)}to{opacity:1;-webkit-transform:scaleX(1);transform:scaleX(1)}}.bounceIn{-webkit-animation-name:bounceIn;animation-name:bounceIn}@-webkit-keyframes bounceInDown{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(0,-3000px,0);transform:translate3d(0,-3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,25px,0);transform:translate3d(0,25px,0)}75%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}90%{-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0)}to{-webkit-transform:none;transform:none}}@keyframes bounceInDown{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(0,-3000px,0);transform:translate3d(0,-3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,25px,0);transform:translate3d(0,25px,0)}75%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}90%{-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0)}to{-webkit-transform:none;transform:none}}.bounceInDown{-webkit-animation-name:bounceInDown;animation-name:bounceInDown}@-webkit-keyframes bounceInLeft{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(-3000px,0,0);transform:translate3d(-3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(25px,0,0);transform:translate3d(25px,0,0)}75%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}90%{-webkit-transform:translate3d(5px,0,0);transform:translate3d(5px,0,0)}to{-webkit-transform:none;transform:none}}@keyframes bounceInLeft{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(-3000px,0,0);transform:translate3d(-3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(25px,0,0);transform:translate3d(25px,0,0)}75%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}90%{-webkit-transform:translate3d(5px,0,0);transform:translate3d(5px,0,0)}to{-webkit-transform:none;transform:none}}.bounceInLeft{-webkit-animation-name:bounceInLeft;animation-name:bounceInLeft}@-webkit-keyframes bounceInRight{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(3000px,0,0);transform:translate3d(3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}to{-webkit-transform:none;transform:none}}@keyframes bounceInRight{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(3000px,0,0);transform:translate3d(3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}to{-webkit-transform:none;transform:none}}.bounceInRight{-webkit-animation-name:bounceInRight;animation-name:bounceInRight}@-webkit-keyframes bounceInUp{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(0,3000px,0);transform:translate3d(0,3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}75%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}90%{-webkit-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes bounceInUp{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(0,3000px,0);transform:translate3d(0,3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}75%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}90%{-webkit-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.bounceInUp{-webkit-animation-name:bounceInUp;animation-name:bounceInUp}@-webkit-keyframes bounceOut{20%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}50%,55%{opacity:1;-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}to{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}}@keyframes bounceOut{20%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}50%,55%{opacity:1;-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}to{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}}.bounceOut{-webkit-animation-name:bounceOut;animation-name:bounceOut}@-webkit-keyframes bounceOutDown{20%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}to{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}@keyframes bounceOutDown{20%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}to{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}.bounceOutDown{-webkit-animation-name:bounceOutDown;animation-name:bounceOutDown}@-webkit-keyframes bounceOutLeft{20%{opacity:1;-webkit-transform:translate3d(20px,0,0);transform:translate3d(20px,0,0)}to{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}@keyframes bounceOutLeft{20%{opacity:1;-webkit-transform:translate3d(20px,0,0);transform:translate3d(20px,0,0)}to{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}.bounceOutLeft{-webkit-animation-name:bounceOutLeft;animation-name:bounceOutLeft}@-webkit-keyframes bounceOutRight{20%{opacity:1;-webkit-transform:translate3d(-20px,0,0);transform:translate3d(-20px,0,0)}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}@keyframes bounceOutRight{20%{opacity:1;-webkit-transform:translate3d(-20px,0,0);transform:translate3d(-20px,0,0)}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}.bounceOutRight{-webkit-animation-name:bounceOutRight;animation-name:bounceOutRight}@-webkit-keyframes bounceOutUp{20%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,20px,0);transform:translate3d(0,20px,0)}to{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}@keyframes bounceOutUp{20%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,20px,0);transform:translate3d(0,20px,0)}to{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}.bounceOutUp{-webkit-animation-name:bounceOutUp;animation-name:bounceOutUp}@-webkit-keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.fadeIn{-webkit-animation-name:fadeIn;animation-name:fadeIn}@-webkit-keyframes fadeInDown{0%{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInDown{0%{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInDown{-webkit-animation-name:fadeInDown;animation-name:fadeInDown}@-webkit-keyframes fadeInDownBig{0%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInDownBig{0%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInDownBig{-webkit-animation-name:fadeInDownBig;animation-name:fadeInDownBig}@-webkit-keyframes fadeInLeft{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInLeft{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInLeft{-webkit-animation-name:fadeInLeft;animation-name:fadeInLeft}@-webkit-keyframes fadeInLeftBig{0%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInLeftBig{0%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInLeftBig{-webkit-animation-name:fadeInLeftBig;animation-name:fadeInLeftBig}@-webkit-keyframes fadeInRight{0%{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInRight{0%{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInRight{-webkit-animation-name:fadeInRight;animation-name:fadeInRight}@-webkit-keyframes fadeInRightBig{0%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInRightBig{0%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInRightBig{-webkit-animation-name:fadeInRightBig;animation-name:fadeInRightBig}@-webkit-keyframes fadeInUp{0%{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInUp{0%{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInUp{-webkit-animation-name:fadeInUp;animation-name:fadeInUp}@-webkit-keyframes fadeInUpBig{0%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInUpBig{0%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInUpBig{-webkit-animation-name:fadeInUpBig;animation-name:fadeInUpBig}@-webkit-keyframes fadeOut{0%{opacity:1}to{opacity:0}}@keyframes fadeOut{0%{opacity:1}to{opacity:0}}.fadeOut{-webkit-animation-name:fadeOut;animation-name:fadeOut}@-webkit-keyframes fadeOutDown{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}@keyframes fadeOutDown{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}.fadeOutDown{-webkit-animation-name:fadeOutDown;animation-name:fadeOutDown}@-webkit-keyframes fadeOutDownBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}@keyframes fadeOutDownBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}.fadeOutDownBig{-webkit-animation-name:fadeOutDownBig;animation-name:fadeOutDownBig}@-webkit-keyframes fadeOutLeft{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}@keyframes fadeOutLeft{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.fadeOutLeft{-webkit-animation-name:fadeOutLeft;animation-name:fadeOutLeft}@-webkit-keyframes fadeOutLeftBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}@keyframes fadeOutLeftBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}.fadeOutLeftBig{-webkit-animation-name:fadeOutLeftBig;animation-name:fadeOutLeftBig}@-webkit-keyframes fadeOutRight{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}@keyframes fadeOutRight{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.fadeOutRight{-webkit-animation-name:fadeOutRight;animation-name:fadeOutRight}@-webkit-keyframes fadeOutRightBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}@keyframes fadeOutRightBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}.fadeOutRightBig{-webkit-animation-name:fadeOutRightBig;animation-name:fadeOutRightBig}@-webkit-keyframes fadeOutUp{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}@keyframes fadeOutUp{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}.fadeOutUp{-webkit-animation-name:fadeOutUp;animation-name:fadeOutUp}@-webkit-keyframes fadeOutUpBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}@keyframes fadeOutUpBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}.fadeOutUpBig{-webkit-animation-name:fadeOutUpBig;animation-name:fadeOutUpBig}@-webkit-keyframes flip{0%{-webkit-transform:perspective(400px) rotateY(-1turn);transform:perspective(400px) rotateY(-1turn)}0%,40%{-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}40%{-webkit-transform:perspective(400px) translateZ(150px) rotateY(-190deg);transform:perspective(400px) translateZ(150px) rotateY(-190deg)}50%{-webkit-transform:perspective(400px) translateZ(150px) rotateY(-170deg);transform:perspective(400px) translateZ(150px) rotateY(-170deg)}50%,80%{-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}80%{-webkit-transform:perspective(400px) scale3d(.95,.95,.95);transform:perspective(400px) scale3d(.95,.95,.95)}to{-webkit-transform:perspective(400px);transform:perspective(400px);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}}@keyframes flip{0%{-webkit-transform:perspective(400px) rotateY(-1turn);transform:perspective(400px) rotateY(-1turn)}0%,40%{-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}40%{-webkit-transform:perspective(400px) translateZ(150px) rotateY(-190deg);transform:perspective(400px) translateZ(150px) rotateY(-190deg)}50%{-webkit-transform:perspective(400px) translateZ(150px) rotateY(-170deg);transform:perspective(400px) translateZ(150px) rotateY(-170deg)}50%,80%{-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}80%{-webkit-transform:perspective(400px) scale3d(.95,.95,.95);transform:perspective(400px) scale3d(.95,.95,.95)}to{-webkit-transform:perspective(400px);transform:perspective(400px);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}}.animated.flip{-webkit-backface-visibility:visible;backface-visibility:visible;-webkit-animation-name:flip;animation-name:flip}@-webkit-keyframes flipInX{0%{-webkit-transform:perspective(400px) rotateX(90deg);transform:perspective(400px) rotateX(90deg);opacity:0}0%,40%{-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}40%{-webkit-transform:perspective(400px) rotateX(-20deg);transform:perspective(400px) rotateX(-20deg)}60%{-webkit-transform:perspective(400px) rotateX(10deg);transform:perspective(400px) rotateX(10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotateX(-5deg);transform:perspective(400px) rotateX(-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}@keyframes flipInX{0%{-webkit-transform:perspective(400px) rotateX(90deg);transform:perspective(400px) rotateX(90deg);opacity:0}0%,40%{-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}40%{-webkit-transform:perspective(400px) rotateX(-20deg);transform:perspective(400px) rotateX(-20deg)}60%{-webkit-transform:perspective(400px) rotateX(10deg);transform:perspective(400px) rotateX(10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotateX(-5deg);transform:perspective(400px) rotateX(-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}.flipInX{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipInX;animation-name:flipInX}@-webkit-keyframes flipInY{0%{-webkit-transform:perspective(400px) rotateY(90deg);transform:perspective(400px) rotateY(90deg);opacity:0}0%,40%{-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}40%{-webkit-transform:perspective(400px) rotateY(-20deg);transform:perspective(400px) rotateY(-20deg)}60%{-webkit-transform:perspective(400px) rotateY(10deg);transform:perspective(400px) rotateY(10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotateY(-5deg);transform:perspective(400px) rotateY(-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}@keyframes flipInY{0%{-webkit-transform:perspective(400px) rotateY(90deg);transform:perspective(400px) rotateY(90deg);opacity:0}0%,40%{-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}40%{-webkit-transform:perspective(400px) rotateY(-20deg);transform:perspective(400px) rotateY(-20deg)}60%{-webkit-transform:perspective(400px) rotateY(10deg);transform:perspective(400px) rotateY(10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotateY(-5deg);transform:perspective(400px) rotateY(-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}.flipInY{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipInY;animation-name:flipInY}@-webkit-keyframes flipOutX{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotateX(-20deg);transform:perspective(400px) rotateX(-20deg);opacity:1}to{-webkit-transform:perspective(400px) rotateX(90deg);transform:perspective(400px) rotateX(90deg);opacity:0}}@keyframes flipOutX{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotateX(-20deg);transform:perspective(400px) rotateX(-20deg);opacity:1}to{-webkit-transform:perspective(400px) rotateX(90deg);transform:perspective(400px) rotateX(90deg);opacity:0}}.flipOutX{-webkit-animation-name:flipOutX;animation-name:flipOutX;-webkit-backface-visibility:visible!important;backface-visibility:visible!important}@-webkit-keyframes flipOutY{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotateY(-15deg);transform:perspective(400px) rotateY(-15deg);opacity:1}to{-webkit-transform:perspective(400px) rotateY(90deg);transform:perspective(400px) rotateY(90deg);opacity:0}}@keyframes flipOutY{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotateY(-15deg);transform:perspective(400px) rotateY(-15deg);opacity:1}to{-webkit-transform:perspective(400px) rotateY(90deg);transform:perspective(400px) rotateY(90deg);opacity:0}}.flipOutY{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipOutY;animation-name:flipOutY}@-webkit-keyframes lightSpeedIn{0%{-webkit-transform:translate3d(100%,0,0) skewX(-30deg);transform:translate3d(100%,0,0) skewX(-30deg);opacity:0}60%{-webkit-transform:skewX(20deg);transform:skewX(20deg)}60%,80%{opacity:1}80%{-webkit-transform:skewX(-5deg);transform:skewX(-5deg)}to{-webkit-transform:none;transform:none;opacity:1}}@keyframes lightSpeedIn{0%{-webkit-transform:translate3d(100%,0,0) skewX(-30deg);transform:translate3d(100%,0,0) skewX(-30deg);opacity:0}60%{-webkit-transform:skewX(20deg);transform:skewX(20deg)}60%,80%{opacity:1}80%{-webkit-transform:skewX(-5deg);transform:skewX(-5deg)}to{-webkit-transform:none;transform:none;opacity:1}}.lightSpeedIn{-webkit-animation-name:lightSpeedIn;animation-name:lightSpeedIn;-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}@-webkit-keyframes lightSpeedOut{0%{opacity:1}to{-webkit-transform:translate3d(100%,0,0) skewX(30deg);transform:translate3d(100%,0,0) skewX(30deg);opacity:0}}@keyframes lightSpeedOut{0%{opacity:1}to{-webkit-transform:translate3d(100%,0,0) skewX(30deg);transform:translate3d(100%,0,0) skewX(30deg);opacity:0}}.lightSpeedOut{-webkit-animation-name:lightSpeedOut;animation-name:lightSpeedOut;-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}@-webkit-keyframes rotateIn{0%{transform-origin:center;-webkit-transform:rotate(-200deg);transform:rotate(-200deg);opacity:0}0%,to{-webkit-transform-origin:center}to{transform-origin:center;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateIn{0%{transform-origin:center;-webkit-transform:rotate(-200deg);transform:rotate(-200deg);opacity:0}0%,to{-webkit-transform-origin:center}to{transform-origin:center;-webkit-transform:none;transform:none;opacity:1}}.rotateIn{-webkit-animation-name:rotateIn;animation-name:rotateIn}@-webkit-keyframes rotateInDownLeft{0%{transform-origin:left bottom;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInDownLeft{0%{transform-origin:left bottom;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInDownLeft{-webkit-animation-name:rotateInDownLeft;animation-name:rotateInDownLeft}@-webkit-keyframes rotateInDownRight{0%{transform-origin:right bottom;-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInDownRight{0%{transform-origin:right bottom;-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInDownRight{-webkit-animation-name:rotateInDownRight;animation-name:rotateInDownRight}@-webkit-keyframes rotateInUpLeft{0%{transform-origin:left bottom;-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInUpLeft{0%{transform-origin:left bottom;-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInUpLeft{-webkit-animation-name:rotateInUpLeft;animation-name:rotateInUpLeft}@-webkit-keyframes rotateInUpRight{0%{transform-origin:right bottom;-webkit-transform:rotate(-90deg);transform:rotate(-90deg);opacity:0}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInUpRight{0%{transform-origin:right bottom;-webkit-transform:rotate(-90deg);transform:rotate(-90deg);opacity:0}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInUpRight{-webkit-animation-name:rotateInUpRight;animation-name:rotateInUpRight}@-webkit-keyframes rotateOut{0%{transform-origin:center;opacity:1}0%,to{-webkit-transform-origin:center}to{transform-origin:center;-webkit-transform:rotate(200deg);transform:rotate(200deg);opacity:0}}@keyframes rotateOut{0%{transform-origin:center;opacity:1}0%,to{-webkit-transform-origin:center}to{transform-origin:center;-webkit-transform:rotate(200deg);transform:rotate(200deg);opacity:0}}.rotateOut{-webkit-animation-name:rotateOut;animation-name:rotateOut}@-webkit-keyframes rotateOutDownLeft{0%{transform-origin:left bottom;opacity:1}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}}@keyframes rotateOutDownLeft{0%{transform-origin:left bottom;opacity:1}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}}.rotateOutDownLeft{-webkit-animation-name:rotateOutDownLeft;animation-name:rotateOutDownLeft}@-webkit-keyframes rotateOutDownRight{0%{transform-origin:right bottom;opacity:1}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}}@keyframes rotateOutDownRight{0%{transform-origin:right bottom;opacity:1}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}}.rotateOutDownRight{-webkit-animation-name:rotateOutDownRight;animation-name:rotateOutDownRight}@-webkit-keyframes rotateOutUpLeft{0%{transform-origin:left bottom;opacity:1}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}}@keyframes rotateOutUpLeft{0%{transform-origin:left bottom;opacity:1}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}}.rotateOutUpLeft{-webkit-animation-name:rotateOutUpLeft;animation-name:rotateOutUpLeft}@-webkit-keyframes rotateOutUpRight{0%{transform-origin:right bottom;opacity:1}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:rotate(90deg);transform:rotate(90deg);opacity:0}}@keyframes rotateOutUpRight{0%{transform-origin:right bottom;opacity:1}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:rotate(90deg);transform:rotate(90deg);opacity:0}}.rotateOutUpRight{-webkit-animation-name:rotateOutUpRight;animation-name:rotateOutUpRight}@-webkit-keyframes hinge{0%{transform-origin:top left}0%,20%,60%{-webkit-transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}20%,60%{-webkit-transform:rotate(80deg);transform:rotate(80deg);transform-origin:top left}40%,80%{-webkit-transform:rotate(60deg);transform:rotate(60deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;opacity:1}to{-webkit-transform:translate3d(0,700px,0);transform:translate3d(0,700px,0);opacity:0}}@keyframes hinge{0%{transform-origin:top left}0%,20%,60%{-webkit-transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}20%,60%{-webkit-transform:rotate(80deg);transform:rotate(80deg);transform-origin:top left}40%,80%{-webkit-transform:rotate(60deg);transform:rotate(60deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;opacity:1}to{-webkit-transform:translate3d(0,700px,0);transform:translate3d(0,700px,0);opacity:0}}.hinge{-webkit-animation-name:hinge;animation-name:hinge}@-webkit-keyframes rollIn{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0) rotate(-120deg);transform:translate3d(-100%,0,0) rotate(-120deg)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes rollIn{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0) rotate(-120deg);transform:translate3d(-100%,0,0) rotate(-120deg)}to{opacity:1;-webkit-transform:none;transform:none}}.rollIn{-webkit-animation-name:rollIn;animation-name:rollIn}@-webkit-keyframes rollOut{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(100%,0,0) rotate(120deg);transform:translate3d(100%,0,0) rotate(120deg)}}@keyframes rollOut{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(100%,0,0) rotate(120deg);transform:translate3d(100%,0,0) rotate(120deg)}}.rollOut{-webkit-animation-name:rollOut;animation-name:rollOut}@-webkit-keyframes zoomIn{0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%{opacity:1}}@keyframes zoomIn{0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%{opacity:1}}.zoomIn{-webkit-animation-name:zoomIn;animation-name:zoomIn}@-webkit-keyframes zoomInDown{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInDown{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInDown{-webkit-animation-name:zoomInDown;animation-name:zoomInDown}@-webkit-keyframes zoomInLeft{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(10px,0,0);transform:scale3d(.475,.475,.475) translate3d(10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInLeft{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(10px,0,0);transform:scale3d(.475,.475,.475) translate3d(10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInLeft{-webkit-animation-name:zoomInLeft;animation-name:zoomInLeft}@-webkit-keyframes zoomInRight{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInRight{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInRight{-webkit-animation-name:zoomInRight;animation-name:zoomInRight}@-webkit-keyframes zoomInUp{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInUp{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInUp{-webkit-animation-name:zoomInUp;animation-name:zoomInUp}@-webkit-keyframes zoomOut{0%{opacity:1}50%{-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%,to{opacity:0}}@keyframes zoomOut{0%{opacity:1}50%{-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%,to{opacity:0}}.zoomOut{-webkit-animation-name:zoomOut;animation-name:zoomOut}@-webkit-keyframes zoomOutDown{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomOutDown{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomOutDown{-webkit-animation-name:zoomOutDown;animation-name:zoomOutDown}@-webkit-keyframes zoomOutLeft{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(42px,0,0);transform:scale3d(.475,.475,.475) translate3d(42px,0,0)}to{opacity:0;-webkit-transform:scale(.1) translate3d(-2000px,0,0);transform:scale(.1) translate3d(-2000px,0,0);-webkit-transform-origin:left center;transform-origin:left center}}@keyframes zoomOutLeft{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(42px,0,0);transform:scale3d(.475,.475,.475) translate3d(42px,0,0)}to{opacity:0;-webkit-transform:scale(.1) translate3d(-2000px,0,0);transform:scale(.1) translate3d(-2000px,0,0);-webkit-transform-origin:left center;transform-origin:left center}}.zoomOutLeft{-webkit-animation-name:zoomOutLeft;animation-name:zoomOutLeft}@-webkit-keyframes zoomOutRight{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-42px,0,0);transform:scale3d(.475,.475,.475) translate3d(-42px,0,0)}to{opacity:0;-webkit-transform:scale(.1) translate3d(2000px,0,0);transform:scale(.1) translate3d(2000px,0,0);-webkit-transform-origin:right center;transform-origin:right center}}@keyframes zoomOutRight{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-42px,0,0);transform:scale3d(.475,.475,.475) translate3d(-42px,0,0)}to{opacity:0;-webkit-transform:scale(.1) translate3d(2000px,0,0);transform:scale(.1) translate3d(2000px,0,0);-webkit-transform-origin:right center;transform-origin:right center}}.zoomOutRight{-webkit-animation-name:zoomOutRight;animation-name:zoomOutRight}@-webkit-keyframes zoomOutUp{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomOutUp{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomOutUp{-webkit-animation-name:zoomOutUp;animation-name:zoomOutUp}@-webkit-keyframes slideInDown{0%{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes slideInDown{0%{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.slideInDown{-webkit-animation-name:slideInDown;animation-name:slideInDown}@-webkit-keyframes slideInLeft{0%{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes slideInLeft{0%{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.slideInLeft{-webkit-animation-name:slideInLeft;animation-name:slideInLeft}@-webkit-keyframes slideInRight{0%{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes slideInRight{0%{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.slideInRight{-webkit-animation-name:slideInRight;animation-name:slideInRight}@-webkit-keyframes slideInUp{0%{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes slideInUp{0%{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.slideInUp{-webkit-animation-name:slideInUp;animation-name:slideInUp}@-webkit-keyframes slideOutDown{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}@keyframes slideOutDown{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}.slideOutDown{-webkit-animation-name:slideOutDown;animation-name:slideOutDown}@-webkit-keyframes slideOutLeft{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}@keyframes slideOutLeft{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.slideOutLeft{-webkit-animation-name:slideOutLeft;animation-name:slideOutLeft}@-webkit-keyframes slideOutRight{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}@keyframes slideOutRight{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.slideOutRight{-webkit-animation-name:slideOutRight;animation-name:slideOutRight}@-webkit-keyframes slideOutUp{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}@keyframes slideOutUp{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}.slideOutUp{-webkit-animation-name:slideOutUp;animation-name:slideOutUp}
================================================
FILE: public/jvs-ui-public/cdn/iconfont/1.0.0/index.css
================================================
[class^="icon-"]{
font-family: "iconfont" !important;
/* 以下内容参照第三方图标库本身的规则 */
font-size: 18px !important;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.jvs-icon-select__item i {
font-family: "iconfont" !important;
/* 以下内容参照第三方图标库本身的规则 */
font-size: 24px !important;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.el-menu-item [class^=icon-] {
margin-right: 5px;
width: 24px;
text-align: center;
font-size: 18px;
vertical-align: middle;
}
.el-submenu [class^=icon-] {
vertical-align: middle;
margin-right: 5px;
width: 24px;
text-align: center;
font-size: 18px;
}
================================================
FILE: public/jvs-ui-public/cdn/jvs/jvs.css
================================================
html,
body,
#app {
height: 100%;
margin: 0;
padding: 0;
}
.jvs-home {
/* background-color: #303133; */
background-color: #fff;
height: 100%;
display: flex;
flex-direction: column;
}
.jvs-home__main {
user-select: none;
width: 100%;
flex-grow: 1;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
position: relative;
}
.jvs-home__footer {
width: 100%;
flex-grow: 0;
text-align: center;
padding: 1em 0;
}
.jvs-home__footer > a {
font-size: 12px;
color: #ABABAB;
text-decoration: none;
}
.jvs-home__loading {
height: 32px;
width: 32px;
margin-bottom: 20px;
}
.jvs-home__title {
/* color: #FFF; */
font-size: 14px;
margin-bottom: 10px;
color: #303133;
display: none;
}
.jvs-home__sub-title {
/* color: #ABABAB; */
font-size: 12px;
color: #303133;
display: none;
}
.jvs-home__loading {
height: 32px;
width: 32px;
margin-bottom: 20px;
color: #303133;
animation: loadingAll 1.5s linear infinite;
}
@keyframes loadingAll{
0%{-webkit-transform:rotate(0deg);}
25%{-webkit-transform:rotate(90deg);}
50%{-webkit-transform:rotate(180deg);}
75%{-webkit-transform:rotate(270deg);}
100%{-webkit-transform:rotate(360deg);}
}
.jvs-home__loading_gif{
display:block;
width: 450px;
height: 360px;
/* position: absolute; */
/* top: 50px; */
}
================================================
FILE: public/jvs-ui-public/cdn/store/1.3.20/store.js
================================================
'use strict'
// Module export pattern from
// https://github.com/umdjs/umd/blob/master/returnExports.js
;(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define([], factory)
} else if (typeof exports === 'object') {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports,
// like Node.
module.exports = factory()
} else {
// Browser globals (root is window)
root.store = factory()
}
}(this, function () {
// Store.js
var store = {}
var win = (typeof window !== 'undefined' ? window : global)
var doc = win.document
var localStorageName = 'localStorage'
var scriptTag = 'script'
var storage
store.disabled = false
store.version = '1.3.20'
store.set = function (key, value) {}
store.get = function (key, defaultVal) {}
store.has = function (key) { return store.get(key) !== undefined }
store.remove = function (key) {}
store.clear = function () {}
store.transact = function (key, defaultVal, transactionFn) {
if (transactionFn == null) {
transactionFn = defaultVal
defaultVal = null
}
if (defaultVal == null) {
defaultVal = {}
}
var val = store.get(key, defaultVal)
transactionFn(val)
store.set(key, val)
}
store.getAll = function () {}
store.forEach = function () {}
store.serialize = function (value) {
return JSON.stringify(value)
}
store.deserialize = function (value) {
if (typeof value !== 'string') { return undefined }
try { return JSON.parse(value) } catch (e) { return value || undefined }
}
// Functions to encapsulate questionable FireFox 3.6.13 behavior
// when about.config::dom.storage.enabled === false
// See https://github.com/marcuswestin/store.js/issues#issue/13
function isLocalStorageNameSupported () {
try { return (localStorageName in win && win[localStorageName]) } catch (err) { return false }
}
if (isLocalStorageNameSupported()) {
storage = win[localStorageName]
store.set = function (key, val) {
if (val === undefined) { return store.remove(key) }
storage.setItem(key, store.serialize(val))
return val
}
store.get = function (key, defaultVal) {
var val = store.deserialize(storage.getItem(key))
return (val === undefined ? defaultVal : val)
}
store.remove = function (key) { storage.removeItem(key) }
store.clear = function () { storage.clear() }
store.getAll = function () {
var ret = {}
store.forEach(function (key, val) {
ret[key] = val
})
return ret
}
store.forEach = function (callback) {
for (var i = 0; i < storage.length; i++) {
var key = storage.key(i)
callback(key, store.get(key))
}
}
} else if (doc && doc.documentElement.addBehavior) {
var storageOwner,
storageContainer
// Since #userData storage applies only to specific paths, we need to
// somehow link our data to a specific path. We choose /favicon.ico1
// as a pretty safe option, since all browsers already make a request to
// this URL anyway and being a 404 will not hurt us here. We wrap an
// iframe pointing to the favicon in an ActiveXObject(htmlfile) object
// (see: http://msdn.microsoft.com/en-us/library/aa752574(v=VS.85).aspx)
// since the iframe access rules appear to allow direct access and
// manipulation of the document element, even for a 404 page. This
// document can be used instead of the current document (which would
// have been limited to the current path) to perform #userData storage.
try {
storageContainer = new ActiveXObject('htmlfile')
storageContainer.open()
// storageContainer.write('<' + scriptTag + '>document.w=window</' + scriptTag + '><iframe src="/favicon.ico1"></iframe>')
storageContainer.write('<' + scriptTag + '>document.w=window</' + scriptTag + '><iframe src=""></iframe>')
storageContainer.close()
storageOwner = storageContainer.w.frames[0].document
storage = storageOwner.createElement('div')
} catch (e) {
// somehow ActiveXObject instantiation failed (perhaps some special
// security settings or otherwse), fall back to per-path storage
storage = doc.createElement('div')
storageOwner = doc.body
}
var withIEStorage = function (storeFunction) {
return function () {
var args = Array.prototype.slice.call(arguments, 0)
args.unshift(storage)
// See http://msdn.microsoft.com/en-us/library/ms531081(v=VS.85).aspx
// and http://msdn.microsoft.com/en-us/library/ms531424(v=VS.85).aspx
storageOwner.appendChild(storage)
storage.addBehavior('#default#userData')
storage.load(localStorageName)
var result = storeFunction.apply(store, args)
storageOwner.removeChild(storage)
return result
}
}
// In IE7, keys cannot start with a digit or contain certain chars.
// See https://github.com/marcuswestin/store.js/issues/40
// See https://github.com/marcuswestin/store.js/issues/83
var forbiddenCharsRegex = new RegExp("[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]", 'g')
var ieKeyFix = function (key) {
return key.replace(/^d/, '___$&').replace(forbiddenCharsRegex, '___')
}
store.set = withIEStorage(function (storage, key, val) {
key = ieKeyFix(key)
if (val === undefined) { return store.remove(key) }
storage.setAttribute(key, store.serialize(val))
storage.save(localStorageName)
return val
})
store.get = withIEStorage(function (storage, key, defaultVal) {
key = ieKeyFix(key)
var val = store.deserialize(storage.getAttribute(key))
return (val === undefined ? defaultVal : val)
})
store.remove = withIEStorage(function (storage, key) {
key = ieKeyFix(key)
storage.removeAttribute(key)
storage.save(localStorageName)
})
store.clear = withIEStorage(function (storage) {
var attributes = storage.XMLDocument.documentElement.attributes
storage.load(localStorageName)
for (var i = attributes.length - 1; i >= 0; i--) {
storage.removeAttribute(attributes[i].name)
}
storage.save(localStorageName)
})
store.getAll = function (storage) {
var ret = {}
store.forEach(function (key, val) {
ret[key] = val
})
return ret
}
store.forEach = withIEStorage(function (storage, callback) {
var attributes = storage.XMLDocument.documentElement.attributes
for (var i = 0, attr; attr = attributes[i]; ++i) {
callback(attr.name, store.deserialize(storage.getAttribute(attr.name)))
}
})
}
try {
var testKey = '__storejs__'
store.set(testKey, testKey)
if (store.get(testKey) != testKey) { store.disabled = true }
store.remove(testKey)
} catch (e) {
store.disabled = true
}
store.enabled = !store.disabled
return store
}))
================================================
FILE: public/jvs-ui-public/icon.js
================================================
$(document).ready(function(){
htmlobj=$.ajax({url:"/admin/mainPage/getMainIcon",async:false,
success:function(data){
// console.log(data);
var link = document.createElement('link');
link.type = 'image/x-icon';
link.rel = 'shortcut icon';
link.src = 'data:image/jpg;base64,'+data.data;
document.getElementsByTagName('head')[0].appendChild(link);
console.log($("[rel='shortcut icon']").attr("src"));
}
});
});
================================================
FILE: src/App.vue
================================================
<template>
<div id="app">
<div class="basic-cont-box">
<router-view />
</div>
</div>
</template>
<script>
import store from '@/store'
import {sendRouter, getToken} from '@/api/index'
// constants
import * as globalTypes from '@/store/types/global'
import icoImg from '@/styles/titleMg.png'
export default {
name: 'app',
data() {
return {
icoImgURL: icoImg
}
},
watch: {},
created() {
let routerList = JSON.parse(sessionStorage.getItem('routerList'))
// sendRouter(routerList) // 先暂时屏蔽发送本地路由
var link = document.createElement('link')
link.type = 'image/x-icon'
link.rel = 'shortcut icon'
link.href = this.icoImgURL
document.getElementsByTagName('head')[0].appendChild(link);
},
methods: {},
computed: {}
}
</script>
<style lang="scss">
#app {
width: 100%;
height: 100vh;
overflow: hidden;
}
ul, li {
list-style: none;
}
.basic-cont-box{
// padding: 8px 10px;
position: relative;
height: 100%;
box-sizing: border-box;
}
</style>
<style lang="scss" scoped>
.theme-text{
position: fixed;
right: 0;
top: 50%;
z-index: 9999999999999;
}
.theme-box {
width: 100%;
height: 100%;
}
</style>
================================================
FILE: src/api/common.js
================================================
import request from '@/router/axios'
// 公共的字典转换接口
export function byKeyDicData (url) {
return request({
url: url,
method: 'get'
})
}
// 部门人员树
export function getDeptUserTree(){
return request({
url: `/mgr/jvs-auth//dept/user/tree`,
method:'get'
})
}
// 搜索用户
export function searchUser(params){
return request({
url: `/mgr/jvs-auth//user/user/search`,
method:'get',
params: params
})
}
================================================
FILE: src/api/index.js
================================================
import request from "@/router/axios"
// 获取下拉列表
export const getSelectData = (str) => {
return request({
url: str,
method: 'get',
})
}
================================================
FILE: src/api/login.js
================================================
import request from "@/router/axios";
import {scope, client_id, client_secret, grant_type} from '@/const/const'
export const loginByUsername = (username, password, code, randomStr) => {
return request({
url: `/auth/oauth/token`,
headers: {
isToken: false,
},
method: "post",
params: { username, password, grant_type, scope, client_id, client_secret }
});
};
export const refreshToken = (refresh_token, tenantId) => {
const grant_type = "refresh_token";
return request({
url: "/auth/oauth/token",
headers: {
isToken: false,
},
method: "post",
params: { grant_type, scope, client_id, client_secret, refresh_token: refresh_token, switch: tenantId }
});
};
export function getQRcode(params) {
return request({
url: "/mgr/upms/oauth",
method: "get",
params: params
});
}
export function getCheck(data) {
return request({
url: "/weixin/check",
method: "get",
params: data,
// 设置超时时间,直接进行下一次请求
timeout: 30 * 1000
});
}
// 发送验证码
export function getPhone(data) {
return request({
url: `/auth/phone/sms/verification/${data.phone}`,
method: "get"
});
}
// 忘记密码---发送验证码
export function getPhoneCode(data) {
return request({
url: `/mgr/upms/reset/code/${data.phone}/${data.idStr}`, // /mgr/upms/user/phone/${data.phone}
method: "get"
});
}
// 验证码登录
export function codeLogin(data) {
return request({
url: "/auth/login/other",
method: "get",
headers: {
isToken: false,
// tenantId: store.getters.tenantId ? store.getters.tenantId : 0
},
params: { client_id, client_secret, login_other_auth_parameter: data }
});
}
// 微信登录
export function wxOpenidLogin(data) {
return request({
url: "/auth/login/wx/token",
method: "get",
headers: {
isToken: false,
},
params: data
});
}
// APP二维码登录
export function appQrLogin(data) {
return request({
url: "/mgr/upms/app/oauth",
method: "get",
headers: {
isToken: false,
},
params: data
});
}
// 检查APP扫码
export function appCheck(data){
return request({
url: `/mgr/upms/app/check/${data.uuid}`,
method: "get",
headers: {
isToken: false,
},
params: data
});
}
// app登录
export function appLogin(data) {
return request({
url: "/auth/login/app/token",
method: "get",
headers: {
isToken: false,
},
params: data
});
}
export const resetPass = (data) => {
return request({
url: "/mgr/upms/reset/verify/password",
headers: {
isToken: false,
// Accept: "application/x-www-form-urlencoded"
"Content-type": "text/plain", // "application/json"
},
method: "post",
data, // {ciphertext: str}
});
};
// 退出登录
export const loginoutHandle = () => {
return request({
url: `/auth/token/logout`,
method: "get"
});
};
================================================
FILE: src/api/newDesign.js
================================================
import request from '@/router/axios'
// 默认请求
export const sendRequire = (url, method, data) => {
let obj = {
url: url,
method: method
}
if(data) {
if(method == 'get' || method == 'delete') {
obj.params = data
}else{
obj.data = data
}
}
return request(obj)
}
// 自定义请求
export const sendMyRequire = (http, data) => {
let obj = {
url: http.url,
method: http.httpMethod,
headers: {
'Content-Type': http.requestContentType
}
}
if(data) {
if(http.requestContentType == 'application/x-www-form-urlencoded') {
obj.params = data
}else{
obj.data = data
}
}
if(http.headers) {
obj.headers = Object.assign(http.headers, http.headers)
}
return request(obj)
}
// 绑定手机
export function bindPhone(data) {
return request({
url: "/mgr/jvs-auth/index/bind/phone",
method: "put",
params: data
});
}
// 发送手机验证码
export function sendPhoneCode(phone) {
return request({
url: `/auth/phone/sms/bind/${phone}`, // `/auth/phone/sms/verification/${phone}`,
method: "get",
});
}
================================================
FILE: src/components/QRcode/index.vue
================================================
<!-- -->
<template>
<div class='weixin'>
<div
class="weixincode"
v-loading="URLLoading"
>
<img
v-show="RQURL"
:src="RQURL"
@click="init"
/>
<!-- <template v-if="ReqType==='bind'"> -->
<div class="tips-box">
<div v-if="showContent.title">{{showContent.title}}</div>
<div v-if="showContent.content">{{bottomtext ? bottomtext : showContent.content}}</div>
</div>
<!-- </template> -->
</div>
</div>
</template>
<script>
// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
// 例如:import 《组件名称》 from '《组件路径》';
import { getQRcode, getCheck, appQrLogin, appCheck } from '@/api/login'
export default {
// import引入的组件需要注入到对象中才能使用
components: {},
props: {
loginType: { type: String, default: "" }, ReqType: { type: String, default: '' },
bottomtext: {
type: String,
default: ''
}
},
data () {
// 这里存放数据
return {
// 二维码拿到的
RQURL: '',
URLLoading: false,
isReq: false,
getStatusSetInterval: null,
UUID: '',
showContent: {
title: '',
content: '请使用微信扫码登录'
},
qrType: 'weixin'
}
},
// 监听属性 类似于data概念
computed: {},
// 监控data中的数据变化
watch: {},
// 方法集合
methods: {
clear () {
clearInterval(this.getStatusSetInterval)
},
init (type) {
if (type) {
this.qrType = type
}
this.showContent = {
title: '',
content: this.qrType == 'weixin' ? '请使用微信扫码登录' : '请使用APP扫码登录'
}
this.clear()
this.isReq = false
this.RQURL = '/auth/just/login/WECHAT_OPEN'
// this.getQRcodeUrl()
},
getQRcodeUrl () {
this.URLLoading = true
if (this.qrType == 'weixin') {
let query = {}
if(this.$route && this.$route.query) {
query = this.$route.query
}
getQRcode(query).then(res => {
this.URLLoading = false
if (res.data.code !== 500 && res.data.data) {
this.RQURL = res.data.data.imgData
this.UUID = res.data.data.wxUUID
this.getStatusSetInterval = setInterval(() => {
if (!this.isReq) {
this.getLoginStatus()
}
}, 1000)
}else{
this.RQURL = 'https://tool.oschina.net/action/qrcode/generate?data=http%3A%2F%2F10.0.1.127%2F%23%2Flogin&output=image%2Fgif&error=L&type=0&margin=0&size=4'
}
}).catch(res => {
console.log(res)
})
} else {
appQrLogin().then(res => {
this.URLLoading = false
if (res.data.code !== 500) {
this.RQURL = res.data.data.imgData
this.UUID = res.data.data.appUUID
this.getStatusSetInterval = setInterval(() => {
if (!this.isReq) {
this.getLoginStatus()
}
}, 3000)
}
})
}
},
CheckImgExists (imgurl) {
var ImgObj = new Image(); //判断图片是否存在
ImgObj.src = imgurl;
//存在图片
if (ImgObj.fileSize > 0 || (ImgObj.width > 0 && ImgObj.height > 0)) {
return true;
} else {
return false;
}
},
getLoginStatus () {
this.isReq = true
if (this.qrType == 'weixin') {
let time = new Date().getTime()
getCheck({ uuid: this.UUID, '_': time }).then(res => {
if (res.data.status === 405) {
this.isReq = true
clearInterval(this.getStatusSetInterval)
this.$emit("submit", res.data.result.code, 'weixin')
} if (res.data.status === 403) {
clearInterval(this.getStatusSetInterval)
this.init(this.qrType)
} else if (res.data.status === 404) {
this.showContent = res.data.msg
this.isReq = false
} else {
this.isReq = false
}
}).catch(res => {
this.isReq = false
})
} else {
appCheck({ uuid: this.UUID, }).then(res => {
// if (res.data.code == 0) {
if (res.data.data.code == 0) {
if (res.data.data.isLogin) {
clearInterval(this.getStatusSetInterval)
this.$emit("submit", {
scanType: res.data.data.scanType,
// userId: res.data.data.userId,
uuid: this.UUID
}, 'app')
} else {
this.isReq = false
}
} else {
clearInterval(this.getStatusSetInterval)
this.init(this.qrType)
}
}).catch(res => {
this.isReq = false
})
}
}
},
// 生命周期 - 创建完成(可以访问当前this实例)
created () {
},
// 生命周期 - 挂载完成(可以访问DOM元素)
mounted () {
},
beforeCreate () { }, // 生命周期 - 创建之前
beforeMount () { }, // 生命周期 - 挂载之前
beforeUpdate () { }, // 生命周期 - 更新之前
updated () { }, // 生命周期 - 更新之后
beforeDestroy () { }, // 生命周期 - 销毁之前
destroyed () { }, // 生命周期 - 销毁完成
activated () { } // 如果页面有keep-alive缓存功能,这个函数会触发
}
</script>
<style lang='scss' scoped>
//@import url(); 引入公共css类
.weixinlogin {
width: 0;
height: 0;
border-top: 100px solid #c0c4cc;
border-left: 100px solid transparent;
position: absolute;
top: 0;
right: 0;
}
.weixin {
display: flex;
justify-content: center;
align-items: center;
height: 340px;
}
.weixincode {
// height: 300px;
width: 300px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
img {
display: block;
width: 100%;
height: 100%;
}
}
.tips-box {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
// background-color: #aca9a9;
border-radius: 50px;
height: 50px;
box-sizing: border-box;
color: #999;
}
</style>
================================================
FILE: src/components/api.js
================================================
import request from '@/router/axios'
// 用户列表
export function getUserList(query) {
return request({
url: "/mgr/jvs-auth//user/page",
method: "get",
params: query
});
}
// 所有用户
export function getUserAll(query) {
return request({
url: "/mgr/jvs-auth//user/user/search",
method: "get",
params: query
});
}
================================================
FILE: src/components/basic-assembly/button.vue
================================================
<template>
<el-button
:size="size || defaultSet.size"
:type="type || defaultSet.type"
:plain="plain || defaultSet.plain"
:round="round || defaultSet.round"
:circle="circle || defaultSet.circle"
:loading="loading || defaultSet.loading"
:disabled="disabled || defaultSet.disabled"
:icon="icon || defaultSet.icon"
:autofocus="autofocus || defaultSet.autofocus"
:native-type="nativeType || defaultSet.nativeType"
v-if="$permissionMatch(permisionFlag)"
@click="clickHandle"
>
<span v-if="permisionFlag">{{$permissionLabel(permisionFlag, defaultText)}}</span>
<slot></slot>
<!-- 其余插槽待拓展。。。。。。 -->
</el-button>
</template>
<script>
export default {
name: "jvs-button",
props: {
size: {
type: String,
default: ''
},
type: {
type: String,
default: ''
},
plain: {
type: Boolean,
default: false
},
round: {
type: Boolean,
default: false
},
circle: {
type: Boolean,
default: false
},
loading: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
icon: {
type: String,
default: ''
},
autofocus: {
type: Boolean,
default: false
},
nativeType: {
type: String,
default: 'button'
},
permisionFlag: {
type: String,
default: ''
},
defaultText: {
type: String,
default: ''
}
},
data () {
return {
defaultSet: {
size: 'mini', // 尺寸
type: '', // 类型
plain: false, // 是否朴素按钮
round: false, // 是否圆角按钮
circle: false, // 是否圆形按钮
loading: false, // 是否加载中状态
disabled: false, // 是否禁用状态
icon: '', // 图标类名
autofocus: false, // 是否默认聚焦
nativeType: 'button',
permisionFlag: '', // 权限标识
},
}
},
created () {
},
methods: {
clickHandle () {
this.$emit('click', true)
}
}
}
</script>
================================================
FILE: src/components/basic-assembly/form.vue
================================================
<template>
<el-form
:model="formDatas"
:ref="refs || defalutSet.refs"
:option="option || defalutSet.option"
:class="{'jvs-form': true, 'jvs-form-autoflexable': (option.labelWidth == 'auto' || option.labelwidth == 'auto' || option.formAuto )}"
:size="$store.state.params.form.size || option.size || option.formsize || 'mini'"
:inline="option.inline || defalutSet.option.inline"
:label-position="option.formAlign || defalutSet.option.formAlign"
:label-width="option.labelWidth || defalutSet.option.labelWidth"
:disabled='option.disabled'
:validateOnRuleChange="false"
>
<slot name="formTop"></slot>
<el-row style="width:100%;">
<!-- v-if="!option.isSearch || (option.isSearch && item.search == true)" -->
<el-col
v-for="item in option.column"
:key="item.prop"
:span="isSearch==true?(item.searchSpan || option.searchSpan || 24):(item.span || option.span || 24)"
v-show="item.display == false ? item.display : true"
:class="{'no-label-form-item': item.hideLabel}"
>
<el-form-item
:class='{
"form-item-no-label": ( (!item.label && item.type != "tab") || (["tableForm","divider","p","section"].indexOf(item.type) > -1) ),
"form-item-no-label-tab": (!item.label && item.type == "tab")
}'
:label='item.type == "tableForm" ? (item.editable ? item.label : "") : item.label'
:prop="item.prop"
v-if="(item.prop !== freshDom) && (item.type !='title' && (!item.children || item.children.length == 0) || item.type == 'formbox') && $permissionMatch(item.permisionFlag) && (item.display == false ? item.display : true)"
:rules="item.rules"
>
<FormItem
v-if="!item.formSlot"
:form="formDatas"
:item="item"
:originOption="option"
:defalutSet="defalutSet"
@formChange="formChange"
:userList="userList"
:rowData="rowData"
:resetRadom="resetRadom"
@validateHandle="validateHandle"
/>
<!-- 自定义列插槽 -->
<div v-if="item.formSlot">
<slot :name="item.prop+'Form'"></slot>
<!-- 右侧提示 -->
<el-tooltip
v-if="item.tips && item.tips.position == 'right' && item.tips.text"
class="form-item-tooltip"
effect="dark"
:content="item.tips.text"
placement="top"
>
<i class="el-icon-question"></i>
</el-tooltip>
</div>
<!-- 换行提示 -->
<el-row
v-if="item.tips && item.tips.position == 'bottom'"
class="form-item-tips"
>
<span v-html="item.tips.text"></span>
</el-row>
</el-form-item>
<h5 v-if="item.type == 'title'">{{item.label}}</h5>
<!-- 子表单项 -->
<el-row v-if="item.type != 'formbox' && item.children && item.children.length > 0">
<el-form-item
:label="item.label"
:prop="item.prop"
:rules="item.rules"
v-if="(item.prop !== freshDom) && (item.display == false ? item.display : true)"
:class='(!item.label || (["tableForm","divider","p","tab","section"].indexOf(item.type) > -1))? "form-item-no-label" : ""'
>
<FormItem
v-if="!item.formSlot"
:form="formDatas"
:item="item"
:originOption="option"
:defalutSet="defalutSet"
@formChange="formChange"
:userList="userList"
:rowData="rowData"
:resetRadom="resetRadom"
@validateHandle="validateHandle"
/>
<!-- 自定义列插槽 -->
<div v-if="item.formSlot">
<slot :name="item.prop+'Form'"></slot>
<!-- 右侧提示 -->
<el-tooltip
v-if="item.tips && item.tips.position == 'right' && item.tips.text"
class="form-item-tooltip"
effect="dark"
:content="item.tips.text"
placement="top"
>
<i class="el-icon-question"></i>
</el-tooltip>
</div>
<!-- 换行提示 -->
<el-row
v-if="item.tips && item.tips.position == 'bottom'"
class="form-item-tips"
>
<span v-html="item.tips.text"></span>
</el-row>
</el-form-item>
<el-col
v-for="it in item.children"
:key="it.prop"
:span="isSearch==true?(it.searchSpan || option.searchSpan || 24):(it.span || option.span || 24)"
v-if="linkbindHandle(formDatas[item.prop], it.linkbind)"
>
<el-form-item
:label="it.label"
:prop="it.prop"
v-if="(it.prop !== freshDom) && $permissionMatch(it.permisionFlag) && (!option.isSearch || (option.isSearch && it.search == true)) && (it.display == false ? it.display : true)"
:rules="it.rules"
:class='{
"form-item-no-label": (!it.label || (["tableForm","divider","p","tab","section"].indexOf(it.type) > -1))
}'
>
<FormItem
v-if="!it.formSlot"
:form="formDatas"
:item="it"
:formRef="refs || defalutSet.refs"
:originOption="option"
:defalutSet="defalutSet"
@formChange="formChange"
:userList="userList"
:rowData="rowData"
:resetRadom="resetRadom"
@validateHandle="validateHandle"
/>
<!-- 自定义列插槽 -->
<div v-if="it.formSlot">
<slot :name="it.prop+'Form'"></slot>
<!-- 右侧提示 -->
<el-tooltip
v-if="it.tips && it.tips.position == 'right' && it.tips.text"
class="form-item-tooltip"
effect="dark"
:content="it.tips.text"
placement="top"
>
<i class="el-icon-question"></i>
</el-tooltip>
</div>
<!-- 换行提示 -->
<el-row
v-if="it.tips && it.tips.position == 'bottom'"
class="form-item-tips"
>
<span v-html="it.tips.text"></span>
</el-row>
</el-form-item>
</el-col>
</el-row>
</el-col>
<el-col
:span="option.isSearch ? 6 : 24"
v-if="option.column.length > 0 && option.btnHide!==true"
class="form-item-btn"
>
<el-form-item class="form-btn-bar">
<template v-if="isSearch">
<el-button
size="mini"
v-if="!(option.searchBtn == false)"
type="primary"
@click="submitForm(refs || defalutSet.refs)"
:loading="option.submitLoading"
>{{option.searchBtnText || defalutSet.option.searchBtnText}}</el-button>
<el-button
size="mini"
v-if="!(option.emptyBtn == false)"
@click="resetForm(refs || defalutSet.refs)"
>{{option.emptyBtnText || defalutSet.option.emptyBtnText}}</el-button>
</template>
<template v-if="!isSearch">
<el-button
size="mini"
v-if="!(option.submitBtn == false)"
type="primary"
@click="submitForm(refs || defalutSet.refs)"
:loading="option.submitLoading"
>{{option.submitBtnText || defalutSet.option.submitBtnText}}</el-button>
<el-button
size="mini"
v-if="!(option.emptyBtn == false)"
@click="resetForm(refs || defalutSet.refs)"
>{{option.emptyBtnText || defalutSet.option.emptyBtnText}}</el-button>
<el-button
size="mini"
v-if="!(option.cancal == false)"
@click="$emit('cancalClick')"
>{{option.cancalBtnText || defalutSet.option.cancalBtnText}}</el-button>
</template>
<slot name="formButton"></slot>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
import FormItem from './formitem'
import {getDeptList, getRoleList, getPostList} from '../api'
export default {
name: "jvsForm",
components: { FormItem },
props: {
// 是否为搜索表单
isSearch: {
type: Boolean,
default: false
},
// 表单绑定
refs: {
type: String,
default: 'ruleForm'
},
// 表单对象
formData: {
type: Object,
default: () => {
return {}
}
},
// 表单数据
defalutFormData: {
type: Object,
default: () => {
return {}
}
},
// 表单设置
option: {
type: Object,
default: () => {
return {
formAlign: 'right', //对其方式
inline: false, // 表单项是否可以同行,当垂直方向空间受限且表单较简单时,可以在一行内放置表单
labelWidth: 'auto', // label宽
searchBtn: true,
searchBtnText: '',
submitBtn: true, // 提交按钮是否显示,默认显示
submitBtnText: '保存', // 提交按钮文字,默认 提交
emptyBtn: true, // 重置按钮,默认显示
emptyBtnText: '', // 重置按钮文字,默认 重置
isSearch: false, // 是否为搜索表单
cancal: true, // 取消按钮, 默认显示
cancalBtnText: '取消',
column: [ // 字段
{
label: '', // 文字
prop: '', // 字段
type: '', // 文本类型,默认input
dicData: [], // 字典数据
span: 24, // 表单项栅格比,默认24
formSlot: false, // 是否自定义
permisionFlag: '', // 权限标识
rules: [], // 校验规则
linkbind: '', // 父级联动控制对应的表单值
}
],
}
}
},
rowData: {
type: Object
}
},
computed: {
// formDatas: {
// get: function () {
// return this.formData
// },
// set: function () { }
// }
},
data () {
return {
formDatas: {}, // 表单对象
defalutSet: {
refs: 'ruleForm',
option: {
formAlign: 'right', //对其方式
inline: false, // 表单项是否可以同行,当垂直方向空间受限且表单较简单时,可以在一行内放置表单
labelWidth: 'auto', // label宽
searchBtn: true, // 搜索按钮是否显示,默认显示
searchBtnText: '查询', // 搜索按钮,默认查询
submitBtn: true, // 提交按钮是否显示,默认显示
submitBtnText: '提交', // 提交按钮文字,默认 提交
emptyBtn: true, // 重置按钮,默认显示
emptyBtnText: '重置', // 重置按钮文字,默认 重置
cancalBtnText: '取消', // 取消按钮文字, 默认 取消
}
},
userList: [], // 用户列表
clearAll: false, // 重置是否为初始对象{}
resetRadom: -1, // 通知子项重置随机数 -1不重置
resetData: "", // 原始数据,用于重置
freshDom: ''
}
},
created () {
this.resetData = JSON.stringify(this.formData)
this.formDatas = this.formData
if (this.defalutFormData) {
for (let i in this.defalutFormData) {
this.formDatas[i] = this.defalutFormData[i]
}
}
if(JSON.stringify(this.formDatas) == '{}') {
this.clearAll = true
}
this.getConst()
},
methods: {
submitForm (formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
this.$emit('submit', this.formDatas)
} else {
console.log('error submit!!')
return false;
}
});
},
resetForm (formName) {
if (this.option.isSearch === true) {
this.formDatas = {}
} else {
if(this.clearAll) {
this.formDatas = {}
}else{
this.$refs[formName].resetFields()
}
this.resetRadom = Math.random()
if(this.resetData.startsWith('{')) {
this.$set(this, 'formDatas', JSON.parse(this.resetData))
}
}
this.$emit('reset', formName)
},
formChange (form) {
this.$emit('formChange', form)
},
async getConst () {
let deptBool = false
let roleBool = false
let postBool = false
// 优化:表单内无对应公共组件不发请求
for(let i in this.option.column) {
if(this.option.column[i].type == 'department') {
deptBool = true
}
if(this.option.column[i].type == 'role') {
roleBool = true
}
if(this.option.column[i].type == 'post') {
postBool = true
}
// 加入自定义校验
if(this.option.column[i].regularExpression) {
let required = false
if(this.option.column[i].rules && this.option.column[i].rules[0].required) {
required = true
}
let str = '/' + this.option.column[i].regularExpression + '/'
let _this = this
this.option.column[i].rules.push({
validator: function(rule, value, callback) {
if(eval(str).test(value)) {
callback()
}else{
let msg = '正则校验不通过'
if(_this.option.column[i].regularMessage) {
msg = _this.option.column[i].regularMessage
}
if(required == false && !value) {
callback()
}else{
callback(new Error(msg));
}
}
},
trigger: ['blur', 'change']
})
}
// 嵌套项包含公共组件
if(['tab', 'step'].indexOf(this.option.column[i].type) > -1) {
for(let ti in this.option.column[i].column) {
for(let tci in this.option.column[i].column[ti]) {
if(this.option.column[i].column[ti][tci].type == 'department') {
deptBool = true
}
if(this.option.column[i].column[ti][tci].type == 'role') {
roleBool = true
}
if(this.option.column[i].column[ti][tci].type == 'post') {
postBool = true
}
}
}
}
if((this.option.column[i].children && this.option.column[i].children.length > 0) || ['tableForm'].indexOf(this.option.column[i].type) > -1) {
let tl = []
if(['tableForm'].indexOf(this.option.column[i].type) > -1) {
tl = this.option.column[i].tableColumn
}else{
tl = this.option.column[i].children
}
}
}
},
// 联动控制
linkbindHandle (val, bind) {
let bool = true
if(bind && ['boolean', 'number'].indexOf(typeof bind) == -1) {
let arr = (bind instanceof Array) ? bind : bind.split(',')
if(val instanceof Array) {
let tb = false
for(let i in val) {
if(arr.indexOf(val[i]) > -1 || arr.indexOf((val[i] + '')) > -1) {
tb = true
}
}
bool = tb
}else{
if(arr.indexOf(val) > -1 || arr.indexOf((val + '')) > -1) {
bool = true
}else{
bool = false
}
}
}else{
if(bind || bind === 0 || bind === false) {
if(val || val === 0 || val === false) {
if(bind !== val) {
bool = false
}
}else{
bool = true
}
}else{
bool = true
}
}
return bool
},
validateHandle (data) {
let type = data.type
let item = data.item
this.freshDom = item.prop
if(type == 'clear') {
this.$refs[this.refs || this.defalutSet.refs].clearValidate(item.prop)
}else{
this.$refs[this.refs || this.defalutSet.refs].validateField(item.prop)
}
this.$nextTick( () => {
this.freshDom = ''
})
this.$forceUpdate()
}
}
};
</script>
<style lang="scss">
.jvs-form {
h5 {
margin: 0;
padding: 0;
margin-bottom: 10px;
}
.el-form-item.form-btn-bar {
// margin: 10px;
.el-form-item__content {
text-align: center;
margin-left: 0 !important;
}
}
.no-label-form-item{
.el-form-item{
.el-form-item__content{
margin-left: 0!important;
}
}
}
}
.jvs-form-autoflexable {
.el-form-item {
display: flex;
margin: 0 10px;
.el-form-item__label-wrap {
margin-left: 0 !important;
word-break: keep-all;
}
.el-form-item__content {
margin-left: 0 !important;
flex: 1;
div {
.el-input,
.el-select {
width: 100%;
}
}
}
}
}
.form-item-tooltip {
display: inline-block;
margin: 0 10px;
}
.form-item-no-label-tab{
>.el-form-item__content{
margin-left: 0!important;
}
}
.form-item-no-label{
.el-form-item__content{
margin-left: 0!important;
}
}
.form-item-tips{
font-size: 12px;
color: #c3c3c3;
width: 100%;
}
</style>
================================================
FILE: src/components/basic-assembly/formcard.vue
================================================
<template>
<div class="form-card">
<el-tabs :class="{'no-data-tab': (!tabData || tabData.length == 0)}" v-model="activeName" type="card" editable @edit="handleTabsEdit">
<el-tab-pane
v-for="(item, index) in tabData"
:key="item.name"
:label="item.title"
:name="item.name"
>
<el-form
v-if="forms && index < forms.length"
:model="forms[index]"
:ref="formRef || 'ruleForm'"
class="demo-dynamic"
size='mini'
:label-position="originOption.formAlign || defalutSet.option.formAlign"
:label-width="originOption.labelWidth || defalutSet.option.labelWidth"
:disabled='originOption.disabled'
>
<el-row v-if="formItem.children && formItem.children.length > 0" style="width:100%;">
<el-col
v-for="it in formItem.children"
:key="'formcard'+index+it.prop"
:span="it.span || 24"
v-show="it.display == false ? it.display : true"
:class="{'no-label-form-item': it.hideLabel}"
>
<!-- 一般项 -->
<el-form-item
v-if="(it.type !='title' && (!it.children || it.children.length == 0) || it.type == 'formbox') && $permissionMatch(it.permisionFlag) && (it.display == false ? it.display : true)"
:label="it.label"
:prop='it.prop'
:rules='it.rules'
v-model="forms[index][it.prop]"
:label-width="it.type==='iframe'?'0':(originOption.labelWidth || defalutSet.option.labelWidth)"
:class='{"form-item-no-label": ( (!it.label && it.type != "tab") || (["tableForm","divider","p","section"].indexOf(it.type) > -1) ), "form-item-no-label-tab": (!it.label && it.type == "tab")}'
>
<FormItem
:item="it"
:form="forms[index]"
:reinitFlag="reinitFlag"
:originOption="originOption"
:defalutSet="defalutSet"
:roleOption="roleOption"
:userList="userList"
:departmentList="departmentList"
:postList="postList"
:resetRadom="resetRadom"
@formChange="formChange"
/>
</el-form-item>
<!-- 子表单项 -->
<el-row v-if="it.type != 'formbox' && it.children && it.children.length > 0">
<el-form-item
:label="it.label"
:prop="it.prop"
:rules="it.rules"
v-if="(it.display == false ? it.display : true)"
v-model="forms[index][it.prop]"
:class='(!it.label || (["tableForm","divider","p","tab","section"].indexOf(it.type) > -1))? "form-item-no-label" : ""'
>
<FormItem
v-if="!it.formSlot"
:form="forms[index]"
:reinitFlag="reinitFlag"
:item="it"
:originOption="originOption"
:defalutSet="defalutSet"
@formChange="formChange"
:roleOption="roleOption"
:userList="userList"
:departmentList="departmentList"
:postList="postList"
:resetRadom="resetRadom"
/>
<!-- 自定义列插槽 -->
<div v-if="it.formSlot">
<slot :name="it.prop+'Form'"></slot>
<!-- 右侧提示 -->
<el-tooltip
v-if="it.tips && it.tips.position == 'right' && it.tips.text"
class="form-item-tooltip"
effect="dark"
:content="it.tips.text"
placement="top"
>
<i class="el-icon-question"></i>
</el-tooltip>
</div>
<!-- 换行提示 -->
<el-row
v-if="it.tips && it.tips.position == 'bottom'"
class="form-item-tips"
>
<span v-html="it.tips.text"></span>
</el-row>
</el-form-item>
<el-col
v-for="itc in it.children"
:key="itc.prop+'formcard-contrl-item'"
:span="itc.span || originOption.span || 24"
>
<el-form-item
:label="itc.label"
:prop="itc.prop"
v-if="itc.display === false ? false : linkbindHandle(forms[index][it.prop], itc.linkbind)"
:rules="itc.rules"
v-model="forms[index][itc.prop]"
:class='(!itc.label || (["tableForm","divider","p","tab","section"].indexOf(itc.type) > -1))? "form-item-no-label" : ""'
>
<FormItem
v-if="!itc.formSlot"
:form="forms[index]"
:item="itc"
:formRef="defalutSet.refs"
:originOption="originOption"
:defalutSet="defalutSet"
@formChange="formChange"
:roleOption="roleOption"
:userList="userList"
:departmentList="departmentList"
:postList="postList"
:resetRadom="resetRadom"
/>
<!-- 自定义列插槽 -->
<div v-if="itc.formSlot">
<slot :name="itc.prop+'Form'"></slot>
<!-- 右侧提示 -->
<el-tooltip
v-if="itc.tips && itc.tips.position == 'right' && itc.tips.text"
class="form-item-tooltip"
effect="dark"
:content="itc.tips.text"
placement="top"
>
<i class="el-icon-question"></i>
</el-tooltip>
</div>
<!-- 换行提示 -->
<el-row
v-if="itc.tips && itc.tips.position == 'bottom'"
class="form-item-tips"
>
<span v-html="itc.tips.text"></span>
</el-row>
</el-form-item>
</el-col>
</el-row>
</el-col>
</el-row>
<slot :name="item.name"></slot>
</el-form>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
export default {
name: 'card-form',
components: {
FormItem: () => import('@/components/basic-assembly/formitem')
},
props: {
// 表单传递对象
forms: {
type: Array,
default: () => {
return []
}
},
// 表单结构对象
formItem: {
type: Object,
default: () => {
return {}
}
},
formRef: {
type: String,
default: 'ruleForm'
},
originOption: {
type: Object
},
// 用户列表
userList : {
type: Array,
default: () => {
return []
}
},
// 角色列表
roleOption: {
type: Array,
default: () => {
return []
}
},
// 部门列表
departmentList: {
type: Array,
default: () => {
return []
}
},
// 岗位列表
postList: {
type: Array,
default: () => {
return []
}
},
resetRadom: {
type: Number
}
},
data() {
return {
activeName: '0',
tabIndex: 0,
tabData: [],
reinitFlag: -1,
defalutSet: {
refs: 'ruleForm',
option: {
formAlign: 'right', //对其方式
inline: false, // 表单项是否可以同行,当垂直方向空间受限且表单较简单时,可以在一行内放置表单
labelWidth: 'auto', // label宽
searchBtn: true, // 搜索按钮是否显示,默认显示
searchBtnText: '查询', // 搜索按钮,默认查询
submitBtn: true, // 提交按钮是否显示,默认显示
submitBtnText: '提交', // 提交按钮文字,默认 提交
emptyBtn: true, // 重置按钮,默认显示
emptyBtnText: '重置', // 重置按钮文字,默认 重置
cancalBtnText: '取消', // 取消按钮文字, 默认 取消
}
},
}
},
methods: {
handleTabsEdit(targetName, action) {
if (action === 'add') {
let newTabName = ++this.tabIndex + '';
this.tabData.push({
title: this.formItem.label ? (this.formItem.label + (this.tabData.length+1)) : ('表单卡片' + (this.tabData.length+1) ),
name: newTabName
});
this.activeName = newTabName;
this.forms.push({})
this.reinitFlag = Math.random()
this.$forceUpdate()
}
if (action === 'remove') {
let tabs = this.tabData;
let activeName = this.activeName;
if (activeName === targetName) {
tabs.forEach((tab, index) => {
if (tab.name === targetName) {
let nextTab = tabs[index + 1] || tabs[index - 1];
if (nextTab) {
activeName = nextTab.name;
}
}
});
}
this.activeName = activeName;
this.tabData = tabs.filter(tab => tab.name !== targetName);
for(let i in this.tabData) {
i = Number.parseInt(i)
this.tabData[i].title = this.formItem.label ? (this.formItem.label + (i+1)) : ('表单卡片' + (i+1) )
}
}
},
formChange (form) {
let index = -1
for(let i in this.tabData) {
if(this.tabData[i].name == this.activeName) {
index = i
}
}
if(index > -1) {
this.$set(this.forms, index, form)
this.$forceUpdate()
this.$emit('formChange', this.forms)
}
},
// 联动控制
linkbindHandle (val, bind) {
let bool = true
if(bind) {
if(val) {
let arr = bind.split(',')
if(val instanceof Array) {
let tb = false
for(let i in val) {
if(arr.indexOf(val[i]) > -1) {
tb = true
}
}
bool = tb
}else{
if(arr.indexOf(val) > -1) {
bool = true
}else{
bool = false
}
}
}
}
return bool
},
init () {
this.tabData = []
if(this.forms && this.forms.length > 0) {
for(let i in this.forms) {
this.tabData.push({
name: (Number.parseInt(i)+1) + "",
title: this.formItem.label ? (this.formItem.label + (Number.parseInt(i)+1)) : ('表单卡片' + (Number.parseInt(i)+1) )
})
}
this.activeName = '1'
}
let tcol = this.formItem.children
for(let t in tcol) {
if(tcol[t].regularExpression){
let required = false
if(tcol[t].rules && tcol[t].rules[0].required) {
required = true
}
let str = '/' + tcol[t].regularExpression + '/'
let _this = this
tcol[t].rules.push({
validator: function(rule, value, callback) {
if(eval(str).test(value)) {
callback()
}else{
let msg = '正则校验不通过'
if(tcol[t].regularMessage) {
msg = tcol[t].regularMessage
}
if(required == false && !value) {
callback()
}else{
callback(new Error(msg));
}
}
},
trigger: ['blur', 'change']
})
}
}
}
},
created () {
this.init()
},
watch: {
resetRadom: {
handler (newVal , oldVal) {
if(newVal > -1) {
this.init()
}
}
}
}
}
</script>
<style lang="scss">
.form-card{
width: 100%;
.el-tabs--card.no-data-tab>.el-tabs__header{
border-color: #fff;
.el-tabs__nav{
border-color: #fff;
}
}
}
</style>
================================================
FILE: src/components/basic-assembly/formitem.vue
================================================
<template>
<div class="jvs-form-item" style="display:flex;align-items:center;">
<el-input
v-model="forms[item.prop]"
v-if='item.type==="input" || !item.type'
:show-word-limit="item.showwordlimit"
:minlength="item.minlength"
:maxlength="item.maxlength"
:placeholder="item.placeholder || item.label"
:clearable="item.clearable"
:show-password="item.showpassword"
:disabled="item.disabled"
:prefix-icon="item.prefixicon"
:suffix-icon="item.suffixicon"
:size="$store.state.params.form.size || item.size || 'mini'"
@blur="formChange"
>
<template v-if='item.prepend' slot="prepend">{{item.prepend}}</template>
<template v-if='item.append' slot="append">{{item.append}}</template>
</el-input>
<span class="el-form-item__error" v-if='errorShow'>{{item.regularMessage}}</span>
<el-input
v-model="forms[item.prop]"
v-if='item.type==="InputReadOnly" || item.type==="inputReadOnly"'
:disabled="item.disabled || true"
:placeholder="item.placeholder || item.label"
:size="$store.state.params.form.size || item.size || 'mini'"
></el-input>
<el-input
type="textarea"
v-if='item.type==="textarea"'
v-model="forms[item.prop]"
:rows="item.rows"
:show-word-limit="item.showwordlimit"
:minlength="item.minlength"
:maxlength="item.maxlength"
:placeholder="item.placeholder || item.label"
:clearable="item.clearable"
:disabled="item.disabled"
:size="$store.state.params.form.size || item.size || 'mini'"
:autosize="item.autoSize || false"
@blur="formChange"
></el-input>
<el-input
type="textarea"
v-if='item.type==="textareaReadOnly"'
v-model="forms[item.prop]"
rows="2"
:placeholder="item.placeholder || item.label"
:disabled="item.disabled || true"
:size="$store.state.params.form.size || item.size || 'mini'"
></el-input>
<el-input-number
v-if='item.type==="inputNumber"'
v-model="forms[item.prop]"
:min="item.min"
:max="item.max"
:step="item.step"
:step-strictly="item.stepstrictly"
:precision="item.precision"
:disabled="item.disabled"
:controls-position="item.controlsposition"
:placeholder="item.placeholder || item.label"
:size="$store.state.params.form.size || item.size || 'mini'"
@change="formChange"
></el-input-number>
<el-select
v-if='item.type==="select"'
v-model="forms[item.prop]"
:placeholder="item.placeholder || item.label"
:multiple="item.multiple"
:collapse-tags="!item.collapsetags"
:disabled="item.disabled"
:clearable="item.clearable"
:filterable="item.filterable"
:allow-create="item.allowcreate"
:size="$store.state.params.form.size || item.size || 'mini'"
@change="formChange"
>
<el-option
v-for="(sitem) in selectOption"
:key="sitem[(item.props && item.props.value) || 'value']+item.prop +Math.random() + Date.now().toString()"
:label="sitem[(item.props && item.props.label) || 'label']"
:value="sitem[(item.props && item.props.value) || 'value']"
>
<span style="float: left">{{ sitem[(item.props && item.props.label) || 'label'] }}</span>
<span v-if="sitem.tip" style="float: right; color: #8492a6; font-size: 13px">{{ sitem.tip }}</span>
</el-option>
</el-select>
<el-switch
v-if='item.type==="switch"'
v-model="forms[item.prop]"
:disabled="item.disabled"
:active-text="item.activetext"
:inactive-text="item.inactivetext"
:active-color="item.activecolor"
:inactive-color="item.inactivecolor"
:size="$store.state.params.form.size || item.size || 'mini'"
@change="formChange"
></el-switch>
<el-slider
v-if='item.type==="slider"'
v-model="forms[item.prop]"
:min="item.min"
:max="item.max"
:disabled="item.disabled"
:step="item.step"
:show-stops="item.showstops"
:show-input="item.showinput"
:range="item.range"
:size="$store.state.params.form.size || item.size || 'mini'"
@change="formChange"
></el-slider>
<el-time-select
v-if='item.type==="timeSelect"'
v-model="forms[item.prop]"
:disabled="item.disabled"
:clearable="item.clearable"
:picker-options="item.pickeroptions"
:placeholder="item.placeholder || item.label"
:prefix-icon="item.prefixicon"
value-format="HH:mm:ss"
:default-value="item.defaultValue"
:size="$store.state.params.form.size || item.size || 'mini'"
@change="formChange"
></el-time-select>
<el-time-picker
v-if='item.type==="timePicker"'
v-model="forms[item.prop]"
:disabled="item.disabled"
:clearable="item.clearable"
:placeholder="item.placeholder || item.label"
:prefix-icon="item.prefixicon"
:is-range="item.isrange"
:start-placeholder="item.startplaceholder"
:end-placeholder="item.endplaceholder"
:range-separator="item.rangeseparator"
value-format="HH:mm:ss"
:default-value="item.defaultValue"
:size="$store.state.params.form.size || item.size || 'mini'"
@change="formChange"
></el-time-picker>
<el-date-picker
v-if='(item.type==="datePicker") && ( item.datetype=="date" || item.datetype=="dates" || item.datetype=="daterange")'
v-model="forms[item.prop]"
:type="item.datetype"
:placeholder="item.placeholder || item.label"
:clearable="item.clearable"
:disabled="item.disabled"
:prefix-icon="item.prefixicon"
value-format="yyyy-MM-dd"
:start-placeholder="item.startplaceholder"
:end-placeholder="item.endplaceholder"
:range-separator="item.rangeseparator"
:picker-options="startEndLimitHandle"
:default-value="item.defaultValue"
:size="$store.state.params.form.size || item.size || 'mini'"
@change="formChange"
></el-date-picker>
<el-date-picker
v-if='(item.type==="datePicker") && item.datetype=="week"'
v-model="forms[item.prop]"
type="week"
format="yyyy 第 WW 周"
value-format="yyyy-MM-dd"
:placeholder="item.placeholder || item.label"
:clearable="item.clearable"
:disabled="item.disabled"
:prefix-icon="item.prefixicon"
:start-placeholder="item.startplaceholder"
:end-placeholder="item.endplaceholder"
:range-separator="item.rangeseparator"
:picker-options="startEndLimitHandle"
:default-value="item.defaultValue"
:size="$store.state.params.form.size || item.size || 'mini'"
@change="formChange"
></el-date-picker>
<el-date-picker
v-if='(item.type==="datePicker")&& ( item.datetype=="month"|| item.datetype=="monthrange" )'
v-model="forms[item.prop]"
:type="item.datetype"
:placeholder="item.placeholder || item.label"
:clearable="item.clearable"
:disabled="item.disabled"
:prefix-icon="item.prefixicon"
value-format="yyyy-MM"
:start-placeholder="item.startplaceholder"
:end-placeholder="item.endplaceholder"
:range-separator="item.rangeseparator"
:picker-options="startEndLimitHandle"
:default-value="item.defaultValue"
:size="$store.state.params.form.size || item.size || 'mini'"
@change="formChange"
></el-date-picker>
<el-date-picker
v-if='(item.type==="datePicker") && item.datetype=="year"'
v-model="forms[item.prop]"
type="year"
:placeholder="item.placeholder || item.label"
:clearable="item.clearable"
:disabled="item.disabled"
:prefix-icon="item.prefixicon"
value-format="yyyy"
:start-placeholder="item.startplaceholder"
:end-placeholder="item.endplaceholder"
:range-separator="item.rangeseparator"
:picker-options="startEndLimitHandle"
:default-value="item.defaultValue"
:size="$store.state.params.form.size || item.size || 'mini'"
@change="formChange"
></el-date-picker>
<el-date-picker
v-if='(item.type==="datePicker") && (item.datetype=="datetime" || item.datetype=="datetimerange")'
v-model="forms[item.prop]"
:type="item.datetype"
:placeholder="item.placeholder || item.label"
:clearable="item.clearable"
:disabled="item.disabled"
:prefix-icon="item.prefixicon"
value-format="yyyy-MM-dd HH:mm:ss"
:start-placeholder="item.startplaceholder"
:end-placeholder="item.endplaceholder"
:range-separator="item.rangeseparator"
:picker-options="startEndLimitHandle"
:default-value="item.defaultValue"
:size="$store.state.params.form.size || item.size || 'mini'"
@change="formChange"
></el-date-picker>
<el-radio-group
v-if='(item.type==="radio")'
v-model="forms[item.prop]"
:disabled="item.disabled"
:size="$store.state.params.form.size || item.size || 'mini'"
@change="formChange"
>
<div v-if='item.radiotype==="yuan" || !item.radiotype'>
<el-radio
v-for="(item2) in selectOption"
:key="item2[(item.props && item.props.value) || 'value']+item2[(item.props && item.props.label) || 'label']+'yuan'"
:label="item2[(item.props && item.props.value) || 'value']"
>{{item2[(item.props && item.props.label) || 'label']}}</el-radio>
</div>
<div v-if='item.radiotype==="button"'>
<el-radio-button
v-for="(item2) in selectOption"
:key="item2[(item.props && item.props.value) || 'value'] + item2[(item.props && item.props.label) || 'label'] +'but'"
:label="item2[(item.props && item.props.value) || 'value']"
>{{item2[(item.props && item.props.label) || 'label']}}</el-radio-button>
</div>
</el-radio-group>
<el-checkbox-group
v-if='(item.type==="checkbox") && forms[item.prop]'
v-model="forms[item.prop]"
:disabled="item.disabled"
:border="item.border"
:min="item.min"
:max="item.max"
:size="$store.state.params.form.size || item.size || 'mini'"
@change="formChange"
>
<div v-if='(item.checkboxtype=== "fang" || !item.checkboxtype) && selectOption && selectOption.length > 0'>
<el-checkbox
v-for="(item2) in selectOption"
:key="item2[(item.props && item.props.value) || 'value']+item.label"
:label="item2[(item.props && item.props.value) || 'value']"
>{{item2[(item.props && item.props.label) || 'label']}}</el-checkbox>
</div>
<div v-if='item.checkboxtype=== "button" && selectOption && selectOption.length > 0'>
<el-checkbox-button
v-for="(item2) in selectOption"
:key="'checkbut'+item2[(item.props && item.props.value) || 'value']+item.label"
:label="item2[(item.props && item.props.value) || 'value']"
>{{item2[(item.props && item.props.label) || 'label']}}</el-checkbox-button>
</div>
</el-checkbox-group>
<!-- 颜色选择器 -->
<el-color-picker v-if="(item.type == 'colorSelect')" v-model="forms[item.prop]" :placeholder="item.placeholder || item.label" @change="formChange"></el-color-picker>
<!-- 图片 -->
<ul
class="el-upload-list el-upload-list--picture-card"
v-if='item.type==="image"'
>
<li
tabindex="0"
class="el-upload-list__item is-success"
v-for="mi in forms[item.prop]"
:key="'image'+mi.url"
@click="handlePictureCardPreview(mi.url)"
>
<el-image style="width: 100%; height: 100%;" :src="mi.url" :fit="item.fit || 'contain'">
<div slot="error" class="image-slot loading-back" style="position:absolute;">
<i class="el-icon-loading" style="font-size: 24px;color:#999;"></i>
</div>
</el-image>
</li>
<li
tabindex="0"
class="el-upload-list__item"
v-if='!forms[item.prop] || forms[item.prop].length==0'
>
<el-image style="width: 100%; height: 100%;" src :fit="item.fit || 'contain'">
<div slot="error" class="image-slot loading-back" style="position:absolute;">
<i class="el-icon-loading" style="font-size: 24px;color:#999;"></i>
</div>
</el-image>
</li>
</ul>
<!-- 上传图片 -->
<el-upload
v-if='(item.type === "imageUpload")'
:class="item.fileList.length < (item.limit ? item.limit : 5) ? 'form-list-upload-img' : 'form-list-upload-img-none'"
:ref="'uploadImageBtn'+'_'+item.prop"
:action="item.action || (item.uploadHttp && item.uploadHttp.url) || ''"
:multiple="item.multipleUpload"
:limit="item.limit || 5"
:headers="item.headers || {}"
:file-list="item.fileList || []"
:size="$store.state.params.form.size || item.size || 'mini'"
list-type="picture-card"
:data="formatUploadData(item)"
accept=".jpg,.jpeg,.png,.gif,.bmp,.JPG,.JPEG,.PBG,.GIF,.BMP"
:auto-upload="true"
:on-success="handleSuccess"
:on-error="item.handleError"
:on-preview="handlePictureCardPreviewUpload"
:on-remove="handleRemove"
:on-change="uploadChangeHandle"
:before-upload="beforeUpload"
>
<i class="el-icon-plus"></i>
<div v-if="imageValidate" slot="tip" class="el-upload__tip" style="color: #F56C6C;font-size: 12px;">只能上传图片,且不超过20M</div>
</el-upload>
<!-- 预览图片 -->
<el-dialog
v-if='item.type === "imageUpload" || item.type === "image"'
class="preViewDialog"
:visible.sync="dialogVisible"
append-to-body
>
<img width="100%" :src="dialogImageUrl" alt />
</el-dialog>
<!-- 上传文件 -->
<el-upload
v-if='item.type === "fileUpload"'
:class="item.fileList.length < (item.limit ? item.limit : 5) ? 'form-list-upload-file' : 'form-list-upload-file-none'"
:ref="'uploadFileBtn'+'_'+item.prop"
:action="item.action || (item.uploadHttp && item.uploadHttp.url) || ''"
:multiple="item.multipleUpload"
:limit="item.limit"
:headers="item.headers"
:file-list="item.fileList"
:size="$store.state.params.form.size || item.size || 'mini'"
:data="formatUploadData(item)"
:auto-upload="true"
:on-success="handleSuccess"
:on-error="item.handleError"
:on-remove="handleRemove"
:on-change="uploadChangeHandle"
:before-upload="beforeUpload"
>
<el-button slot="trigger" size="mini" type="primary">选取文件</el-button>
<div v-if="fileValidate" slot="tip" class="el-upload__tip" style="color: #F56C6C;font-size: 12px;">文件大小不超过20M</div>
</el-upload>
<!-- 文件列表 -->
<ul class="el-upload-list el-upload-list--text" v-if="item.type==='file'">
<li
class="el-upload-list__item is-success"
v-for="fi in forms[item.prop]"
:key="'file'+fi.url"
>
<a
class="el-upload-list__item-name"
target="_blank"
:href="fi.url?fi.url:'javascript:void(0)'"
>
<i class="el-icon-document"></i>
{{fi.name}}
</a>
<label class="el-upload-list__item-status-label">
<i class="el-icon-upload-success el-icon-circle-check"></i>
</label>
<i class="el-icon-close"></i>
</li>
<li class="el-upload-list__item" v-if='!forms[item.prop] || forms[item.prop].length==0'>
<a class="el-upload-list__item-name">
<i class="el-icon-document"></i>
{{'文件名称'}}
</a>
</li>
</ul>
<!-- 选项卡 -->
<jvs-tab
style="width: 100%;"
:originOption="originOption"
:defalutSet="defalutSet"
:formRef="formRef"
v-if="item.type=='tab'"
:active="item.activeName"
:formItem="item"
:forms="forms[item.prop]"
:option="{type:'card', column: item.dicData}"
:userList="userList"
:resetRadom="resetRadom"
@tab-click="tabClick"
@formChange="tabFormchange">
</jvs-tab>
<!-- <el-tabs v-model="item.activeName" type="card" @tab-click="item.handleClick(item.activeName)" v-if="item.type==='tab'">
<el-tab-pane v-for="ti in item.dicData" :key="'tab'+ti.value" :label="ti.label" :name="ti.value"></el-tab-pane>
</el-tabs> -->
<!-- 展示的表格 -->
<!-- <el-table
v-if="item.type==='TableReadOnly' || item.type==='tableReadOnly'"
:data="forms[item.prop]"
:border="item.border"
highlight-current-row
class="tb-edit"
align="center"
style="width: 100%;cursor:pointer;"
>
<el-table-column
v-for="(ti) in item.option"
:key="''+ti.value+'table'"
:prop="ti.value"
:label="ti.label"
style="text-align:center;"
></el-table-column>
</el-table> -->
<!-- 描述框 -->
<div
v-if="item.type==='box'"
:style="'height: 32px;line-height:28px;text-align:'+item.contentposition+';font-size:'+item.fontsize+'px;color:'+item.textcolor+';font-weight:'+item.fontweight+';'"
>
{{forms[item.prop]}}
<span v-if='!forms[item.prop]'>{{item.text}}</span>
</div>
<!-- 链接 -->
<a
v-if="item.type =='link'"
:href="forms[item.prop]?forms[item.prop]:'javascript:void(0);'"
:target="item.openType"
:style="'height: 32px;line-height:28px;text-align:'+item.contentposition+';font-size:'+item.fontsize+'px;color:'+item.textcolor+';font-weight:'+item.fontweight+';text-decoration:'+item.textdecoration+';'"
>{{item.text}}</a>
<!-- 嵌入页面 -->
<div v-if="item.type==='iframe'" :style="'width:100%;height:'+item.iframeheight+';background:#ecf5ff;'">
<iframe
:name="item.id"
:id="item.prop"
:src="item.iframeurl"
frameborder="0"
width="100%"
height="100%"
scrolling="scroll"
></iframe>
</div>
<!-- 图标选择器 -->
<div class="form-item-icon-selct" style="position: relative;" v-if="item.type == 'iconSelect'" :id="'icon-select-item-'+item.prop">
<el-popover
placement="bottom"
:width="getWidth(item)"
v-if="!item.disabled"
trigger="click">
<div class="icon-select-tool">
<i v-for="(it, itx) in iconList" :key="itx+it" :class="it" @click="checkIcon(item.prop, it)"></i>
</div>
<div slot="reference" style="display:flex;align-items: center;">
<el-input v-model="forms[item.prop]" placeholder="图标" :disabled="item.disabled"></el-input>
<i v-if="forms[item.prop]" :class="forms[item.prop]" style="margin-left:10px;"></i>
</div>
</el-popover>
<div v-else style="display:flex;align-items: center;">
<el-input v-model="forms[item.prop]" placeholder="图标" :disabled="item.disabled"></el-input>
<i v-if="forms[item.prop]" :class="forms[item.prop]" style="margin-left:10px;"></i>
</div>
</div>
<!-- p文字 -->
<p v-if="item.type === 'p'" :style="{'text-align': item.contentposition,'font-size':item.fontsize+'px',color:item.textcolor}">{{item.text}}</p>
<!-- 分割线 -->
<el-divider v-if="item.type === 'divider'" :content-position='item.contentposition'>{{item.text}}</el-divider>
<!-- 用户组件 -->
<userForm
v-if="item.type==='user'"
:form="forms"
:prop="item.prop"
:selectable="item.multiple"
:defaultValue="item.defaultValue"
:enableinput="item.allowinput"
:disabled="item.disabled"
:resetRadom="resetRadom"
@change="formChange" /> <!-- @formChange="tabFormchange" -->
<!-- 计数器 滑块 显示单位 -->
<span v-if="['inputNumber', 'slider'].indexOf(item.type) > -1 && item.unit" style="padding-left: 5px;">{{item.unit}}</span>
<!-- 地区选择 -->
<el-cascader
v-if="item.type==='chinaArea'"
v-model="forms[item.prop]"
size="mini"
:options="chinaAreaList"
clearable
:show-all-levels="item.showalllevels"
:collapse-tags="!item.collapsetags"
:disabled="item.disabled"
:props="{
expandTrigger: 'hover',
multiple: item.multiple === false ? item.multiple : true,
label: 'name',
value: item.emitKey ? item.emitKey : 'code',
emitPath: item.emitPath
}"
@change="formChange"
>
</el-cascader>
<!-- 富文本 -->
<div v-if="item.type === 'htmlEditor'" :id="item.prop+'-editor'"></div>
<!-- 按钮 -->
<jvs-button v-if="item.type === 'button'" :disabled="item.disabled" :type="item.buttonType" :round="item.buttonRound" :size="item.size" @click="btnClick">{{item.text}}</jvs-button>
<!-- 级联选择 -->
<el-cascader
v-if="item.type==='cascader'"
v-model="forms[item.prop]"
size="mini"
:options="cascaderList"
clearable
:show-all-levels="item.showalllevels"
:collapse-tags="!item.collapsetags"
:disabled="item.disabled"
:props="{
expandTrigger: 'hover',
multiple: item.multiple === false ? item.multiple : true,
label: 'name',
value: item.emitKey ? item.emitKey : 'value',
emitPath: item.emitPath
}"
@change="formChange"
>
</el-cascader>
<!-- 表单卡片 -->
<formCard
v-if="item.type == 'formbox'"
:formItem="item"
:forms="forms[item.prop]"
:originOption="originOption"
:defalutSet="defalutSet"
:userList="userList"
:resetRadom="resetRadom"
@formChange="tabFormchange"
>
</formCard>
<!-- 右侧提示 -->
<el-tooltip v-if="item.tips && item.tips.position == 'right' && item.tips.text" class="form-item-tooltip" effect="dark" :content="item.tips.text" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
</div>
</template>
<script>
import userForm from './userForm'
import iconList from '@/const/iconfont'
import systemIcon from '@/const/systemIcon'
import formCard from './formcard'
// import {getSelectData, getFetchTable, getLineDataOfGet, getFormReviewData} from '../api/tableDesignsenior'
import {getSelectData} from '@/api/index'
import {areaList} from '@/const/chinaArea.js'
import E from 'wangeditor'
import {sendMyRequire} from '@/api/newDesign'
export default {
name: "formitem",
components: {
userForm,
formCard,
},
props: {
// 表单对象
form: {
type: Object,
default: () => {
return {}
}
},
// 表单内的组件对象
item: {
type: Object,
default: () => {
return {}
}
},
originOption: {
type: Object
},
defalutSet: {
type: Object
},
formRef: {
type: String,
default: 'ruleForm'
},
// 用户列表
userList : {
type: Array,
default: () => {
return []
}
},
// 是否需要刷新组件
freshBoolean: {
type: Boolean
},
// 是否需要重新初始化
reinitFlag: {
type: Number
},
// 表格行数据
rowData: {
type: Object
},
resetRadom: {
type: Number
}
},
computed: {
forms () {
return this.form
},
},
data () {
return {
selectOption: [],
startEndLimitHandle: {
disabledDate: time => {
let bool=false
if (!this.item.startLimit) {
let end=new Date(this.item.endLimit).getTime()
if (time.getTime()<=end) {
bool=false
} else {
bool=true
}
}
if (!this.item.endLimit) {
let start=new Date(this.item.startLimit).getTime()
if (time.getTime()>=start-8.64e7) {
bool=false
} else {
bool=true
}
}
if (!this.item.startLimit&&!this.item.endLimit) {
bool=false
}
if (this.item.startLimit&&this.item.endLimit) {
let start=new Date(this.item.startLimit).getTime()
let end=new Date(this.item.endLimit).getTime()
if (time.getTime()>=start-8.64e7&&time.getTime()<=end) {
bool=false
} else {
bool=true
}
}
return bool
}
},
errorShow: false, // 自定义验证提示错误
dialogVisible: false, // 预览图片弹框
dialogImageUrl: '', // 预览图片地址
iconList: [...iconList, ...systemIcon], // 图标列表
chinaAreaList: areaList,
cascaderList: [], // 级联选择数据
editor: null, // 富文本
pathArr: [], // 路径结果
imageValidate: false,
fileValidate: false,
eventList: ['button', 'input', 'textarea', 'inputNumber', 'select', 'slider', 'switch', 'datePicker', 'timeSelect', 'timePicker',
'radio', 'checkbox', 'imageUpload', 'fileUpload', 'htmlEditor', 'cascader', 'chinaArea', 'user'],
initHtml: '', // 记录富文本初始值
};
},
methods: {
changeHandle (val) {
this.$set(this.item, 'currVal', val)
this.$set(this.forms, this.item.prop, val)
this.formChange()
this.$forceUpdate()
},
uploadChangeHandle (file, fileList) {
// console.log('upload change.....')
// console.log(fileList)
this.$forceUpdate()
let obj={}
obj[this.item.prop]=fileList
this.$emit('currentValueHandle', obj)
},
beforeUpload (file) {
if(file.size > 20971520) {
if(this.item.type == 'imageUpload') {
this.imageValidate = true
}else{
this.fileValidate = true
}
return false
}else{
if(this.item.type == 'imageUpload') {
this.imageValidate = false
}else{
this.fileValidate = false
}
}
},
async initItem () {
if (!this.item.dicUrl && !this.item.url) {
if (this.item.dicData) {
this.selectOption=this.item.dicData
}
} else {
let url=this.item.dicUrl || this.item.url
if (!url) {
return false
}
getSelectData(url).then(res => {
if(res.data.code === 0) {
this.selectOption = []
for(let sitem in res.data.data){
if(typeof res.data.data[sitem] == 'string') {
this.selectOption.push({
label: res.data.data[sitem],
value: res.data.data[sitem]
})
}else{
// this.selectOption.push({
// label: res.data.data[sitem][this.item.props.label ? this.item.props.label : 'label'],
// value: res.data.data[sitem][this.item.props.value ? this.item.props.value : 'value']
// })
this.selectOption.push(res.data.data[sitem])
}
}
}
})
}
if(['checkbox', 'formbox'].indexOf(this.item.type) > -1) {
!this.forms[this.item.prop] && (this.$set(this.forms, this.item.prop, []))
}
// 下拉切换是否多选时,初始化数据类型
if(this.item.type == 'select') {
if(this.item.multiple) {
!this.forms[this.item.prop] && (this.$set(this.forms, this.item.prop, []))
}else{
if((!this.forms[this.item.prop] && this.forms[this.item.prop] !== 0 && this.forms[this.item.prop] !== false) || this.forms[this.item.prop] instanceof Array) {
this.$set(this.forms, this.item.prop, "")
}
}
}
// 滑块
if(this.item.type == 'slider') {
if(this.item.range) {
!this.forms[this.item.prop] && (this.$set(this.forms, this.item.prop, [0, this.item.max / 2]))
}else{
if(!this.forms[this.item.prop] || this.forms[this.item.prop] instanceof Array) {
this.$set(this.forms, this.item.prop, 0)
}
}
}
// 表单项默认值填充,权重小于表单初始化值
if(this.item.defaultValue || this.item.defaultValue === false || this.item.defaultValue === "") {
(!this.forms[this.item.prop] && this.forms[this.item.prop] !== false && this.forms[this.item.prop] !== 0) && (this.$set(this.forms, this.item.prop, this.item.defaultValue))
}
// tab选项卡 step步骤条
if(['tab'].indexOf(this.item.type) > -1) {
if(this.item.dicData && this.item.dicData.length > 0) {
!this.forms[this.item.prop] && (this.$set(this.forms, this.item.prop, {}))
for(let col in this.item.column) {
if(this.item.column[col] && this.item.column[col].length > 0) {
!this.forms[this.item.prop][col] && (this.$set(this.forms[this.item.prop], col, {}))
}
}
}
}
if(['imageUpload', 'fileUpload'].indexOf(this.item.type) > -1 && this.forms[this.item.prop]){
this.$set(this.item, 'fileList', this.forms[this.item.prop])
}
this.$forceUpdate()
},
handlePictureCardPreview (url) {
this.dialogImageUrl=url
this.dialogVisible=true
},
handlePictureCardPreviewUpload (file) {
this.dialogImageUrl=file.url
this.dialogVisible=true
},
checkIcon (key, icon) {
this.form[key] = icon
this.$forceUpdate()
},
// 字段值改变传出表单
formChange () {
this.$emit('formChange', this.form)
if(this.eventList.indexOf(this.item.type) > -1) {
this.eventRequireHandle()
}
if(this.item.type == 'user') {
if(this.item.rules && this.item.rules.length > 0) {
if(this.item.rules[0].required) {
if(this.item.multiple) {
if(this.form[this.item.prop].length > 0) {
this.$emit('validateHandle', {type: 'clear', item: this.item})
}else{
this.$emit('validateHandle', {type: 'validate', item: this.item})
}
}else{
if(this.form[this.item.prop]) {
this.$emit('validateHandle', {type: 'clear', item: this.item})
}else{
this.$emit('validateHandle', {type: 'validate', item: this.item})
}
}
}
}
}
},
// 选项卡formchange
tabFormchange (data) {
this.$set(this.form, this.item.prop, data)
this.formChange()
this.$forceUpdate()
},
addRowHandle () {
if(!this.forms[this.item.prop]) {
this.$set(this.forms, this.item.prop, [])
}
this.forms[this.item.prop].push({})
},
deleteRow (row, index) {
this.forms[this.item.prop].splice(index, 1)
},
// 同步表格数据
setTableHandle (data) {
this.$set(this.forms, this.item.prop, data)
},
// 获取宽度占比
getWidth (item) {
let w = 400
if(item.prop && document.getElementById('icon-select-item-'+item.prop)) {
w = document.getElementById('icon-select-item-'+item.prop).clientWidth
}
return w
},
// 初始化富文本
initEditor (prop) {
let that = this
this.$nextTick(() => {
let _this = that
if(_this.editor) {
_this.editor.destroy()
}
_this.editor = null
$('#' + prop + '-editor').html("")
_this.editor = new E('#' + prop + '-editor')
_this.editor.config.height = 400
// _this.editor.config.uploadImgShowBase64 = true
_this.editor.config.menus = [
'head',
'bold',
'fontSize',
'fontName',
'italic',
'underline',
'strikeThrough',
'indent',
'lineHeight',
'foreColor',
'backColor',
'link',
'list',
'justify',
'quote',
'emoticon',
'image',
'table',
'code',
'splitLine',
'undo',
'redo',
]
_this.editor.config.onblur = function (newHtml) {
let vb = false
if(!newHtml || JSON.stringify(newHtml) == '" "' || newHtml == '<p></p>' && newHtml == '<p><br></p>') {
_this.$set(_this.form, prop, "")
vb = false
}else{
_this.$set(_this.form, prop, newHtml)
vb = true
}
if(_this.item.rules && _this.item.rules.length > 0) {
if(_this.item.rules[0].required) {
if(vb) {
_this.$emit('validateHandle', {type: 'clear', item: _this.item})
}else{
_this.$emit('validateHandle', {type: 'validate', item: _this.item})
}
}
}
_this.eventRequireHandle()
}
_this.editor.config.onchange = function (newHtml) {
let vb = false
if(!newHtml || JSON.stringify(newHtml) == '" "' || newHtml == '<p></p>' && newHtml == '<p><br></p>') {
_this.$set(_this.form, prop, "")
vb = false
}else{
_this.$set(_this.form, prop, newHtml)
vb = true
}
if(_this.item.rules && _this.item.rules.length > 0) {
if(_this.item.rules[0].required) {
if(vb) {
_this.$emit('validateHandle', {type: 'clear', item: _this.item})
}else{
_this.$emit('validateHandle', {type: 'validate', item: _this.item})
}
}
}
}
// _this.editor.config.uploadImgServer = '/api/file/upload/jvshtmleditor'
_this.editor.config.uploadImgServer = '/mgr/document//upload/jvs-public'
_this.editor.config.uploadFileName = 'file'
_this.editor.config.uploadImgHooks = {
// 图片上传并返回了结果,图片插入已成功
success: function(xhr) {
console.log('success', xhr)
},
// 图片上传并返回了结果,但图片插入时出错了
fail: function(xhr, editor, resData) {
console.log('fail', resData)
},
// 上传图片出错,一般为 http 请求的错误
error: function(xhr, editor, resData) {
console.log('error', xhr, resData)
},
// 图片上传并返回了结果,想要自己把图片插入到编辑器中
// 例如服务器端返回的不是 { errno: 0, data: [...] } 这种格式,可使用 customInsert
customInsert: function(insertImgFn, result) {
// insertImgFn 可把图片插入到编辑器,传入图片 src ,执行函数即可
if(result.code == 0 && result.data && result.data.fileLink) {
// let url = result.data.filelink.indexOf('?') ? result.data.filelink.split('?')[0] : result.data.filelink
insertImgFn(result.data.fileLink)
}
}
}
_this.editor.create()
if(_this.form[prop]) {
_this.form[prop] = _this.form[prop].replace(/</g, "<")
_this.form[prop] = _this.form[prop].replace(/>/g, ">")
_this.editor.txt.html(_this.form[prop])
_this.initHtml = _this.form[prop]
}
if(_this.item.disabled) {
_this.editor.disable()
}else{
_this.editor.enable()
}
})
this.$forceUpdate()
},
tabClick (name) {
if(this.item.handleClick) {
this.item.handleClick(name)
}
},
// 按钮点击
btnClick () {
if(this.item.eventType == 'url') {
if(this.item.openUrl) {
this.$openUrl(this.item.openUrl, this.item.newWindowOpen ? '_blank' : '_self')
}
}else{
this.eventRequireHandle()
}
},
// 上传成功回调
handleSuccess (res, file, fileList) {
if(res.code === 0){
let obj = {
name: res.data.originalFileName,
url: res.data.filelink,
fileName: res.data.fileName
}
this.item.fileList.push(obj)
let temp = {
key: this.item.prop,
fileList: this.item.fileList
}
this.$emit('file', temp)
this.$set(this.forms, this.item.prop, this.item.fileList)
this.eventRequireHandle()
}
},
eventRequireHandle () {
if(this.item.eventHttp) {
let tp = JSON.parse(JSON.stringify(this.item.eventHttp))
if(this.$store.state.labelValue && this.$store.state.labelValue.requestContentType) {
tp.requestContentType = this.$store.state.labelValue.requestContentType[tp.requestContentType]
}
if(tp && tp.url) {
sendMyRequire(tp, this.form).then(res => {
if(res.data.code == 0) {
if(res.data.msg) {
this.$message.success(res.data.msg)
if(res.data.data) {
for(let i in res.data.data) {
this.$set(this.form, i, res.data.data[i])
}
this.$emit('formChange', this.form)
}
}
}
}).catch(e => {})
}
}
},
// 处理上传参数
formatUploadData (item) {
let obj = {}
if(item.uploadHttp) {
obj = item.uploadHttp.parameters
}
return obj
},
// 删除
handleRemove (file, fileList) {
for(let i in this.item.fileList) {
if(this.item.fileList[i].uid == file.uid) {
this.item.fileList.splice(i, 1)
let temp = {
key: this.item.prop,
fileList: this.item.fileList
}
this.$emit('file', temp)
this.$set(this.forms, this.item.prop, this.item.fileList)
}
}
}
},
watch: {
item: {
handler () {
this.initItem()
// 下拉框 单选 自定义选择
if(this.item.currVal) {
if(this.item.multiple) {
if(this.item.currVal instanceof Array !== true) {
this.$set(this.forms, this.item.prop, [])
}else{
this.$set(this.forms, this.item.prop, this.item.currVal)
}
}else{
if(this.item.currVal instanceof Array !== true) {
this.$set(this.forms, this.item.prop, this.item.currVal)
}else{
this.$set(this.forms, this.item.prop, "")
}
}
}
if(this.item.type == 'htmlEditor') {
$('#' + this.item.prop + '-editor').html("")
this.initEditor(this.item.prop)
}
if(['imageUpload', 'fileUpload'].indexOf(this.item.type) > -1) {
if(this.item.rules && this.item.rules.length > 0) {
if(this.item.rules[0].required) {
if(this.forms[this.item.prop].length > 0) {
this.$emit('validateHandle', {type: 'clear', item: this.item})
}else{
this.$emit('validateHandle', {type: 'validate', item: this.item})
}
}
}
}
},
deep: true
},
freshBoolean: {
handler(newVal, oldVal) {
if(this.item.type == 'htmlEditor') {
$('#' + this.item.prop + '-editor').html("")
this.initEditor(this.item.prop)
}else{
$('#' + this.item.prop + '-editor').html("")
this.editor.destroy()
}
}
},
reinitFlag: {
handler(newVal, oldVal) {
if(newVal != -1) {
this.initItem()
}
}
},
resetRadom: {
handler (newVal, oldVal) {
if(newVal > -1) {
if(this.item.type == 'htmlEditor') {
this.editor.txt.html(this.initHtml)
}
if(this.item.type == 'checkbox') {
if(!this.forms[this.item.prop]) {
this.$set(this.forms, this.item.prop, [])
}
}
}
}
}
},
created () {
this.initItem()
},
mounted () {
if(this.item.type == 'htmlEditor') {
$('#' + this.item.prop + '-editor').html("")
this.initEditor(this.item.prop)
}
}
};
</script>
<style lang="scss">
.loading-back {
width: 100%;
height: 100%;
background: #f5f7fa;
display: flex;
justify-content: center;
align-items: center;
}
.form-list-upload-img {
.el-upload--picture-card {
display: inline-block;
}
}
.form-list-upload-img-none {
.el-upload--picture-card {
display: none;
}
}
.form-list-upload-file {
.el-upload--text {
display: inline-block;
}
}
.form-list-upload-file-none {
.el-upload--text {
display: none;
}
}
.icon-select-tool{
// margin-top: 10px;
display: flex;
flex-wrap: wrap;
height: 200px;
scrollbar-width: none; /* firefox */
-ms-overflow-style: none; /* IE 10+ */
overflow-x: hidden;
overflow-y: auto;
// box-shadow: 0 0 10px #ccc;
i{
margin: 10px;
display: block;
width: 20px;
height: 20px;
line-height: 20px;
cursor: pointer;
}
i:hover{
color: #409EFF;
}
}
.icon-select-tool::-webkit-scrollbar {
display: none; /* Chrome Safari */
}
.icon-select-tool-position{
position: absolute;
height: 158px;
top: 45px;
margin: 0;
z-index: 9;
}
.jvs-form-item{
min-height: 32px;
.el-slider, p, .el-input-number, .el-select, .el-date-editor, .form-item-icon-selct, .el-tabs, .el-cascader, .user-info-list{
flex: 1;
}
.el-input-number{
.el-input__inner{
text-align: left;
}
}
.el-input-number.is-disabled{
flex: none;
width: auto;
.el-input{
width: auto;
.el-input__inner{
padding-right: 0;
}
}
}
}
</style>
================================================
FILE: src/components/basic-assembly/levelForm.vue
================================================
<template>
<jvs-tab :active="activeName" type="card" :option="levelFormOption">
<template v-for="item in levelFormOption.column" :slot="item.name">
<jvs-form v-if="item.formOption" :key="item.name+'level'" :defalutFormData="item.defaultData" :option="item.formOption"></jvs-form>
</template>
</jvs-tab>
</template>
<script>
export default {
name: 'jvs-form-level',
props: {
active: {
type: String,
default: ''
},
// 选项卡配置
option: {
type: Object,
default: () => {
return {}
}
}
},
data () {
return {
activeName: 'form1',
levelFormOption: {},
defaultSet: {
column: [
{
label: '表单一',
name: 'form1',
defaultData: {}, // 表单默认值
formOption: {
column: [
{
label: '文本框',
prop: 'input'
}
]
}
}
]
}
}
},
created () {
if(this.active) {
this.activeName = this.active
}
if(this.option) {
this.levelFormOption = this.option
this.activeName = this.option.column[0].name
}else{
this.levelFormOption = this.defaultSet
this.activeName = this.option.column[0].name
}
},
}
</script>
<style lang="scss">
</style>
================================================
FILE: src/components/basic-assembly/stepForm.vue
================================================
<template>
<jvs-tab :active="activeName" type="card" :option="stepFormOption" @tab-click="tabClick">
<template v-for="(item, index) in stepFormOption.column" :slot="item.name">
<jvs-form v-if="item.formOption" :key="item.name+'level'" :defalutFormData="item.defaultData" :option="item.formOption" @submit="submitHandle">
<template slot="formButton">
<jvs-button v-if="index > 0" @click="lastStep(index)">上一步</jvs-button>
</template>
</jvs-form>
</template>
</jvs-tab>
</template>
<script>
export default {
name: 'jvs-form-step',
props: {
active: {
type: String,
default: ''
},
// 选项卡配置
option: {
type: Object,
default: () => {
return {}
}
}
},
data () {
return {
activeName: '',
stepFormOption: {},
defaultSet: {
column: [
{
label: '表单一',
name: 'form1',
defaultData: {}, // 表单默认值
formOption: {
column: [
{
label: '文本框',
prop: 'input'
}
]
}
}
]
}
}
},
created () {
if(this.active) {
this.activeName = this.active
}
if(this.option) {
this.stepFormOption = this.option
this.activeName = this.option.column[0].name
}else{
this.stepFormOption = this.defaultSet
this.activeName = this.defaultSet.column[0].name
}
// 全部设置disable
for(let i in this.stepFormOption.column) {
this.stepFormOption.column[i].disabled = true
}
},
methods: {
// tab切换
tabClick (tab) {
this.activeName = tab
},
// 上一步
lastStep (index) {
index = Number.parseInt(index)
this.activeName = this.stepFormOption.column[index-1].name
this.$forceUpdate()
},
// 提交,下一步
submitHandle (form) {
if(form) {
// 数据操作
// 下一步
let index = this.getIndexOfForm(this.activeName)
this.stepFormOption.column[index].disabled = false
if(index == this.stepFormOption.column.length - 1) {
this.activeName = this.stepFormOption.column[index].name
}else{
this.activeName = this.stepFormOption.column[index+1].name
}
}
},
getIndexOfForm (active) {
for(let i in this.stepFormOption.column) {
if(this.stepFormOption.column[i].name == active) {
return Number.parseInt(i)
}
}
return -1
}
}
}
</script>
<style lang="scss">
</style>
================================================
FILE: src/components/basic-assembly/tab.vue
================================================
<template>
<el-tabs
v-model="activeName"
:type="option.type || defaultOption.type"
:tab-position="option.tabPosition || defaultOption.tabPosition"
:stretch="option.stretch || defaultOption.stretch"
@tab-click="handleClick"
>
<el-tab-pane
v-for="item in option.column"
:key="item.name"
:label="item.label"
:disabled="item.disabled"
:name="item.name"
:lazy="item.lazy"
>
<el-form
:model="forms[item.name]"
:ref="formRef || 'ruleForm'"
class="demo-dynamic"
size='mini'
:label-position="(originOption && originOption.formAlign) || defalutSet.option.formAlign"
:label-width="(originOption && originOption.labelWidth) || defalutSet.option.labelWidth"
:disabled='(originOption && originOption.disabled)'
>
<el-row v-if="formItem.column && formItem.column[item.name] && formItem.column[item.name].length > 0" style="width:100%;">
<el-col
v-for="it in formItem.column[item.name]"
:key="it.prop"
:span="it.span || 24"
v-show="it.display == false ? it.display : true"
:class="{'no-label-form-item': it.hideLabel}"
>
<!-- 一般项 -->
<el-form-item
v-if="(it.type !='title' && (!it.children || it.children.length == 0) || it.type == 'formbox') && $permissionMatch(it.permisionFlag) && (it.display == false ? it.display : true)"
:label="it.label"
:prop='it.prop'
:rules='it.rules'
v-model="forms[item.name][it.prop]"
:label-width="it.type==='iframe'?'0':((originOption && originOption.labelWidth) || defalutSet.option.labelWidth)"
:class='{"form-item-no-label": ( (!it.label && it.type != "tab") || (["tableForm","divider","p","section"].indexOf(it.type) > -1) ), "form-item-no-label-tab": (!it.label && it.type == "tab")}'
>
<FormItem :item="it" :form="forms[item.name]"
:originOption="originOption"
:defalutSet="defalutSet"
:userList="userList"
:resetRadom="resetRadom"
@formChange="formChange" />
</el-form-item>
<!-- 子表单项 -->
<el-row v-if="it.type != 'formbox' && it.children && it.children.length > 0">
<el-form-item
:label="it.label"
:prop="it.prop"
:rules="it.rules"
v-if="(it.display == false ? it.display : true)"
v-model="forms[item.name][it.prop]"
:class='(!it.label || (["tableForm","divider","p","tab","section"].indexOf(it.type) > -1))? "form-item-no-label" : ""'
>
<FormItem
v-if="!it.formSlot"
:form="forms[item.name]"
:item="it"
:originOption="originOption"
:defalutSet="defalutSet"
@formChange="formChange"
:userList="userList"
:resetRadom="resetRadom"
/>
<!-- 自定义列插槽 -->
<div v-if="it.formSlot">
<slot :name="it.prop+'Form'"></slot>
<!-- 右侧提示 -->
<el-tooltip
v-if="it.tips && it.tips.position == 'right' && it.tips.text"
class="form-item-tooltip"
effect="dark"
:content="it.tips.text"
placement="top"
>
<i class="el-icon-question"></i>
</el-tooltip>
</div>
<!-- 换行提示 -->
<el-row
v-if="it.tips && it.tips.position == 'bottom'"
class="form-item-tips"
>
<span v-html="it.tips.text"></span>
</el-row>
</el-form-item>
<el-col
v-for="itc in it.children"
:key="itc.prop"
:span="itc.span || originOption.span || 24"
>
<el-form-item
:label="itc.label"
:prop="itc.prop"
v-if="itc.display === false ? false : linkbindHandle(forms[item.name][it.prop], itc.linkbind)"
:rules="itc.rules"
v-model="forms[item.name][itc.prop]"
:class='{"form-item-no-label": (!itc.label || (["tableForm","divider","p","tab","section"].indexOf(itc.type) > -1))}'
>
<FormItem
v-if="!itc.formSlot"
:form="forms[item.name]"
:item="itc"
:formRef="defalutSet.refs"
:originOption="originOption"
:defalutSet="defalutSet"
@formChange="formChange"
:userList="userList"
:resetRadom="resetRadom"
/>
<!-- 自定义列插槽 -->
<div v-if="itc.formSlot">
<slot :name="itc.prop+'Form'"></slot>
<!-- 右侧提示 -->
<el-tooltip
v-if="itc.tips && itc.tips.position == 'right' && itc.tips.text"
class="form-item-tooltip"
effect="dark"
:content="itc.tips.text"
placement="top"
>
<i class="el-icon-question"></i>
</el-tooltip>
</div>
<!-- 换行提示 -->
<el-row
v-if="itc.tips && itc.tips.position == 'bottom'"
class="form-item-tips"
>
<span v-html="itc.tips.text"></span>
</el-row>
</el-form-item>
</el-col>
</el-row>
</el-col>
</el-row>
<slot :name="item.name"></slot>
</el-form>
</el-tab-pane>
</el-tabs>
</template>
<script>
import FormItem from './formitem'
export default {
name: "jvs-tab",
components: {FormItem},
props: {
// 绑定值,选中选项卡的 name
active: {
type: String,
default: ''
},
// 选项卡配置
option: {
type: Object,
default: () => {
return {}
}
},
// 表单传递对象
forms: {
type: Object,
default: () => {
return {}
}
},
// 表单结构对象
formItem: {
type: Object,
default: () => {
return {}
}
},
formRef: {
type: String,
default: 'ruleForm'
},
originOption: {
type: Object
},
// 用户列表
userList : {
type: Array,
default: () => {
return []
}
},
resetRadom: {
type: Number
}
},
data () {
return {
activeName: '',
defaultOption: {
type: '', // tab风格, card/border-card
tabPosition: 'top', // 选项卡所在位置, top/right/bottom/left
stretch: false, // 标签的宽度是否自撑开
column: [
{
label: '', // 选项卡标题
disabled: false, // 是否禁用
name: '', // 与选项卡绑定值 value 对应的标识符,表示选项卡别名, 该选项卡在选项卡列表中的顺序值,如第一个选项卡则为'1'
lazy: false, // 标签是否延迟渲染
permisionFlag: '', // 权限标识
}
]
},
defalutSet: {
refs: 'ruleForm',
option: {
formAlign: 'right', //对其方式
inline: false, // 表单项是否可以同行,当垂直方向空间受限且表单较简单时,可以在一行内放置表单
labelWidth: 'auto', // label宽
searchBtn: true, // 搜索按钮是否显示,默认显示
searchBtnText: '查询', // 搜索按钮,默认查询
submitBtn: true, // 提交按钮是否显示,默认显示
submitBtnText: '提交', // 提交按钮文字,默认 提交
emptyBtn: true, // 重置按钮,默认显示
emptyBtnText: '重置', // 重置按钮文字,默认 重置
cancalBtnText: '取消', // 取消按钮文字, 默认 取消
}
},
initData: ""
}
},
created () {
this.dealPermission()
if(this.active) {
this.activeName = this.active
}
this.initData = JSON.stringify(this.forms)
},
methods: {
handleClick (tab, event) {
this.activeName = tab.name
this.$emit('tab-click', tab.name)
},
// 处理权限
dealPermission () {
for(let i in this.option.column) {
if(!this.option.column[i].permisionFlag) {
this.option.column[i].show = true
}else{
this.option.column[i].show = this.$permissionMatch(this.option.column[i].permisionFlag)
}
// 加入自定义校验
if(this.formItem && this.formItem.column) {
let tcol = this.formItem.column[this.option.column[i].name]
if(tcol && tcol.length > 0) {
for(let t in tcol) {
if(tcol[t].regularExpression){
let required = false
if(tcol[t].rules && tcol[t].rules[0].required) {
required = true
}
let str = '/' + tcol[t].regularExpression + '/'
let _this = this
tcol[t].rules.push({
validator: function(rule, value, callback) {
if(eval(str).test(value)) {
callback()
}else{
let msg = '正则校验不通过'
if(tcol[t].regularMessage) {
msg = tcol[t].regularMessage
}
if(required == false && !value) {
callback()
}else{
callback(new Error(msg));
}
}
},
trigger: ['blur', 'change']
})
}
}
}
}
}
this.option.column = this.option.column.
gitextract_eh24v6ax/ ├── .browserslistrc ├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── .postcssrc.js ├── CHANGELOG.sh ├── LICENSE ├── README.en.md ├── README.md ├── babel.config.js ├── docker/ │ ├── Dockerfile │ ├── docker-compose.yml │ └── my.conf ├── expendPlugins/ │ └── chart/ │ └── chartmix.css ├── package.json ├── public/ │ ├── index.html │ └── jvs-ui-public/ │ ├── cdn/ │ │ ├── animate/ │ │ │ └── 3.5.2/ │ │ │ └── animate.css │ │ ├── iconfont/ │ │ │ └── 1.0.0/ │ │ │ └── index.css │ │ ├── jvs/ │ │ │ └── jvs.css │ │ └── store/ │ │ └── 1.3.20/ │ │ └── store.js │ ├── icon.js │ └── svg/ │ └── favicon.ico1 ├── src/ │ ├── App.vue │ ├── api/ │ │ ├── common.js │ │ ├── index.js │ │ ├── login.js │ │ └── newDesign.js │ ├── components/ │ │ ├── QRcode/ │ │ │ └── index.vue │ │ ├── api.js │ │ ├── basic-assembly/ │ │ │ ├── button.vue │ │ │ ├── form.vue │ │ │ ├── formcard.vue │ │ │ ├── formitem.vue │ │ │ ├── levelForm.vue │ │ │ ├── stepForm.vue │ │ │ ├── tab.vue │ │ │ ├── table.vue │ │ │ ├── userForm.vue │ │ │ └── userSelector.vue │ │ ├── basic-container/ │ │ │ ├── loading.vue │ │ │ ├── login/ │ │ │ │ └── loginForm.vue │ │ │ └── main.vue │ │ ├── doc-lib/ │ │ │ ├── api.js │ │ │ ├── excel/ │ │ │ │ └── index.vue │ │ │ ├── flow/ │ │ │ │ └── index.vue │ │ │ ├── html/ │ │ │ │ └── index.vue │ │ │ ├── index.vue │ │ │ ├── map/ │ │ │ │ └── index.vue │ │ │ └── show.vue │ │ ├── error-page/ │ │ │ └── 404.vue │ │ ├── iframe/ │ │ │ └── main.vue │ │ ├── index.js │ │ ├── page-footer/ │ │ │ └── FooterContent.vue │ │ └── page-header/ │ │ ├── PageHeader.vue │ │ └── titlePageHeader.vue │ ├── config/ │ │ └── env.js │ ├── const/ │ │ ├── chinaArea.js │ │ ├── columnTypeList.js │ │ ├── const.js │ │ ├── errorCode.js │ │ ├── iconList.js │ │ ├── iconfont.js │ │ ├── systemIcon.js │ │ └── website.js │ ├── error.js │ ├── filters/ │ │ └── index.js │ ├── main.js │ ├── permission.js │ ├── router/ │ │ ├── axios.js │ │ ├── jvs-router.js │ │ ├── page/ │ │ │ └── index.js │ │ ├── router.js │ │ └── views/ │ │ └── index.js │ ├── store/ │ │ ├── getters.js │ │ ├── index.js │ │ ├── modules/ │ │ │ ├── common.js │ │ │ ├── konwledge.js │ │ │ ├── tags.js │ │ │ └── user.js │ │ └── types/ │ │ └── global.js │ ├── styles/ │ │ ├── animate/ │ │ │ └── vue-transition.scss │ │ ├── common.scss │ │ ├── element-ui.scss │ │ ├── login.scss │ │ ├── media.scss │ │ ├── mixin.scss │ │ ├── normalize.scss │ │ ├── reset2.0.scss │ │ ├── resetAll.scss │ │ ├── sidebar.scss │ │ ├── tags.scss │ │ ├── themes/ │ │ │ ├── common/ │ │ │ │ ├── mixins.scss │ │ │ │ └── variables.scss │ │ │ └── index.scss │ │ ├── tiptap.scss │ │ ├── tiptapView.scss │ │ ├── top.scss │ │ └── variables.scss │ ├── util/ │ │ ├── date.js │ │ ├── eventBus.js │ │ ├── login.js │ │ ├── permision.js │ │ ├── store.js │ │ ├── url.js │ │ ├── util.js │ │ └── validate.js │ └── views/ │ ├── catalogview/ │ │ └── index.vue │ ├── common/ │ │ ├── Comment.vue │ │ ├── KnowSet.vue │ │ ├── LuckySheet.vue │ │ ├── MemberSet.vue │ │ ├── MindElixir.vue │ │ ├── Tiptap.vue │ │ ├── Topology.vue │ │ ├── api.js │ │ ├── draw.js │ │ ├── search.vue │ │ ├── show.vue │ │ ├── tiptap/ │ │ │ ├── extension.js │ │ │ └── tiptapPlugin.js │ │ ├── toolbar.vue │ │ └── topbar.vue │ ├── companyInfo/ │ │ └── index.vue │ ├── index/ │ │ ├── api.js │ │ ├── baseInfo.vue │ │ ├── index.vue │ │ └── page.vue │ ├── info/ │ │ ├── icon/ │ │ │ ├── demo.css │ │ │ ├── demo_index.html │ │ │ ├── iconfont.css │ │ │ ├── iconfont.js │ │ │ └── iconfont.json │ │ └── index.vue │ ├── main/ │ │ └── wx/ │ │ └── login.vue │ ├── my/ │ │ └── icon/ │ │ └── index.js │ └── view/ │ ├── api.js │ ├── diclibApi.js │ └── index.vue └── vue.config.js
SYMBOL INDEX (107 symbols across 26 files)
FILE: public/jvs-ui-public/cdn/store/1.3.20/store.js
function isLocalStorageNameSupported (line 64) | function isLocalStorageNameSupported () {
FILE: src/api/common.js
function byKeyDicData (line 4) | function byKeyDicData (url) {
function getDeptUserTree (line 12) | function getDeptUserTree(){
function searchUser (line 20) | function searchUser(params){
FILE: src/api/login.js
function getQRcode (line 27) | function getQRcode(params) {
function getCheck (line 35) | function getCheck(data) {
function getPhone (line 46) | function getPhone(data) {
function getPhoneCode (line 54) | function getPhoneCode(data) {
function codeLogin (line 62) | function codeLogin(data) {
function wxOpenidLogin (line 74) | function wxOpenidLogin(data) {
function appQrLogin (line 85) | function appQrLogin(data) {
function appCheck (line 97) | function appCheck(data){
function appLogin (line 108) | function appLogin(data) {
FILE: src/api/newDesign.js
function bindPhone (line 42) | function bindPhone(data) {
function sendPhoneCode (line 51) | function sendPhoneCode(phone) {
FILE: src/components/api.js
function getUserList (line 4) | function getUserList(query) {
function getUserAll (line 12) | function getUserAll(query) {
FILE: src/const/columnTypeList.js
constant NUMBER_QUERY_TYPE (line 5) | const NUMBER_QUERY_TYPE = ['EQ', 'NE', 'GT', 'GE', 'LT', 'LE', 'BETWEEN']
constant VARCHAR_QUERY_TYPE (line 6) | const VARCHAR_QUERY_TYPE = ['LIKE', 'LIKE_LEFT', 'LIKE_RIGHT', 'EQ']
FILE: src/const/const.js
function get16LenString (line 27) | function get16LenString (str) {
FILE: src/filters/index.js
function pluralize (line 1) | function pluralize (time, label) {
function dateFormat (line 11) | function dateFormat (date, type) {
function timeAgo (line 45) | function timeAgo (time) {
function parseTime (line 56) | function parseTime (time, cFormat) {
function formatTime (line 92) | function formatTime (time, option) {
function nFormatter (line 116) | function nFormatter (num, digits) {
function html2Text (line 133) | function html2Text (val) {
function toThousandslsFilter (line 139) | function toThousandslsFilter (num) {
function dicFormat (line 145) | function dicFormat (val, options, props) {
FILE: src/router/jvs-router.js
function objToform (line 10) | function objToform(obj) {
method component (line 83) | component(resolve) {
FILE: src/router/router.js
method scrollBehavior (line 10) | scrollBehavior (to, from, savedPosition) {
FILE: src/store/getters.js
method [globalTypes.GET_DIRECTION] (line 28) | [globalTypes.GET_DIRECTION](state) {
method [globalTypes.GET_THEME] (line 31) | [globalTypes.GET_THEME](state) {
FILE: src/store/index.js
method [globalTypes.UPDATE_DIRECTION] (line 45) | [globalTypes.UPDATE_DIRECTION](state, direction) {
method [globalTypes.UPDATE_THEME] (line 48) | [globalTypes.UPDATE_THEME](state, theme) {
FILE: src/store/modules/tags.js
function setFistTag (line 16) | function setFistTag (list) {
FILE: src/store/modules/user.js
function addPath (line 14) | function addPath(ele, first) {
method LoginByUsername (line 69) | LoginByUsername({ commit }, userInfo) {
method GetUserInfo (line 159) | GetUserInfo({ commit }) {
method RefreshToken (line 175) | RefreshToken({ commit, state }, tenantId) {
method LogOut (line 193) | LogOut({ commit }) {
method FedLogOut (line 217) | FedLogOut({ commit }) {
FILE: src/store/types/global.js
constant GET_DIRECTION (line 10) | const GET_DIRECTION = 'APP/GET_DIRECTION';
constant GET_THEME (line 11) | const GET_THEME = 'APP/GET_THEME';
constant UPDATE_DIRECTION (line 14) | const UPDATE_DIRECTION = 'APP/UPDATE_DIRECTION';
constant UPDATE_THEME (line 15) | const UPDATE_THEME = 'APP/UPDATE_THEME';
FILE: src/util/date.js
function dateFormat (line 32) | function dateFormat(date) {
FILE: src/util/permision.js
method install (line 3) | install (Vue, options) {
FILE: src/util/url.js
method install (line 7) | install (Vue, options) {
FILE: src/util/util.js
function listen (line 183) | function listen() {
FILE: src/util/validate.js
function isEmail (line 9) | function isEmail (s) {
function isMobile (line 17) | function isMobile (s) {
function isPhone (line 25) | function isPhone (s) {
function isURL (line 33) | function isURL (s) {
function isvalidUsername (line 37) | function isvalidUsername (str) {
function validateURL (line 43) | function validateURL (textval) {
function validateLowerCase (line 49) | function validateLowerCase (str) {
function validateUpperCase (line 55) | function validateUpperCase (str) {
function validatAlphabets (line 61) | function validatAlphabets (str) {
function validateEmail (line 88) | function validateEmail (email) {
function cardid (line 96) | function cardid (code) {
function isvalidatemobile (line 179) | function isvalidatemobile (phone) {
function validatename (line 206) | function validatename (name) {
function validatenum (line 215) | function validatenum (num, type) {
function validatenumord (line 229) | function validatenumord (num, type) {
function validatenull (line 243) | function validatenull (val) {
FILE: src/views/common/api.js
function documentSearch (line 4) | function documentSearch(params) {
function readNumber (line 13) | function readNumber(id) {
function editLog (line 21) | function editLog(params) {
function getLike (line 30) | function getLike(params) {
function giveGood (line 39) | function giveGood(params) {
function getComment (line 48) | function getComment(id,data) {
function leaveMsg (line 57) | function leaveMsg(data) {
function setLibrary (line 67) | function setLibrary(data) {
function addLibrary (line 76) | function addLibrary(data) {
function queryMember (line 85) | function queryMember(id, params) {
function setMemberRole (line 94) | function setMemberRole(documentId, userId, role) {
function addMember (line 102) | function addMember(data) {
function delMember (line 128) | function delMember(documentId, userId) {
function delMsg (line 136) | function delMsg(id) {
function uploadImage (line 144) | function uploadImage(data) {
FILE: src/views/common/tiptap/extension.js
class myHeading (line 4) | class myHeading extends Heading {
method constructor (line 5) | constructor(props,myAttribute) {
method schema (line 8) | get schema () {
class myFontSize (line 32) | class myFontSize extends FontSize {
method constructor (line 33) | constructor(props,myAttribute) {
method schema (line 36) | get schema () {
FILE: src/views/common/tiptap/tiptapPlugin.js
constant SIZE_PATTERN (line 2) | const SIZE_PATTERN = /([\d.]+)(px || pt)/i;
constant ALIGN_PATTERN (line 9) | const ALIGN_PATTERN = new RegExp(`(${Alignment.left}|${Alignment.center}...
constant DEFAULT_LINE_HEIGHT (line 10) | const DEFAULT_LINE_HEIGHT = '100%';
constant NUMBER_VALUE_PATTERN (line 11) | const NUMBER_VALUE_PATTERN = /^\d+(.\d+)?$/;
function convertToPX (line 14) | function convertToPX (styleValue) {
function headingToDOM (line 25) | function headingToDOM (node) {
function getAttrs (line 55) | function getAttrs (dom) {
function paragraphNodeSpecGetAttrs (line 78) | function paragraphNodeSpecGetAttrs (dom) {
function toDOM (line 98) | function toDOM (node) {
function transformCSStoLineHeight (line 126) | function transformCSStoLineHeight (value) {
FILE: src/views/index/api.js
function getDcLibraryList (line 4) | function getDcLibraryList(query) {
function knowledgesOwner (line 13) | function knowledgesOwner(query) {
function delDcLibrary (line 22) | function delDcLibrary(id) {
FILE: src/views/info/icon/iconfont.js
function d (line 1) | function d(){i||(i=!0,n())}
function m (line 1) | function m(){try{o.documentElement.doScroll("left")}catch(t){return void...
FILE: src/views/view/api.js
function getLibTree (line 4) | function getLibTree(id) {
function getLibEditLog (line 13) | function getLibEditLog(params) {
function getLibMember (line 22) | function getLibMember(id,params) {
function getDocumentList (line 31) | function getDocumentList(id) {
Condensed preview — 139 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,028K chars).
[
{
"path": ".browserslistrc",
"chars": 32,
"preview": "> 1%\nlast 2 versions\nnot ie <= 8"
},
{
"path": ".editorconfig",
"chars": 244,
"preview": "# http://editorconfig.org\n\nroot = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size = 2\nend_of_line = lf\ninsert"
},
{
"path": ".eslintrc.js",
"chars": 364,
"preview": "module.exports = {\n root: true,\n env: {\n node: true\n },\n 'extends': [\n \"plugin:vue/essential\"\n"
},
{
"path": ".gitignore",
"chars": 214,
"preview": ".DS_Store\nnode_modules\n/dist\n\n# local env files\n.env.local\n.env.*.local\n\n# Log files\nnpm-debug.log*\nyarn-debug.log*\nyarn"
},
{
"path": ".postcssrc.js",
"chars": 58,
"preview": "module.exports = {\n plugins: {\n autoprefixer: {}\n }\n}"
},
{
"path": "CHANGELOG.sh",
"chars": 1757,
"preview": "#!/bin/bash\n## Author LinkinStar\n\n# solve the space by IFS\nIFS=`echo -en \"\\n\\b\"`\necho -en $IFS\n\nif [ -f \"CHANGELOG.md\" ]"
},
{
"path": "LICENSE",
"chars": 11357,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.en.md",
"chars": 7463,
"preview": "\n\n### Applicable scenarios:\n*Applicable to enterprises and teams, it provides online notes, knowledg"
},
{
"path": "README.md",
"chars": 4070,
"preview": "\n\n### 适用场景:\n* 适用于企业、团队,提供在线笔记、知识沉淀、在线产品手册、知识库、在线电子教程等功能。\n\n### 解决的问题:\n- **数据资产化的问题** :没有合适的文件管理工具,很难"
},
{
"path": "babel.config.js",
"chars": 81,
"preview": "module.exports = {\n presets: [\n ['@vue/app', { useBuiltIns: \"entry\" }]\n ]\n}\n"
},
{
"path": "docker/Dockerfile",
"chars": 294,
"preview": "FROM nginx:1.15.4\nVOLUME /tmp\nENV LANG en_US.UTF-8\nCOPY dist /usr/share/nginx/html/\nENV TZ=Asia/Shanghai\nRUN ln -snf /u"
},
{
"path": "docker/docker-compose.yml",
"chars": 288,
"preview": "version: '3'\nservices:\n jvs-knowledge-ui:\n build:\n context: .\n restart: always\n container_name: jvs-knowl"
},
{
"path": "docker/my.conf",
"chars": 1584,
"preview": "server {\n listen 80;\n server_name localhost;\n add_header X-Content-Type-Options nosniff;\n charset utf-8;\n client_he"
},
{
"path": "expendPlugins/chart/chartmix.css",
"chars": 2750,
"preview": ".luckysheet-datavisual-quick-menu{width:120px;overflow:auto;margin-top:15px}.luckysheet-datavisual-quick-menu::-webkit-s"
},
{
"path": "package.json",
"chars": 1587,
"preview": "{\n \"name\": \"jvs-knowledge-ui\",\n \"version\": \"2020.09.24\",\n \"private\": true,\n \"scripts\": {\n \"pre\": \"cnpm install ||"
},
{
"path": "public/index.html",
"chars": 2994,
"preview": "<!DOCTYPE html>\n<html>\n\n<head>\n <title>无忧 - 企业文档</title>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset="
},
{
"path": "public/jvs-ui-public/cdn/animate/3.5.2/animate.css",
"chars": 52789,
"preview": "@charset \"UTF-8\";\n\n/*!\n * animate.css -http://daneden.me/animate\n * Version - 3.5.1\n * Licensed under the MIT license - "
},
{
"path": "public/jvs-ui-public/cdn/iconfont/1.0.0/index.css",
"chars": 720,
"preview": "\n[class^=\"icon-\"]{\n\tfont-family: \"iconfont\" !important;\n\t/* 以下内容参照第三方图标库本身的规则 */\n\tfont-size: 18px !important;\n\tfont-styl"
},
{
"path": "public/jvs-ui-public/cdn/jvs/jvs.css",
"chars": 1469,
"preview": "html,\nbody,\n#app {\n height: 100%;\n margin: 0;\n padding: 0;\n}\n\n.jvs-home {\n /* background-color: #303133; */\n"
},
{
"path": "public/jvs-ui-public/cdn/store/1.3.20/store.js",
"chars": 7069,
"preview": "'use strict'\n// Module export pattern from\n// https://github.com/umdjs/umd/blob/master/returnExports.js\n;(function (root"
},
{
"path": "public/jvs-ui-public/icon.js",
"chars": 481,
"preview": "$(document).ready(function(){\n htmlobj=$.ajax({url:\"/admin/mainPage/getMainIcon\",async:false,\n success:function(da"
},
{
"path": "src/App.vue",
"chars": 1284,
"preview": "<template>\n <div id=\"app\">\n <div class=\"basic-cont-box\">\n <router-view />\n </div>\n </div>\n</template>\n\n<scr"
},
{
"path": "src/api/common.js",
"chars": 427,
"preview": "import request from '@/router/axios'\n\n// 公共的字典转换接口\nexport function byKeyDicData (url) {\n return request({\n url: url,"
},
{
"path": "src/api/index.js",
"chars": 150,
"preview": "import request from \"@/router/axios\"\n\n// 获取下拉列表\nexport const getSelectData = (str) => {\n return request({\n url: st"
},
{
"path": "src/api/login.js",
"chars": 2861,
"preview": "import request from \"@/router/axios\";\nimport {scope, client_id, client_secret, grant_type} from '@/const/const'\n\nexport "
},
{
"path": "src/api/newDesign.js",
"chars": 1085,
"preview": "import request from '@/router/axios'\n\n// 默认请求\nexport const sendRequire = (url, method, data) => {\n let obj = {\n url:"
},
{
"path": "src/components/QRcode/index.vue",
"chars": 5824,
"preview": "<!-- -->\n<template>\n <div class='weixin'>\n <div\n class=\"weixincode\"\n v-loading=\"URLLoading\"\n >\n <"
},
{
"path": "src/components/api.js",
"chars": 336,
"preview": "import request from '@/router/axios'\n\n// 用户列表\nexport function getUserList(query) {\n return request({\n url: \"/mgr/jvs"
},
{
"path": "src/components/basic-assembly/button.vue",
"chars": 2016,
"preview": "<template>\n <el-button\n :size=\"size || defaultSet.size\"\n :type=\"type || defaultSet.type\"\n :plain=\"plain || def"
},
{
"path": "src/components/basic-assembly/form.vue",
"chars": 16905,
"preview": "<template>\n <el-form\n :model=\"formDatas\"\n :ref=\"refs || defalutSet.refs\"\n :option=\"option || defalutSet.option"
},
{
"path": "src/components/basic-assembly/formcard.vue",
"chars": 12132,
"preview": "<template>\n <div class=\"form-card\">\n <el-tabs :class=\"{'no-data-tab': (!tabData || tabData.length == 0)}\" v-model=\"a"
},
{
"path": "src/components/basic-assembly/formitem.vue",
"chars": 40905,
"preview": "<template>\n <div class=\"jvs-form-item\" style=\"display:flex;align-items:center;\">\n <el-input\n v-model=\"forms[ite"
},
{
"path": "src/components/basic-assembly/levelForm.vue",
"chars": 1354,
"preview": "<template>\n <jvs-tab :active=\"activeName\" type=\"card\" :option=\"levelFormOption\">\n <template v-for=\"item in levelForm"
},
{
"path": "src/components/basic-assembly/stepForm.vue",
"chars": 2580,
"preview": "<template>\n <jvs-tab :active=\"activeName\" type=\"card\" :option=\"stepFormOption\" @tab-click=\"tabClick\">\n <template v-f"
},
{
"path": "src/components/basic-assembly/tab.vue",
"chars": 11021,
"preview": "<template>\n <el-tabs\n v-model=\"activeName\"\n :type=\"option.type || defaultOption.type\"\n :tab-position=\"option.t"
},
{
"path": "src/components/basic-assembly/table.vue",
"chars": 21588,
"preview": "<template>\n <div class=\"jvs-table\">\n <PageHeader :title=\"pageheadertitle\" :class=\"{'jvs-table-titleTop': true, 'jvs-"
},
{
"path": "src/components/basic-assembly/userForm.vue",
"chars": 6044,
"preview": "<template>\n <div class=\"user-info-list\">\n <div>\n <el-input size=\"mini\" placeholder=\"请选择用户\" :disabled=\"disableBo"
},
{
"path": "src/components/basic-assembly/userSelector.vue",
"chars": 10512,
"preview": "<template>\n <el-dialog\n title=\"请选择成员\"\n :visible.sync=\"dialogVisible\"\n :before-close=\"closeDialog\"\n append-t"
},
{
"path": "src/components/basic-container/loading.vue",
"chars": 1387,
"preview": "<template>\n <div class=\"jvs-loading\">\n <div class=\"content\">\n <div class=\"img-box\"></div>\n <div class=\"tit"
},
{
"path": "src/components/basic-container/login/loginForm.vue",
"chars": 28351,
"preview": "<template>\n <div>\n <el-dialog\n ref=\"loginComDialog\"\n :modal=\"modal\"\n :class=\"{'login-component-dialog"
},
{
"path": "src/components/basic-container/main.vue",
"chars": 674,
"preview": "<template>\n <div :class=\"{'basic-container': true, 'basic-container--block':block}\">\n <!-- <el-card> -->\n <slot"
},
{
"path": "src/components/doc-lib/api.js",
"chars": 678,
"preview": "import request from '@/router/axios'\n\n// 保存文档\nexport const saveContent = (contentId, data) => {\n return request({\n u"
},
{
"path": "src/components/doc-lib/excel/index.vue",
"chars": 4258,
"preview": "<template>\n <div class=\"hello\">\n <div style=\"position: absolute; top: 0\">\n <!-- <input style=\"font-size: 16px\" "
},
{
"path": "src/components/doc-lib/flow/index.vue",
"chars": 729,
"preview": "<template>\n <div class=\"home\">\n <!-- 使用topology组件 -->\n <topology\n :data=\"content\"\n id=\"previewFalse\"\n "
},
{
"path": "src/components/doc-lib/html/index.vue",
"chars": 2675,
"preview": "<template>\n <div class=\"html-design\">\n <el-tiptap\n height=\"100%\"\n :extensions=\"extensions\"\n :content="
},
{
"path": "src/components/doc-lib/index.vue",
"chars": 11875,
"preview": "<template>\n <div class=\"doc-lib-box\">\n <title-page-header @save=\"saveHandle\" @close=\"close\">\n <template slot=\"l"
},
{
"path": "src/components/doc-lib/map/index.vue",
"chars": 2187,
"preview": "<template>\n <div class=\"outer\">\n <div id=\"map\" style=\"width: 1000px; height: 500px\"></div>\n </div>\n</template>\n\n<sc"
},
{
"path": "src/components/doc-lib/show.vue",
"chars": 5632,
"preview": "<template>\n <div class=\"doc-lib-show preview-editor-context\">\n <topology v-if=\"type == 'document_flow'\" preview=\"tru"
},
{
"path": "src/components/error-page/404.vue",
"chars": 2271,
"preview": "<template>\n <div class=\"error404\">\n <div class=\"error404-body-con\">\n <el-card class=\"box-card page-404-box\">\n "
},
{
"path": "src/components/iframe/main.vue",
"chars": 4262,
"preview": "<template>\n <div>\n <basic-container>\n <!-- 顶部菜单nav -->\n <menuNav />\n <div class=\"outer-container\">\n "
},
{
"path": "src/components/index.js",
"chars": 764,
"preview": "import Vue from 'vue'\nimport basicContainer from './basic-container/main'\nimport jvsForm from './basic-assembly/form'\nim"
},
{
"path": "src/components/page-footer/FooterContent.vue",
"chars": 4755,
"preview": "<template>\n <div class=\"footer-box\">\n <div class=\"content-wrapper wrapped\">\n <div class=\"link-box\">\n <di"
},
{
"path": "src/components/page-header/PageHeader.vue",
"chars": 1229,
"preview": "<template>\n <el-card :body-style=\"{padding: title ? '10px 0' : 0}\" :class=\"{'header-top-open': show, 'header-top-close'"
},
{
"path": "src/components/page-header/titlePageHeader.vue",
"chars": 3617,
"preview": "<template>\n <div :class=\"{ 'title-page-header': true, 'header-top-open': show, 'header-top-close': !show }\">\n <div :"
},
{
"path": "src/config/env.js",
"chars": 543,
"preview": "// 配置编译环境和线上环境之间的切换\nconst env = process.env\nlet baseUrl = ''\nlet iconfontVersion = ['567566_qo5lxgtishg', '667895_v7uduh"
},
{
"path": "src/const/chinaArea.js",
"chars": 209627,
"preview": "export const areaList =\n[\n\t{\n\t\t\"code\": \"110000\",\n\t\t\"name\": \"北京市\",\n\t\t\"children\": [\n\t\t\t{\n\t\t\t\t\"code\": \"110000\",\n\t\t\t\t\"name\""
},
{
"path": "src/const/columnTypeList.js",
"chars": 3046,
"preview": "/**\n * 数值 支持查询条件(等于 大于 小于 大于等于 小于等于 区间)\n**/\n\nconst NUMBER_QUERY_TYPE = ['EQ', 'NE', 'GT', 'GE', 'LT', 'LE', 'BETWEEN']\nc"
},
{
"path": "src/const/const.js",
"chars": 776,
"preview": "import { Base64 } from 'js-base64'\nexport const scope = \"server\";\nexport const client_id = \"knowledge\";\nexport const cli"
},
{
"path": "src/const/errorCode.js",
"chars": 74,
"preview": "export default {\n '000': '操作太频繁,请勿重复请求',\n 'default': '系统未知错误,请反馈给管理员'\n}\n"
},
{
"path": "src/const/iconList.js",
"chars": 1069,
"preview": "export default [\n {\n label: '图标',\n list: [\n 'icon-quanxianguanli',\n 'icon-yonghuguanli',\n 'icon-ji"
},
{
"path": "src/const/iconfont.js",
"chars": 4992,
"preview": "export default [\n 'icon-caizhengting',\n 'icon-caidanguanli4',\n 'icon-daiban1',\n 'icon-daibandengdaishenhe',\n"
},
{
"path": "src/const/systemIcon.js",
"chars": 4896,
"preview": "export default [\n \"icon-tishi\", \n \"icon-tishi1\", \n \"icon-xiaoxi\", \n \"icon-icon-operation\", \n \"icon-xiaoxi1\", \n \"ic"
},
{
"path": "src/const/website.js",
"chars": 632,
"preview": "export default {\n title: '文档',\n logo: '菜单',\n key: 'jvs', //配置主键,目前用于存储\n indexTitle: '文档',\n whiteList: ['/login', "
},
{
"path": "src/error.js",
"chars": 435,
"preview": "import Vue from 'vue'\n\nVue.config.errorHandler = function (err, vm, info) {\n Vue.nextTick(() => {\n if (process.env.N"
},
{
"path": "src/filters/index.js",
"chars": 3821,
"preview": "function pluralize (time, label) {\n if (time === 1) {\n return time + label\n }\n return time + label + 's'\n}\n\n/**\n *"
},
{
"path": "src/main.js",
"chars": 1962,
"preview": "import 'babel-polyfill'\nimport 'classlist-polyfill'\nimport Vue from 'vue'\nimport axios from './router/axios'\nimport VueA"
},
{
"path": "src/permission.js",
"chars": 1341,
"preview": "/**\n * 全站权限配置\n *\n */\nimport router from './router/router'\nimport store from '@/store'\nimport {validatenull} from '@/util"
},
{
"path": "src/router/axios.js",
"chars": 5819,
"preview": "import { serialize, noEmptyOfObject } from \"@/util/util\";\nimport { getStore } from \"../util/store\";\nimport NProgress fro"
},
{
"path": "src/router/jvs-router.js",
"chars": 2947,
"preview": "import Axios from \"axios\";\n\nlet RouterPlugin = function() {\n this.$router = null;\n this.$store = null;\n};\nRouterPlugin"
},
{
"path": "src/router/page/index.js",
"chars": 567,
"preview": "export default [\n\t{\n path: '/404',\n component: () =>\n import ( /* webpackChunkName: \"page\" */ '"
},
{
"path": "src/router/router.js",
"chars": 915,
"preview": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\nimport jvsRouter from './jvs-router'\nimport Store from '../stor"
},
{
"path": "src/router/views/index.js",
"chars": 1394,
"preview": "export default [\n {\n path: \"/page\",\n name: \"首页\",\n component: () =>\n import(/* webpackChunkName: \"page\" */"
},
{
"path": "src/store/getters.js",
"chars": 1285,
"preview": "import * as globalTypes from \"./types/global\";\nconst getters = {\n tag: state => state.tags.tag,\n website: state => sta"
},
{
"path": "src/store/index.js",
"chars": 1323,
"preview": "import Vue from 'vue'\nimport Vuex from 'vuex'\nimport common from './modules/common'\nimport user from './modules/user'\nim"
},
{
"path": "src/store/modules/common.js",
"chars": 4376,
"preview": "import { getStore, removeStore, setStore } from \"@/util/store\";\nimport website from \"@/const/website\";\nconst common = {\n"
},
{
"path": "src/store/modules/konwledge.js",
"chars": 430,
"preview": "import { getStore, removeStore, setStore } from '@/util/store'\nconst konwledge = {\n state: {\n konwledgeInfo: getStor"
},
{
"path": "src/store/modules/tags.js",
"chars": 2279,
"preview": "import { getStore, setStore } from '@/util/store'\nimport { diff } from '@/util/util'\nimport website from '@/const/websit"
},
{
"path": "src/store/modules/user.js",
"chars": 8956,
"preview": "import { getStore, setStore } from \"@/util/store\";\nimport { isURL } from \"@/util/validate\";\nimport {\n loginByUsername,\n"
},
{
"path": "src/store/types/global.js",
"chars": 305,
"preview": "/*\n * @component global.js\n * @description 全局类型\n * @author wangying\n */\n\n// actions\n\n// getters\nexport const GET_DIRECTI"
},
{
"path": "src/styles/animate/vue-transition.scss",
"chars": 1003,
"preview": "// 过渡动画 横向渐变\n.fade-transverse-leave-active,\n.fade-transverse-enter-active {\n transition: all .5s;\n}\n\n.fade-transverse"
},
{
"path": "src/styles/common.scss",
"chars": 551,
"preview": "// 全局变量\n@import './variables.scss';\n// ele样式覆盖\n@import './element-ui.scss';\n// 顶部右侧显示\n@import './top.scss';\n// 导航标签\n@imp"
},
{
"path": "src/styles/element-ui.scss",
"chars": 1357,
"preview": ".el-dropdown-menu__item {\n font-size: 12px !important;\n line-height: 28px !important;\n}\n\n.el-card.is-always-shadow {\n "
},
{
"path": "src/styles/login.scss",
"chars": 2998,
"preview": "\n.login-container {\n display: flex;\n align-items: center;\n position: relative;\n width: 100%;\n height: 100%;\n margi"
},
{
"path": "src/styles/media.scss",
"chars": 2869,
"preview": ".jvs-left,\n.jvs-header,\n.jvs-top,\n.jvs-logo,\n.jvs-layout\n.login-logo,\n.jvs-main {\n transition: all .3s;\n}\n.jvs-contai"
},
{
"path": "src/styles/mixin.scss",
"chars": 1757,
"preview": "@mixin clearfix {\n &:after {\n content: \"\";\n display: table;\n clear: both;\n }\n}\n\n@mixin scroll"
},
{
"path": "src/styles/normalize.scss",
"chars": 9915,
"preview": "/*! normalize.css v2.1.2 | MIT License | git.io/normalize */\n/*\n/*! 我就是自己看看,然后翻译下下,让大家看看 */\n\n/* ========================"
},
{
"path": "src/styles/reset2.0.scss",
"chars": 5168,
"preview": "// 弹框\n.el-dialog__wrapper:not(.form-fullscreen-dialog){\n .el-dialog{\n .el-dialog__header{\n height: 20px;\n "
},
{
"path": "src/styles/resetAll.scss",
"chars": 4706,
"preview": "/**\n * 统一修改\n * 全屏弹框的表单、\n * 表格\n * 按钮\n*/\n\n// 全屏表单 form-fullscreen-dialog\n.form-fullscreen-dialog{\n .el-dialog.is-ful"
},
{
"path": "src/styles/sidebar.scss",
"chars": 2091,
"preview": ".jvs-sidebar {\n user-select: none;\n position: relative;\n margin-top: 64px;\n height: 100%;\n position: relative;\n //"
},
{
"path": "src/styles/tags.scss",
"chars": 2345,
"preview": "\n\n.jvs-tags {\n user-select: none; \n position: relative;\n padding: 0 10px;\n margin-bottom: 10px;\n box-sizi"
},
{
"path": "src/styles/themes/common/mixins.scss",
"chars": 379,
"preview": "// 主题映射方法\n@mixin themify($themes: $themes) {\n @each $theme-name, $map in $themes {\n .theme-#{$theme-name} & {\n "
},
{
"path": "src/styles/themes/common/variables.scss",
"chars": 620,
"preview": "// theme\n$left-width: 295px;\n$white-color: white;\n$black-color: black;\n$font-family: 'SourceHanSansCN';\n$themes: (\n lig"
},
{
"path": "src/styles/themes/index.scss",
"chars": 1923,
"preview": "@import './common/variables';\n@import './common/mixins';\n\n.theme-box {\n @include themify() {\n color: themed('primary"
},
{
"path": "src/styles/tiptap.scss",
"chars": 45,
"preview": ".el-tiptap-popper__menu{\n padding: 0 12px;\n}"
},
{
"path": "src/styles/tiptapView.scss",
"chars": 120,
"preview": ".htmShow .el-tiptap-editor__menu-bar{\n display: none;\n}\n.htmShow .el-tiptap-editor__menu-bubble{\n display: none;\n}"
},
{
"path": "src/styles/top.scss",
"chars": 1752,
"preview": ".jvs-top {\n padding: 0 20px;\n position: relative;\n box-shadow: 0 1px 4px rgba(0,21,41,.08);\n color: rgba(0, "
},
{
"path": "src/styles/variables.scss",
"chars": 25,
"preview": "//main\n$mainBg: #f5f5f5;\n"
},
{
"path": "src/util/date.js",
"chars": 1417,
"preview": "/**\n * wyQAQ\n * 1396871452@qq.com\n */\nexport const calcDate = (date1, date2) => {\n var date3 = date2 - date1\n\n var day"
},
{
"path": "src/util/eventBus.js",
"chars": 135,
"preview": "import Vue from 'vue';\nimport {declare} from '@/views/common/draw'\nexport default new Vue();\nwindow.onload = function() "
},
{
"path": "src/util/login.js",
"chars": 433,
"preview": "/**\n * wyQAQ\n * 1396871452@qq.com\n */\nimport Vue from 'vue'\nimport loginForm from '@/components/basic-container/login/lo"
},
{
"path": "src/util/permision.js",
"chars": 1102,
"preview": "import store from '@/store'\nexport default {\n install (Vue, options) {\n // 权限匹配\n /**\n * \n * @param {Strin"
},
{
"path": "src/util/store.js",
"chars": 1937,
"preview": "/**\n * wyQAQ\n * 1396871452@qq.com\n */\nimport {\n validatenull\n} from '@/util/validate'\nimport website from '@/const/webs"
},
{
"path": "src/util/url.js",
"chars": 523,
"preview": "/**\n * wyQAQ\n * 1396871452@qq.com\n */\nimport Vue from 'vue'\nexport default {\n install (Vue, options) {\n // 打开链接 用于 预"
},
{
"path": "src/util/util.js",
"chars": 8250,
"preview": "import {validatenull} from './validate'\nimport request from '@/router/axios'\nimport * as CryptoJS from'crypto-js'\n\n// 表单"
},
{
"path": "src/util/validate.js",
"chars": 5224,
"preview": "/**\n * wyQAQ\n * 1396871452@qq.com\n */\n/**\n * 邮箱\n * @param {*} s\n */\nexport function isEmail (s) {\n return /^([a-zA-Z0-9"
},
{
"path": "src/views/catalogview/index.vue",
"chars": 5349,
"preview": "<template>\n <div class=\"catalogview\">\n <div class=\"top\">\n <div class=\"left\">\n <figure>\n <img sr"
},
{
"path": "src/views/common/Comment.vue",
"chars": 10184,
"preview": "<template>\n <div class=\"communication\">\n <ul style=\"position:relative\">\n <li>\n <i class=\"iconfont icon-r"
},
{
"path": "src/views/common/KnowSet.vue",
"chars": 6921,
"preview": "<template>\n <div>\n <h3 class=\"hfm\">封面</h3>\n <div class=\"backCont\">\n <div class=\"back\">\n <!-- <img sty"
},
{
"path": "src/views/common/LuckySheet.vue",
"chars": 4603,
"preview": "<template>\n <div class=\"hello\">\n <div style=\"position: absolute; top: 0\">\n <!-- <input style=\"font-size: 16px\" "
},
{
"path": "src/views/common/MemberSet.vue",
"chars": 15638,
"preview": "<template>\n <div class=\"member-set-info\">\n <div :class=\"{'member-list': true}\">\n <div class=\"member-list-loadin"
},
{
"path": "src/views/common/MindElixir.vue",
"chars": 2207,
"preview": "<template>\n <div class=\"outer\">\n <div id=\"map\"></div>\n </div>\n</template>\n\n<script>\nimport MindElixir, { E } from \""
},
{
"path": "src/views/common/Tiptap.vue",
"chars": 10411,
"preview": "<template>\n <div class=\"el-tiptap-editor__wrapper\" v-if=\"type == 'document_html'\" ref=\"paste\" @paste.stop.prevent=\"past"
},
{
"path": "src/views/common/Topology.vue",
"chars": 1491,
"preview": "<template>\n <div class=\"home my-topology\">\n <!-- 使用topology组件 -->\n <topology\n :data=\"content\"\n id=\"prev"
},
{
"path": "src/views/common/api.js",
"chars": 2857,
"preview": "import request from '@/router/axios'\n\n// 获取目录树\nexport function documentSearch(params) {\n return request({\n url: `/mg"
},
{
"path": "src/views/common/draw.js",
"chars": 584,
"preview": "import { consoleDraw } from '@/util/util'\nexport const declare = () => {\n consoleDraw('%c此框架为公共免费使用,为保证大家有一个流畅的使用环境,特此将"
},
{
"path": "src/views/common/search.vue",
"chars": 6481,
"preview": "<template>\n <div class=\"knowledge-search-com\">\n <h5 v-if=\"listData && listData.length > 0\" class=\"total-title\">找到<b>"
},
{
"path": "src/views/common/show.vue",
"chars": 10079,
"preview": "<template>\n <div class=\"doc-lib-show preview-editor-context\">\n <topology v-if=\"type == 'document_flow'\" preview=\"tru"
},
{
"path": "src/views/common/tiptap/extension.js",
"chars": 1507,
"preview": "import {Heading, FontSize} from 'element-tiptap'\nimport {convertToPX, headingToDOM, ParagraphNodeSpec, getAttrs} from '."
},
{
"path": "src/views/common/tiptap/tiptapPlugin.js",
"chars": 2923,
"preview": "import { v4 as uuidv4 } from 'uuid';\nconst SIZE_PATTERN = /([\\d.]+)(px || pt)/i;\nexport const Alignment = {\n left: 'lef"
},
{
"path": "src/views/common/toolbar.vue",
"chars": 4231,
"preview": "<template>\n <div class=\"knowledge-tool-bar\">\n <!-- , 'directory' -->\n <!-- <p v-if=\"['knowledge'].indexOf(nodeInf"
},
{
"path": "src/views/common/topbar.vue",
"chars": 7448,
"preview": "<template>\n <div class=\"knowledge-top-bar\">\n <div class=\"left\" @click=\"goHome\">\n <img :src=\"logoImg\" />\n </d"
},
{
"path": "src/views/companyInfo/index.vue",
"chars": 3915,
"preview": "<template>\n <div>\n <topbar :inKeyword=\"topKeyword\" @searchChange=\"allSearchChange\"></topbar>\n <div class=\"company"
},
{
"path": "src/views/index/api.js",
"chars": 517,
"preview": "import request from '@/router/axios'\n\n// 查询用户有权限的知识库\nexport function getDcLibraryList(query) {\n return request({\n ur"
},
{
"path": "src/views/index/baseInfo.vue",
"chars": 12323,
"preview": "<template>\n <div class=\"base-info\">\n <div class=\"left\">\n <div class=\"base\">\n <ul>\n <li v-for=\"i"
},
{
"path": "src/views/index/index.vue",
"chars": 7112,
"preview": "<template>\n <div class=\"knowledge-index-page\">\n <div v-if=\"systemJud\">\n <p class=\"phoneSym\">手机端暂不支持</p>\n </d"
},
{
"path": "src/views/index/page.vue",
"chars": 6553,
"preview": "<template>\n <div class=\"not-login-page\">\n <div class=\"banner\">\n <div class=\"text-desc\">\n <h4>企业内部在线文档</h"
},
{
"path": "src/views/info/icon/demo.css",
"chars": 8305,
"preview": "/* Logo 字体 */\n@font-face {\n font-family: \"iconfont logo\";\n src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.e"
},
{
"path": "src/views/info/icon/demo_index.html",
"chars": 13167,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\"/>\n <title>iconfont Demo</title>\n <link rel=\"shortcut icon\" href="
},
{
"path": "src/views/info/icon/iconfont.css",
"chars": 843,
"preview": "@font-face {\n font-family: \"iconfont\"; /* Project id 2656771 */\n src: url('iconfont.woff2?t=1628043039155') format('wo"
},
{
"path": "src/views/info/icon/iconfont.js",
"chars": 8218,
"preview": "!function(t){var e,c,n,o,i,a='<svg><symbol id=\"icon-icon\" viewBox=\"0 0 1024 1024\"><path d=\"M967.111111 227.555556c0-125."
},
{
"path": "src/views/info/icon/iconfont.json",
"chars": 1488,
"preview": "{\n \"id\": \"2656771\",\n \"name\": \"1\",\n \"font_family\": \"iconfont\",\n \"css_prefix_text\": \"icon-\",\n \"description\": \"\",\n \"g"
},
{
"path": "src/views/info/index.vue",
"chars": 11702,
"preview": "<template>\n <div>\n <div class=\"infoZhan\" v-if=\"infoShow\" :style=\"'width:calc(100% - '+ treeWidth +'px );'\"></div>\n "
},
{
"path": "src/views/main/wx/login.vue",
"chars": 2238,
"preview": "<template>\n <div></div>\n</template>\n<script>\nimport { mapGetters } from 'vuex'\nexport default {\n computed: {\n ...ma"
},
{
"path": "src/views/my/icon/index.js",
"chars": 667,
"preview": "import docType from './wendang.png'\nimport set from './shezhi.png'\nimport share from './fenxiang.png'\nimport liebiao fro"
},
{
"path": "src/views/view/api.js",
"chars": 704,
"preview": "import request from '@/router/axios'\n\n// 获取目录树\nexport function getLibTree(id) {\n return request({\n url: `/mgr/docume"
},
{
"path": "src/views/view/diclibApi.js",
"chars": 1591,
"preview": "import request from '@/router/axios'\n\n// 分页查询\nexport const pageList = (params) => {\n return request({\n url: `/mgr/do"
},
{
"path": "src/views/view/index.vue",
"chars": 42794,
"preview": "<template>\n <div class=\"konwledge-base-view\">\n <topbar :inKeyword=\"topKeyword\" @searchChange=\"allSearchChange\"></top"
},
{
"path": "vue.config.js",
"chars": 1961,
"preview": "/**\n * 配置该文件可以参考:\n * https://cli.vuejs.org/zh/config/#%E7%9B%AE%E6%A0%87%E6%B5%8F%E8%A7%88%E5%99%A8\n *\n */\nconst url = \""
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the RKQF-JVS/jvs-knowledge-ui GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 139 files (829.6 KB), approximately 262.0k tokens, and a symbol index with 107 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.