Full Code of RKQF-JVS/jvs-knowledge-ui for AI

main 8e8e742249ab cached
139 files
829.6 KB
262.0k tokens
107 symbols
1 requests
Download .txt
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
================================================
![输入图片说明](img/1.png)

### 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:
![输入图片说明](img/2.png)
![输入图片说明](img/3.png)
-
![输入图片说明](img/4.png)
-
![输入图片说明](img/5.png)
-
![输入图片说明](img/6.png)
![输入图片说明](img/7.png)
![输入图片说明](img/8.png)
### 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
================================================
![输入图片说明](img/1.png)

### 适用场景:
* 适用于企业、团队,提供在线笔记、知识沉淀、在线产品手册、知识库、在线电子教程等功能。

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

**无忧·企业文档=企业级知识库+在线编辑工具集+企业搜索引擎+内容展示平台**
![输入图片说明](img/%E5%9C%BA%E6%99%AF%E5%9B%BE%E7%89%87%E4%BB%8B%E7%BB%8D.png)


### 技术栈选择

- 前端: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


### **体验地址与账号说明**
![输入图片说明](img/image%E8%B4%A6%E5%8F%B7.png)
账号说明:

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


地址说明:
![输入图片说明](img/jvs%E4%BA%A7%E5%93%81%E4%BD%93%E7%B3%BB.png)
- 管理平台(含管理平台、低代码):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/


部分截图:

![image](https://github.com/RKQF-JVS/jvs-knowledge-ui/assets/94048608/bcbbfb87-708c-43d6-91ff-51c4b28b94b5)
-
![image](https://github.com/RKQF-JVS/jvs-knowledge-ui/assets/94048608/64c35f5a-8883-4172-81af-b616d63358c1)
-
![image](https://github.com/RKQF-JVS/jvs-knowledge-ui/assets/94048608/f8db8da0-5b2a-44d5-a66b-2105932445f1)
-
![image](https://github.com/RKQF-JVS/jvs-knowledge-ui/assets/94048608/381bddbf-8a54-4ff0-9e55-73d83216c36a)
-
![image](https://github.com/RKQF-JVS/jvs-knowledge-ui/assets/94048608/9064a8c0-6654-4d18-92ce-3d0852cde622)
-
![image](https://github.com/RKQF-JVS/jvs-knowledge-ui/assets/94048608/b59eb016-e933-44a1-be57-1ef14875b2d9)
-
![image](https://github.com/RKQF-JVS/jvs-knowledge-ui/assets/94048608/b55a225a-4592-41b2-93f4-258487f47830)
-
![image](https://github.com/RKQF-JVS/jvs-knowledge-ui/assets/94048608/e2243775-9d0a-470e-b65a-bc13b7baf8f4)
-
![image](https://github.com/RKQF-JVS/jvs-knowledge-ui/assets/94048608/08bca2d9-b472-41a2-bcc2-0ac1afd6fe3f)

-



### 快速部署文档
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" />


























如因人数限制无法加群时,可加运营同学拉入技术交流群

![谭京](https://github.com/user-attachments/assets/53838ea6-d0c7-4bb1-abf2-cdfb99cb9743)



### 历史更新记录:
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(/&lt;/g, "<")
          _this.form[prop] = _this.form[prop].replace(/&gt;/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.
Download .txt
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
Download .txt
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": "![输入图片说明](img/1.png)\n\n### Applicable scenarios:\n*Applicable to enterprises and teams, it provides online notes, knowledg"
  },
  {
    "path": "README.md",
    "chars": 4070,
    "preview": "![输入图片说明](img/1.png)\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.

Copied to clipboard!