From 08690e2fd123a710406a101a2a5bd98fa0992502 Mon Sep 17 00:00:00 2001
From: gjj <Ganjj@probim.com.cn>
Date: Tue, 07 Feb 2023 17:20:34 +0800
Subject: [PATCH] 项目迁移

---
 src/assets/img/unfold.png                                                |    0 
 src/views/OAManagement/examine/components/content.vue                    |  222 
 src/assets/img/c_curomer.png                                             |    0 
 src/assets/aside/workbench.png                                           |    0 
 src/views/OAManagement/task/components/subTask.vue                       |  324 
 src/views/OAManagement/task/components/particulars.vue                   | 2080 +
 src/assets/fonts/demo_index.html                                         |  329 
 src/assets/img/project/task_tag.png                                      |    0 
 src/assets/aside/total_active.png                                        |    0 
 src/assets/img/selection_add_user.png                                    |    0 
 src/views/clients/product/ProductIndex.vue                               |  591 
 src/api/businessIntelligence/index.js                                    |   72 
 src/views/clients/components/CRMCreateView.vue                           | 2201 +
 src/assets/aside/total.png                                               |    0 
 src/components/CreateCom/XhDateTime.vue                                  |   43 
 src/components/CreateCom/CrmRelative.vue                                 |  377 
 src/components/vuePictureViewer/img/pre_close.png                        |    0 
 build/vue-loader.conf.js                                                 |   22 
 src/api/login.js                                                         |   62 
 src/assets/img/step_success.png                                          |    0 
 src/assets/401_images/401.gif                                            |    0 
 src/components/CreateCom/XhRelativeInput.vue                             |  226 
 src/assets/aside/dilivery.png                                            |    0 
 src/directives/photo/index.js                                            |   91 
 src/assets/css/normalize.css                                             |  460 
 src/components/CreateCom/XhDate.vue                                      |   29 
 src/components/CreateCom/arrayMixin.js                                   |   44 
 src/components/Examine/CheckFlow.vue                                     |  237 
 src/components/SlideView.vue                                             |  129 
 src/assets/img/update_files.png                                          |    0 
 src/views/OAManagement/examine/components/examineCategorySelect.vue      |  148 
 src/views/OAManagement/journal/newDialog.vue                             |  616 
 src/directives/focus.js                                                  |    7 
 src/assets/img/file_img.png                                              |    0 
 src/assets/img/system/app/crm_disable.png                                |    0 
 src/views/OAManagement/journal/content.vue                               |  217 
 src/assets/img/system/app/call_disable.png                               |    0 
 src/views/welcome/Welcome.vue                                            |   13 
 src/utils/emoji-data.js                                                  |    3 
 src/views/clients/businessContracts/BusinessContractsIndex.vue           |  264 
 src/assets/img/crm_multiuser.png                                         |    0 
 package-lock.json                                                        | 14372 ++++++++++
 src/assets/img/zhibiao.png                                               |    0 
 src/components/Examine/ExamineInfo.vue                                   |  443 
 src/views/OAManagement/task/mixins/listTaskDetail.js                     |   64 
 src/api/customermanagement/business.js                                   |  129 
 src/assets/aside/personnel_active.png                                    |    0 
 src/assets/aside/customer_active.png                                     |    0 
 src/assets/img/jd_business.png                                           |    0 
 src/views/clients/components/followLog/components/FollowRecordCell.vue   |  437 
 src/views/clients/mixins/table.js                                        |  791 
 src/views/clients/contacts/ContactsDetail.vue                            |  240 
 src/assets/img/work_task.png                                             |    0 
 src/assets/img/field_leads_manager.png                                   |    0 
 src/assets/img/section_reset_name.png                                    |    0 
 src/assets/img/collapse_gray.png                                         |    0 
 src/assets/img/follow_record.png                                         |    0 
 src/assets/img/goOut.png                                                 |    0 
 src/assets/img/work_examine.png                                          |    0 
 src/components/CreateCom/XhRelativeInputS.vue                            |  214 
 src/assets/img/contacts_detail.png                                       |    0 
 src/views/404.vue                                                        |   88 
 src/views/clients/components/CRMAllDetail.vue                            |  179 
 src/views/clients/businessChances/BusinessChancesDetail.vue              |  694 
 src/assets/img/work_statistics.png                                       |    0 
 src/assets/img/selection_delete_user.png                                 |    0 
 src/components/CreateCom/XhUserCell.vue                                  |  162 
 src/assets/img/project/project_filtrate.png                              |    0 
 src/components/CreateCom/CrmRelativeTable.vue                            |  590 
 src/assets/aside/business_active.png                                     |    0 
 src/assets/img/c_log.png                                                 |    0 
 src/components/CreateCom/XhUser.vue                                      |  240 
 src/api/customermanagement/offer.js                                      |   62 
 src/assets/img/button_add_black.png                                      |    0 
 src/views/clients/components/duplicateCheck/checkContent.vue             |  336 
 src/views/clients/business/components/BusinessFollow.vue                 |  208 
 src/assets/img/system/app/project_enable.png                             |    0 
 src/assets/img/system/schedule_module.png                                |    0 
 src/assets/img/add_task.png                                              |    0 
 src/components/CreateCom/index.js                                        |   21 
 config/dev.env.js                                                        |    8 
 src/components/vuePictureViewer/img/pre_left.png                         |    0 
 src/views/clients/components/RelativeReturnMoney.vue                     |  451 
 src/assets/img/task_add.png                                              |    0 
 src/views/clients/mixins/followLogType.js                                |  102 
 src/components/flexbox/index.js                                          |    7 
 src/assets/img/jianbao.png                                               |    0 
 src/assets/img/project/task_ellipsis.png                                 |    0 
 src/views/OAManagement/task/index.vue                                    |  266 
 src/views/clients/components/followLog/styles/followcell.scss            |  174 
 src/components/selectEmployee/membersDep.vue                             |  622 
 src/assets/img/c_filtrate.png                                            |    0 
 src/views/clients/clue/components/ClueFollow.vue                         |  169 
 src/assets/img/system/app/phone.png                                      |    0 
 src/views/OAManagement/addressBook/staff.vue                             |   75 
 src/assets/img/relevance_business.png                                    |    0 
 src/views/clients/businessContracts/BusinessContractsDetail.vue          |  217 
 src/styles/mixin.scss                                                    |   44 
 src/assets/img/head.png                                                  |    0 
 src/assets/img/task_close.png                                            |    0 
 src/views/OAManagement/workbench/schedule.vue                            |  236 
 src/styles/xr-theme.css                                                  |    9 
 build/webpack.dev.conf.js                                                |   97 
 src/components/vuePictureViewer/img/pre_min.png                          |    0 
 src/components/CreateCom/XhReceivablesPlan.vue                           |   70 
 src/assets/img/close.png                                                 |    0 
 src/views/OAManagement/workbench/tabsContent.vue                         |  262 
 src/assets/img/login/login_bg.png                                        |    0 
 src/assets/aside/delete.png                                              |    0 
 src/views/clients/mixins/detail.js                                       |  127 
 src/components/MapView.vue                                               |   93 
 src/views/clients/styles/followcell.scss                                 |  170 
 src/views/clients/components/RelativeProduct.vue                         |  391 
 src/assets/img/smiling_face.png                                          |    0 
 src/assets/img/system/leads_pool_module.png                              |    0 
 src/assets/fonts/iconfont.json                                           |   58 
 src/views/clients/model/crmTypeModel.js                                  |   12 
 src/views/clients/components/RelativeHandle.vue                          |  161 
 src/assets/img/journal_comment.png                                       |    0 
 src/assets/img/login/login.png                                           |    0 
 src/components/vuePictureViewer/img/pre_down.png                         |    0 
 src/views/OAManagement/components/relatedBusinessCell/index.vue          |  115 
 src/views/clients/components/RelativeBusiness.vue                        |  409 
 src/styles/transition.scss                                               |   46 
 src/assets/img/project/smiling_face.png                                  |    0 
 src/utils/dist/request.dev.js                                            |  119 
 src/assets/img/project/task_end_time.png                                 |    0 
 package.json                                                             |  104 
 src/assets/aside/order.png                                               |    0 
 src/assets/aside/business.png                                            |    0 
 src/views/OAManagement/journal/index.vue                                 |  383 
 src/components/flexbox/flexbox.vue                                       |   81 
 src/assets/img/project/schedule.png                                      |    0 
 build/check-versions.js                                                  |   54 
 src/views/OAManagement/notice/newDialog.vue                              |  340 
 src/assets/img/contract_detail.png                                       |    0 
 src/assets/img/send_business.png                                         |    0 
 src/assets/img/add_schedule.png                                          |    0 
 src/views/OAManagement/examine/components/relatedBusiness.vue            |  141 
 src/views/clients/components/RelativeApproval.vue                        |  239 
 src/assets/img/system/app/oa_enable.png                                  |    0 
 src/assets/img/selection_lock.png                                        |    0 
 src/components/HelloWorld.vue                                            |  113 
 src/views/clients/styles/detailview.scss                                 |   15 
 src/store/modules/user.js                                                |  134 
 src/views/OAManagement/journal/journalCell.vue                           |  814 
 src/store/index.js                                                       |   24 
 src/assets/img/accessory.png                                             |    0 
 src/views/clients/components/duplicateCheck/index.vue                    |  124 
 src/views/company/ApartmentManage.vue                                    |  466 
 src/assets/img/project/task_subtask.png                                  |    0 
 src/assets/img/file_txt.png                                              |    0 
 src/views/clients/components/RelativeOffers.vue                          |  324 
 src/api/systemManagement/officalAuthority.js                             |   42 
 src/assets/img/sea_detail.png                                            |    0 
 src/components/CreateCom/objMixin.js                                     |   42 
 static/.gitkeep                                                          |    0 
 src/assets/img/clue_detail.png                                           |    0 
 src/assets/img/work_schedule.png                                         |    0 
 src/utils/types.js                                                       |   11 
 src/utils/index.js                                                       |  501 
 src/components/vuePictureViewer/img/pre_right.png                        |    0 
 src/views/clients/business/BusinessDetail.vue                            |  726 
 src/assets/fonts/iconfont.woff2                                          |    0 
 src/assets/img/task_accessory.png                                        |    0 
 src/views/clients/contract/components/ContractFollow.vue                 |  197 
 src/assets/img/business_dot.png                                          |    0 
 src/components/CreateCom/XhSelect.vue                                    |   67 
 src/assets/fonts/iconfont.woff                                           |    0 
 src/assets/img/file_pdf.png                                              |    0 
 src/api/customermanagement/contract.js                                   |   62 
 src/assets/img/cancel_associated.png                                     |    0 
 src/styles/index.scss                                                    |  223 
 src/components/CreateCom/stringMixin.js                                  |   49 
 src/utils/baseconfig.js                                                  |    5 
 src/assets/img/fold.png                                                  |    0 
 src/assets/img/nopermission.png                                          |    0 
 src/views/clients/components/CRMTableHead.vue                            |  636 
 src/assets/img/person_dot.png                                            |    0 
 src/assets/img/selection_disable.png                                     |    0 
 src/components/CreateCom/XhBusinessStatus.vue                            |   67 
 src/views/OAManagement/components/fileCell/index.vue                     |  124 
 src/views/clients/components/RelativeTeam.vue                            |  286 
 src/views/clients/businessCustomer/components/CustomerFollow.vue         |  142 
 src/assets/img/structure.png                                             |    0 
 src/assets/fonts/iconfont.js                                             |    1 
 src/assets/img/logo.png                                                  |    0 
 src/assets/img/project/task_accessory.png                                |    0 
 src/assets/img/step_wait.png                                             |    0 
 src/api/customermanagement/product.js                                    |   14 
 src/assets/aside/company_active.png                                      |    0 
 src/views/OAManagement/examine/components/xhLeaves.vue                   |  278 
 src/directives/empty/empty.scss                                          |    7 
 src/assets/img/login/logo.png                                            |    0 
 src/assets/img/system/app/project_disable.png                            |    0 
 src/assets/img/field_other_manager.png                                   |    0 
 src/assets/img/collapse_right.png                                        |    0 
 src/assets/img/follow_log.png                                            |    0 
 src/views/OAManagement/schedule/components/details.vue                   |  234 
 src/assets/img/file_zip.png                                              |    0 
 src/store/modules/oa.js                                                  |   70 
 src/views/OAManagement/examine/components/examineCell.vue                |  304 
 .editorconfig                                                            |    9 
 src/assets/img/examine_head.png                                          |    0 
 src/views/clients/components/followLog/TaskLog.vue                       |  192 
 src/assets/img/scene_add.png                                             |    0 
 src/components/CreateView.vue                                            |   83 
 src/views/clients/components/filterForm/filterContent.vue                |  156 
 src/assets/img/selection_reset.png                                       |    0 
 src/views/clients/styles/relativecrm.scss                                |  148 
 src/views/clients/components/followLog/ExamineLog.vue                    |  207 
 src/assets/img/archive_project.png                                       |    0 
 src/components/DetailCell.vue                                            |   84 
 src/views/PWS/Subscriptions.vue                                          |  315 
 README.md                                                                |   21 
 src/assets/img/add_notice.png                                            |    0 
 src/assets/img/project/task_close.png                                    |    0 
 src/main.js                                                              |   88 
 src/assets/aside/workbench_active.png                                    |    0 
 src/assets/img/project/relevance_file.png                                |    0 
 src/views/clients/businessContracts/components/ContractFollow.vue        |  197 
 src/api/pwsApi/ewsAnalyze.js                                             |   11 
 src/views/OAManagement/addressBook/department.vue                        |  104 
 src/assets/img/check_revoke.png                                          |    0 
 src/components/CreateCom/XhTextarea.vue                                  |   41 
 src/views/OAManagement/examine/components/examineSection.vue             |  170 
 src/assets/img/add_examine.png                                           |    0 
 src/views/401.vue                                                        |  129 
 src/components/CreateCom/XhProuctCate.vue                                |   61 
 src/directives/empty/index.js                                            |  102 
 favicon.ico                                                              |    0 
 src/assets/img/system/leads_module.png                                   |    0 
 src/assets/aside/order_active.png                                        |    0 
 src/styles/animate.css                                                   | 3623 ++
 src/components/vuePictureViewer/index.vue                                |  753 
 src/views/module/ModuleManage.vue                                        |  484 
 src/components/CreateSections.vue                                        |   72 
 src/views/clients/contacts/components/ContactsFollow.vue                 |  184 
 src/views/clients/businessChances/components/BusinessFollow.vue          |  208 
 src/directives/scrollx/index.js                                          |  135 
 src/utils/dom.js                                                         |   45 
 src/views/clients/components/CRMImport.vue                               |  804 
 src/assets/img/project/t_set.png                                         |    0 
 src/views/clients/components/CRMFullScreenDetail.vue                     |  161 
 src/store/modules/permission.js                                          |  141 
 src/api/customermanagement/customerManage.js                             |  125 
 src/assets/img/business_detail.png                                       |    0 
 src/utils/validate.js                                                    |   27 
 src/views/company/systemSetting.vue                                      |  196 
 src/components/CreateCom/XhMultipleSelect.vue                            |   45 
 src/assets/img/system/app/crm_enable.png                                 |    0 
 src/directives/photo/photo.vue                                           |   79 
 src/assets/img/file_unknown.png                                          |    0 
 src/views/clients/components/sceneForm/SceneCreate.vue                   |  640 
 src/assets/aside/export.png                                              |    0 
 src/assets/img/system/task_module.png                                    |    0 
 src/assets/img/work_log.png                                              |    0 
 src/assets/img/project/task_priority.png                                 |    0 
 src/assets/img/scene_set.png                                             |    0 
 src/assets/img/system/app/hrm.png                                        |    0 
 src/assets/img/money_detail.png                                          |    0 
 src/components/CreateCom/XhStrucUserCell.vue                             |  134 
 src/assets/fonts/demo.css                                                |  539 
 .babelrc                                                                 |   12 
 src/directives/style.scss                                                |    2 
 src/views/clients/styles/followlog.scss                                  |  122 
 src/assets/img/c_business.png                                            |    0 
 src/filters/index.js                                                     |   35 
 src/views/clients/businessChances/BusinessChancesIndex.vue               |  557 
 src/assets/img/c_receivables.png                                         |    0 
 src/components/vuePictureViewer/img/pre_rotate.png                       |    0 
 src/views/OAManagement/notice/index.vue                                  |  267 
 src/store/modules/customer.js                                            |   61 
 src/assets/img/deadline.png                                              |    0 
 src/components/CreateCom/XhStructure.vue                                 |  246 
 src/views/login/index.vue                                                |  733 
 src/assets/aside/system_active.png                                       |    0 
 src/assets/img/project/task_add.png                                      |    0 
 src/assets/img/tablefilter.png                                           |    0 
 src/components/Examine/CreateExamineInfo.vue                             |  244 
 src/components/Examine/ExamineHandle.vue                                 |  246 
 src/views/OAManagement/task/components/tag/tagIndex.vue                  |  394 
 src/views/OAManagement/styles/content.scss                               |   24 
 build/build.js                                                           |   41 
 src/assets/img/selection_alloc.png                                       |    0 
 src/assets/img/selection_export.png                                      |    0 
 src/views/clients/components/followLog/RecordLog.vue                     |  169 
 src/assets/img/check_cancel.png                                          |    0 
 src/assets/fonts/iconfont.eot                                            |    0 
 src/assets/img/t_set.png                                                 |    0 
 src/directives/index.js                                                  |   24 
 src/assets/img/check_suc.png                                             |    0 
 src/views/OAManagement/examine/components/xhExpenses.vue                 |  408 
 src/assets/img/button_add_white.png                                      |    0 
 src/assets/img/close2x.png                                               |    0 
 src/assets/img/system/examine_module.png                                 |    0 
 src/views/clients/components/sceneForm/SceneList.vue                     |  160 
 src/views/OAManagement/workbench/index.vue                               |  247 
 src/assets/img/selection_putseas.png                                     |    0 
 src/views/company/offcialAuthority.vue                                   |  418 
 src/assets/aside/personnel.png                                           |    0 
 src/assets/img/no_data.png                                               |    0 
 src/assets/img/c_contract.png                                            |    0 
 src/views/clients/businessCustomer/BusinessCustomerManage.vue            |  561 
 src/styles/element-variables.scss                                        |   38 
 src/assets/img/system/app/inventory.png                                  |    0 
 src/components/emoji.vue                                                 |  130 
 src/views/clients/components/followLog/components/FollowScheduleCell.vue |  252 
 src/components/reminder.vue                                              |   60 
 src/components/timeTypeSelect/index.vue                                  |  184 
 src/views/OAManagement/schedule/index.vue                                |  394 
 src/views/clients/components/CRMBaseInfo.vue                             |  481 
 src/assets/aside/check.png                                               |    0 
 src/components/relatedBusiness.vue                                       |  240 
 src/views/clients/customer/components/CustomerFollow.vue                 |  184 
 .eslintrc.js                                                             |   34 
 index.html                                                               |   25 
 src/assets/img/task_ellipsis.png                                         |    0 
 src/views/clients/components/selectionHandle/TeamsHandle.vue             |  230 
 src/assets/img/qushi.png                                                 |    0 
 src/assets/img/field_receivables_manager.png                             |    0 
 src/views/home/Home.vue                                                  |  518 
 src/assets/img/comment.png                                               |    0 
 config/index.js                                                          |   87 
 src/views/clients/mixins/loading.js                                      |   29 
 src/views/clients/customer/CustomerDetail.vue                            |  329 
 src/views/clients/components/followLog/components/FollowRecordTable.vue  |  449 
 src/components/CreateCom/CrmRelativeCell.vue                             |  179 
 src/assets/img/task_edit_def.png                                         |    0 
 src/views/OAManagement/task/components/newDialog.vue                     |  443 
 src/router/index.js                                                      |  190 
 src/assets/img/selection_convert_customer.png                            |    0 
 src/assets/img/project/task_download.png                                 |    0 
 src/assets/img/file_word.png                                             |    0 
 src/views/clients/customer/clientsManage.vue                             |  663 
 src/views/clients/components/filterForm/index.vue                        |  648 
 src/assets/404_images/404.png                                            |    0 
 src/api/moduleManage/moduleManage.js                                     |   35 
 .gitignore                                                               |   14 
 src/assets/img/logo_bg.png                                               |    0 
 src/views/clients/customer/test.vue                                      |  151 
 src/views/clients/components/CRMCreateFileView.vue                       |  696 
 src/assets/img/field_customer_manager.png                                |    0 
 build/logo.png                                                           |    0 
 src/views/clients/styles/table.scss                                      |  146 
 src/assets/img/check_create.png                                          |    0 
 src/assets/aside/system.png                                              |    0 
 src/views/clients/clue/ClueIndex.vue                                     |  131 
 src/views/clients/components/followLog/ScheduleLog.vue                   |  199 
 src/views/OAManagement/examine/components/examineDetail.vue              |  586 
 src/assets/img/field_business_manager.png                                |    0 
 src/assets/img/field_contacts_manager.png                                |    0 
 src/views/clients/components/fieldsManager/FieldsSet.vue                 |  538 
 src/views/clients/components/sceneForm/SceneSet.vue                      |  648 
 src/assets/img/file_ppt.png                                              |    0 
 src/assets/img/sprite/vue-emoji.png                                      |    0 
 src/assets/404_images/404_cloud.png                                      |    0 
 src/assets/img/delete_task.png                                           |    0 
 src/assets/img/c_contact.png                                             |    0 
 src/assets/img/project/head.png                                          |    0 
 src/assets/aside/financial.png                                           |    0 
 src/assets/img/project/task_circle.png                                   |    0 
 src/views/PWS/EwsAnalyze.vue                                             |  411 
 build/webpack.prod.conf.js                                               |  145 
 build/webpack.base.conf.js                                               |   92 
 src/api/systemManagement/departmentManage.js                             |   63 
 src/components/EditImage.vue                                             |  156 
 src/assets/img/send_contacts.png                                         |    0 
 src/assets/img/field_contract_manager.png                                |    0 
 src/App.vue                                                              |   19 
 src/views/company/staffLog.vue                                           |  254 
 src/views/clients/sealOffers/SealOfferIndex.vue                          |  260 
 myproject@1.0.0                                                          |    0 
 src/assets/img/work_notice.png                                           |    0 
 src/views/clients/clue/ClueDetail.vue                                    |  181 
 src/views/clients/sealContract/SealContractIndex.vue                     |  257 
 src/assets/img/collapse_white.png                                        |    0 
 src/views/OAManagement/workbench/task.vue                                |  241 
 src/views/OAManagement/notice/edit.vue                                   |  206 
 src/assets/img/post.png                                                  |    0 
 src/views/OAManagement/examine/index.vue                                 |  197 
 src/views/OAManagement/task/components/tag/editTag.vue                   |  134 
 src/assets/aside/product.png                                             |    0 
 src/assets/img/project/project_add.png                                   |    0 
 src/assets/img/check_wait.png                                            |    0 
 src/styles/calendars.scss                                                |  168 
 src/views/clients/components/RelativeContacts.vue                        |  349 
 src/assets/img/selection_edit.png                                        |    0 
 src/components/CreateCom/XhStructureCell.vue                             |  142 
 src/views/clients/business/BusinessIndex.vue                             |  483 
 src/assets/img/more_dot.png                                              |    0 
 src/directives/empty/empty.vue                                           |   97 
 src/assets/img/file_video.png                                            |    0 
 src/styles/emoji-sprite.scss                                             | 3558 ++
 src/views/clients/components/RelativeContract.vue                        |  327 
 src/views/clients/components/Sections.vue                                |  145 
 src/components/CreateCom/XhInputSelect.vue                               |  201 
 src/assets/img/add_journal.png                                           |    0 
 src/assets/img/selection_deal_status.png                                 |    0 
 src/views/clients/contract/ContractIndex.vue                             |  265 
 src/assets/img/system/customer_pool_module.png                           |    0 
 src/views/OAManagement/task/components/myTask.vue                        |  283 
 src/api/pwsApi/subscriptions.js                                          |   18 
 static/client.js                                                         |   62 
 .postcssrc.js                                                            |   10 
 src/assets/fonts/iconfont.css                                            |  341 
 src/components/CreateCom/XhFiles.vue                                     |  203 
 src/assets/aside/import.png                                              |    0 
 src/views/clients/components/RelativeFiles.vue                           |  318 
 src/store/modules/app.js                                                 |   85 
 src/api/common.js                                                        |  314 
 src/views/OAManagement/notice/noticeCell.vue                             |  199 
 src/assets/img/check_fail.png                                            |    0 
 src/views/clients/components/CRMExport.vue                               |  340 
 src/views/OAManagement/workbench/tabsJournal.vue                         |   78 
 src/styles/iconPath.scss                                                 |  171 
 src/views/clients/components/MixAdd.vue                                  |  819 
 src/assets/fonts/iconfont.ttf                                            |    0 
 src/components/flexbox/flexbox-item.vue                                  |   62 
 src/assets/img/send_img.png                                              |    0 
 src/views/OAManagement/examine/components/examineCreateView.vue          | 1096 
 src/api/customermanagement/contacts.js                                   |   62 
 src/assets/img/file_excle.png                                            |    0 
 src/styles/element-ui.scss                                               |  122 
 src/assets/aside/company.png                                             |    0 
 src/utils/request.js                                                     |  113 
 src/views/clients/components/CRMListHead.vue                             |   74 
 src/assets/img/selection_unlock.png                                      |    0 
 src/components/CreateCom/XhInput.vue                                     |   36 
 src/views/clients/customer/components/BusinessCheck.vue                  |  170 
 .eslintignore                                                            |    4 
 src/views/company/employeeManage/components/EmployeeDetail.vue           |  231 
 src/assets/img/relevance_file.png                                        |    0 
 src/assets/img/setting.png                                               |    0 
 src/views/clients/sealContract/SealContractDetail.vue                    |  217 
 src/assets/img/send_file.png                                             |    0 
 src/views/clients/contract/ContractDetail.vue                            |  217 
 src/views/OAManagement/styles/tabs.scss                                  |   22 
 src/views/OAManagement/schedule/components/createSchedule.vue            |  647 
 src/assets/img/customer_detail.png                                       |    0 
 src/assets/img/project/send_contacts.png                                 |    0 
 src/utils/auth.js                                                        |   35 
 src/views/login/logining.vue                                             |   67 
 src/components/vuePictureViewer/img/pre_max.png                          |    0 
 src/assets/img/selection_get.png                                         |    0 
 src/assets/img/selection_delete.png                                      |    0 
 src/assets/img/system/app/oa_disable.png                                 |    0 
 src/views/clients/offers/OfferIndex.vue                                  |  261 
 src/views/clients/components/selectionHandle/DealStatusHandle.vue        |  150 
 src/views/company/employeeManage/EmployeeManage.vue                      | 1800 +
 src/assets/img/system/log_module.png                                     |    0 
 src/store/getters.js                                                     |   48 
 webpack-dev-server                                                       |    0 
 src/assets/aside/financial_active.png                                    |    0 
 src/views/clients/components/RelativeSchedule.vue                        |  230 
 src/assets/img/no_task.png                                               |    0 
 src/assets/img/project/archive_project.png                               |    0 
 src/views/clients/contacts/ContactsIndex.vue                             |  315 
 src/assets/img/logo.jpg                                                  |    0 
 src/api/systemManagement/employeeManage.js                               |   62 
 src/assets/img/mobile.png                                                |    0 
 src/components/CreateCom/XhProduct.vue                                   |  391 
 src/directives/photo/photo.scss                                          |    7 
 src/components/CreateCom/XhCustomerAddress.vue                           |  397 
 src/views/clients/styles/crmdetail.scss                                  |   48 
 src/assets/img/loudou.png                                                |    0 
 src/assets/img/selection_start.png                                       |    0 
 src/views/OAManagement/addressBook/index.vue                             |  187 
 src/assets/img/product_detail.png                                        |    0 
 config/prod.env.js                                                       |    6 
 src/api/systemManagement/log.js                                          |   14 
 src/views/OAManagement/task/components/taskCell.vue                      |  332 
 build/utils.js                                                           |  109 
 src/utils/emoji.js                                                       |   30 
 src/views/clients/components/selectionHandle/AllocHandle.vue             |  154 
 src/views/clients/components/CRMTableFilter.vue                          |  221 
 src/assets/img/system/notice_module.png                                  |    0 
 src/assets/aside/customer.png                                            |    0 
 src/views/clients/components/followLog/JournalLog.vue                    |  279 
 src/views/clients/components/selectionHandle/TransferHandle.vue          |  219 
 src/views/clients/businessCustomer/components/BusinessCheck.vue          |  170 
 src/assets/fonts/iconfont.svg                                            |   47 
 src/views/OAManagement/task/components/tag/newTag.vue                    |  158 
 src/assets/401_images/1.gif                                              |    0 
 src/assets/img/loading.gif                                               |    0 
 src/assets/img/selection_transfer.png                                    |    0 
 src/components/common/SIdentify.vue                                      |  164 
 src/views/clients/businessCustomer/BusinessCustomerDetail.vue            |  271 
 src/utils/cache.js                                                       |   46 
 src/assets/img/system/app/call_enable.png                                |    0 
 src/styles/xr-theme.scss                                                 |   33 
 src/assets/img/project/my_task.png                                       |    0 
 src/assets/img/empty.png                                                 |    0 
 src/assets/img/field_product_manager.png                                 |    0 
 src/views/clients/components/CRMDetailHead.vue                           |  596 
 src/assets/aside/product_active.png                                      |    0 
 src/views/OAManagement/notice/details.vue                                |  180 
 497 files changed, 86,136 insertions(+), 2 deletions(-)

diff --git a/.babelrc b/.babelrc
new file mode 100644
index 0000000..3a280ba
--- /dev/null
+++ b/.babelrc
@@ -0,0 +1,12 @@
+{
+  "presets": [
+    ["env", {
+      "modules": false,
+      "targets": {
+        "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
+      }
+    }],
+    "stage-2"
+  ],
+  "plugins": ["transform-vue-jsx", "transform-runtime"]
+}
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..9d08a1a
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,9 @@
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 0000000..e1fcc9c
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,4 @@
+/build/
+/config/
+/dist/
+/*.js
diff --git a/.eslintrc.js b/.eslintrc.js
new file mode 100644
index 0000000..2e0c04b
--- /dev/null
+++ b/.eslintrc.js
@@ -0,0 +1,34 @@
+// https://eslint.org/docs/user-guide/configuring
+
+module.exports = {
+  root: true,
+  parserOptions: {
+    parser: 'babel-eslint'
+  },
+  env: {
+    browser: true,
+  },
+  extends: [
+    // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
+    // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
+    'plugin:vue/essential', 
+    // https://github.com/standard/standard/blob/master/docs/RULES-en.md
+    'standard'
+  ],
+  globals: {
+    "BMap": "readonly",
+    "BMAP_STATUS_SUCCESS": "readonly",
+    "fullcalendar": "readonly"
+  },
+  // required to lint *.vue files
+  plugins: [
+    'vue'
+  ],
+  // add your custom rules here
+  rules: {
+    // allow async-await
+    'generator-star-spacing': 'off',
+    // allow debugger during development
+    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
+  }
+}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..541a820
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,14 @@
+.DS_Store
+node_modules/
+/dist/
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
diff --git a/.postcssrc.js b/.postcssrc.js
new file mode 100644
index 0000000..eee3e92
--- /dev/null
+++ b/.postcssrc.js
@@ -0,0 +1,10 @@
+// https://github.com/michael-ciniawsky/postcss-load-config
+
+module.exports = {
+  "plugins": {
+    "postcss-import": {},
+    "postcss-url": {},
+    // to edit target browsers: use "browserslist" field in package.json
+    "autoprefixer": {}
+  }
+}
diff --git a/README.md b/README.md
index 962899b..2dc6c48 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,21 @@
-## Probim-crm
+# myproject
 
-CRM前端
+> DCGY-CRM
 
+## Build Setup
+
+``` bash
+# install dependencies
+npm install
+
+# serve with hot reload at localhost:8080
+npm run dev
+
+# build for production with minification
+npm run build
+
+# build for production and view the bundle analyzer report
+npm run build --report
+```
+
+For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader).
diff --git a/build/build.js b/build/build.js
new file mode 100644
index 0000000..8f2ad8a
--- /dev/null
+++ b/build/build.js
@@ -0,0 +1,41 @@
+'use strict'
+require('./check-versions')()
+
+process.env.NODE_ENV = 'production'
+
+const ora = require('ora')
+const rm = require('rimraf')
+const path = require('path')
+const chalk = require('chalk')
+const webpack = require('webpack')
+const config = require('../config')
+const webpackConfig = require('./webpack.prod.conf')
+
+const spinner = ora('building for production...')
+spinner.start()
+
+rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
+  if (err) throw err
+  webpack(webpackConfig, (err, stats) => {
+    spinner.stop()
+    if (err) throw err
+    process.stdout.write(stats.toString({
+      colors: true,
+      modules: false,
+      children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
+      chunks: false,
+      chunkModules: false
+    }) + '\n\n')
+
+    if (stats.hasErrors()) {
+      console.log(chalk.red('  Build failed with errors.\n'))
+      process.exit(1)
+    }
+
+    console.log(chalk.cyan('  Build complete.\n'))
+    console.log(chalk.yellow(
+      '  Tip: built files are meant to be served over an HTTP server.\n' +
+      '  Opening index.html over file:// won\'t work.\n'
+    ))
+  })
+})
diff --git a/build/check-versions.js b/build/check-versions.js
new file mode 100644
index 0000000..3ef972a
--- /dev/null
+++ b/build/check-versions.js
@@ -0,0 +1,54 @@
+'use strict'
+const chalk = require('chalk')
+const semver = require('semver')
+const packageConfig = require('../package.json')
+const shell = require('shelljs')
+
+function exec (cmd) {
+  return require('child_process').execSync(cmd).toString().trim()
+}
+
+const versionRequirements = [
+  {
+    name: 'node',
+    currentVersion: semver.clean(process.version),
+    versionRequirement: packageConfig.engines.node
+  }
+]
+
+if (shell.which('npm')) {
+  versionRequirements.push({
+    name: 'npm',
+    currentVersion: exec('npm --version'),
+    versionRequirement: packageConfig.engines.npm
+  })
+}
+
+module.exports = function () {
+  const warnings = []
+
+  for (let i = 0; i < versionRequirements.length; i++) {
+    const mod = versionRequirements[i]
+
+    if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
+      warnings.push(mod.name + ': ' +
+        chalk.red(mod.currentVersion) + ' should be ' +
+        chalk.green(mod.versionRequirement)
+      )
+    }
+  }
+
+  if (warnings.length) {
+    console.log('')
+    console.log(chalk.yellow('To use this template, you must update following to modules:'))
+    console.log()
+
+    for (let i = 0; i < warnings.length; i++) {
+      const warning = warnings[i]
+      console.log('  ' + warning)
+    }
+
+    console.log()
+    process.exit(1)
+  }
+}
diff --git a/build/logo.png b/build/logo.png
new file mode 100644
index 0000000..f3d2503
--- /dev/null
+++ b/build/logo.png
Binary files differ
diff --git a/build/utils.js b/build/utils.js
new file mode 100644
index 0000000..8f79587
--- /dev/null
+++ b/build/utils.js
@@ -0,0 +1,109 @@
+'use strict'
+const path = require('path')
+const config = require('../config')
+const ExtractTextPlugin = require('extract-text-webpack-plugin')
+const packageConfig = require('../package.json')
+
+exports.assetsPath = function (_path) {
+  const assetsSubDirectory = process.env.NODE_ENV === 'production'
+    ? config.build.assetsSubDirectory
+    : config.dev.assetsSubDirectory
+
+  return path.posix.join(assetsSubDirectory, _path)
+}
+
+exports.cssLoaders = function (options) {
+  options = options || {}
+
+  const cssLoader = {
+    loader: 'css-loader',
+    options: {
+      sourceMap: options.sourceMap
+    }
+  }
+  
+  const px2remLoader = {
+    loader: 'px2rem-loader',
+    options: {
+      remUnit: 192
+    }
+  }
+
+  const postcssLoader = {
+    loader: 'postcss-loader',
+    options: {
+      sourceMap: options.sourceMap
+    }
+  }
+
+  // generate loader string to be used with extract text plugin
+  function generateLoaders (loader, loaderOptions) {
+    const loaders = options.usePostCSS ? [cssLoader, postcssLoader, px2remLoader] : [cssLoader, px2remLoader]
+
+    if (loader) {
+      loaders.push({
+        loader: loader + '-loader',
+        options: Object.assign({}, loaderOptions, {
+          sourceMap: options.sourceMap
+        })
+      })
+    }
+
+    // Extract CSS when that option is specified
+    // (which is the case during production build)
+    if (options.extract) {
+      return ExtractTextPlugin.extract({
+        use: loaders,
+        fallback: 'vue-style-loader',
+        publicPath: '../../'
+      })
+    } else {
+      return ['vue-style-loader'].concat(loaders)
+    }
+  }
+
+  // https://vue-loader.vuejs.org/en/configurations/extract-css.html
+  return {
+    css: generateLoaders(),
+    postcss: generateLoaders(),
+    less: generateLoaders('less'),
+    sass: generateLoaders('sass', { indentedSyntax: true }),
+    scss: generateLoaders('sass'),
+    stylus: generateLoaders('stylus'),
+    styl: generateLoaders('stylus')
+  }
+}
+
+// Generate loaders for standalone style files (outside of .vue)
+exports.styleLoaders = function (options) {
+  const output = []
+  const loaders = exports.cssLoaders(options)
+
+  for (const extension in loaders) {
+    const loader = loaders[extension]
+    output.push({
+      test: new RegExp('\\.' + extension + '$'),
+      use: loader
+    })
+  }
+
+  return output
+}
+
+exports.createNotifierCallback = () => {
+  const notifier = require('node-notifier')
+
+  return (severity, errors) => {
+    if (severity !== 'error') return
+
+    const error = errors[0]
+    const filename = error.file && error.file.split('!').pop()
+
+    notifier.notify({
+      title: packageConfig.name,
+      message: severity + ': ' + error.name,
+      subtitle: filename || '',
+      icon: path.join(__dirname, 'logo.png')
+    })
+  }
+}
diff --git a/build/vue-loader.conf.js b/build/vue-loader.conf.js
new file mode 100644
index 0000000..33ed58b
--- /dev/null
+++ b/build/vue-loader.conf.js
@@ -0,0 +1,22 @@
+'use strict'
+const utils = require('./utils')
+const config = require('../config')
+const isProduction = process.env.NODE_ENV === 'production'
+const sourceMapEnabled = isProduction
+  ? config.build.productionSourceMap
+  : config.dev.cssSourceMap
+
+module.exports = {
+  loaders: utils.cssLoaders({
+    sourceMap: sourceMapEnabled,
+    extract: isProduction
+  }),
+  cssSourceMap: sourceMapEnabled,
+  cacheBusting: config.dev.cacheBusting,
+  transformToRequire: {
+    video: ['src', 'poster'],
+    source: 'src',
+    img: 'src',
+    image: 'xlink:href'
+  }
+}
diff --git a/build/webpack.base.conf.js b/build/webpack.base.conf.js
new file mode 100644
index 0000000..1f4f47e
--- /dev/null
+++ b/build/webpack.base.conf.js
@@ -0,0 +1,92 @@
+'use strict'
+const path = require('path')
+const utils = require('./utils')
+const config = require('../config')
+const vueLoaderConfig = require('./vue-loader.conf')
+
+function resolve (dir) {
+  return path.join(__dirname, '..', dir)
+}
+
+const createLintingRule = () => ({
+  test: /\.(js|vue)$/,
+  loader: 'eslint-loader',
+  enforce: 'pre',
+  include: [resolve('src'), resolve('test')],
+  options: {
+    formatter: require('eslint-friendly-formatter'),
+    emitWarning: !config.dev.showEslintErrorsInOverlay
+  }
+})
+
+module.exports = {
+  context: path.resolve(__dirname, '../'),
+  entry: {
+    app: './src/main.js'
+  },
+  output: {
+    path: config.build.assetsRoot,
+    filename: '[name].js',
+    publicPath: process.env.NODE_ENV === 'production'
+      ? config.build.assetsPublicPath
+      : config.dev.assetsPublicPath
+  },
+  resolve: {
+    extensions: ['.js', '.vue', '.json'],
+    alias: {
+      'vue$': 'vue/dist/vue.esm.js',
+      '@': resolve('src'),
+    }
+  },
+  module: {
+    rules: [
+      ...(config.dev.useEslint ? [createLintingRule()] : []),
+      {
+        test: /\.vue$/,
+        loader: 'vue-loader',
+        options: vueLoaderConfig
+      },
+      {
+        test: /\.js$/,
+        loader: 'babel-loader',
+        include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
+      },
+      {
+        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
+        loader: 'url-loader',
+        options: {
+          limit: 10000,
+          name: utils.assetsPath('img/[name].[hash:7].[ext]')
+        }
+      },
+      {
+        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
+        loader: 'url-loader',
+        options: {
+          limit: 10000,
+          name: utils.assetsPath('media/[name].[hash:7].[ext]')
+        }
+      },
+      {
+        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
+        loader: 'url-loader',
+        options: {
+          limit: 10000,
+          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
+        }
+      }
+    ]
+  },
+  node: {
+    // prevent webpack from injecting useless setImmediate polyfill because Vue
+    // source contains it (although only uses it if it's native).
+    setImmediate: false,
+    // prevent webpack from injecting mocks to Node native modules
+    // that does not make sense for the client
+    dgram: 'empty',
+    fs: 'empty',
+    net: 'empty',
+    tls: 'empty',
+    child_process: 'empty'
+  }
+}
diff --git a/build/webpack.dev.conf.js b/build/webpack.dev.conf.js
new file mode 100644
index 0000000..5d9bb38
--- /dev/null
+++ b/build/webpack.dev.conf.js
@@ -0,0 +1,97 @@
+'use strict'
+const utils = require('./utils')
+const webpack = require('webpack')
+const config = require('../config')
+const merge = require('webpack-merge')
+const path = require('path')
+const baseWebpackConfig = require('./webpack.base.conf')
+const CopyWebpackPlugin = require('copy-webpack-plugin')
+const HtmlWebpackPlugin = require('html-webpack-plugin')
+const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
+const portfinder = require('portfinder')
+
+const HOST = process.env.HOST
+const PORT = process.env.PORT && Number(process.env.PORT)
+
+const devWebpackConfig = merge(baseWebpackConfig, {
+  module: {
+    rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
+  },
+  // cheap-module-eval-source-map is faster for development
+  devtool: config.dev.devtool,
+
+  // these devServer options should be customized in /config/index.js
+  devServer: {
+    clientLogLevel: 'warning',
+    historyApiFallback: {
+      rewrites: [
+        { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
+      ],
+    },
+    hot: true,
+    contentBase: false, // since we use CopyWebpackPlugin.
+    compress: true,
+    host: HOST || config.dev.host,
+    port: PORT || config.dev.port,
+    open: config.dev.autoOpenBrowser,
+    overlay: config.dev.errorOverlay
+      ? { warnings: false, errors: true }
+      : false,
+    publicPath: config.dev.assetsPublicPath,
+    proxy: config.dev.proxyTable,
+    quiet: true, // necessary for FriendlyErrorsPlugin
+    watchOptions: {
+      poll: config.dev.poll,
+    },
+    disableHostCheck: true
+  },
+  plugins: [
+    new webpack.DefinePlugin({
+      'process.env': require('../config/dev.env')
+    }),
+    new webpack.HotModuleReplacementPlugin(),
+    new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
+    new webpack.NoEmitOnErrorsPlugin(),
+    // https://github.com/ampedandwired/html-webpack-plugin
+    new HtmlWebpackPlugin({
+      filename: 'index.html',
+      template: 'index.html',
+      favicon: 'favicon.ico',
+      inject: true
+    }),
+    // copy custom static assets
+    new CopyWebpackPlugin([
+      {
+        from: path.resolve(__dirname, '../static'),
+        to: config.dev.assetsSubDirectory,
+        ignore: ['.*']
+      }
+    ])
+  ]
+})
+
+module.exports = new Promise((resolve, reject) => {
+  portfinder.basePort = process.env.PORT || config.dev.port
+  portfinder.getPort((err, port) => {
+    if (err) {
+      reject(err)
+    } else {
+      // publish the new Port, necessary for e2e tests
+      process.env.PORT = port
+      // add port to devServer config
+      devWebpackConfig.devServer.port = port
+
+      // Add FriendlyErrorsPlugin
+      devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
+        compilationSuccessInfo: {
+          messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
+        },
+        onErrors: config.dev.notifyOnErrors
+        ? utils.createNotifierCallback()
+        : undefined
+      }))
+
+      resolve(devWebpackConfig)
+    }
+  })
+})
diff --git a/build/webpack.prod.conf.js b/build/webpack.prod.conf.js
new file mode 100644
index 0000000..d9f99f6
--- /dev/null
+++ b/build/webpack.prod.conf.js
@@ -0,0 +1,145 @@
+'use strict'
+const path = require('path')
+const utils = require('./utils')
+const webpack = require('webpack')
+const config = require('../config')
+const merge = require('webpack-merge')
+const baseWebpackConfig = require('./webpack.base.conf')
+const CopyWebpackPlugin = require('copy-webpack-plugin')
+const HtmlWebpackPlugin = require('html-webpack-plugin')
+const ExtractTextPlugin = require('extract-text-webpack-plugin')
+const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
+const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
+
+const env = require('../config/prod.env')
+
+const webpackConfig = merge(baseWebpackConfig, {
+  module: {
+    rules: utils.styleLoaders({
+      sourceMap: config.build.productionSourceMap,
+      extract: true,
+      usePostCSS: true
+    })
+  },
+  devtool: config.build.productionSourceMap ? config.build.devtool : false,
+  output: {
+    path: config.build.assetsRoot,
+    filename: utils.assetsPath('js/[name].[chunkhash].js'),
+    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
+  },
+  plugins: [
+    // http://vuejs.github.io/vue-loader/en/workflow/production.html
+    new webpack.DefinePlugin({
+      'process.env': env
+    }),
+    new UglifyJsPlugin({
+      uglifyOptions: {
+        compress: {
+          warnings: false
+        }
+      },
+      sourceMap: config.build.productionSourceMap,
+      parallel: true
+    }),
+    // extract css into its own file
+    new ExtractTextPlugin({
+      filename: utils.assetsPath('css/[name].[contenthash].css'),
+      // Setting the following option to `false` will not extract CSS from codesplit chunks.
+      // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
+      // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`, 
+      // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
+      allChunks: true,
+    }),
+    // Compress extracted CSS. We are using this plugin so that possible
+    // duplicated CSS from different components can be deduped.
+    new OptimizeCSSPlugin({
+      cssProcessorOptions: config.build.productionSourceMap
+        ? { safe: true, map: { inline: false } }
+        : { safe: true }
+    }),
+    // generate dist index.html with correct asset hash for caching.
+    // you can customize output by editing /index.html
+    // see https://github.com/ampedandwired/html-webpack-plugin
+    new HtmlWebpackPlugin({
+      filename: config.build.index,
+      template: 'index.html',
+      inject: true,
+      minify: {
+        removeComments: true,
+        collapseWhitespace: true,
+        removeAttributeQuotes: true
+        // more options:
+        // https://github.com/kangax/html-minifier#options-quick-reference
+      },
+      // necessary to consistently work with multiple chunks via CommonsChunkPlugin
+      chunksSortMode: 'dependency'
+    }),
+    // keep module.id stable when vendor modules does not change
+    new webpack.HashedModuleIdsPlugin(),
+    // enable scope hoisting
+    new webpack.optimize.ModuleConcatenationPlugin(),
+    // split vendor js into its own file
+    new webpack.optimize.CommonsChunkPlugin({
+      name: 'vendor',
+      minChunks (module) {
+        // any required modules inside node_modules are extracted to vendor
+        return (
+          module.resource &&
+          /\.js$/.test(module.resource) &&
+          module.resource.indexOf(
+            path.join(__dirname, '../node_modules')
+          ) === 0
+        )
+      }
+    }),
+    // extract webpack runtime and module manifest to its own file in order to
+    // prevent vendor hash from being updated whenever app bundle is updated
+    new webpack.optimize.CommonsChunkPlugin({
+      name: 'manifest',
+      minChunks: Infinity
+    }),
+    // This instance extracts shared chunks from code splitted chunks and bundles them
+    // in a separate chunk, similar to the vendor chunk
+    // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
+    new webpack.optimize.CommonsChunkPlugin({
+      name: 'app',
+      async: 'vendor-async',
+      children: true,
+      minChunks: 3
+    }),
+
+    // copy custom static assets
+    new CopyWebpackPlugin([
+      {
+        from: path.resolve(__dirname, '../static'),
+        to: config.build.assetsSubDirectory,
+        ignore: ['.*']
+      }
+    ])
+  ]
+})
+
+if (config.build.productionGzip) {
+  const CompressionWebpackPlugin = require('compression-webpack-plugin')
+
+  webpackConfig.plugins.push(
+    new CompressionWebpackPlugin({
+      asset: '[path].gz[query]',
+      algorithm: 'gzip',
+      test: new RegExp(
+        '\\.(' +
+        config.build.productionGzipExtensions.join('|') +
+        ')$'
+      ),
+      threshold: 10240,
+      minRatio: 0.8
+    })
+  )
+}
+
+if (config.build.bundleAnalyzerReport) {
+  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
+  webpackConfig.plugins.push(new BundleAnalyzerPlugin())
+}
+
+module.exports = webpackConfig
diff --git a/config/dev.env.js b/config/dev.env.js
new file mode 100644
index 0000000..8a3b5f8
--- /dev/null
+++ b/config/dev.env.js
@@ -0,0 +1,8 @@
+'use strict'
+const merge = require('webpack-merge')
+const prodEnv = require('./prod.env')
+
+module.exports = merge(prodEnv, {
+  NODE_ENV: '"development"',
+  BASE_API: '"/api/"',
+})
diff --git a/config/index.js b/config/index.js
new file mode 100644
index 0000000..39812da
--- /dev/null
+++ b/config/index.js
@@ -0,0 +1,87 @@
+'use strict'
+const { debug } = require('console')
+// Template version: 1.3.1
+// see http://vuejs-templates.github.io/webpack for documentation.
+
+const path = require('path')
+
+module.exports = {
+  dev: {
+
+    // Paths
+    assetsSubDirectory: 'static',
+    assetsPublicPath: '/',
+    proxyTable: {
+      '/api': {
+        // target: 'http://192.168.2.107:8080',
+        target: 'http://api.crm.urlink.com.cn',
+        changeOrigin: true,
+        logLevel: 'debug',
+        pathRewrite: {
+          '^/api': '/api'
+        }
+      }
+    },
+
+    // Various Dev Server settings
+    host: '127.0.0.1', // can be overwritten by process.env.HOST
+    port: 80, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
+    autoOpenBrowser: false,
+    errorOverlay: true,
+    notifyOnErrors: true,
+    poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
+
+    // Use Eslint Loader?
+    // If true, your code will be linted during bundling and
+    // linting errors and warnings will be shown in the console.
+    useEslint: true,
+    // If true, eslint errors and warnings will also be shown in the error overlay
+    // in the browser.
+    showEslintErrorsInOverlay: false,
+
+    /**
+     * Source Maps
+     */
+
+    // https://webpack.js.org/configuration/devtool/#development
+    devtool: 'cheap-module-eval-source-map',
+
+    // If you have problems debugging vue-files in devtools,
+    // set this to false - it *may* help
+    // https://vue-loader.vuejs.org/en/options.html#cachebusting
+    cacheBusting: true,
+
+    cssSourceMap: true
+  },
+
+  build: {
+    // Template for index.html
+    index: path.resolve(__dirname, '../dist/index.html'),
+
+    // Paths
+    assetsRoot: path.resolve(__dirname, '../dist'),
+    assetsSubDirectory: 'static',
+    assetsPublicPath: './',
+
+    /**
+     * Source Maps
+     */
+
+    productionSourceMap: true,
+    // https://webpack.js.org/configuration/devtool/#production
+    devtool: '#source-map',
+
+    // Gzip off by default as many popular static hosts such as
+    // Surge or Netlify already gzip all static assets for you.
+    // Before setting to `true`, make sure to:
+    // npm install --save-dev compression-webpack-plugin
+    productionGzip: false,
+    productionGzipExtensions: ['js', 'css'],
+
+    // Run the build command with an extra argument to
+    // View the bundle analyzer report after build finishes:
+    // `npm run build --report`
+    // Set to `true` or `false` to always turn it on or off
+    bundleAnalyzerReport: process.env.npm_config_report
+  }
+}
diff --git a/config/prod.env.js b/config/prod.env.js
new file mode 100644
index 0000000..d341116
--- /dev/null
+++ b/config/prod.env.js
@@ -0,0 +1,6 @@
+'use strict'
+module.exports = {
+  NODE_ENV: '"production"',
+  // BASE_API: '"http://www.probim.cn:6683/api/"'
+  BASE_API: '"http://api.crm.urlink.com.cn/api/"'
+}
diff --git a/favicon.ico b/favicon.ico
new file mode 100644
index 0000000..c82cdc3
--- /dev/null
+++ b/favicon.ico
Binary files differ
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..f3ccab5
--- /dev/null
+++ b/index.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+  <meta charset="utf-8">
+  <meta name="viewport" content="width=device-width,initial-scale=1.0">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
+  <title>北京友联华宇科技有限公司CRM</title>
+  <link rel="shortcut icon"  href="favicon.ico"/>
+  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vue-slider-component@latest/theme/default.css" />
+  <script src="./static/client.js"></script>
+</head>
+
+<body>
+  <!-- <script type="text/javascript" src="//api.map.baidu.com/api?v=3.0&ak=P7azLi4fZLciLuZU8GZsKRoLztn6LnCO"></script> -->
+  <!-- 企业微信扫码登录 -->
+  <script
+      src="https://rescdn.qqmail.com/node/ww/wwopenmng/js/sso/wwLogin-1.0.0.js"
+      type="text/javascript"
+  ></script>
+  <div id="app"></div>
+  <!-- built files will be auto injected -->
+</body>
+
+</html>
diff --git a/myproject@1.0.0 b/myproject@1.0.0
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/myproject@1.0.0
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..0dc8109
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,14372 @@
+{
+  "name": "myproject",
+  "version": "1.0.0",
+  "lockfileVersion": 1,
+  "requires": true,
+  "dependencies": {
+    "@babel/code-frame": {
+      "version": "7.0.0-beta.44",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz",
+      "integrity": "sha512-cuAuTTIQ9RqcFRJ/Y8PvTh+paepNcaGxwQwjIDRWPXmzzyAeCO4KqS9ikMvq0MCbRk6GlYKwfzStrcP3/jSL8g==",
+      "dev": true,
+      "requires": {
+        "@babel/highlight": "7.0.0-beta.44"
+      }
+    },
+    "@babel/generator": {
+      "version": "7.0.0-beta.44",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.44.tgz",
+      "integrity": "sha512-5xVb7hlhjGcdkKpMXgicAVgx8syK5VJz193k0i/0sLP6DzE6lRrU1K3B/rFefgdo9LPGMAOOOAWW4jycj07ShQ==",
+      "dev": true,
+      "requires": {
+        "@babel/types": "7.0.0-beta.44",
+        "jsesc": "^2.5.1",
+        "lodash": "^4.2.0",
+        "source-map": "^0.5.0",
+        "trim-right": "^1.0.1"
+      },
+      "dependencies": {
+        "jsesc": {
+          "version": "2.5.2",
+          "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
+          "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
+          "dev": true
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        }
+      }
+    },
+    "@babel/helper-function-name": {
+      "version": "7.0.0-beta.44",
+      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz",
+      "integrity": "sha512-MHRG2qZMKMFaBavX0LWpfZ2e+hLloT++N7rfM3DYOMUOGCD8cVjqZpwiL8a0bOX3IYcQev1ruciT0gdFFRTxzg==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-get-function-arity": "7.0.0-beta.44",
+        "@babel/template": "7.0.0-beta.44",
+        "@babel/types": "7.0.0-beta.44"
+      }
+    },
+    "@babel/helper-get-function-arity": {
+      "version": "7.0.0-beta.44",
+      "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz",
+      "integrity": "sha512-w0YjWVwrM2HwP6/H3sEgrSQdkCaxppqFeJtAnB23pRiJB5E/O9Yp7JAAeWBl+gGEgmBFinnTyOv2RN7rcSmMiw==",
+      "dev": true,
+      "requires": {
+        "@babel/types": "7.0.0-beta.44"
+      }
+    },
+    "@babel/helper-split-export-declaration": {
+      "version": "7.0.0-beta.44",
+      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz",
+      "integrity": "sha512-aQ7QowtkgKKzPGf0j6u77kBMdUFVBKNHw2p/3HX/POt5/oz8ec5cs0GwlgM8Hz7ui5EwJnzyfRmkNF1Nx1N7aA==",
+      "dev": true,
+      "requires": {
+        "@babel/types": "7.0.0-beta.44"
+      }
+    },
+    "@babel/highlight": {
+      "version": "7.0.0-beta.44",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.44.tgz",
+      "integrity": "sha512-Il19yJvy7vMFm8AVAh6OZzaFoAd0hbkeMZiX3P5HGD+z7dyI7RzndHB0dg6Urh/VAFfHtpOIzDUSxmY6coyZWQ==",
+      "dev": true,
+      "requires": {
+        "chalk": "^2.0.0",
+        "esutils": "^2.0.2",
+        "js-tokens": "^3.0.0"
+      }
+    },
+    "@babel/template": {
+      "version": "7.0.0-beta.44",
+      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.44.tgz",
+      "integrity": "sha512-w750Sloq0UNifLx1rUqwfbnC6uSUk0mfwwgGRfdLiaUzfAOiH0tHJE6ILQIUi3KYkjiCDTskoIsnfqZvWLBDng==",
+      "dev": true,
+      "requires": {
+        "@babel/code-frame": "7.0.0-beta.44",
+        "@babel/types": "7.0.0-beta.44",
+        "babylon": "7.0.0-beta.44",
+        "lodash": "^4.2.0"
+      },
+      "dependencies": {
+        "babylon": {
+          "version": "7.0.0-beta.44",
+          "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.44.tgz",
+          "integrity": "sha512-5Hlm13BJVAioCHpImtFqNOF2H3ieTOHd0fmFGMxOJ9jgeFqeAwsv3u5P5cR7CSeFrkgHsT19DgFJkHV0/Mcd8g==",
+          "dev": true
+        }
+      }
+    },
+    "@babel/traverse": {
+      "version": "7.0.0-beta.44",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.0.0-beta.44.tgz",
+      "integrity": "sha512-UHuDz8ukQkJCDASKHf+oDt3FVUzFd+QYfuBIsiNu/4+/ix6pP/C+uQZJ6K1oEfbCMv/IKWbgDEh7fcsnIE5AtA==",
+      "dev": true,
+      "requires": {
+        "@babel/code-frame": "7.0.0-beta.44",
+        "@babel/generator": "7.0.0-beta.44",
+        "@babel/helper-function-name": "7.0.0-beta.44",
+        "@babel/helper-split-export-declaration": "7.0.0-beta.44",
+        "@babel/types": "7.0.0-beta.44",
+        "babylon": "7.0.0-beta.44",
+        "debug": "^3.1.0",
+        "globals": "^11.1.0",
+        "invariant": "^2.2.0",
+        "lodash": "^4.2.0"
+      },
+      "dependencies": {
+        "babylon": {
+          "version": "7.0.0-beta.44",
+          "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.44.tgz",
+          "integrity": "sha512-5Hlm13BJVAioCHpImtFqNOF2H3ieTOHd0fmFGMxOJ9jgeFqeAwsv3u5P5cR7CSeFrkgHsT19DgFJkHV0/Mcd8g==",
+          "dev": true
+        },
+        "debug": {
+          "version": "3.2.7",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+          "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+          "dev": true,
+          "requires": {
+            "ms": "^2.1.1"
+          }
+        },
+        "globals": {
+          "version": "11.12.0",
+          "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+          "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+          "dev": true
+        },
+        "ms": {
+          "version": "2.1.3",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+          "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+          "dev": true
+        }
+      }
+    },
+    "@babel/types": {
+      "version": "7.0.0-beta.44",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.44.tgz",
+      "integrity": "sha512-5eTV4WRmqbaFM3v9gHAIljEQJU4Ssc6fxL61JN+Oe2ga/BwyjzjamwkCVVAQjHGuAX8i0BWo42dshL8eO5KfLQ==",
+      "dev": true,
+      "requires": {
+        "esutils": "^2.0.2",
+        "lodash": "^4.2.0",
+        "to-fast-properties": "^2.0.0"
+      },
+      "dependencies": {
+        "to-fast-properties": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+          "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
+          "dev": true
+        }
+      }
+    },
+    "@fullcalendar/common": {
+      "version": "5.5.1",
+      "resolved": "https://registry.npmjs.org/@fullcalendar/common/-/common-5.5.1.tgz",
+      "integrity": "sha512-tfVlX4aBHxCDJAVkUm93FXScOhmdz6/vUy/ISfpNeRNYuUvhJbmjoH67DpGNdS3we2n6/dVte021TE4Bbo4uRA==",
+      "requires": {
+        "ical.js": "^1.4.0",
+        "tslib": "^2.0.3"
+      },
+      "dependencies": {
+        "tslib": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
+          "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A=="
+        }
+      }
+    },
+    "@fullcalendar/core": {
+      "version": "5.5.1",
+      "resolved": "https://registry.npmjs.org/@fullcalendar/core/-/core-5.5.1.tgz",
+      "integrity": "sha512-6OAtYhgWekZExakbB3NUiIPZHsebBQQfwdWpccYYEKb5DZi3mf4gUb8CCrvfBp6YXx0hhYNlglPLcfJgxpy5Bg==",
+      "requires": {
+        "@fullcalendar/common": "~5.5.0",
+        "preact": "^10.0.5",
+        "tslib": "^2.0.3"
+      },
+      "dependencies": {
+        "tslib": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
+          "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A=="
+        }
+      }
+    },
+    "@fullcalendar/daygrid": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/@fullcalendar/daygrid/-/daygrid-5.5.0.tgz",
+      "integrity": "sha512-O/59C3ihElLsPnkjlD1xUgAf3v7WEARXVO+wZfASKtK14Ccux2MA9mWUA1+80m9q8on7SYL36ORhrea7GKy/qQ==",
+      "requires": {
+        "@fullcalendar/common": "~5.5.0",
+        "tslib": "^2.0.3"
+      },
+      "dependencies": {
+        "tslib": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
+          "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A=="
+        }
+      }
+    },
+    "@fullcalendar/vue": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/@fullcalendar/vue/-/vue-5.5.0.tgz",
+      "integrity": "sha512-CLqUyEc1OvPSmYl8zA92WZktoHZvDN3q58f4g91IOcjTWsBP3fVie9eOVFN6OxHTwQ9nekvnC0Y/fM4OFZJ1hQ==",
+      "requires": {
+        "@fullcalendar/core": "~5.5.0",
+        "tslib": "^2.0.3"
+      },
+      "dependencies": {
+        "tslib": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
+          "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A=="
+        }
+      }
+    },
+    "@types/json5": {
+      "version": "0.0.29",
+      "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
+      "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
+      "dev": true
+    },
+    "@types/q": {
+      "version": "1.5.4",
+      "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz",
+      "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==",
+      "dev": true
+    },
+    "abbrev": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+      "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
+    },
+    "accepts": {
+      "version": "1.3.7",
+      "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
+      "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
+      "dev": true,
+      "requires": {
+        "mime-types": "~2.1.24",
+        "negotiator": "0.6.2"
+      }
+    },
+    "acorn": {
+      "version": "5.7.4",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz",
+      "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==",
+      "dev": true
+    },
+    "acorn-dynamic-import": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz",
+      "integrity": "sha1-x1K9IQvvZ5UBtsbLf8hPj0cVjMQ=",
+      "dev": true,
+      "requires": {
+        "acorn": "^4.0.3"
+      },
+      "dependencies": {
+        "acorn": {
+          "version": "4.0.13",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz",
+          "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=",
+          "dev": true
+        }
+      }
+    },
+    "acorn-jsx": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz",
+      "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=",
+      "dev": true,
+      "requires": {
+        "acorn": "^3.0.4"
+      },
+      "dependencies": {
+        "acorn": {
+          "version": "3.3.0",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz",
+          "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=",
+          "dev": true
+        }
+      }
+    },
+    "adler-32": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.2.0.tgz",
+      "integrity": "sha1-aj5r8KY5ALoVZSgIyxXGgT0aXyU=",
+      "requires": {
+        "exit-on-epipe": "~1.0.1",
+        "printj": "~1.1.0"
+      }
+    },
+    "ajv": {
+      "version": "5.5.2",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
+      "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
+      "dev": true,
+      "requires": {
+        "co": "^4.6.0",
+        "fast-deep-equal": "^1.0.0",
+        "fast-json-stable-stringify": "^2.0.0",
+        "json-schema-traverse": "^0.3.0"
+      }
+    },
+    "ajv-keywords": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz",
+      "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=",
+      "dev": true
+    },
+    "align-text": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
+      "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.0.2",
+        "longest": "^1.0.1",
+        "repeat-string": "^1.5.2"
+      }
+    },
+    "alphanum-sort": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz",
+      "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=",
+      "dev": true
+    },
+    "amdefine": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
+      "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU="
+    },
+    "ansi-escapes": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz",
+      "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==",
+      "dev": true
+    },
+    "ansi-html": {
+      "version": "0.0.7",
+      "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz",
+      "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=",
+      "dev": true
+    },
+    "ansi-regex": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+      "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+    },
+    "ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "requires": {
+        "color-convert": "^1.9.0"
+      }
+    },
+    "anymatch": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
+      "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      }
+    },
+    "aproba": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
+      "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
+    },
+    "are-we-there-yet": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
+      "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
+      "requires": {
+        "delegates": "^1.0.0",
+        "readable-stream": "^2.0.6"
+      }
+    },
+    "argparse": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "requires": {
+        "sprintf-js": "~1.0.2"
+      }
+    },
+    "arr-diff": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+      "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+      "dev": true
+    },
+    "arr-flatten": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+      "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+      "dev": true
+    },
+    "arr-union": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+      "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
+      "dev": true
+    },
+    "array-find-index": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
+      "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E="
+    },
+    "array-flatten": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+      "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=",
+      "dev": true
+    },
+    "array-includes": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.2.tgz",
+      "integrity": "sha512-w2GspexNQpx+PutG3QpT437/BenZBj0M/MZGn5mzv/MofYqo0xmRHzn4lFsoDlWJ+THYsGJmFlW68WlDFx7VRw==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.0",
+        "define-properties": "^1.1.3",
+        "es-abstract": "^1.18.0-next.1",
+        "get-intrinsic": "^1.0.1",
+        "is-string": "^1.0.5"
+      }
+    },
+    "array-union": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+      "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
+      "dev": true,
+      "requires": {
+        "array-uniq": "^1.0.1"
+      }
+    },
+    "array-uniq": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
+      "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
+      "dev": true
+    },
+    "array-unique": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+      "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
+      "dev": true
+    },
+    "array.prototype.flat": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz",
+      "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.0",
+        "define-properties": "^1.1.3",
+        "es-abstract": "^1.18.0-next.1"
+      }
+    },
+    "asn1": {
+      "version": "0.2.4",
+      "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
+      "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+      "requires": {
+        "safer-buffer": "~2.1.0"
+      }
+    },
+    "asn1.js": {
+      "version": "5.4.1",
+      "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
+      "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
+      "dev": true,
+      "requires": {
+        "bn.js": "^4.0.0",
+        "inherits": "^2.0.1",
+        "minimalistic-assert": "^1.0.0",
+        "safer-buffer": "^2.1.0"
+      },
+      "dependencies": {
+        "bn.js": {
+          "version": "4.11.9",
+          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
+          "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
+          "dev": true
+        }
+      }
+    },
+    "assert": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz",
+      "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==",
+      "dev": true,
+      "requires": {
+        "object-assign": "^4.1.1",
+        "util": "0.10.3"
+      },
+      "dependencies": {
+        "inherits": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+          "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=",
+          "dev": true
+        },
+        "util": {
+          "version": "0.10.3",
+          "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
+          "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
+          "dev": true,
+          "requires": {
+            "inherits": "2.0.1"
+          }
+        }
+      }
+    },
+    "assert-plus": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+      "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+    },
+    "assign-symbols": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+      "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
+      "dev": true
+    },
+    "ast-types": {
+      "version": "0.9.6",
+      "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.9.6.tgz",
+      "integrity": "sha1-ECyenpAF0+fjgpvwxPok7oYu6bk=",
+      "dev": true
+    },
+    "async": {
+      "version": "2.6.3",
+      "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
+      "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
+      "dev": true,
+      "requires": {
+        "lodash": "^4.17.14"
+      }
+    },
+    "async-each": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
+      "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==",
+      "dev": true
+    },
+    "async-foreach": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz",
+      "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI="
+    },
+    "async-limiter": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
+      "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
+      "dev": true
+    },
+    "async-validator": {
+      "version": "1.8.5",
+      "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-1.8.5.tgz",
+      "integrity": "sha512-tXBM+1m056MAX0E8TL2iCjg8WvSyXu0Zc8LNtYqrVeyoL3+esHRZ4SieE9fKQyyU09uONjnMEjrNBMqT0mbvmA==",
+      "requires": {
+        "babel-runtime": "6.x"
+      }
+    },
+    "asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
+    },
+    "atob": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+      "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+      "dev": true
+    },
+    "autoprefixer": {
+      "version": "7.2.6",
+      "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-7.2.6.tgz",
+      "integrity": "sha512-Iq8TRIB+/9eQ8rbGhcP7ct5cYb/3qjNYAR2SnzLCEcwF6rvVOax8+9+fccgXk4bEhQGjOZd5TLhsksmAdsbGqQ==",
+      "dev": true,
+      "requires": {
+        "browserslist": "^2.11.3",
+        "caniuse-lite": "^1.0.30000805",
+        "normalize-range": "^0.1.2",
+        "num2fraction": "^1.2.2",
+        "postcss": "^6.0.17",
+        "postcss-value-parser": "^3.2.3"
+      }
+    },
+    "aws-sign2": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+      "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
+    },
+    "aws4": {
+      "version": "1.11.0",
+      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
+      "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA=="
+    },
+    "axios": {
+      "version": "0.21.1",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
+      "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
+      "requires": {
+        "follow-redirects": "^1.10.0"
+      }
+    },
+    "babel-code-frame": {
+      "version": "6.26.0",
+      "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
+      "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
+      "dev": true,
+      "requires": {
+        "chalk": "^1.1.3",
+        "esutils": "^2.0.2",
+        "js-tokens": "^3.0.2"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          }
+        },
+        "supports-color": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+          "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+          "dev": true
+        }
+      }
+    },
+    "babel-core": {
+      "version": "6.26.3",
+      "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz",
+      "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==",
+      "dev": true,
+      "requires": {
+        "babel-code-frame": "^6.26.0",
+        "babel-generator": "^6.26.0",
+        "babel-helpers": "^6.24.1",
+        "babel-messages": "^6.23.0",
+        "babel-register": "^6.26.0",
+        "babel-runtime": "^6.26.0",
+        "babel-template": "^6.26.0",
+        "babel-traverse": "^6.26.0",
+        "babel-types": "^6.26.0",
+        "babylon": "^6.18.0",
+        "convert-source-map": "^1.5.1",
+        "debug": "^2.6.9",
+        "json5": "^0.5.1",
+        "lodash": "^4.17.4",
+        "minimatch": "^3.0.4",
+        "path-is-absolute": "^1.0.1",
+        "private": "^0.1.8",
+        "slash": "^1.0.0",
+        "source-map": "^0.5.7"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        }
+      }
+    },
+    "babel-eslint": {
+      "version": "8.2.6",
+      "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.2.6.tgz",
+      "integrity": "sha512-aCdHjhzcILdP8c9lej7hvXKvQieyRt20SF102SIGyY4cUIiw6UaAtK4j2o3dXX74jEmy0TJ0CEhv4fTIM3SzcA==",
+      "dev": true,
+      "requires": {
+        "@babel/code-frame": "7.0.0-beta.44",
+        "@babel/traverse": "7.0.0-beta.44",
+        "@babel/types": "7.0.0-beta.44",
+        "babylon": "7.0.0-beta.44",
+        "eslint-scope": "3.7.1",
+        "eslint-visitor-keys": "^1.0.0"
+      },
+      "dependencies": {
+        "babylon": {
+          "version": "7.0.0-beta.44",
+          "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.44.tgz",
+          "integrity": "sha512-5Hlm13BJVAioCHpImtFqNOF2H3ieTOHd0fmFGMxOJ9jgeFqeAwsv3u5P5cR7CSeFrkgHsT19DgFJkHV0/Mcd8g==",
+          "dev": true
+        }
+      }
+    },
+    "babel-generator": {
+      "version": "6.26.1",
+      "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz",
+      "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==",
+      "dev": true,
+      "requires": {
+        "babel-messages": "^6.23.0",
+        "babel-runtime": "^6.26.0",
+        "babel-types": "^6.26.0",
+        "detect-indent": "^4.0.0",
+        "jsesc": "^1.3.0",
+        "lodash": "^4.17.4",
+        "source-map": "^0.5.7",
+        "trim-right": "^1.0.1"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        }
+      }
+    },
+    "babel-helper-bindify-decorators": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz",
+      "integrity": "sha1-FMGeXxQte0fxmlJDHlKxzLxAozA=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "^6.22.0",
+        "babel-traverse": "^6.24.1",
+        "babel-types": "^6.24.1"
+      }
+    },
+    "babel-helper-builder-binary-assignment-operator-visitor": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz",
+      "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=",
+      "dev": true,
+      "requires": {
+        "babel-helper-explode-assignable-expression": "^6.24.1",
+        "babel-runtime": "^6.22.0",
+        "babel-types": "^6.24.1"
+      }
+    },
+    "babel-helper-call-delegate": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz",
+      "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=",
+      "dev": true,
+      "requires": {
+        "babel-helper-hoist-variables": "^6.24.1",
+        "babel-runtime": "^6.22.0",
+        "babel-traverse": "^6.24.1",
+        "babel-types": "^6.24.1"
+      }
+    },
+    "babel-helper-define-map": {
+      "version": "6.26.0",
+      "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz",
+      "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=",
+      "dev": true,
+      "requires": {
+        "babel-helper-function-name": "^6.24.1",
+        "babel-runtime": "^6.26.0",
+        "babel-types": "^6.26.0",
+        "lodash": "^4.17.4"
+      }
+    },
+    "babel-helper-explode-assignable-expression": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz",
+      "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "^6.22.0",
+        "babel-traverse": "^6.24.1",
+        "babel-types": "^6.24.1"
+      }
+    },
+    "babel-helper-explode-class": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz",
+      "integrity": "sha1-fcKjkQ3uAHBW4eMdZAztPVTqqes=",
+      "dev": true,
+      "requires": {
+        "babel-helper-bindify-decorators": "^6.24.1",
+        "babel-runtime": "^6.22.0",
+        "babel-traverse": "^6.24.1",
+        "babel-types": "^6.24.1"
+      }
+    },
+    "babel-helper-function-name": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz",
+      "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=",
+      "dev": true,
+      "requires": {
+        "babel-helper-get-function-arity": "^6.24.1",
+        "babel-runtime": "^6.22.0",
+        "babel-template": "^6.24.1",
+        "babel-traverse": "^6.24.1",
+        "babel-types": "^6.24.1"
+      }
+    },
+    "babel-helper-get-function-arity": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz",
+      "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "^6.22.0",
+        "babel-types": "^6.24.1"
+      }
+    },
+    "babel-helper-hoist-variables": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz",
+      "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "^6.22.0",
+        "babel-types": "^6.24.1"
+      }
+    },
+    "babel-helper-optimise-call-expression": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz",
+      "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "^6.22.0",
+        "babel-types": "^6.24.1"
+      }
+    },
+    "babel-helper-regex": {
+      "version": "6.26.0",
+      "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz",
+      "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "^6.26.0",
+        "babel-types": "^6.26.0",
+        "lodash": "^4.17.4"
+      }
+    },
+    "babel-helper-remap-async-to-generator": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz",
+      "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=",
+      "dev": true,
+      "requires": {
+        "babel-helper-function-name": "^6.24.1",
+        "babel-runtime": "^6.22.0",
+        "babel-template": "^6.24.1",
+        "babel-traverse": "^6.24.1",
+        "babel-types": "^6.24.1"
+      }
+    },
+    "babel-helper-replace-supers": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz",
+      "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=",
+      "dev": true,
+      "requires": {
+        "babel-helper-optimise-call-expression": "^6.24.1",
+        "babel-messages": "^6.23.0",
+        "babel-runtime": "^6.22.0",
+        "babel-template": "^6.24.1",
+        "babel-traverse": "^6.24.1",
+        "babel-types": "^6.24.1"
+      }
+    },
+    "babel-helper-vue-jsx-merge-props": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-2.0.3.tgz",
+      "integrity": "sha512-gsLiKK7Qrb7zYJNgiXKpXblxbV5ffSwR0f5whkPAaBAR4fhi6bwRZxX9wBlIc5M/v8CCkXUbXZL4N/nSE97cqg=="
+    },
+    "babel-helpers": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz",
+      "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "^6.22.0",
+        "babel-template": "^6.24.1"
+      }
+    },
+    "babel-loader": {
+      "version": "7.1.5",
+      "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-7.1.5.tgz",
+      "integrity": "sha512-iCHfbieL5d1LfOQeeVJEUyD9rTwBcP/fcEbRCfempxTDuqrKpu0AZjLAQHEQa3Yqyj9ORKe2iHfoj4rHLf7xpw==",
+      "dev": true,
+      "requires": {
+        "find-cache-dir": "^1.0.0",
+        "loader-utils": "^1.0.2",
+        "mkdirp": "^0.5.1"
+      }
+    },
+    "babel-messages": {
+      "version": "6.23.0",
+      "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
+      "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "^6.22.0"
+      }
+    },
+    "babel-plugin-check-es2015-constants": {
+      "version": "6.22.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz",
+      "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "^6.22.0"
+      }
+    },
+    "babel-plugin-syntax-async-functions": {
+      "version": "6.13.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz",
+      "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=",
+      "dev": true
+    },
+    "babel-plugin-syntax-async-generators": {
+      "version": "6.13.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz",
+      "integrity": "sha1-a8lj67FuzLrmuStZbrfzXDQqi5o=",
+      "dev": true
+    },
+    "babel-plugin-syntax-class-properties": {
+      "version": "6.13.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz",
+      "integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94=",
+      "dev": true
+    },
+    "babel-plugin-syntax-decorators": {
+      "version": "6.13.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz",
+      "integrity": "sha1-MSVjtNvePMgGzuPkFszurd0RrAs=",
+      "dev": true
+    },
+    "babel-plugin-syntax-dynamic-import": {
+      "version": "6.18.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz",
+      "integrity": "sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo=",
+      "dev": true
+    },
+    "babel-plugin-syntax-exponentiation-operator": {
+      "version": "6.13.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz",
+      "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=",
+      "dev": true
+    },
+    "babel-plugin-syntax-jsx": {
+      "version": "6.18.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz",
+      "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=",
+      "dev": true
+    },
+    "babel-plugin-syntax-object-rest-spread": {
+      "version": "6.13.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
+      "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=",
+      "dev": true
+    },
+    "babel-plugin-syntax-trailing-function-commas": {
+      "version": "6.22.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz",
+      "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=",
+      "dev": true
+    },
+    "babel-plugin-transform-async-generator-functions": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz",
+      "integrity": "sha1-8FiQAUX9PpkHpt3yjaWfIVJYpds=",
+      "dev": true,
+      "requires": {
+        "babel-helper-remap-async-to-generator": "^6.24.1",
+        "babel-plugin-syntax-async-generators": "^6.5.0",
+        "babel-runtime": "^6.22.0"
+      }
+    },
+    "babel-plugin-transform-async-to-generator": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz",
+      "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=",
+      "dev": true,
+      "requires": {
+        "babel-helper-remap-async-to-generator": "^6.24.1",
+        "babel-plugin-syntax-async-functions": "^6.8.0",
+        "babel-runtime": "^6.22.0"
+      }
+    },
+    "babel-plugin-transform-class-properties": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz",
+      "integrity": "sha1-anl2PqYdM9NvN7YRqp3vgagbRqw=",
+      "dev": true,
+      "requires": {
+        "babel-helper-function-name": "^6.24.1",
+        "babel-plugin-syntax-class-properties": "^6.8.0",
+        "babel-runtime": "^6.22.0",
+        "babel-template": "^6.24.1"
+      }
+    },
+    "babel-plugin-transform-decorators": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz",
+      "integrity": "sha1-eIAT2PjGtSIr33s0Q5Df13Vp4k0=",
+      "dev": true,
+      "requires": {
+        "babel-helper-explode-class": "^6.24.1",
+        "babel-plugin-syntax-decorators": "^6.13.0",
+        "babel-runtime": "^6.22.0",
+        "babel-template": "^6.24.1",
+        "babel-types": "^6.24.1"
+      }
+    },
+    "babel-plugin-transform-es2015-arrow-functions": {
+      "version": "6.22.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz",
+      "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "^6.22.0"
+      }
+    },
+    "babel-plugin-transform-es2015-block-scoped-functions": {
+      "version": "6.22.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz",
+      "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "^6.22.0"
+      }
+    },
+    "babel-plugin-transform-es2015-block-scoping": {
+      "version": "6.26.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz",
+      "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "^6.26.0",
+        "babel-template": "^6.26.0",
+        "babel-traverse": "^6.26.0",
+        "babel-types": "^6.26.0",
+        "lodash": "^4.17.4"
+      }
+    },
+    "babel-plugin-transform-es2015-classes": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz",
+      "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=",
+      "dev": true,
+      "requires": {
+        "babel-helper-define-map": "^6.24.1",
+        "babel-helper-function-name": "^6.24.1",
+        "babel-helper-optimise-call-expression": "^6.24.1",
+        "babel-helper-replace-supers": "^6.24.1",
+        "babel-messages": "^6.23.0",
+        "babel-runtime": "^6.22.0",
+        "babel-template": "^6.24.1",
+        "babel-traverse": "^6.24.1",
+        "babel-types": "^6.24.1"
+      }
+    },
+    "babel-plugin-transform-es2015-computed-properties": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz",
+      "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "^6.22.0",
+        "babel-template": "^6.24.1"
+      }
+    },
+    "babel-plugin-transform-es2015-destructuring": {
+      "version": "6.23.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz",
+      "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "^6.22.0"
+      }
+    },
+    "babel-plugin-transform-es2015-duplicate-keys": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz",
+      "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "^6.22.0",
+        "babel-types": "^6.24.1"
+      }
+    },
+    "babel-plugin-transform-es2015-for-of": {
+      "version": "6.23.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz",
+      "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "^6.22.0"
+      }
+    },
+    "babel-plugin-transform-es2015-function-name": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz",
+      "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=",
+      "dev": true,
+      "requires": {
+        "babel-helper-function-name": "^6.24.1",
+        "babel-runtime": "^6.22.0",
+        "babel-types": "^6.24.1"
+      }
+    },
+    "babel-plugin-transform-es2015-literals": {
+      "version": "6.22.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz",
+      "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "^6.22.0"
+      }
+    },
+    "babel-plugin-transform-es2015-modules-amd": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz",
+      "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=",
+      "dev": true,
+      "requires": {
+        "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1",
+        "babel-runtime": "^6.22.0",
+        "babel-template": "^6.24.1"
+      }
+    },
+    "babel-plugin-transform-es2015-modules-commonjs": {
+      "version": "6.26.2",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz",
+      "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==",
+      "dev": true,
+      "requires": {
+        "babel-plugin-transform-strict-mode": "^6.24.1",
+        "babel-runtime": "^6.26.0",
+        "babel-template": "^6.26.0",
+        "babel-types": "^6.26.0"
+      }
+    },
+    "babel-plugin-transform-es2015-modules-systemjs": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz",
+      "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=",
+      "dev": true,
+      "requires": {
+        "babel-helper-hoist-variables": "^6.24.1",
+        "babel-runtime": "^6.22.0",
+        "babel-template": "^6.24.1"
+      }
+    },
+    "babel-plugin-transform-es2015-modules-umd": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz",
+      "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=",
+      "dev": true,
+      "requires": {
+        "babel-plugin-transform-es2015-modules-amd": "^6.24.1",
+        "babel-runtime": "^6.22.0",
+        "babel-template": "^6.24.1"
+      }
+    },
+    "babel-plugin-transform-es2015-object-super": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz",
+      "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=",
+      "dev": true,
+      "requires": {
+        "babel-helper-replace-supers": "^6.24.1",
+        "babel-runtime": "^6.22.0"
+      }
+    },
+    "babel-plugin-transform-es2015-parameters": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz",
+      "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=",
+      "dev": true,
+      "requires": {
+        "babel-helper-call-delegate": "^6.24.1",
+        "babel-helper-get-function-arity": "^6.24.1",
+        "babel-runtime": "^6.22.0",
+        "babel-template": "^6.24.1",
+        "babel-traverse": "^6.24.1",
+        "babel-types": "^6.24.1"
+      }
+    },
+    "babel-plugin-transform-es2015-shorthand-properties": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz",
+      "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "^6.22.0",
+        "babel-types": "^6.24.1"
+      }
+    },
+    "babel-plugin-transform-es2015-spread": {
+      "version": "6.22.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz",
+      "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "^6.22.0"
+      }
+    },
+    "babel-plugin-transform-es2015-sticky-regex": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz",
+      "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=",
+      "dev": true,
+      "requires": {
+        "babel-helper-regex": "^6.24.1",
+        "babel-runtime": "^6.22.0",
+        "babel-types": "^6.24.1"
+      }
+    },
+    "babel-plugin-transform-es2015-template-literals": {
+      "version": "6.22.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz",
+      "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "^6.22.0"
+      }
+    },
+    "babel-plugin-transform-es2015-typeof-symbol": {
+      "version": "6.23.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz",
+      "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "^6.22.0"
+      }
+    },
+    "babel-plugin-transform-es2015-unicode-regex": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz",
+      "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=",
+      "dev": true,
+      "requires": {
+        "babel-helper-regex": "^6.24.1",
+        "babel-runtime": "^6.22.0",
+        "regexpu-core": "^2.0.0"
+      }
+    },
+    "babel-plugin-transform-exponentiation-operator": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz",
+      "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=",
+      "dev": true,
+      "requires": {
+        "babel-helper-builder-binary-assignment-operator-visitor": "^6.24.1",
+        "babel-plugin-syntax-exponentiation-operator": "^6.8.0",
+        "babel-runtime": "^6.22.0"
+      }
+    },
+    "babel-plugin-transform-object-rest-spread": {
+      "version": "6.26.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz",
+      "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=",
+      "dev": true,
+      "requires": {
+        "babel-plugin-syntax-object-rest-spread": "^6.8.0",
+        "babel-runtime": "^6.26.0"
+      }
+    },
+    "babel-plugin-transform-regenerator": {
+      "version": "6.26.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz",
+      "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=",
+      "dev": true,
+      "requires": {
+        "regenerator-transform": "^0.10.0"
+      }
+    },
+    "babel-plugin-transform-runtime": {
+      "version": "6.23.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.23.0.tgz",
+      "integrity": "sha1-iEkNRGUC6puOfvsP4J7E2ZR5se4=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "^6.22.0"
+      }
+    },
+    "babel-plugin-transform-strict-mode": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz",
+      "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "^6.22.0",
+        "babel-types": "^6.24.1"
+      }
+    },
+    "babel-plugin-transform-vue-jsx": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-vue-jsx/-/babel-plugin-transform-vue-jsx-3.7.0.tgz",
+      "integrity": "sha512-W39X07/n3oJMQd8tALBO+440NraGSF//Lo1ydd/9Nme3+QiRGFBb1Q39T9iixh0jZPPbfv3so18tNoIgLatymw==",
+      "dev": true,
+      "requires": {
+        "esutils": "^2.0.2"
+      }
+    },
+    "babel-preset-env": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.7.0.tgz",
+      "integrity": "sha512-9OR2afuKDneX2/q2EurSftUYM0xGu4O2D9adAhVfADDhrYDaxXV0rBbevVYoY9n6nyX1PmQW/0jtpJvUNr9CHg==",
+      "dev": true,
+      "requires": {
+        "babel-plugin-check-es2015-constants": "^6.22.0",
+        "babel-plugin-syntax-trailing-function-commas": "^6.22.0",
+        "babel-plugin-transform-async-to-generator": "^6.22.0",
+        "babel-plugin-transform-es2015-arrow-functions": "^6.22.0",
+        "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0",
+        "babel-plugin-transform-es2015-block-scoping": "^6.23.0",
+        "babel-plugin-transform-es2015-classes": "^6.23.0",
+        "babel-plugin-transform-es2015-computed-properties": "^6.22.0",
+        "babel-plugin-transform-es2015-destructuring": "^6.23.0",
+        "babel-plugin-transform-es2015-duplicate-keys": "^6.22.0",
+        "babel-plugin-transform-es2015-for-of": "^6.23.0",
+        "babel-plugin-transform-es2015-function-name": "^6.22.0",
+        "babel-plugin-transform-es2015-literals": "^6.22.0",
+        "babel-plugin-transform-es2015-modules-amd": "^6.22.0",
+        "babel-plugin-transform-es2015-modules-commonjs": "^6.23.0",
+        "babel-plugin-transform-es2015-modules-systemjs": "^6.23.0",
+        "babel-plugin-transform-es2015-modules-umd": "^6.23.0",
+        "babel-plugin-transform-es2015-object-super": "^6.22.0",
+        "babel-plugin-transform-es2015-parameters": "^6.23.0",
+        "babel-plugin-transform-es2015-shorthand-properties": "^6.22.0",
+        "babel-plugin-transform-es2015-spread": "^6.22.0",
+        "babel-plugin-transform-es2015-sticky-regex": "^6.22.0",
+        "babel-plugin-transform-es2015-template-literals": "^6.22.0",
+        "babel-plugin-transform-es2015-typeof-symbol": "^6.23.0",
+        "babel-plugin-transform-es2015-unicode-regex": "^6.22.0",
+        "babel-plugin-transform-exponentiation-operator": "^6.22.0",
+        "babel-plugin-transform-regenerator": "^6.22.0",
+        "browserslist": "^3.2.6",
+        "invariant": "^2.2.2",
+        "semver": "^5.3.0"
+      },
+      "dependencies": {
+        "browserslist": {
+          "version": "3.2.8",
+          "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz",
+          "integrity": "sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==",
+          "dev": true,
+          "requires": {
+            "caniuse-lite": "^1.0.30000844",
+            "electron-to-chromium": "^1.3.47"
+          }
+        }
+      }
+    },
+    "babel-preset-es2015": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz",
+      "integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=",
+      "dev": true,
+      "requires": {
+        "babel-plugin-check-es2015-constants": "^6.22.0",
+        "babel-plugin-transform-es2015-arrow-functions": "^6.22.0",
+        "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0",
+        "babel-plugin-transform-es2015-block-scoping": "^6.24.1",
+        "babel-plugin-transform-es2015-classes": "^6.24.1",
+        "babel-plugin-transform-es2015-computed-properties": "^6.24.1",
+        "babel-plugin-transform-es2015-destructuring": "^6.22.0",
+        "babel-plugin-transform-es2015-duplicate-keys": "^6.24.1",
+        "babel-plugin-transform-es2015-for-of": "^6.22.0",
+        "babel-plugin-transform-es2015-function-name": "^6.24.1",
+        "babel-plugin-transform-es2015-literals": "^6.22.0",
+        "babel-plugin-transform-es2015-modules-amd": "^6.24.1",
+        "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1",
+        "babel-plugin-transform-es2015-modules-systemjs": "^6.24.1",
+        "babel-plugin-transform-es2015-modules-umd": "^6.24.1",
+        "babel-plugin-transform-es2015-object-super": "^6.24.1",
+        "babel-plugin-transform-es2015-parameters": "^6.24.1",
+        "babel-plugin-transform-es2015-shorthand-properties": "^6.24.1",
+        "babel-plugin-transform-es2015-spread": "^6.22.0",
+        "babel-plugin-transform-es2015-sticky-regex": "^6.24.1",
+        "babel-plugin-transform-es2015-template-literals": "^6.22.0",
+        "babel-plugin-transform-es2015-typeof-symbol": "^6.22.0",
+        "babel-plugin-transform-es2015-unicode-regex": "^6.24.1",
+        "babel-plugin-transform-regenerator": "^6.24.1"
+      }
+    },
+    "babel-preset-stage-2": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz",
+      "integrity": "sha1-2eKWD7PXEYfw5k7sYrwHdnIZvcE=",
+      "dev": true,
+      "requires": {
+        "babel-plugin-syntax-dynamic-import": "^6.18.0",
+        "babel-plugin-transform-class-properties": "^6.24.1",
+        "babel-plugin-transform-decorators": "^6.24.1",
+        "babel-preset-stage-3": "^6.24.1"
+      }
+    },
+    "babel-preset-stage-3": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz",
+      "integrity": "sha1-g2raCp56f6N8sTj7kyb4eTSkg5U=",
+      "dev": true,
+      "requires": {
+        "babel-plugin-syntax-trailing-function-commas": "^6.22.0",
+        "babel-plugin-transform-async-generator-functions": "^6.24.1",
+        "babel-plugin-transform-async-to-generator": "^6.24.1",
+        "babel-plugin-transform-exponentiation-operator": "^6.24.1",
+        "babel-plugin-transform-object-rest-spread": "^6.22.0"
+      }
+    },
+    "babel-register": {
+      "version": "6.26.0",
+      "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz",
+      "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=",
+      "dev": true,
+      "requires": {
+        "babel-core": "^6.26.0",
+        "babel-runtime": "^6.26.0",
+        "core-js": "^2.5.0",
+        "home-or-tmp": "^2.0.0",
+        "lodash": "^4.17.4",
+        "mkdirp": "^0.5.1",
+        "source-map-support": "^0.4.15"
+      }
+    },
+    "babel-runtime": {
+      "version": "6.26.0",
+      "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+      "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+      "requires": {
+        "core-js": "^2.4.0",
+        "regenerator-runtime": "^0.11.0"
+      }
+    },
+    "babel-template": {
+      "version": "6.26.0",
+      "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz",
+      "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "^6.26.0",
+        "babel-traverse": "^6.26.0",
+        "babel-types": "^6.26.0",
+        "babylon": "^6.18.0",
+        "lodash": "^4.17.4"
+      }
+    },
+    "babel-traverse": {
+      "version": "6.26.0",
+      "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
+      "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=",
+      "dev": true,
+      "requires": {
+        "babel-code-frame": "^6.26.0",
+        "babel-messages": "^6.23.0",
+        "babel-runtime": "^6.26.0",
+        "babel-types": "^6.26.0",
+        "babylon": "^6.18.0",
+        "debug": "^2.6.8",
+        "globals": "^9.18.0",
+        "invariant": "^2.2.2",
+        "lodash": "^4.17.4"
+      }
+    },
+    "babel-types": {
+      "version": "6.26.0",
+      "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
+      "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "^6.26.0",
+        "esutils": "^2.0.2",
+        "lodash": "^4.17.4",
+        "to-fast-properties": "^1.0.3"
+      }
+    },
+    "babylon": {
+      "version": "6.18.0",
+      "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
+      "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
+      "dev": true
+    },
+    "balanced-match": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+    },
+    "base": {
+      "version": "0.11.2",
+      "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+      "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+      "dev": true,
+      "requires": {
+        "cache-base": "^1.0.1",
+        "class-utils": "^0.3.5",
+        "component-emitter": "^1.2.1",
+        "define-property": "^1.0.0",
+        "isobject": "^3.0.1",
+        "mixin-deep": "^1.2.0",
+        "pascalcase": "^0.1.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^1.0.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        },
+        "kind-of": {
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+          "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+          "dev": true
+        }
+      }
+    },
+    "base64-js": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+      "dev": true
+    },
+    "batch": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
+      "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=",
+      "dev": true
+    },
+    "bcrypt-pbkdf": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+      "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+      "requires": {
+        "tweetnacl": "^0.14.3"
+      }
+    },
+    "bfj-node4": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/bfj-node4/-/bfj-node4-5.3.1.tgz",
+      "integrity": "sha512-SOmOsowQWfXc7ybFARsK3C4MCOWzERaOMV/Fl3Tgjs+5dJWyzo3oa127jL44eMbQiAN17J7SvAs2TRxEScTUmg==",
+      "dev": true,
+      "requires": {
+        "bluebird": "^3.5.1",
+        "check-types": "^7.3.0",
+        "tryer": "^1.0.0"
+      }
+    },
+    "big.js": {
+      "version": "5.2.2",
+      "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
+      "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
+      "dev": true
+    },
+    "binary-extensions": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+      "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+      "dev": true,
+      "optional": true
+    },
+    "block-stream": {
+      "version": "0.0.9",
+      "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
+      "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=",
+      "requires": {
+        "inherits": "~2.0.0"
+      }
+    },
+    "bluebird": {
+      "version": "3.7.2",
+      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+      "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
+      "dev": true
+    },
+    "bmaplib.curveline": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/bmaplib.curveline/-/bmaplib.curveline-1.0.0.tgz",
+      "integrity": "sha512-9wcFMVhiYxNPqpvsLDAADn3qDhNzXp2mA6VyHSHg2XOAgSooC7ZiujdFhy0sp+0QYjTfJ/MjmLuNoUg2HHxH4Q=="
+    },
+    "bmaplib.heatmap": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/bmaplib.heatmap/-/bmaplib.heatmap-1.0.4.tgz",
+      "integrity": "sha512-rmhqUARBpUSJ9jXzUI2j7dIOqnc38bqubkx/8a349U2qtw/ulLUwyzRD535OrA8G7w5cz4aPKm6/rNvUAarg/Q=="
+    },
+    "bmaplib.lushu": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/bmaplib.lushu/-/bmaplib.lushu-1.0.7.tgz",
+      "integrity": "sha512-LVvgpESPii6xGxyjnQjq8u+ic4NjvhdCPV/RiSS/PGTUdZKeTDS7prSpleJLZH3ES0+oc0gYn8bw0LtPYUSz2w=="
+    },
+    "bmaplib.markerclusterer": {
+      "version": "1.0.13",
+      "resolved": "https://registry.npmjs.org/bmaplib.markerclusterer/-/bmaplib.markerclusterer-1.0.13.tgz",
+      "integrity": "sha512-VrLyWSiuDEVNi0yUfwOhFQ6z1oEEHS4w36GNu3iASu6p52QIx9uAXMUkuSCHReNR0bj2Cp9SA1dSx5RpojXajQ==",
+      "requires": {
+        "bmaplib.texticonoverlay": "^1.0.2"
+      }
+    },
+    "bmaplib.texticonoverlay": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/bmaplib.texticonoverlay/-/bmaplib.texticonoverlay-1.0.2.tgz",
+      "integrity": "sha512-4ZTWr4ZP3B6qEWput5Tut16CfZgII38YwM3bpyb4gFTQyORlKYryFp9WHWrwZZaHlOyYDAXG9SX0hka43jTADg=="
+    },
+    "bn.js": {
+      "version": "5.1.3",
+      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz",
+      "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==",
+      "dev": true
+    },
+    "body-parser": {
+      "version": "1.19.0",
+      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
+      "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
+      "dev": true,
+      "requires": {
+        "bytes": "3.1.0",
+        "content-type": "~1.0.4",
+        "debug": "2.6.9",
+        "depd": "~1.1.2",
+        "http-errors": "1.7.2",
+        "iconv-lite": "0.4.24",
+        "on-finished": "~2.3.0",
+        "qs": "6.7.0",
+        "raw-body": "2.4.0",
+        "type-is": "~1.6.17"
+      }
+    },
+    "bonjour": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz",
+      "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=",
+      "dev": true,
+      "requires": {
+        "array-flatten": "^2.1.0",
+        "deep-equal": "^1.0.1",
+        "dns-equal": "^1.0.0",
+        "dns-txt": "^2.0.2",
+        "multicast-dns": "^6.0.1",
+        "multicast-dns-service-types": "^1.1.0"
+      },
+      "dependencies": {
+        "array-flatten": {
+          "version": "2.1.2",
+          "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
+          "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==",
+          "dev": true
+        }
+      }
+    },
+    "boolbase": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+      "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
+      "dev": true
+    },
+    "brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "requires": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "braces": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "fill-range": "^7.0.1"
+      }
+    },
+    "brorand": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
+      "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=",
+      "dev": true
+    },
+    "browserify-aes": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
+      "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
+      "dev": true,
+      "requires": {
+        "buffer-xor": "^1.0.3",
+        "cipher-base": "^1.0.0",
+        "create-hash": "^1.1.0",
+        "evp_bytestokey": "^1.0.3",
+        "inherits": "^2.0.1",
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "browserify-cipher": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz",
+      "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==",
+      "dev": true,
+      "requires": {
+        "browserify-aes": "^1.0.4",
+        "browserify-des": "^1.0.0",
+        "evp_bytestokey": "^1.0.0"
+      }
+    },
+    "browserify-des": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz",
+      "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==",
+      "dev": true,
+      "requires": {
+        "cipher-base": "^1.0.1",
+        "des.js": "^1.0.0",
+        "inherits": "^2.0.1",
+        "safe-buffer": "^5.1.2"
+      }
+    },
+    "browserify-rsa": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz",
+      "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==",
+      "dev": true,
+      "requires": {
+        "bn.js": "^5.0.0",
+        "randombytes": "^2.0.1"
+      }
+    },
+    "browserify-sign": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz",
+      "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==",
+      "dev": true,
+      "requires": {
+        "bn.js": "^5.1.1",
+        "browserify-rsa": "^4.0.1",
+        "create-hash": "^1.2.0",
+        "create-hmac": "^1.1.7",
+        "elliptic": "^6.5.3",
+        "inherits": "^2.0.4",
+        "parse-asn1": "^5.1.5",
+        "readable-stream": "^3.6.0",
+        "safe-buffer": "^5.2.0"
+      },
+      "dependencies": {
+        "readable-stream": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+          "dev": true,
+          "requires": {
+            "inherits": "^2.0.3",
+            "string_decoder": "^1.1.1",
+            "util-deprecate": "^1.0.1"
+          }
+        },
+        "safe-buffer": {
+          "version": "5.2.1",
+          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+          "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+          "dev": true
+        }
+      }
+    },
+    "browserify-zlib": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
+      "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
+      "dev": true,
+      "requires": {
+        "pako": "~1.0.5"
+      }
+    },
+    "browserslist": {
+      "version": "2.11.3",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-2.11.3.tgz",
+      "integrity": "sha512-yWu5cXT7Av6mVwzWc8lMsJMHWn4xyjSuGYi4IozbVTLUOEYPSagUB8kiMDUHA1fS3zjr8nkxkn9jdvug4BBRmA==",
+      "dev": true,
+      "requires": {
+        "caniuse-lite": "^1.0.30000792",
+        "electron-to-chromium": "^1.3.30"
+      }
+    },
+    "buffer": {
+      "version": "4.9.2",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz",
+      "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==",
+      "dev": true,
+      "requires": {
+        "base64-js": "^1.0.2",
+        "ieee754": "^1.1.4",
+        "isarray": "^1.0.0"
+      }
+    },
+    "buffer-from": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+      "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
+      "dev": true
+    },
+    "buffer-indexof": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz",
+      "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==",
+      "dev": true
+    },
+    "buffer-xor": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
+      "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=",
+      "dev": true
+    },
+    "builtin-status-codes": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
+      "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=",
+      "dev": true
+    },
+    "bytes": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
+      "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
+      "dev": true
+    },
+    "cacache": {
+      "version": "10.0.4",
+      "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz",
+      "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==",
+      "dev": true,
+      "requires": {
+        "bluebird": "^3.5.1",
+        "chownr": "^1.0.1",
+        "glob": "^7.1.2",
+        "graceful-fs": "^4.1.11",
+        "lru-cache": "^4.1.1",
+        "mississippi": "^2.0.0",
+        "mkdirp": "^0.5.1",
+        "move-concurrently": "^1.0.1",
+        "promise-inflight": "^1.0.1",
+        "rimraf": "^2.6.2",
+        "ssri": "^5.2.4",
+        "unique-filename": "^1.1.0",
+        "y18n": "^4.0.0"
+      }
+    },
+    "cache-base": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+      "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+      "dev": true,
+      "requires": {
+        "collection-visit": "^1.0.0",
+        "component-emitter": "^1.2.1",
+        "get-value": "^2.0.6",
+        "has-value": "^1.0.0",
+        "isobject": "^3.0.1",
+        "set-value": "^2.0.0",
+        "to-object-path": "^0.3.0",
+        "union-value": "^1.0.0",
+        "unset-value": "^1.0.0"
+      }
+    },
+    "call-bind": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+      "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+      "dev": true,
+      "requires": {
+        "function-bind": "^1.1.1",
+        "get-intrinsic": "^1.0.2"
+      }
+    },
+    "caller-callsite": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
+      "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=",
+      "dev": true,
+      "requires": {
+        "callsites": "^2.0.0"
+      },
+      "dependencies": {
+        "callsites": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
+          "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=",
+          "dev": true
+        }
+      }
+    },
+    "caller-path": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz",
+      "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=",
+      "dev": true,
+      "requires": {
+        "callsites": "^0.2.0"
+      }
+    },
+    "callsites": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz",
+      "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=",
+      "dev": true
+    },
+    "camel-case": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz",
+      "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=",
+      "dev": true,
+      "requires": {
+        "no-case": "^2.2.0",
+        "upper-case": "^1.1.1"
+      }
+    },
+    "camelcase": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
+      "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=",
+      "dev": true
+    },
+    "camelcase-keys": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
+      "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
+      "requires": {
+        "camelcase": "^2.0.0",
+        "map-obj": "^1.0.0"
+      },
+      "dependencies": {
+        "camelcase": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
+          "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8="
+        }
+      }
+    },
+    "caniuse-api": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.6.1.tgz",
+      "integrity": "sha1-tTTnxzTE+B7F++isoq0kNUuWLGw=",
+      "dev": true,
+      "requires": {
+        "browserslist": "^1.3.6",
+        "caniuse-db": "^1.0.30000529",
+        "lodash.memoize": "^4.1.2",
+        "lodash.uniq": "^4.5.0"
+      },
+      "dependencies": {
+        "browserslist": {
+          "version": "1.7.7",
+          "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz",
+          "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=",
+          "dev": true,
+          "requires": {
+            "caniuse-db": "^1.0.30000639",
+            "electron-to-chromium": "^1.2.7"
+          }
+        }
+      }
+    },
+    "caniuse-db": {
+      "version": "1.0.30001177",
+      "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30001177.tgz",
+      "integrity": "sha512-bu5ZkVbh3c1i17W/AtuQ2O16jeDKIS8aTtAW1x+b+nYBWLb6x0lMrHfSHXuD+0eJnuKUBYFsZW4BlmvGoT0KgA==",
+      "dev": true
+    },
+    "caniuse-lite": {
+      "version": "1.0.30001177",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001177.tgz",
+      "integrity": "sha512-6Ld7t3ifCL02jTj3MxPMM5wAYjbo4h/TAQGFTgv1inihP1tWnWp8mxxT4ut4JBEHLbpFXEXJJQ119JCJTBkYDw==",
+      "dev": true
+    },
+    "caseless": {
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+      "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
+    },
+    "center-align": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
+      "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=",
+      "dev": true,
+      "requires": {
+        "align-text": "^0.1.3",
+        "lazy-cache": "^1.0.3"
+      }
+    },
+    "cfb": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.0.tgz",
+      "integrity": "sha512-sXMvHsKCICVR3Naq+J556K+ExBo9n50iKl6LGarlnvuA2035uMlGA/qVrc0wQtow5P1vJEw9UyrKLCbtIKz+TQ==",
+      "requires": {
+        "adler-32": "~1.2.0",
+        "crc-32": "~1.2.0",
+        "printj": "~1.1.2"
+      }
+    },
+    "chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "dev": true,
+      "requires": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      }
+    },
+    "change-case": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/change-case/-/change-case-3.0.2.tgz",
+      "integrity": "sha512-Mww+SLF6MZ0U6kdg11algyKd5BARbyM4TbFBepwowYSR5ClfQGCGtxNXgykpN0uF/bstWeaGDT4JWaDh8zWAHA==",
+      "dev": true,
+      "requires": {
+        "camel-case": "^3.0.0",
+        "constant-case": "^2.0.0",
+        "dot-case": "^2.1.0",
+        "header-case": "^1.0.0",
+        "is-lower-case": "^1.1.0",
+        "is-upper-case": "^1.1.0",
+        "lower-case": "^1.1.1",
+        "lower-case-first": "^1.0.0",
+        "no-case": "^2.3.2",
+        "param-case": "^2.1.0",
+        "pascal-case": "^2.0.0",
+        "path-case": "^2.1.0",
+        "sentence-case": "^2.1.0",
+        "snake-case": "^2.1.0",
+        "swap-case": "^1.1.0",
+        "title-case": "^2.1.0",
+        "upper-case": "^1.1.1",
+        "upper-case-first": "^1.1.0"
+      }
+    },
+    "chardet": {
+      "version": "0.4.2",
+      "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz",
+      "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=",
+      "dev": true
+    },
+    "check-types": {
+      "version": "7.4.0",
+      "resolved": "https://registry.npmjs.org/check-types/-/check-types-7.4.0.tgz",
+      "integrity": "sha512-YbulWHdfP99UfZ73NcUDlNJhEIDgm9Doq9GhpyXbF+7Aegi3CVV7qqMCKTTqJxlvEvnQBp9IA+dxsGN6xK/nSg==",
+      "dev": true
+    },
+    "chokidar": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.0.tgz",
+      "integrity": "sha512-JgQM9JS92ZbFR4P90EvmzNpSGhpPBGBSj10PILeDyYFwp4h2/D9OM03wsJ4zW1fEp4ka2DGrnUeD7FuvQ2aZ2Q==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "anymatch": "~3.1.1",
+        "braces": "~3.0.2",
+        "fsevents": "~2.3.1",
+        "glob-parent": "~5.1.0",
+        "is-binary-path": "~2.1.0",
+        "is-glob": "~4.0.1",
+        "normalize-path": "~3.0.0",
+        "readdirp": "~3.5.0"
+      }
+    },
+    "chownr": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+      "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
+      "dev": true
+    },
+    "cipher-base": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
+      "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.1",
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "circular-json": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
+      "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==",
+      "dev": true
+    },
+    "clap": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz",
+      "integrity": "sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==",
+      "dev": true,
+      "requires": {
+        "chalk": "^1.1.3"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          }
+        },
+        "supports-color": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+          "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+          "dev": true
+        }
+      }
+    },
+    "class-utils": {
+      "version": "0.3.6",
+      "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+      "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+      "dev": true,
+      "requires": {
+        "arr-union": "^3.1.0",
+        "define-property": "^0.2.5",
+        "isobject": "^3.0.0",
+        "static-extend": "^0.1.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        }
+      }
+    },
+    "clean-css": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz",
+      "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==",
+      "dev": true,
+      "requires": {
+        "source-map": "~0.6.0"
+      }
+    },
+    "cli-cursor": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
+      "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
+      "dev": true,
+      "requires": {
+        "restore-cursor": "^2.0.0"
+      }
+    },
+    "cli-spinners": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-1.3.1.tgz",
+      "integrity": "sha512-1QL4544moEsDVH9T/l6Cemov/37iv1RtoKf7NJ04A60+4MREXNfx/QvavbH6QoGdsD4N4Mwy49cmaINR/o2mdg==",
+      "dev": true
+    },
+    "cli-width": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz",
+      "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==",
+      "dev": true
+    },
+    "cliui": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
+      "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=",
+      "dev": true,
+      "requires": {
+        "center-align": "^0.1.1",
+        "right-align": "^0.1.1",
+        "wordwrap": "0.0.2"
+      }
+    },
+    "clone": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
+      "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
+      "dev": true
+    },
+    "clone-deep": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
+      "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==",
+      "dev": true,
+      "requires": {
+        "is-plain-object": "^2.0.4",
+        "kind-of": "^6.0.2",
+        "shallow-clone": "^3.0.0"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+          "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+          "dev": true
+        }
+      }
+    },
+    "co": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
+      "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
+      "dev": true
+    },
+    "coa": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/coa/-/coa-1.0.4.tgz",
+      "integrity": "sha1-qe8VNmDWqGqL3sAomlxoTSF0Mv0=",
+      "dev": true,
+      "requires": {
+        "q": "^1.1.2"
+      }
+    },
+    "coalescy": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/coalescy/-/coalescy-1.0.0.tgz",
+      "integrity": "sha1-SwZYRrg2NhrabEtKSr9LwcrDG/E=",
+      "dev": true
+    },
+    "code-point-at": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+      "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
+    },
+    "codepage": {
+      "version": "1.14.0",
+      "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.14.0.tgz",
+      "integrity": "sha1-jL4lSBMjVZ19MHVxsP/5HnodL5k=",
+      "requires": {
+        "commander": "~2.14.1",
+        "exit-on-epipe": "~1.0.1"
+      },
+      "dependencies": {
+        "commander": {
+          "version": "2.14.1",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz",
+          "integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw=="
+        }
+      }
+    },
+    "collection-visit": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+      "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
+      "dev": true,
+      "requires": {
+        "map-visit": "^1.0.0",
+        "object-visit": "^1.0.0"
+      }
+    },
+    "color": {
+      "version": "0.11.4",
+      "resolved": "https://registry.npmjs.org/color/-/color-0.11.4.tgz",
+      "integrity": "sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q=",
+      "dev": true,
+      "requires": {
+        "clone": "^1.0.2",
+        "color-convert": "^1.3.0",
+        "color-string": "^0.3.0"
+      }
+    },
+    "color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "requires": {
+        "color-name": "1.1.3"
+      }
+    },
+    "color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
+    },
+    "color-string": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz",
+      "integrity": "sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=",
+      "dev": true,
+      "requires": {
+        "color-name": "^1.0.0"
+      }
+    },
+    "colorette": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz",
+      "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==",
+      "dev": true
+    },
+    "colormin": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/colormin/-/colormin-1.1.2.tgz",
+      "integrity": "sha1-6i90IKcrlogaOKrlnsEkpvcpgTM=",
+      "dev": true,
+      "requires": {
+        "color": "^0.11.0",
+        "css-color-names": "0.0.4",
+        "has": "^1.0.1"
+      }
+    },
+    "colors": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
+      "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=",
+      "dev": true
+    },
+    "combined-stream": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+      "requires": {
+        "delayed-stream": "~1.0.0"
+      }
+    },
+    "commander": {
+      "version": "2.17.1",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
+      "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg=="
+    },
+    "commondir": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+      "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
+      "dev": true
+    },
+    "component-emitter": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+      "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
+      "dev": true
+    },
+    "compressible": {
+      "version": "2.0.18",
+      "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
+      "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==",
+      "dev": true,
+      "requires": {
+        "mime-db": ">= 1.43.0 < 2"
+      }
+    },
+    "compression": {
+      "version": "1.7.4",
+      "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz",
+      "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==",
+      "dev": true,
+      "requires": {
+        "accepts": "~1.3.5",
+        "bytes": "3.0.0",
+        "compressible": "~2.0.16",
+        "debug": "2.6.9",
+        "on-headers": "~1.0.2",
+        "safe-buffer": "5.1.2",
+        "vary": "~1.1.2"
+      },
+      "dependencies": {
+        "bytes": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
+          "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=",
+          "dev": true
+        }
+      }
+    },
+    "concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+    },
+    "concat-stream": {
+      "version": "1.6.2",
+      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+      "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+      "dev": true,
+      "requires": {
+        "buffer-from": "^1.0.0",
+        "inherits": "^2.0.3",
+        "readable-stream": "^2.2.2",
+        "typedarray": "^0.0.6"
+      }
+    },
+    "connect-history-api-fallback": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz",
+      "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==",
+      "dev": true
+    },
+    "console-browserify": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz",
+      "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==",
+      "dev": true
+    },
+    "console-control-strings": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+      "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
+    },
+    "consolidate": {
+      "version": "0.14.5",
+      "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.14.5.tgz",
+      "integrity": "sha1-WiUEe8dvcwcmZ8jLUsmJiI9JTGM=",
+      "dev": true,
+      "requires": {
+        "bluebird": "^3.1.1"
+      }
+    },
+    "constant-case": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-2.0.0.tgz",
+      "integrity": "sha1-QXV2TTidP6nI7NKRhu1gBSQ7akY=",
+      "dev": true,
+      "requires": {
+        "snake-case": "^2.1.0",
+        "upper-case": "^1.1.1"
+      }
+    },
+    "constants-browserify": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
+      "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=",
+      "dev": true
+    },
+    "contains-path": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz",
+      "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=",
+      "dev": true
+    },
+    "content-disposition": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
+      "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "5.1.2"
+      }
+    },
+    "content-type": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+      "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
+      "dev": true
+    },
+    "convert-source-map": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz",
+      "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "~5.1.1"
+      }
+    },
+    "cookie": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
+      "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==",
+      "dev": true
+    },
+    "cookie-signature": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+      "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=",
+      "dev": true
+    },
+    "copy-anything": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.1.tgz",
+      "integrity": "sha512-lA57e7viQHOdPQcrytv5jFeudZZOXuyk47lZym279FiDQ8jeZomXiGuVf6ffMKkJ+3TIai3J1J3yi6M+/4U35g==",
+      "dev": true,
+      "requires": {
+        "is-what": "^3.7.1"
+      }
+    },
+    "copy-concurrently": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz",
+      "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==",
+      "dev": true,
+      "requires": {
+        "aproba": "^1.1.1",
+        "fs-write-stream-atomic": "^1.0.8",
+        "iferr": "^0.1.5",
+        "mkdirp": "^0.5.1",
+        "rimraf": "^2.5.4",
+        "run-queue": "^1.0.0"
+      }
+    },
+    "copy-descriptor": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+      "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
+      "dev": true
+    },
+    "copy-webpack-plugin": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.6.0.tgz",
+      "integrity": "sha512-Y+SQCF+0NoWQryez2zXn5J5knmr9z/9qSQt7fbL78u83rxmigOy8X5+BFn8CFSuX+nKT8gpYwJX68ekqtQt6ZA==",
+      "dev": true,
+      "requires": {
+        "cacache": "^10.0.4",
+        "find-cache-dir": "^1.0.0",
+        "globby": "^7.1.1",
+        "is-glob": "^4.0.0",
+        "loader-utils": "^1.1.0",
+        "minimatch": "^3.0.4",
+        "p-limit": "^1.0.0",
+        "serialize-javascript": "^1.4.0"
+      }
+    },
+    "core-js": {
+      "version": "2.6.12",
+      "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
+      "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ=="
+    },
+    "core-util-is": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+    },
+    "cosmiconfig": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
+      "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
+      "dev": true,
+      "requires": {
+        "import-fresh": "^2.0.0",
+        "is-directory": "^0.3.1",
+        "js-yaml": "^3.13.1",
+        "parse-json": "^4.0.0"
+      },
+      "dependencies": {
+        "esprima": {
+          "version": "4.0.1",
+          "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+          "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+          "dev": true
+        },
+        "js-yaml": {
+          "version": "3.14.1",
+          "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+          "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+          "dev": true,
+          "requires": {
+            "argparse": "^1.0.7",
+            "esprima": "^4.0.0"
+          }
+        },
+        "parse-json": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+          "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
+          "dev": true,
+          "requires": {
+            "error-ex": "^1.3.1",
+            "json-parse-better-errors": "^1.0.1"
+          }
+        }
+      }
+    },
+    "crc-32": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.0.tgz",
+      "integrity": "sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA==",
+      "requires": {
+        "exit-on-epipe": "~1.0.1",
+        "printj": "~1.1.0"
+      }
+    },
+    "create-ecdh": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz",
+      "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==",
+      "dev": true,
+      "requires": {
+        "bn.js": "^4.1.0",
+        "elliptic": "^6.5.3"
+      },
+      "dependencies": {
+        "bn.js": {
+          "version": "4.11.9",
+          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
+          "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
+          "dev": true
+        }
+      }
+    },
+    "create-hash": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
+      "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
+      "dev": true,
+      "requires": {
+        "cipher-base": "^1.0.1",
+        "inherits": "^2.0.1",
+        "md5.js": "^1.3.4",
+        "ripemd160": "^2.0.1",
+        "sha.js": "^2.4.0"
+      }
+    },
+    "create-hmac": {
+      "version": "1.1.7",
+      "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
+      "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
+      "dev": true,
+      "requires": {
+        "cipher-base": "^1.0.3",
+        "create-hash": "^1.1.0",
+        "inherits": "^2.0.1",
+        "ripemd160": "^2.0.0",
+        "safe-buffer": "^5.0.1",
+        "sha.js": "^2.4.8"
+      }
+    },
+    "cross-spawn": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
+      "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
+      "dev": true,
+      "requires": {
+        "lru-cache": "^4.0.1",
+        "shebang-command": "^1.2.0",
+        "which": "^1.2.9"
+      }
+    },
+    "crypto-browserify": {
+      "version": "3.12.0",
+      "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
+      "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==",
+      "dev": true,
+      "requires": {
+        "browserify-cipher": "^1.0.0",
+        "browserify-sign": "^4.0.0",
+        "create-ecdh": "^4.0.0",
+        "create-hash": "^1.1.0",
+        "create-hmac": "^1.1.0",
+        "diffie-hellman": "^5.0.0",
+        "inherits": "^2.0.1",
+        "pbkdf2": "^3.0.3",
+        "public-encrypt": "^4.0.0",
+        "randombytes": "^2.0.0",
+        "randomfill": "^1.0.3"
+      }
+    },
+    "css": {
+      "version": "2.2.4",
+      "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz",
+      "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.3",
+        "source-map": "^0.6.1",
+        "source-map-resolve": "^0.5.2",
+        "urix": "^0.1.0"
+      }
+    },
+    "css-color-names": {
+      "version": "0.0.4",
+      "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
+      "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=",
+      "dev": true
+    },
+    "css-declaration-sorter": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz",
+      "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==",
+      "dev": true,
+      "requires": {
+        "postcss": "^7.0.1",
+        "timsort": "^0.3.0"
+      },
+      "dependencies": {
+        "postcss": {
+          "version": "7.0.35",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz",
+          "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^2.4.2",
+            "source-map": "^0.6.1",
+            "supports-color": "^6.1.0"
+          }
+        },
+        "supports-color": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+          "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
+      }
+    },
+    "css-loader": {
+      "version": "0.28.11",
+      "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.28.11.tgz",
+      "integrity": "sha512-wovHgjAx8ZIMGSL8pTys7edA1ClmzxHeY6n/d97gg5odgsxEgKjULPR0viqyC+FWMCL9sfqoC/QCUBo62tLvPg==",
+      "dev": true,
+      "requires": {
+        "babel-code-frame": "^6.26.0",
+        "css-selector-tokenizer": "^0.7.0",
+        "cssnano": "^3.10.0",
+        "icss-utils": "^2.1.0",
+        "loader-utils": "^1.0.2",
+        "lodash.camelcase": "^4.3.0",
+        "object-assign": "^4.1.1",
+        "postcss": "^5.0.6",
+        "postcss-modules-extract-imports": "^1.2.0",
+        "postcss-modules-local-by-default": "^1.2.0",
+        "postcss-modules-scope": "^1.1.0",
+        "postcss-modules-values": "^1.3.0",
+        "postcss-value-parser": "^3.3.0",
+        "source-list-map": "^2.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "css-select": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz",
+      "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==",
+      "dev": true,
+      "requires": {
+        "boolbase": "^1.0.0",
+        "css-what": "^3.2.1",
+        "domutils": "^1.7.0",
+        "nth-check": "^1.0.2"
+      }
+    },
+    "css-select-base-adapter": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz",
+      "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==",
+      "dev": true
+    },
+    "css-selector-tokenizer": {
+      "version": "0.7.3",
+      "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz",
+      "integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==",
+      "dev": true,
+      "requires": {
+        "cssesc": "^3.0.0",
+        "fastparse": "^1.1.2"
+      }
+    },
+    "css-tree": {
+      "version": "1.0.0-alpha.37",
+      "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz",
+      "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==",
+      "dev": true,
+      "requires": {
+        "mdn-data": "2.0.4",
+        "source-map": "^0.6.1"
+      }
+    },
+    "css-what": {
+      "version": "3.4.2",
+      "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz",
+      "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==",
+      "dev": true
+    },
+    "cssesc": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+      "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+      "dev": true
+    },
+    "cssfilter": {
+      "version": "0.0.10",
+      "resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz",
+      "integrity": "sha1-xtJnJjKi5cg+AT5oZKQs6N79IK4="
+    },
+    "cssnano": {
+      "version": "3.10.0",
+      "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-3.10.0.tgz",
+      "integrity": "sha1-Tzj2zqK5sX+gFJDyPx3GjqZcHDg=",
+      "dev": true,
+      "requires": {
+        "autoprefixer": "^6.3.1",
+        "decamelize": "^1.1.2",
+        "defined": "^1.0.0",
+        "has": "^1.0.1",
+        "object-assign": "^4.0.1",
+        "postcss": "^5.0.14",
+        "postcss-calc": "^5.2.0",
+        "postcss-colormin": "^2.1.8",
+        "postcss-convert-values": "^2.3.4",
+        "postcss-discard-comments": "^2.0.4",
+        "postcss-discard-duplicates": "^2.0.1",
+        "postcss-discard-empty": "^2.0.1",
+        "postcss-discard-overridden": "^0.1.1",
+        "postcss-discard-unused": "^2.2.1",
+        "postcss-filter-plugins": "^2.0.0",
+        "postcss-merge-idents": "^2.1.5",
+        "postcss-merge-longhand": "^2.0.1",
+        "postcss-merge-rules": "^2.0.3",
+        "postcss-minify-font-values": "^1.0.2",
+        "postcss-minify-gradients": "^1.0.1",
+        "postcss-minify-params": "^1.0.4",
+        "postcss-minify-selectors": "^2.0.4",
+        "postcss-normalize-charset": "^1.1.0",
+        "postcss-normalize-url": "^3.0.7",
+        "postcss-ordered-values": "^2.1.0",
+        "postcss-reduce-idents": "^2.2.2",
+        "postcss-reduce-initial": "^1.0.0",
+        "postcss-reduce-transforms": "^1.0.3",
+        "postcss-svgo": "^2.1.1",
+        "postcss-unique-selectors": "^2.0.2",
+        "postcss-value-parser": "^3.2.3",
+        "postcss-zindex": "^2.0.1"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "autoprefixer": {
+          "version": "6.7.7",
+          "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.7.7.tgz",
+          "integrity": "sha1-Hb0cg1ZY41zj+ZhAmdsAWFx4IBQ=",
+          "dev": true,
+          "requires": {
+            "browserslist": "^1.7.6",
+            "caniuse-db": "^1.0.30000634",
+            "normalize-range": "^0.1.2",
+            "num2fraction": "^1.2.2",
+            "postcss": "^5.2.16",
+            "postcss-value-parser": "^3.2.3"
+          }
+        },
+        "browserslist": {
+          "version": "1.7.7",
+          "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz",
+          "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=",
+          "dev": true,
+          "requires": {
+            "caniuse-db": "^1.0.30000639",
+            "electron-to-chromium": "^1.2.7"
+          }
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "cssnano-preset-default": {
+      "version": "4.0.7",
+      "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz",
+      "integrity": "sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA==",
+      "dev": true,
+      "requires": {
+        "css-declaration-sorter": "^4.0.1",
+        "cssnano-util-raw-cache": "^4.0.1",
+        "postcss": "^7.0.0",
+        "postcss-calc": "^7.0.1",
+        "postcss-colormin": "^4.0.3",
+        "postcss-convert-values": "^4.0.1",
+        "postcss-discard-comments": "^4.0.2",
+        "postcss-discard-duplicates": "^4.0.2",
+        "postcss-discard-empty": "^4.0.1",
+        "postcss-discard-overridden": "^4.0.1",
+        "postcss-merge-longhand": "^4.0.11",
+        "postcss-merge-rules": "^4.0.3",
+        "postcss-minify-font-values": "^4.0.2",
+        "postcss-minify-gradients": "^4.0.2",
+        "postcss-minify-params": "^4.0.2",
+        "postcss-minify-selectors": "^4.0.2",
+        "postcss-normalize-charset": "^4.0.1",
+        "postcss-normalize-display-values": "^4.0.2",
+        "postcss-normalize-positions": "^4.0.2",
+        "postcss-normalize-repeat-style": "^4.0.2",
+        "postcss-normalize-string": "^4.0.2",
+        "postcss-normalize-timing-functions": "^4.0.2",
+        "postcss-normalize-unicode": "^4.0.1",
+        "postcss-normalize-url": "^4.0.1",
+        "postcss-normalize-whitespace": "^4.0.2",
+        "postcss-ordered-values": "^4.1.2",
+        "postcss-reduce-initial": "^4.0.3",
+        "postcss-reduce-transforms": "^4.0.2",
+        "postcss-svgo": "^4.0.2",
+        "postcss-unique-selectors": "^4.0.1"
+      },
+      "dependencies": {
+        "browserslist": {
+          "version": "4.16.1",
+          "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.1.tgz",
+          "integrity": "sha512-UXhDrwqsNcpTYJBTZsbGATDxZbiVDsx6UjpmRUmtnP10pr8wAYr5LgFoEFw9ixriQH2mv/NX2SfGzE/o8GndLA==",
+          "dev": true,
+          "requires": {
+            "caniuse-lite": "^1.0.30001173",
+            "colorette": "^1.2.1",
+            "electron-to-chromium": "^1.3.634",
+            "escalade": "^3.1.1",
+            "node-releases": "^1.1.69"
+          }
+        },
+        "caniuse-api": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
+          "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==",
+          "dev": true,
+          "requires": {
+            "browserslist": "^4.0.0",
+            "caniuse-lite": "^1.0.0",
+            "lodash.memoize": "^4.1.2",
+            "lodash.uniq": "^4.5.0"
+          }
+        },
+        "coa": {
+          "version": "2.0.2",
+          "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz",
+          "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==",
+          "dev": true,
+          "requires": {
+            "@types/q": "^1.5.1",
+            "chalk": "^2.4.1",
+            "q": "^1.1.2"
+          }
+        },
+        "color": {
+          "version": "3.1.3",
+          "resolved": "https://registry.npmjs.org/color/-/color-3.1.3.tgz",
+          "integrity": "sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^1.9.1",
+            "color-string": "^1.5.4"
+          }
+        },
+        "color-string": {
+          "version": "1.5.4",
+          "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.4.tgz",
+          "integrity": "sha512-57yF5yt8Xa3czSEW1jfQDE79Idk0+AkN/4KWad6tbdxUmAs3MvjxlWSWD4deYytcRfoZ9nhKyFl1kj5tBvidbw==",
+          "dev": true,
+          "requires": {
+            "color-name": "^1.0.0",
+            "simple-swizzle": "^0.2.2"
+          }
+        },
+        "csso": {
+          "version": "4.2.0",
+          "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz",
+          "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==",
+          "dev": true,
+          "requires": {
+            "css-tree": "^1.1.2"
+          },
+          "dependencies": {
+            "css-tree": {
+              "version": "1.1.2",
+              "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.2.tgz",
+              "integrity": "sha512-wCoWush5Aeo48GLhfHPbmvZs59Z+M7k5+B1xDnXbdWNcEF423DoFdqSWE0PM5aNk5nI5cp1q7ms36zGApY/sKQ==",
+              "dev": true,
+              "requires": {
+                "mdn-data": "2.0.14",
+                "source-map": "^0.6.1"
+              }
+            }
+          }
+        },
+        "esprima": {
+          "version": "4.0.1",
+          "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+          "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+          "dev": true
+        },
+        "is-svg": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz",
+          "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==",
+          "dev": true,
+          "requires": {
+            "html-comment-regex": "^1.1.0"
+          }
+        },
+        "js-yaml": {
+          "version": "3.14.1",
+          "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+          "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+          "dev": true,
+          "requires": {
+            "argparse": "^1.0.7",
+            "esprima": "^4.0.0"
+          }
+        },
+        "mdn-data": {
+          "version": "2.0.14",
+          "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
+          "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
+          "dev": true
+        },
+        "normalize-url": {
+          "version": "3.3.0",
+          "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz",
+          "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==",
+          "dev": true
+        },
+        "postcss": {
+          "version": "7.0.35",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz",
+          "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^2.4.2",
+            "source-map": "^0.6.1",
+            "supports-color": "^6.1.0"
+          }
+        },
+        "postcss-calc": {
+          "version": "7.0.5",
+          "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.5.tgz",
+          "integrity": "sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg==",
+          "dev": true,
+          "requires": {
+            "postcss": "^7.0.27",
+            "postcss-selector-parser": "^6.0.2",
+            "postcss-value-parser": "^4.0.2"
+          }
+        },
+        "postcss-colormin": {
+          "version": "4.0.3",
+          "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz",
+          "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==",
+          "dev": true,
+          "requires": {
+            "browserslist": "^4.0.0",
+            "color": "^3.0.0",
+            "has": "^1.0.0",
+            "postcss": "^7.0.0",
+            "postcss-value-parser": "^3.0.0"
+          },
+          "dependencies": {
+            "postcss-value-parser": {
+              "version": "3.3.1",
+              "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+              "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+              "dev": true
+            }
+          }
+        },
+        "postcss-convert-values": {
+          "version": "4.0.1",
+          "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz",
+          "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==",
+          "dev": true,
+          "requires": {
+            "postcss": "^7.0.0",
+            "postcss-value-parser": "^3.0.0"
+          },
+          "dependencies": {
+            "postcss-value-parser": {
+              "version": "3.3.1",
+              "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+              "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+              "dev": true
+            }
+          }
+        },
+        "postcss-discard-comments": {
+          "version": "4.0.2",
+          "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz",
+          "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==",
+          "dev": true,
+          "requires": {
+            "postcss": "^7.0.0"
+          }
+        },
+        "postcss-discard-duplicates": {
+          "version": "4.0.2",
+          "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz",
+          "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==",
+          "dev": true,
+          "requires": {
+            "postcss": "^7.0.0"
+          }
+        },
+        "postcss-discard-empty": {
+          "version": "4.0.1",
+          "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz",
+          "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==",
+          "dev": true,
+          "requires": {
+            "postcss": "^7.0.0"
+          }
+        },
+        "postcss-discard-overridden": {
+          "version": "4.0.1",
+          "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz",
+          "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==",
+          "dev": true,
+          "requires": {
+            "postcss": "^7.0.0"
+          }
+        },
+        "postcss-merge-longhand": {
+          "version": "4.0.11",
+          "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz",
+          "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==",
+          "dev": true,
+          "requires": {
+            "css-color-names": "0.0.4",
+            "postcss": "^7.0.0",
+            "postcss-value-parser": "^3.0.0",
+            "stylehacks": "^4.0.0"
+          },
+          "dependencies": {
+            "postcss-value-parser": {
+              "version": "3.3.1",
+              "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+              "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+              "dev": true
+            }
+          }
+        },
+        "postcss-merge-rules": {
+          "version": "4.0.3",
+          "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz",
+          "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==",
+          "dev": true,
+          "requires": {
+            "browserslist": "^4.0.0",
+            "caniuse-api": "^3.0.0",
+            "cssnano-util-same-parent": "^4.0.0",
+            "postcss": "^7.0.0",
+            "postcss-selector-parser": "^3.0.0",
+            "vendors": "^1.0.0"
+          },
+          "dependencies": {
+            "postcss-selector-parser": {
+              "version": "3.1.2",
+              "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz",
+              "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==",
+              "dev": true,
+              "requires": {
+                "dot-prop": "^5.2.0",
+                "indexes-of": "^1.0.1",
+                "uniq": "^1.0.1"
+              }
+            }
+          }
+        },
+        "postcss-minify-font-values": {
+          "version": "4.0.2",
+          "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz",
+          "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==",
+          "dev": true,
+          "requires": {
+            "postcss": "^7.0.0",
+            "postcss-value-parser": "^3.0.0"
+          },
+          "dependencies": {
+            "postcss-value-parser": {
+              "version": "3.3.1",
+              "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+              "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+              "dev": true
+            }
+          }
+        },
+        "postcss-minify-gradients": {
+          "version": "4.0.2",
+          "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz",
+          "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==",
+          "dev": true,
+          "requires": {
+            "cssnano-util-get-arguments": "^4.0.0",
+            "is-color-stop": "^1.0.0",
+            "postcss": "^7.0.0",
+            "postcss-value-parser": "^3.0.0"
+          },
+          "dependencies": {
+            "postcss-value-parser": {
+              "version": "3.3.1",
+              "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+              "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+              "dev": true
+            }
+          }
+        },
+        "postcss-minify-params": {
+          "version": "4.0.2",
+          "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz",
+          "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==",
+          "dev": true,
+          "requires": {
+            "alphanum-sort": "^1.0.0",
+            "browserslist": "^4.0.0",
+            "cssnano-util-get-arguments": "^4.0.0",
+            "postcss": "^7.0.0",
+            "postcss-value-parser": "^3.0.0",
+            "uniqs": "^2.0.0"
+          },
+          "dependencies": {
+            "postcss-value-parser": {
+              "version": "3.3.1",
+              "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+              "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+              "dev": true
+            }
+          }
+        },
+        "postcss-minify-selectors": {
+          "version": "4.0.2",
+          "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz",
+          "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==",
+          "dev": true,
+          "requires": {
+            "alphanum-sort": "^1.0.0",
+            "has": "^1.0.0",
+            "postcss": "^7.0.0",
+            "postcss-selector-parser": "^3.0.0"
+          },
+          "dependencies": {
+            "postcss-selector-parser": {
+              "version": "3.1.2",
+              "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz",
+              "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==",
+              "dev": true,
+              "requires": {
+                "dot-prop": "^5.2.0",
+                "indexes-of": "^1.0.1",
+                "uniq": "^1.0.1"
+              }
+            }
+          }
+        },
+        "postcss-normalize-charset": {
+          "version": "4.0.1",
+          "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz",
+          "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==",
+          "dev": true,
+          "requires": {
+            "postcss": "^7.0.0"
+          }
+        },
+        "postcss-normalize-url": {
+          "version": "4.0.1",
+          "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz",
+          "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==",
+          "dev": true,
+          "requires": {
+            "is-absolute-url": "^2.0.0",
+            "normalize-url": "^3.0.0",
+            "postcss": "^7.0.0",
+            "postcss-value-parser": "^3.0.0"
+          },
+          "dependencies": {
+            "postcss-value-parser": {
+              "version": "3.3.1",
+              "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+              "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+              "dev": true
+            }
+          }
+        },
+        "postcss-ordered-values": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz",
+          "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==",
+          "dev": true,
+          "requires": {
+            "cssnano-util-get-arguments": "^4.0.0",
+            "postcss": "^7.0.0",
+            "postcss-value-parser": "^3.0.0"
+          },
+          "dependencies": {
+            "postcss-value-parser": {
+              "version": "3.3.1",
+              "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+              "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+              "dev": true
+            }
+          }
+        },
+        "postcss-reduce-initial": {
+          "version": "4.0.3",
+          "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz",
+          "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==",
+          "dev": true,
+          "requires": {
+            "browserslist": "^4.0.0",
+            "caniuse-api": "^3.0.0",
+            "has": "^1.0.0",
+            "postcss": "^7.0.0"
+          }
+        },
+        "postcss-reduce-transforms": {
+          "version": "4.0.2",
+          "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz",
+          "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==",
+          "dev": true,
+          "requires": {
+            "cssnano-util-get-match": "^4.0.0",
+            "has": "^1.0.0",
+            "postcss": "^7.0.0",
+            "postcss-value-parser": "^3.0.0"
+          },
+          "dependencies": {
+            "postcss-value-parser": {
+              "version": "3.3.1",
+              "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+              "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+              "dev": true
+            }
+          }
+        },
+        "postcss-selector-parser": {
+          "version": "6.0.4",
+          "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz",
+          "integrity": "sha512-gjMeXBempyInaBqpp8gODmwZ52WaYsVOsfr4L4lDQ7n3ncD6mEyySiDtgzCT+NYC0mmeOLvtsF8iaEf0YT6dBw==",
+          "dev": true,
+          "requires": {
+            "cssesc": "^3.0.0",
+            "indexes-of": "^1.0.1",
+            "uniq": "^1.0.1",
+            "util-deprecate": "^1.0.2"
+          }
+        },
+        "postcss-svgo": {
+          "version": "4.0.2",
+          "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.2.tgz",
+          "integrity": "sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw==",
+          "dev": true,
+          "requires": {
+            "is-svg": "^3.0.0",
+            "postcss": "^7.0.0",
+            "postcss-value-parser": "^3.0.0",
+            "svgo": "^1.0.0"
+          },
+          "dependencies": {
+            "postcss-value-parser": {
+              "version": "3.3.1",
+              "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+              "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+              "dev": true
+            }
+          }
+        },
+        "postcss-unique-selectors": {
+          "version": "4.0.1",
+          "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz",
+          "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==",
+          "dev": true,
+          "requires": {
+            "alphanum-sort": "^1.0.0",
+            "postcss": "^7.0.0",
+            "uniqs": "^2.0.0"
+          }
+        },
+        "postcss-value-parser": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz",
+          "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+          "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        },
+        "svgo": {
+          "version": "1.3.2",
+          "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz",
+          "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==",
+          "dev": true,
+          "requires": {
+            "chalk": "^2.4.1",
+            "coa": "^2.0.2",
+            "css-select": "^2.0.0",
+            "css-select-base-adapter": "^0.1.1",
+            "css-tree": "1.0.0-alpha.37",
+            "csso": "^4.0.2",
+            "js-yaml": "^3.13.1",
+            "mkdirp": "~0.5.1",
+            "object.values": "^1.1.0",
+            "sax": "~1.2.4",
+            "stable": "^0.1.8",
+            "unquote": "~1.1.1",
+            "util.promisify": "~1.0.0"
+          }
+        }
+      }
+    },
+    "cssnano-util-get-arguments": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz",
+      "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=",
+      "dev": true
+    },
+    "cssnano-util-get-match": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz",
+      "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=",
+      "dev": true
+    },
+    "cssnano-util-raw-cache": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz",
+      "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==",
+      "dev": true,
+      "requires": {
+        "postcss": "^7.0.0"
+      },
+      "dependencies": {
+        "postcss": {
+          "version": "7.0.35",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz",
+          "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^2.4.2",
+            "source-map": "^0.6.1",
+            "supports-color": "^6.1.0"
+          }
+        },
+        "supports-color": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+          "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
+      }
+    },
+    "cssnano-util-same-parent": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz",
+      "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==",
+      "dev": true
+    },
+    "csso": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/csso/-/csso-2.3.2.tgz",
+      "integrity": "sha1-3dUsWHAz9J6Utx/FVWnyUuj/X4U=",
+      "dev": true,
+      "requires": {
+        "clap": "^1.0.9",
+        "source-map": "^0.5.3"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        }
+      }
+    },
+    "cuint": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz",
+      "integrity": "sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs=",
+      "dev": true
+    },
+    "currently-unhandled": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
+      "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
+      "requires": {
+        "array-find-index": "^1.0.1"
+      }
+    },
+    "cyclist": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz",
+      "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=",
+      "dev": true
+    },
+    "d": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
+      "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
+      "dev": true,
+      "requires": {
+        "es5-ext": "^0.10.50",
+        "type": "^1.0.1"
+      }
+    },
+    "dashdash": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+      "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+      "requires": {
+        "assert-plus": "^1.0.0"
+      }
+    },
+    "de-indent": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
+      "integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=",
+      "dev": true
+    },
+    "debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "requires": {
+        "ms": "2.0.0"
+      }
+    },
+    "decamelize": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+      "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
+    },
+    "decode-uri-component": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+      "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
+      "dev": true
+    },
+    "deep-equal": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
+      "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==",
+      "dev": true,
+      "requires": {
+        "is-arguments": "^1.0.4",
+        "is-date-object": "^1.0.1",
+        "is-regex": "^1.0.4",
+        "object-is": "^1.0.1",
+        "object-keys": "^1.1.1",
+        "regexp.prototype.flags": "^1.2.0"
+      }
+    },
+    "deep-is": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+      "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
+      "dev": true
+    },
+    "deepmerge": {
+      "version": "1.5.2",
+      "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz",
+      "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ=="
+    },
+    "define-properties": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
+      "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
+      "dev": true,
+      "requires": {
+        "object-keys": "^1.0.12"
+      }
+    },
+    "define-property": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+      "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+      "dev": true,
+      "requires": {
+        "is-descriptor": "^1.0.2",
+        "isobject": "^3.0.1"
+      },
+      "dependencies": {
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        },
+        "kind-of": {
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+          "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+          "dev": true
+        }
+      }
+    },
+    "defined": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
+      "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=",
+      "dev": true
+    },
+    "del": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz",
+      "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=",
+      "dev": true,
+      "requires": {
+        "globby": "^6.1.0",
+        "is-path-cwd": "^1.0.0",
+        "is-path-in-cwd": "^1.0.0",
+        "p-map": "^1.1.1",
+        "pify": "^3.0.0",
+        "rimraf": "^2.2.8"
+      },
+      "dependencies": {
+        "globby": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
+          "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=",
+          "dev": true,
+          "requires": {
+            "array-union": "^1.0.1",
+            "glob": "^7.0.3",
+            "object-assign": "^4.0.1",
+            "pify": "^2.0.0",
+            "pinkie-promise": "^2.0.0"
+          },
+          "dependencies": {
+            "pify": {
+              "version": "2.3.0",
+              "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+              "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+              "dev": true
+            }
+          }
+        }
+      }
+    },
+    "delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
+    },
+    "delegates": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+      "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
+    },
+    "depd": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+      "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
+      "dev": true
+    },
+    "des.js": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz",
+      "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.1",
+        "minimalistic-assert": "^1.0.0"
+      }
+    },
+    "destroy": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
+      "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=",
+      "dev": true
+    },
+    "detect-indent": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz",
+      "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=",
+      "dev": true,
+      "requires": {
+        "repeating": "^2.0.0"
+      }
+    },
+    "detect-node": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz",
+      "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==",
+      "dev": true
+    },
+    "diffie-hellman": {
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
+      "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
+      "dev": true,
+      "requires": {
+        "bn.js": "^4.1.0",
+        "miller-rabin": "^4.0.0",
+        "randombytes": "^2.0.0"
+      },
+      "dependencies": {
+        "bn.js": {
+          "version": "4.11.9",
+          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
+          "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
+          "dev": true
+        }
+      }
+    },
+    "dir-glob": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz",
+      "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==",
+      "dev": true,
+      "requires": {
+        "path-type": "^3.0.0"
+      }
+    },
+    "dns-equal": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
+      "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=",
+      "dev": true
+    },
+    "dns-packet": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz",
+      "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==",
+      "dev": true,
+      "requires": {
+        "ip": "^1.1.0",
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "dns-txt": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz",
+      "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=",
+      "dev": true,
+      "requires": {
+        "buffer-indexof": "^1.0.0"
+      }
+    },
+    "doctrine": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+      "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+      "dev": true,
+      "requires": {
+        "esutils": "^2.0.2"
+      }
+    },
+    "dom-converter": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz",
+      "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==",
+      "dev": true,
+      "requires": {
+        "utila": "~0.4"
+      }
+    },
+    "dom-serializer": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
+      "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==",
+      "dev": true,
+      "requires": {
+        "domelementtype": "^2.0.1",
+        "entities": "^2.0.0"
+      },
+      "dependencies": {
+        "domelementtype": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz",
+          "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==",
+          "dev": true
+        }
+      }
+    },
+    "domain-browser": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
+      "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==",
+      "dev": true
+    },
+    "domelementtype": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
+      "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
+      "dev": true
+    },
+    "domhandler": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
+      "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
+      "dev": true,
+      "requires": {
+        "domelementtype": "1"
+      }
+    },
+    "domutils": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
+      "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
+      "dev": true,
+      "requires": {
+        "dom-serializer": "0",
+        "domelementtype": "1"
+      }
+    },
+    "dot-case": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-2.1.1.tgz",
+      "integrity": "sha1-NNzzf1Co6TwrO8qLt/uRVcfaO+4=",
+      "dev": true,
+      "requires": {
+        "no-case": "^2.2.0"
+      }
+    },
+    "dot-prop": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
+      "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==",
+      "dev": true,
+      "requires": {
+        "is-obj": "^2.0.0"
+      }
+    },
+    "duplexer": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
+      "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
+      "dev": true
+    },
+    "duplexify": {
+      "version": "3.7.1",
+      "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
+      "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==",
+      "dev": true,
+      "requires": {
+        "end-of-stream": "^1.0.0",
+        "inherits": "^2.0.1",
+        "readable-stream": "^2.0.0",
+        "stream-shift": "^1.0.0"
+      }
+    },
+    "ecc-jsbn": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+      "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
+      "requires": {
+        "jsbn": "~0.1.0",
+        "safer-buffer": "^2.1.0"
+      }
+    },
+    "ee-first": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+      "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
+      "dev": true
+    },
+    "ejs": {
+      "version": "2.7.4",
+      "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz",
+      "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==",
+      "dev": true
+    },
+    "electron-to-chromium": {
+      "version": "1.3.640",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.640.tgz",
+      "integrity": "sha512-cU6wQdXYzuSPzLdszsa4whStYfmU7CVNnG6c5z6/z9YlCOQ2Xh/uKB1gTxlIRr0ubgSg1/dZuSbUAoeESeQ3sQ==",
+      "dev": true
+    },
+    "element-ui": {
+      "version": "2.14.1",
+      "resolved": "https://registry.npmjs.org/element-ui/-/element-ui-2.14.1.tgz",
+      "integrity": "sha512-Uje0J12dBaXdyvt/EtuDA8diFbYTdO7uI4QCfl7zmEJmE1WxgCSVKhlRRoL8MDonO8pyNVhB4n0AFAR14g56nw==",
+      "requires": {
+        "async-validator": "~1.8.1",
+        "babel-helper-vue-jsx-merge-props": "^2.0.0",
+        "deepmerge": "^1.2.0",
+        "normalize-wheel": "^1.0.1",
+        "resize-observer-polyfill": "^1.5.0",
+        "throttle-debounce": "^1.0.1"
+      }
+    },
+    "elliptic": {
+      "version": "6.5.3",
+      "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz",
+      "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==",
+      "dev": true,
+      "requires": {
+        "bn.js": "^4.4.0",
+        "brorand": "^1.0.1",
+        "hash.js": "^1.0.0",
+        "hmac-drbg": "^1.0.0",
+        "inherits": "^2.0.1",
+        "minimalistic-assert": "^1.0.0",
+        "minimalistic-crypto-utils": "^1.0.0"
+      },
+      "dependencies": {
+        "bn.js": {
+          "version": "4.11.9",
+          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
+          "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
+          "dev": true
+        }
+      }
+    },
+    "emoji-regex": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+      "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA=="
+    },
+    "emojis-list": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
+      "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
+      "dev": true
+    },
+    "encodeurl": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+      "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
+      "dev": true
+    },
+    "end-of-stream": {
+      "version": "1.4.4",
+      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+      "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+      "dev": true,
+      "requires": {
+        "once": "^1.4.0"
+      }
+    },
+    "enhanced-resolve": {
+      "version": "3.4.1",
+      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz",
+      "integrity": "sha1-BCHjOf1xQZs9oT0Smzl5BAIwR24=",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.2",
+        "memory-fs": "^0.4.0",
+        "object-assign": "^4.0.1",
+        "tapable": "^0.2.7"
+      }
+    },
+    "entities": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
+      "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
+      "dev": true
+    },
+    "errno": {
+      "version": "0.1.8",
+      "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
+      "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
+      "dev": true,
+      "requires": {
+        "prr": "~1.0.1"
+      }
+    },
+    "error-ex": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+      "requires": {
+        "is-arrayish": "^0.2.1"
+      }
+    },
+    "error-stack-parser": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.6.tgz",
+      "integrity": "sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ==",
+      "dev": true,
+      "requires": {
+        "stackframe": "^1.1.1"
+      }
+    },
+    "es-abstract": {
+      "version": "1.18.0-next.1",
+      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz",
+      "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==",
+      "dev": true,
+      "requires": {
+        "es-to-primitive": "^1.2.1",
+        "function-bind": "^1.1.1",
+        "has": "^1.0.3",
+        "has-symbols": "^1.0.1",
+        "is-callable": "^1.2.2",
+        "is-negative-zero": "^2.0.0",
+        "is-regex": "^1.1.1",
+        "object-inspect": "^1.8.0",
+        "object-keys": "^1.1.1",
+        "object.assign": "^4.1.1",
+        "string.prototype.trimend": "^1.0.1",
+        "string.prototype.trimstart": "^1.0.1"
+      }
+    },
+    "es-to-primitive": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
+      "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
+      "dev": true,
+      "requires": {
+        "is-callable": "^1.1.4",
+        "is-date-object": "^1.0.1",
+        "is-symbol": "^1.0.2"
+      }
+    },
+    "es5-ext": {
+      "version": "0.10.53",
+      "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz",
+      "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==",
+      "dev": true,
+      "requires": {
+        "es6-iterator": "~2.0.3",
+        "es6-symbol": "~3.1.3",
+        "next-tick": "~1.0.0"
+      }
+    },
+    "es6-iterator": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+      "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
+      "dev": true,
+      "requires": {
+        "d": "1",
+        "es5-ext": "^0.10.35",
+        "es6-symbol": "^3.1.1"
+      }
+    },
+    "es6-map": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz",
+      "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=",
+      "dev": true,
+      "requires": {
+        "d": "1",
+        "es5-ext": "~0.10.14",
+        "es6-iterator": "~2.0.1",
+        "es6-set": "~0.1.5",
+        "es6-symbol": "~3.1.1",
+        "event-emitter": "~0.3.5"
+      }
+    },
+    "es6-promise": {
+      "version": "4.2.8",
+      "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
+      "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
+    },
+    "es6-set": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz",
+      "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=",
+      "dev": true,
+      "requires": {
+        "d": "1",
+        "es5-ext": "~0.10.14",
+        "es6-iterator": "~2.0.1",
+        "es6-symbol": "3.1.1",
+        "event-emitter": "~0.3.5"
+      },
+      "dependencies": {
+        "es6-symbol": {
+          "version": "3.1.1",
+          "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz",
+          "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=",
+          "dev": true,
+          "requires": {
+            "d": "1",
+            "es5-ext": "~0.10.14"
+          }
+        }
+      }
+    },
+    "es6-symbol": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
+      "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
+      "dev": true,
+      "requires": {
+        "d": "^1.0.1",
+        "ext": "^1.1.2"
+      }
+    },
+    "es6-templates": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/es6-templates/-/es6-templates-0.2.3.tgz",
+      "integrity": "sha1-XLmsn7He1usSOTQrgdeSu7QHjuQ=",
+      "dev": true,
+      "requires": {
+        "recast": "~0.11.12",
+        "through": "~2.3.6"
+      }
+    },
+    "es6-weak-map": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz",
+      "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==",
+      "dev": true,
+      "requires": {
+        "d": "1",
+        "es5-ext": "^0.10.46",
+        "es6-iterator": "^2.0.3",
+        "es6-symbol": "^3.1.1"
+      }
+    },
+    "escalade": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+      "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+      "dev": true
+    },
+    "escape-html": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+      "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
+      "dev": true
+    },
+    "escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
+    },
+    "escope": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz",
+      "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=",
+      "dev": true,
+      "requires": {
+        "es6-map": "^0.1.3",
+        "es6-weak-map": "^2.0.1",
+        "esrecurse": "^4.1.0",
+        "estraverse": "^4.1.1"
+      }
+    },
+    "eslint": {
+      "version": "4.19.1",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz",
+      "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==",
+      "dev": true,
+      "requires": {
+        "ajv": "^5.3.0",
+        "babel-code-frame": "^6.22.0",
+        "chalk": "^2.1.0",
+        "concat-stream": "^1.6.0",
+        "cross-spawn": "^5.1.0",
+        "debug": "^3.1.0",
+        "doctrine": "^2.1.0",
+        "eslint-scope": "^3.7.1",
+        "eslint-visitor-keys": "^1.0.0",
+        "espree": "^3.5.4",
+        "esquery": "^1.0.0",
+        "esutils": "^2.0.2",
+        "file-entry-cache": "^2.0.0",
+        "functional-red-black-tree": "^1.0.1",
+        "glob": "^7.1.2",
+        "globals": "^11.0.1",
+        "ignore": "^3.3.3",
+        "imurmurhash": "^0.1.4",
+        "inquirer": "^3.0.6",
+        "is-resolvable": "^1.0.0",
+        "js-yaml": "^3.9.1",
+        "json-stable-stringify-without-jsonify": "^1.0.1",
+        "levn": "^0.3.0",
+        "lodash": "^4.17.4",
+        "minimatch": "^3.0.2",
+        "mkdirp": "^0.5.1",
+        "natural-compare": "^1.4.0",
+        "optionator": "^0.8.2",
+        "path-is-inside": "^1.0.2",
+        "pluralize": "^7.0.0",
+        "progress": "^2.0.0",
+        "regexpp": "^1.0.1",
+        "require-uncached": "^1.0.3",
+        "semver": "^5.3.0",
+        "strip-ansi": "^4.0.0",
+        "strip-json-comments": "~2.0.1",
+        "table": "4.0.2",
+        "text-table": "~0.2.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+          "dev": true
+        },
+        "debug": {
+          "version": "3.2.7",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+          "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+          "dev": true,
+          "requires": {
+            "ms": "^2.1.1"
+          }
+        },
+        "esprima": {
+          "version": "4.0.1",
+          "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+          "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+          "dev": true
+        },
+        "globals": {
+          "version": "11.12.0",
+          "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+          "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+          "dev": true
+        },
+        "js-yaml": {
+          "version": "3.14.1",
+          "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+          "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+          "dev": true,
+          "requires": {
+            "argparse": "^1.0.7",
+            "esprima": "^4.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.1.3",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+          "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+          "dev": true
+        },
+        "strip-ansi": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+          "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^3.0.0"
+          }
+        }
+      }
+    },
+    "eslint-config-standard": {
+      "version": "10.2.1",
+      "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz",
+      "integrity": "sha1-wGHk0GbzedwXzVYsZOgZtN1FRZE=",
+      "dev": true
+    },
+    "eslint-friendly-formatter": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/eslint-friendly-formatter/-/eslint-friendly-formatter-3.0.0.tgz",
+      "integrity": "sha1-J4h0Q1psRuwdlPoLH/SU4w7wQpA=",
+      "dev": true,
+      "requires": {
+        "chalk": "^1.0.0",
+        "coalescy": "1.0.0",
+        "extend": "^3.0.0",
+        "minimist": "^1.2.0",
+        "text-table": "^0.2.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          }
+        },
+        "supports-color": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+          "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+          "dev": true
+        }
+      }
+    },
+    "eslint-import-resolver-node": {
+      "version": "0.3.4",
+      "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz",
+      "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==",
+      "dev": true,
+      "requires": {
+        "debug": "^2.6.9",
+        "resolve": "^1.13.1"
+      }
+    },
+    "eslint-loader": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/eslint-loader/-/eslint-loader-1.9.0.tgz",
+      "integrity": "sha512-40aN976qSNPyb9ejTqjEthZITpls1SVKtwguahmH1dzGCwQU/vySE+xX33VZmD8csU0ahVNCtFlsPgKqRBiqgg==",
+      "dev": true,
+      "requires": {
+        "loader-fs-cache": "^1.0.0",
+        "loader-utils": "^1.0.2",
+        "object-assign": "^4.0.1",
+        "object-hash": "^1.1.4",
+        "rimraf": "^2.6.1"
+      }
+    },
+    "eslint-module-utils": {
+      "version": "2.6.0",
+      "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz",
+      "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==",
+      "dev": true,
+      "requires": {
+        "debug": "^2.6.9",
+        "pkg-dir": "^2.0.0"
+      }
+    },
+    "eslint-plugin-import": {
+      "version": "2.22.1",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz",
+      "integrity": "sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw==",
+      "dev": true,
+      "requires": {
+        "array-includes": "^3.1.1",
+        "array.prototype.flat": "^1.2.3",
+        "contains-path": "^0.1.0",
+        "debug": "^2.6.9",
+        "doctrine": "1.5.0",
+        "eslint-import-resolver-node": "^0.3.4",
+        "eslint-module-utils": "^2.6.0",
+        "has": "^1.0.3",
+        "minimatch": "^3.0.4",
+        "object.values": "^1.1.1",
+        "read-pkg-up": "^2.0.0",
+        "resolve": "^1.17.0",
+        "tsconfig-paths": "^3.9.0"
+      },
+      "dependencies": {
+        "doctrine": {
+          "version": "1.5.0",
+          "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz",
+          "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=",
+          "dev": true,
+          "requires": {
+            "esutils": "^2.0.2",
+            "isarray": "^1.0.0"
+          }
+        }
+      }
+    },
+    "eslint-plugin-node": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-5.2.1.tgz",
+      "integrity": "sha512-xhPXrh0Vl/b7870uEbaumb2Q+LxaEcOQ3kS1jtIXanBAwpMre1l5q/l2l/hESYJGEFKuI78bp6Uw50hlpr7B+g==",
+      "dev": true,
+      "requires": {
+        "ignore": "^3.3.6",
+        "minimatch": "^3.0.4",
+        "resolve": "^1.3.3",
+        "semver": "5.3.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "5.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
+          "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
+          "dev": true
+        }
+      }
+    },
+    "eslint-plugin-promise": {
+      "version": "3.8.0",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.8.0.tgz",
+      "integrity": "sha512-JiFL9UFR15NKpHyGii1ZcvmtIqa3UTwiDAGb8atSffe43qJ3+1czVGN6UtkklpcJ2DVnqvTMzEKRaJdBkAL2aQ==",
+      "dev": true
+    },
+    "eslint-plugin-standard": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-3.1.0.tgz",
+      "integrity": "sha512-fVcdyuKRr0EZ4fjWl3c+gp1BANFJD1+RaWa2UPYfMZ6jCtp5RG00kSaXnK/dE5sYzt4kaWJ9qdxqUfc0d9kX0w==",
+      "dev": true
+    },
+    "eslint-plugin-vue": {
+      "version": "4.7.1",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-4.7.1.tgz",
+      "integrity": "sha512-esETKhVMI7Vdli70Wt4bvAwnZBJeM0pxVX9Yb0wWKxdCJc2EADalVYK/q2FzMw8oKN0wPMdqVCKS8kmR89recA==",
+      "dev": true,
+      "requires": {
+        "vue-eslint-parser": "^2.0.3"
+      }
+    },
+    "eslint-scope": {
+      "version": "3.7.1",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz",
+      "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=",
+      "dev": true,
+      "requires": {
+        "esrecurse": "^4.1.0",
+        "estraverse": "^4.1.1"
+      }
+    },
+    "eslint-visitor-keys": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+      "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+      "dev": true
+    },
+    "espree": {
+      "version": "3.5.4",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz",
+      "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==",
+      "dev": true,
+      "requires": {
+        "acorn": "^5.5.0",
+        "acorn-jsx": "^3.0.0"
+      }
+    },
+    "esprima": {
+      "version": "2.7.3",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz",
+      "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=",
+      "dev": true
+    },
+    "esquery": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz",
+      "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==",
+      "dev": true,
+      "requires": {
+        "estraverse": "^5.1.0"
+      },
+      "dependencies": {
+        "estraverse": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
+          "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
+          "dev": true
+        }
+      }
+    },
+    "esrecurse": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+      "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+      "dev": true,
+      "requires": {
+        "estraverse": "^5.2.0"
+      },
+      "dependencies": {
+        "estraverse": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
+          "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
+          "dev": true
+        }
+      }
+    },
+    "estraverse": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+      "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+      "dev": true
+    },
+    "esutils": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+      "dev": true
+    },
+    "etag": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+      "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
+      "dev": true
+    },
+    "event-emitter": {
+      "version": "0.3.5",
+      "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
+      "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=",
+      "dev": true,
+      "requires": {
+        "d": "1",
+        "es5-ext": "~0.10.14"
+      }
+    },
+    "eventemitter3": {
+      "version": "4.0.7",
+      "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
+      "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
+      "dev": true
+    },
+    "events": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz",
+      "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==",
+      "dev": true
+    },
+    "eventsource": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-0.1.6.tgz",
+      "integrity": "sha1-Cs7ehJ7X3RzMMsgRuxG5RNTykjI=",
+      "dev": true,
+      "requires": {
+        "original": ">=0.0.5"
+      }
+    },
+    "evp_bytestokey": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
+      "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
+      "dev": true,
+      "requires": {
+        "md5.js": "^1.3.4",
+        "safe-buffer": "^5.1.1"
+      }
+    },
+    "execa": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
+      "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=",
+      "dev": true,
+      "requires": {
+        "cross-spawn": "^5.0.1",
+        "get-stream": "^3.0.0",
+        "is-stream": "^1.1.0",
+        "npm-run-path": "^2.0.0",
+        "p-finally": "^1.0.0",
+        "signal-exit": "^3.0.0",
+        "strip-eof": "^1.0.0"
+      }
+    },
+    "exit-on-epipe": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz",
+      "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw=="
+    },
+    "expand-brackets": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+      "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+      "dev": true,
+      "requires": {
+        "debug": "^2.3.3",
+        "define-property": "^0.2.5",
+        "extend-shallow": "^2.0.1",
+        "posix-character-classes": "^0.1.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        },
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        }
+      }
+    },
+    "express": {
+      "version": "4.17.1",
+      "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
+      "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
+      "dev": true,
+      "requires": {
+        "accepts": "~1.3.7",
+        "array-flatten": "1.1.1",
+        "body-parser": "1.19.0",
+        "content-disposition": "0.5.3",
+        "content-type": "~1.0.4",
+        "cookie": "0.4.0",
+        "cookie-signature": "1.0.6",
+        "debug": "2.6.9",
+        "depd": "~1.1.2",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "etag": "~1.8.1",
+        "finalhandler": "~1.1.2",
+        "fresh": "0.5.2",
+        "merge-descriptors": "1.0.1",
+        "methods": "~1.1.2",
+        "on-finished": "~2.3.0",
+        "parseurl": "~1.3.3",
+        "path-to-regexp": "0.1.7",
+        "proxy-addr": "~2.0.5",
+        "qs": "6.7.0",
+        "range-parser": "~1.2.1",
+        "safe-buffer": "5.1.2",
+        "send": "0.17.1",
+        "serve-static": "1.14.1",
+        "setprototypeof": "1.1.1",
+        "statuses": "~1.5.0",
+        "type-is": "~1.6.18",
+        "utils-merge": "1.0.1",
+        "vary": "~1.1.2"
+      }
+    },
+    "ext": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz",
+      "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==",
+      "dev": true,
+      "requires": {
+        "type": "^2.0.0"
+      },
+      "dependencies": {
+        "type": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/type/-/type-2.1.0.tgz",
+          "integrity": "sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==",
+          "dev": true
+        }
+      }
+    },
+    "extend": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
+    },
+    "extend-shallow": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+      "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
+      "dev": true,
+      "requires": {
+        "assign-symbols": "^1.0.0",
+        "is-extendable": "^1.0.1"
+      },
+      "dependencies": {
+        "is-extendable": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+          "dev": true,
+          "requires": {
+            "is-plain-object": "^2.0.4"
+          }
+        }
+      }
+    },
+    "external-editor": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
+      "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==",
+      "dev": true,
+      "requires": {
+        "chardet": "^0.4.0",
+        "iconv-lite": "^0.4.17",
+        "tmp": "^0.0.33"
+      }
+    },
+    "extglob": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+      "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+      "dev": true,
+      "requires": {
+        "array-unique": "^0.3.2",
+        "define-property": "^1.0.0",
+        "expand-brackets": "^2.1.4",
+        "extend-shallow": "^2.0.1",
+        "fragment-cache": "^0.2.1",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^1.0.0"
+          }
+        },
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        },
+        "kind-of": {
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+          "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+          "dev": true
+        }
+      }
+    },
+    "extract-text-webpack-plugin": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extract-text-webpack-plugin/-/extract-text-webpack-plugin-3.0.2.tgz",
+      "integrity": "sha512-bt/LZ4m5Rqt/Crl2HiKuAl/oqg0psx1tsTLkvWbJen1CtD+fftkZhMaQ9HOtY2gWsl2Wq+sABmMVi9z3DhKWQQ==",
+      "dev": true,
+      "requires": {
+        "async": "^2.4.1",
+        "loader-utils": "^1.1.0",
+        "schema-utils": "^0.3.0",
+        "webpack-sources": "^1.0.1"
+      }
+    },
+    "extsprintf": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+      "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
+    },
+    "fast-deep-equal": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
+      "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=",
+      "dev": true
+    },
+    "fast-json-stable-stringify": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
+    },
+    "fast-levenshtein": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+      "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
+      "dev": true
+    },
+    "fastparse": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
+      "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
+      "dev": true
+    },
+    "faye-websocket": {
+      "version": "0.10.0",
+      "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz",
+      "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=",
+      "dev": true,
+      "requires": {
+        "websocket-driver": ">=0.5.1"
+      }
+    },
+    "figures": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
+      "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
+      "dev": true,
+      "requires": {
+        "escape-string-regexp": "^1.0.5"
+      }
+    },
+    "file-entry-cache": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz",
+      "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=",
+      "dev": true,
+      "requires": {
+        "flat-cache": "^1.2.1",
+        "object-assign": "^4.0.1"
+      }
+    },
+    "file-loader": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz",
+      "integrity": "sha512-TGR4HU7HUsGg6GCOPJnFk06RhWgEWFLAGWiT6rcD+GRC2keU3s9RGJ+b3Z6/U73jwwNb2gKLJ7YCrp+jvU4ALg==",
+      "dev": true,
+      "requires": {
+        "loader-utils": "^1.0.2",
+        "schema-utils": "^0.4.5"
+      },
+      "dependencies": {
+        "ajv": {
+          "version": "6.12.6",
+          "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+          "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+          "dev": true,
+          "requires": {
+            "fast-deep-equal": "^3.1.1",
+            "fast-json-stable-stringify": "^2.0.0",
+            "json-schema-traverse": "^0.4.1",
+            "uri-js": "^4.2.2"
+          }
+        },
+        "ajv-keywords": {
+          "version": "3.5.2",
+          "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
+          "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
+          "dev": true
+        },
+        "fast-deep-equal": {
+          "version": "3.1.3",
+          "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+          "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+          "dev": true
+        },
+        "json-schema-traverse": {
+          "version": "0.4.1",
+          "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+          "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+          "dev": true
+        },
+        "schema-utils": {
+          "version": "0.4.7",
+          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz",
+          "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==",
+          "dev": true,
+          "requires": {
+            "ajv": "^6.1.0",
+            "ajv-keywords": "^3.1.0"
+          }
+        }
+      }
+    },
+    "filesize": {
+      "version": "3.6.1",
+      "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz",
+      "integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==",
+      "dev": true
+    },
+    "fill-range": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+      "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "to-regex-range": "^5.0.1"
+      }
+    },
+    "finalhandler": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+      "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+      "dev": true,
+      "requires": {
+        "debug": "2.6.9",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "on-finished": "~2.3.0",
+        "parseurl": "~1.3.3",
+        "statuses": "~1.5.0",
+        "unpipe": "~1.0.0"
+      }
+    },
+    "find-cache-dir": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz",
+      "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=",
+      "dev": true,
+      "requires": {
+        "commondir": "^1.0.1",
+        "make-dir": "^1.0.0",
+        "pkg-dir": "^2.0.0"
+      }
+    },
+    "find-up": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
+      "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
+      "dev": true,
+      "requires": {
+        "locate-path": "^2.0.0"
+      }
+    },
+    "flat-cache": {
+      "version": "1.3.4",
+      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz",
+      "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==",
+      "dev": true,
+      "requires": {
+        "circular-json": "^0.3.1",
+        "graceful-fs": "^4.1.2",
+        "rimraf": "~2.6.2",
+        "write": "^0.2.1"
+      },
+      "dependencies": {
+        "rimraf": {
+          "version": "2.6.3",
+          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+          "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+          "dev": true,
+          "requires": {
+            "glob": "^7.1.3"
+          }
+        }
+      }
+    },
+    "flatten": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.3.tgz",
+      "integrity": "sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==",
+      "dev": true
+    },
+    "flush-write-stream": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz",
+      "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.3",
+        "readable-stream": "^2.3.6"
+      }
+    },
+    "follow-redirects": {
+      "version": "1.13.1",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz",
+      "integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg=="
+    },
+    "for-in": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+      "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+      "dev": true
+    },
+    "forever-agent": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+      "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
+    },
+    "form-data": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+      "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+      "requires": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.6",
+        "mime-types": "^2.1.12"
+      }
+    },
+    "forwarded": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
+      "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=",
+      "dev": true
+    },
+    "frac": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz",
+      "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA=="
+    },
+    "fragment-cache": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+      "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
+      "dev": true,
+      "requires": {
+        "map-cache": "^0.2.2"
+      }
+    },
+    "fresh": {
+      "version": "0.5.2",
+      "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+      "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
+      "dev": true
+    },
+    "friendly-errors-webpack-plugin": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.7.0.tgz",
+      "integrity": "sha512-K27M3VK30wVoOarP651zDmb93R9zF28usW4ocaK3mfQeIEI5BPht/EzZs5E8QLLwbLRJQMwscAjDxYPb1FuNiw==",
+      "dev": true,
+      "requires": {
+        "chalk": "^1.1.3",
+        "error-stack-parser": "^2.0.0",
+        "string-width": "^2.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          }
+        },
+        "supports-color": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+          "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+          "dev": true
+        }
+      }
+    },
+    "from2": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz",
+      "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.1",
+        "readable-stream": "^2.0.0"
+      }
+    },
+    "fs-extra": {
+      "version": "0.16.5",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.16.5.tgz",
+      "integrity": "sha1-GtZh+myGyWCM0bSe/G/Og0k5p1A=",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^3.0.5",
+        "jsonfile": "^2.0.0",
+        "rimraf": "^2.2.8"
+      },
+      "dependencies": {
+        "graceful-fs": {
+          "version": "3.0.12",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.12.tgz",
+          "integrity": "sha512-J55gaCS4iTTJfTXIxSVw3EMQckcqkpdRv3IR7gu6sq0+tbC363Zx6KH/SEwXASK9JRbhyZmVjJEVJIOxYsB3Qg==",
+          "dev": true,
+          "requires": {
+            "natives": "^1.1.3"
+          }
+        }
+      }
+    },
+    "fs-write-stream-atomic": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz",
+      "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.2",
+        "iferr": "^0.1.5",
+        "imurmurhash": "^0.1.4",
+        "readable-stream": "1 || 2"
+      }
+    },
+    "fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+    },
+    "fsevents": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.1.tgz",
+      "integrity": "sha512-YR47Eg4hChJGAB1O3yEAOkGO+rlzutoICGqGo9EZ4lKWokzZRSyIW1QmTzqjtw8MJdj9srP869CuWw/hyzSiBw==",
+      "dev": true,
+      "optional": true
+    },
+    "fstream": {
+      "version": "1.0.12",
+      "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
+      "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
+      "requires": {
+        "graceful-fs": "^4.1.2",
+        "inherits": "~2.0.0",
+        "mkdirp": ">=0.5 0",
+        "rimraf": "2"
+      }
+    },
+    "function-bind": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+    },
+    "functional-red-black-tree": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+      "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
+      "dev": true
+    },
+    "gauge": {
+      "version": "2.7.4",
+      "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
+      "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
+      "requires": {
+        "aproba": "^1.0.3",
+        "console-control-strings": "^1.0.0",
+        "has-unicode": "^2.0.0",
+        "object-assign": "^4.1.0",
+        "signal-exit": "^3.0.0",
+        "string-width": "^1.0.1",
+        "strip-ansi": "^3.0.1",
+        "wide-align": "^1.1.0"
+      },
+      "dependencies": {
+        "is-fullwidth-code-point": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+          "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+          "requires": {
+            "number-is-nan": "^1.0.0"
+          }
+        },
+        "string-width": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+          "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+          "requires": {
+            "code-point-at": "^1.0.0",
+            "is-fullwidth-code-point": "^1.0.0",
+            "strip-ansi": "^3.0.0"
+          }
+        }
+      }
+    },
+    "gaze": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz",
+      "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==",
+      "requires": {
+        "globule": "^1.0.0"
+      }
+    },
+    "get-caller-file": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
+      "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
+      "dev": true
+    },
+    "get-intrinsic": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.2.tgz",
+      "integrity": "sha512-aeX0vrFm21ILl3+JpFFRNe9aUvp6VFZb2/CTbgLb8j75kOhvoNYjt9d8KA/tJG4gSo8nzEDedRl0h7vDmBYRVg==",
+      "dev": true,
+      "requires": {
+        "function-bind": "^1.1.1",
+        "has": "^1.0.3",
+        "has-symbols": "^1.0.1"
+      }
+    },
+    "get-stdin": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
+      "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4="
+    },
+    "get-stream": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
+      "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
+      "dev": true
+    },
+    "get-value": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+      "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
+      "dev": true
+    },
+    "getpass": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+      "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+      "requires": {
+        "assert-plus": "^1.0.0"
+      }
+    },
+    "glob": {
+      "version": "7.1.6",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+      "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+      "requires": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.0.4",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      }
+    },
+    "glob-parent": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
+      "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "is-glob": "^4.0.1"
+      }
+    },
+    "globals": {
+      "version": "9.18.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
+      "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==",
+      "dev": true
+    },
+    "globby": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz",
+      "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=",
+      "dev": true,
+      "requires": {
+        "array-union": "^1.0.1",
+        "dir-glob": "^2.0.0",
+        "glob": "^7.1.2",
+        "ignore": "^3.3.5",
+        "pify": "^3.0.0",
+        "slash": "^1.0.0"
+      }
+    },
+    "globule": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.2.tgz",
+      "integrity": "sha512-7IDTQTIu2xzXkT+6mlluidnWo+BypnbSoEVVQCGfzqnl5Ik8d3e1d4wycb8Rj9tWW+Z39uPWsdlquqiqPCd/pA==",
+      "requires": {
+        "glob": "~7.1.1",
+        "lodash": "~4.17.10",
+        "minimatch": "~3.0.2"
+      }
+    },
+    "graceful-fs": {
+      "version": "4.2.4",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
+      "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw=="
+    },
+    "graceful-readlink": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
+      "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=",
+      "dev": true
+    },
+    "growly": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
+      "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=",
+      "dev": true
+    },
+    "gzip-size": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-4.1.0.tgz",
+      "integrity": "sha1-iuCWJX6r59acRb4rZ8RIEk/7UXw=",
+      "dev": true,
+      "requires": {
+        "duplexer": "^0.1.1",
+        "pify": "^3.0.0"
+      }
+    },
+    "handle-thing": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
+      "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==",
+      "dev": true
+    },
+    "har-schema": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+      "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
+    },
+    "har-validator": {
+      "version": "5.1.5",
+      "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
+      "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
+      "requires": {
+        "ajv": "^6.12.3",
+        "har-schema": "^2.0.0"
+      },
+      "dependencies": {
+        "ajv": {
+          "version": "6.12.6",
+          "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+          "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+          "requires": {
+            "fast-deep-equal": "^3.1.1",
+            "fast-json-stable-stringify": "^2.0.0",
+            "json-schema-traverse": "^0.4.1",
+            "uri-js": "^4.2.2"
+          }
+        },
+        "fast-deep-equal": {
+          "version": "3.1.3",
+          "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+          "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
+        },
+        "json-schema-traverse": {
+          "version": "0.4.1",
+          "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+          "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
+        }
+      }
+    },
+    "has": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+      "requires": {
+        "function-bind": "^1.1.1"
+      }
+    },
+    "has-ansi": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+      "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+      "requires": {
+        "ansi-regex": "^2.0.0"
+      }
+    },
+    "has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+      "dev": true
+    },
+    "has-symbols": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
+      "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
+      "dev": true
+    },
+    "has-unicode": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+      "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
+    },
+    "has-value": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+      "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
+      "dev": true,
+      "requires": {
+        "get-value": "^2.0.6",
+        "has-values": "^1.0.0",
+        "isobject": "^3.0.0"
+      }
+    },
+    "has-values": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+      "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
+      "dev": true,
+      "requires": {
+        "is-number": "^3.0.0",
+        "kind-of": "^4.0.0"
+      },
+      "dependencies": {
+        "is-number": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+          "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+          "dev": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "3.2.2",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+              "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+              "dev": true,
+              "requires": {
+                "is-buffer": "^1.1.5"
+              }
+            }
+          }
+        },
+        "kind-of": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+          "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "hash-base": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
+      "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.4",
+        "readable-stream": "^3.6.0",
+        "safe-buffer": "^5.2.0"
+      },
+      "dependencies": {
+        "readable-stream": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+          "dev": true,
+          "requires": {
+            "inherits": "^2.0.3",
+            "string_decoder": "^1.1.1",
+            "util-deprecate": "^1.0.1"
+          }
+        },
+        "safe-buffer": {
+          "version": "5.2.1",
+          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+          "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+          "dev": true
+        }
+      }
+    },
+    "hash-sum": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz",
+      "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=",
+      "dev": true
+    },
+    "hash.js": {
+      "version": "1.1.7",
+      "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
+      "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.3",
+        "minimalistic-assert": "^1.0.1"
+      }
+    },
+    "he": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+      "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+      "dev": true
+    },
+    "header-case": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/header-case/-/header-case-1.0.1.tgz",
+      "integrity": "sha1-lTWXMZfBRLCWE81l0xfvGZY70C0=",
+      "dev": true,
+      "requires": {
+        "no-case": "^2.2.0",
+        "upper-case": "^1.1.3"
+      }
+    },
+    "hex-color-regex": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz",
+      "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==",
+      "dev": true
+    },
+    "hmac-drbg": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
+      "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
+      "dev": true,
+      "requires": {
+        "hash.js": "^1.0.3",
+        "minimalistic-assert": "^1.0.0",
+        "minimalistic-crypto-utils": "^1.0.1"
+      }
+    },
+    "home-or-tmp": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
+      "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=",
+      "dev": true,
+      "requires": {
+        "os-homedir": "^1.0.0",
+        "os-tmpdir": "^1.0.1"
+      }
+    },
+    "hosted-git-info": {
+      "version": "2.8.8",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
+      "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg=="
+    },
+    "hpack.js": {
+      "version": "2.1.6",
+      "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz",
+      "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.1",
+        "obuf": "^1.0.0",
+        "readable-stream": "^2.0.1",
+        "wbuf": "^1.1.0"
+      }
+    },
+    "hsl-regex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz",
+      "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=",
+      "dev": true
+    },
+    "hsla-regex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz",
+      "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=",
+      "dev": true
+    },
+    "html-comment-regex": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz",
+      "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==",
+      "dev": true
+    },
+    "html-entities": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.4.0.tgz",
+      "integrity": "sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==",
+      "dev": true
+    },
+    "html-minifier": {
+      "version": "3.5.21",
+      "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz",
+      "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==",
+      "dev": true,
+      "requires": {
+        "camel-case": "3.0.x",
+        "clean-css": "4.2.x",
+        "commander": "2.17.x",
+        "he": "1.2.x",
+        "param-case": "2.1.x",
+        "relateurl": "0.2.x",
+        "uglify-js": "3.4.x"
+      }
+    },
+    "html-webpack-plugin": {
+      "version": "2.30.1",
+      "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-2.30.1.tgz",
+      "integrity": "sha1-f5xCG36pHsRg9WUn1430hO51N9U=",
+      "dev": true,
+      "requires": {
+        "bluebird": "^3.4.7",
+        "html-minifier": "^3.2.3",
+        "loader-utils": "^0.2.16",
+        "lodash": "^4.17.3",
+        "pretty-error": "^2.0.2",
+        "toposort": "^1.0.0"
+      },
+      "dependencies": {
+        "big.js": {
+          "version": "3.2.0",
+          "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz",
+          "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==",
+          "dev": true
+        },
+        "emojis-list": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",
+          "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=",
+          "dev": true
+        },
+        "loader-utils": {
+          "version": "0.2.17",
+          "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz",
+          "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=",
+          "dev": true,
+          "requires": {
+            "big.js": "^3.1.3",
+            "emojis-list": "^2.0.0",
+            "json5": "^0.5.0",
+            "object-assign": "^4.0.1"
+          }
+        }
+      }
+    },
+    "htmlparser2": {
+      "version": "3.10.1",
+      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
+      "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
+      "dev": true,
+      "requires": {
+        "domelementtype": "^1.3.1",
+        "domhandler": "^2.3.0",
+        "domutils": "^1.5.1",
+        "entities": "^1.1.1",
+        "inherits": "^2.0.1",
+        "readable-stream": "^3.1.1"
+      },
+      "dependencies": {
+        "entities": {
+          "version": "1.1.2",
+          "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
+          "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+          "dev": true,
+          "requires": {
+            "inherits": "^2.0.3",
+            "string_decoder": "^1.1.1",
+            "util-deprecate": "^1.0.1"
+          }
+        }
+      }
+    },
+    "http-deceiver": {
+      "version": "1.2.7",
+      "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz",
+      "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=",
+      "dev": true
+    },
+    "http-errors": {
+      "version": "1.7.2",
+      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
+      "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
+      "dev": true,
+      "requires": {
+        "depd": "~1.1.2",
+        "inherits": "2.0.3",
+        "setprototypeof": "1.1.1",
+        "statuses": ">= 1.5.0 < 2",
+        "toidentifier": "1.0.0"
+      },
+      "dependencies": {
+        "inherits": {
+          "version": "2.0.3",
+          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+          "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+          "dev": true
+        }
+      }
+    },
+    "http-parser-js": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.3.tgz",
+      "integrity": "sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg==",
+      "dev": true
+    },
+    "http-proxy": {
+      "version": "1.18.1",
+      "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
+      "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
+      "dev": true,
+      "requires": {
+        "eventemitter3": "^4.0.0",
+        "follow-redirects": "^1.0.0",
+        "requires-port": "^1.0.0"
+      }
+    },
+    "http-proxy-middleware": {
+      "version": "0.19.2",
+      "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.2.tgz",
+      "integrity": "sha512-aYk1rTKqLTus23X3L96LGNCGNgWpG4cG0XoZIT1GUPhhulEHX/QalnO6Vbo+WmKWi4AL2IidjuC0wZtbpg0yhQ==",
+      "dev": true,
+      "requires": {
+        "http-proxy": "^1.18.1",
+        "is-glob": "^4.0.0",
+        "lodash": "^4.17.11",
+        "micromatch": "^3.1.10"
+      }
+    },
+    "http-signature": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+      "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+      "requires": {
+        "assert-plus": "^1.0.0",
+        "jsprim": "^1.2.2",
+        "sshpk": "^1.7.0"
+      }
+    },
+    "https-browserify": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
+      "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=",
+      "dev": true
+    },
+    "ical.js": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/ical.js/-/ical.js-1.4.0.tgz",
+      "integrity": "sha512-ltHZuOFNNjcyEYbzDgjemS7LWIFh2vydJeznxQHUh3dnarbxqOYsWONYteBVAq1MEOHnwXFGN2eskZReHclnrA=="
+    },
+    "iconv-lite": {
+      "version": "0.4.24",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+      "dev": true,
+      "requires": {
+        "safer-buffer": ">= 2.1.2 < 3"
+      }
+    },
+    "icss-replace-symbols": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz",
+      "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=",
+      "dev": true
+    },
+    "icss-utils": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-2.1.0.tgz",
+      "integrity": "sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=",
+      "dev": true,
+      "requires": {
+        "postcss": "^6.0.1"
+      }
+    },
+    "ieee754": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+      "dev": true
+    },
+    "iferr": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz",
+      "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=",
+      "dev": true
+    },
+    "ignore": {
+      "version": "3.3.10",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz",
+      "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==",
+      "dev": true
+    },
+    "image-size": {
+      "version": "0.5.5",
+      "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz",
+      "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=",
+      "dev": true,
+      "optional": true
+    },
+    "import-cwd": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz",
+      "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=",
+      "dev": true,
+      "requires": {
+        "import-from": "^2.1.0"
+      }
+    },
+    "import-fresh": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
+      "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=",
+      "dev": true,
+      "requires": {
+        "caller-path": "^2.0.0",
+        "resolve-from": "^3.0.0"
+      },
+      "dependencies": {
+        "caller-path": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz",
+          "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=",
+          "dev": true,
+          "requires": {
+            "caller-callsite": "^2.0.0"
+          }
+        },
+        "resolve-from": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
+          "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=",
+          "dev": true
+        }
+      }
+    },
+    "import-from": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz",
+      "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=",
+      "dev": true,
+      "requires": {
+        "resolve-from": "^3.0.0"
+      },
+      "dependencies": {
+        "resolve-from": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
+          "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=",
+          "dev": true
+        }
+      }
+    },
+    "import-local": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/import-local/-/import-local-1.0.0.tgz",
+      "integrity": "sha512-vAaZHieK9qjGo58agRBg+bhHX3hoTZU/Oa3GESWLz7t1U62fk63aHuDJJEteXoDeTCcPmUT+z38gkHPZkkmpmQ==",
+      "dev": true,
+      "requires": {
+        "pkg-dir": "^2.0.0",
+        "resolve-cwd": "^2.0.0"
+      }
+    },
+    "imurmurhash": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+      "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
+      "dev": true
+    },
+    "in-publish": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.1.tgz",
+      "integrity": "sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ=="
+    },
+    "indent-string": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
+      "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",
+      "requires": {
+        "repeating": "^2.0.0"
+      }
+    },
+    "indexes-of": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
+      "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=",
+      "dev": true
+    },
+    "inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+      "requires": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+    },
+    "inquirer": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz",
+      "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==",
+      "dev": true,
+      "requires": {
+        "ansi-escapes": "^3.0.0",
+        "chalk": "^2.0.0",
+        "cli-cursor": "^2.1.0",
+        "cli-width": "^2.0.0",
+        "external-editor": "^2.0.4",
+        "figures": "^2.0.0",
+        "lodash": "^4.3.0",
+        "mute-stream": "0.0.7",
+        "run-async": "^2.2.0",
+        "rx-lite": "^4.0.8",
+        "rx-lite-aggregates": "^4.0.8",
+        "string-width": "^2.1.0",
+        "strip-ansi": "^4.0.0",
+        "through": "^2.3.6"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+          "dev": true
+        },
+        "strip-ansi": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+          "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^3.0.0"
+          }
+        }
+      }
+    },
+    "internal-ip": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-1.2.0.tgz",
+      "integrity": "sha1-rp+/k7mEh4eF1QqN4bNWlWBYz1w=",
+      "dev": true,
+      "requires": {
+        "meow": "^3.3.0"
+      }
+    },
+    "interpret": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
+      "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
+      "dev": true
+    },
+    "invariant": {
+      "version": "2.2.4",
+      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
+      "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
+      "dev": true,
+      "requires": {
+        "loose-envify": "^1.0.0"
+      }
+    },
+    "invert-kv": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
+      "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=",
+      "dev": true
+    },
+    "ip": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
+      "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=",
+      "dev": true
+    },
+    "ipaddr.js": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+      "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+      "dev": true
+    },
+    "is-absolute-url": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz",
+      "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=",
+      "dev": true
+    },
+    "is-accessor-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+      "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.0.2"
+      }
+    },
+    "is-arguments": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz",
+      "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.0"
+      }
+    },
+    "is-arrayish": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+      "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
+    },
+    "is-binary-path": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "binary-extensions": "^2.0.0"
+      }
+    },
+    "is-buffer": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+      "dev": true
+    },
+    "is-callable": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz",
+      "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==",
+      "dev": true
+    },
+    "is-color-stop": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz",
+      "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=",
+      "dev": true,
+      "requires": {
+        "css-color-names": "^0.0.4",
+        "hex-color-regex": "^1.1.0",
+        "hsl-regex": "^1.0.0",
+        "hsla-regex": "^1.0.0",
+        "rgb-regex": "^1.0.1",
+        "rgba-regex": "^1.0.0"
+      }
+    },
+    "is-core-module": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz",
+      "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==",
+      "requires": {
+        "has": "^1.0.3"
+      }
+    },
+    "is-data-descriptor": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+      "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.0.2"
+      }
+    },
+    "is-date-object": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz",
+      "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==",
+      "dev": true
+    },
+    "is-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+      "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+      "dev": true,
+      "requires": {
+        "is-accessor-descriptor": "^0.1.6",
+        "is-data-descriptor": "^0.1.4",
+        "kind-of": "^5.0.0"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+          "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+          "dev": true
+        }
+      }
+    },
+    "is-directory": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
+      "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=",
+      "dev": true
+    },
+    "is-extendable": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+      "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+      "dev": true
+    },
+    "is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+      "dev": true
+    },
+    "is-finite": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz",
+      "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w=="
+    },
+    "is-fullwidth-code-point": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+      "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
+    },
+    "is-glob": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
+      "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
+      "dev": true,
+      "requires": {
+        "is-extglob": "^2.1.1"
+      }
+    },
+    "is-lower-case": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-1.1.3.tgz",
+      "integrity": "sha1-fhR75HaNxGbbO/shzGCzHmrWk5M=",
+      "dev": true,
+      "requires": {
+        "lower-case": "^1.1.0"
+      }
+    },
+    "is-negative-zero": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz",
+      "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==",
+      "dev": true
+    },
+    "is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "dev": true,
+      "optional": true
+    },
+    "is-obj": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
+      "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
+      "dev": true
+    },
+    "is-path-cwd": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz",
+      "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=",
+      "dev": true
+    },
+    "is-path-in-cwd": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz",
+      "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==",
+      "dev": true,
+      "requires": {
+        "is-path-inside": "^1.0.0"
+      }
+    },
+    "is-path-inside": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz",
+      "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=",
+      "dev": true,
+      "requires": {
+        "path-is-inside": "^1.0.1"
+      }
+    },
+    "is-plain-obj": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
+      "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=",
+      "dev": true
+    },
+    "is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "dev": true,
+      "requires": {
+        "isobject": "^3.0.1"
+      }
+    },
+    "is-regex": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz",
+      "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==",
+      "dev": true,
+      "requires": {
+        "has-symbols": "^1.0.1"
+      }
+    },
+    "is-resolvable": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz",
+      "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==",
+      "dev": true
+    },
+    "is-stream": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+      "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
+      "dev": true
+    },
+    "is-string": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz",
+      "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==",
+      "dev": true
+    },
+    "is-svg": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-2.1.0.tgz",
+      "integrity": "sha1-z2EJDaDZ77yrhyLeum8DIgjbsOk=",
+      "dev": true,
+      "requires": {
+        "html-comment-regex": "^1.1.0"
+      }
+    },
+    "is-symbol": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz",
+      "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==",
+      "dev": true,
+      "requires": {
+        "has-symbols": "^1.0.1"
+      }
+    },
+    "is-typedarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+      "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
+    },
+    "is-upper-case": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-1.1.2.tgz",
+      "integrity": "sha1-jQsfp+eTOh5YSDYA7H2WYcuvdW8=",
+      "dev": true,
+      "requires": {
+        "upper-case": "^1.1.0"
+      }
+    },
+    "is-utf8": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+      "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI="
+    },
+    "is-what": {
+      "version": "3.12.0",
+      "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.12.0.tgz",
+      "integrity": "sha512-2ilQz5/f/o9V7WRWJQmpFYNmQFZ9iM+OXRonZKcYgTkCzjb949Vi4h282PD1UfmgHk666rcWonbRJ++KI41VGw==",
+      "dev": true
+    },
+    "is-windows": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+      "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+      "dev": true
+    },
+    "is-wsl": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
+      "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=",
+      "dev": true
+    },
+    "isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+    },
+    "isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
+    },
+    "isobject": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+      "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+      "dev": true
+    },
+    "isstream": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+      "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
+    },
+    "js-base64": {
+      "version": "2.6.4",
+      "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz",
+      "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ=="
+    },
+    "js-cookie": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz",
+      "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ=="
+    },
+    "js-tokens": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
+      "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
+      "dev": true
+    },
+    "js-yaml": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz",
+      "integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=",
+      "dev": true,
+      "requires": {
+        "argparse": "^1.0.7",
+        "esprima": "^2.6.0"
+      }
+    },
+    "jsbn": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+      "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
+    },
+    "jsesc": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
+      "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=",
+      "dev": true
+    },
+    "json-loader": {
+      "version": "0.5.7",
+      "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz",
+      "integrity": "sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==",
+      "dev": true
+    },
+    "json-parse-better-errors": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
+      "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
+      "dev": true
+    },
+    "json-schema": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+      "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
+    },
+    "json-schema-traverse": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
+      "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
+      "dev": true
+    },
+    "json-stable-stringify-without-jsonify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+      "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
+      "dev": true
+    },
+    "json-stringify-safe": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+      "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
+    },
+    "json3": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz",
+      "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==",
+      "dev": true
+    },
+    "json5": {
+      "version": "0.5.1",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
+      "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
+      "dev": true
+    },
+    "jsonfile": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
+      "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.6"
+      }
+    },
+    "jsprim": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+      "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+      "requires": {
+        "assert-plus": "1.0.0",
+        "extsprintf": "1.3.0",
+        "json-schema": "0.2.3",
+        "verror": "1.10.0"
+      }
+    },
+    "killable": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
+      "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==",
+      "dev": true
+    },
+    "kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+      "dev": true,
+      "requires": {
+        "is-buffer": "^1.1.5"
+      }
+    },
+    "last-call-webpack-plugin": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/last-call-webpack-plugin/-/last-call-webpack-plugin-2.1.2.tgz",
+      "integrity": "sha512-CZc+m2xZm51J8qSwdODeiiNeqh8CYkKEq6Rw8IkE4i/4yqf2cJhjQPsA6BtAV970ePRNhwEOXhy2U5xc5Jwh9Q==",
+      "dev": true,
+      "requires": {
+        "lodash": "^4.17.4",
+        "webpack-sources": "^1.0.1"
+      }
+    },
+    "lazy-cache": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
+      "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=",
+      "dev": true
+    },
+    "lcid": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
+      "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
+      "dev": true,
+      "requires": {
+        "invert-kv": "^1.0.0"
+      }
+    },
+    "less": {
+      "version": "3.13.1",
+      "resolved": "https://registry.npmjs.org/less/-/less-3.13.1.tgz",
+      "integrity": "sha512-SwA1aQXGUvp+P5XdZslUOhhLnClSLIjWvJhmd+Vgib5BFIr9lMNlQwmwUNOjXThF/A0x+MCYYPeWEfeWiLRnTw==",
+      "dev": true,
+      "requires": {
+        "copy-anything": "^2.0.1",
+        "errno": "^0.1.1",
+        "graceful-fs": "^4.1.2",
+        "image-size": "~0.5.0",
+        "make-dir": "^2.1.0",
+        "mime": "^1.4.1",
+        "native-request": "^1.0.5",
+        "source-map": "~0.6.0",
+        "tslib": "^1.10.0"
+      },
+      "dependencies": {
+        "make-dir": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
+          "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "pify": "^4.0.1",
+            "semver": "^5.6.0"
+          }
+        },
+        "pify": {
+          "version": "4.0.1",
+          "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
+          "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
+          "dev": true,
+          "optional": true
+        }
+      }
+    },
+    "less-loader": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-5.0.0.tgz",
+      "integrity": "sha512-bquCU89mO/yWLaUq0Clk7qCsKhsF/TZpJUzETRvJa9KSVEL9SO3ovCvdEHISBhrC81OwC8QSVX7E0bzElZj9cg==",
+      "dev": true,
+      "requires": {
+        "clone": "^2.1.1",
+        "loader-utils": "^1.1.0",
+        "pify": "^4.0.1"
+      },
+      "dependencies": {
+        "clone": {
+          "version": "2.1.2",
+          "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
+          "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=",
+          "dev": true
+        },
+        "pify": {
+          "version": "4.0.1",
+          "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
+          "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
+          "dev": true
+        }
+      }
+    },
+    "levn": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+      "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+      "dev": true,
+      "requires": {
+        "prelude-ls": "~1.1.2",
+        "type-check": "~0.3.2"
+      }
+    },
+    "lib-flexible": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/lib-flexible/-/lib-flexible-0.3.2.tgz",
+      "integrity": "sha1-BvWnSDIxSi01wSA5vJw8otrqpCY="
+    },
+    "linkify-it": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz",
+      "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==",
+      "requires": {
+        "uc.micro": "^1.0.1"
+      }
+    },
+    "load-json-file": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
+      "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.2",
+        "parse-json": "^2.2.0",
+        "pify": "^2.0.0",
+        "strip-bom": "^3.0.0"
+      },
+      "dependencies": {
+        "pify": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+          "dev": true
+        }
+      }
+    },
+    "loader-fs-cache": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/loader-fs-cache/-/loader-fs-cache-1.0.3.tgz",
+      "integrity": "sha512-ldcgZpjNJj71n+2Mf6yetz+c9bM4xpKtNds4LbqXzU/PTdeAX0g3ytnU1AJMEcTk2Lex4Smpe3Q/eCTsvUBxbA==",
+      "dev": true,
+      "requires": {
+        "find-cache-dir": "^0.1.1",
+        "mkdirp": "^0.5.1"
+      },
+      "dependencies": {
+        "find-cache-dir": {
+          "version": "0.1.1",
+          "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz",
+          "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=",
+          "dev": true,
+          "requires": {
+            "commondir": "^1.0.1",
+            "mkdirp": "^0.5.1",
+            "pkg-dir": "^1.0.0"
+          }
+        },
+        "find-up": {
+          "version": "1.1.2",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
+          "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
+          "dev": true,
+          "requires": {
+            "path-exists": "^2.0.0",
+            "pinkie-promise": "^2.0.0"
+          }
+        },
+        "path-exists": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
+          "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
+          "dev": true,
+          "requires": {
+            "pinkie-promise": "^2.0.0"
+          }
+        },
+        "pkg-dir": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz",
+          "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=",
+          "dev": true,
+          "requires": {
+            "find-up": "^1.0.0"
+          }
+        }
+      }
+    },
+    "loader-runner": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz",
+      "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==",
+      "dev": true
+    },
+    "loader-utils": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
+      "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
+      "dev": true,
+      "requires": {
+        "big.js": "^5.2.2",
+        "emojis-list": "^3.0.0",
+        "json5": "^1.0.1"
+      },
+      "dependencies": {
+        "json5": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
+          "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
+          "dev": true,
+          "requires": {
+            "minimist": "^1.2.0"
+          }
+        }
+      }
+    },
+    "locate-path": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
+      "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
+      "dev": true,
+      "requires": {
+        "p-locate": "^2.0.0",
+        "path-exists": "^3.0.0"
+      }
+    },
+    "lockr": {
+      "version": "0.8.5",
+      "resolved": "https://registry.npmjs.org/lockr/-/lockr-0.8.5.tgz",
+      "integrity": "sha512-PyWX+NYcJtk+12cARV5qaR0I2cfpHDplpOOI4KKoJtJufdnXo4sJPmfWhbZUAT5rCMgszzU0DovlSjEKp2u12A=="
+    },
+    "lodash": {
+      "version": "4.17.20",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
+      "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
+    },
+    "lodash.camelcase": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+      "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=",
+      "dev": true
+    },
+    "lodash.memoize": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
+      "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=",
+      "dev": true
+    },
+    "lodash.uniq": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
+      "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=",
+      "dev": true
+    },
+    "log-symbols": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
+      "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==",
+      "dev": true,
+      "requires": {
+        "chalk": "^2.0.1"
+      }
+    },
+    "loglevel": {
+      "version": "1.7.1",
+      "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz",
+      "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==",
+      "dev": true
+    },
+    "longest": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
+      "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=",
+      "dev": true
+    },
+    "loose-envify": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+      "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+      "dev": true,
+      "requires": {
+        "js-tokens": "^3.0.0 || ^4.0.0"
+      }
+    },
+    "loud-rejection": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
+      "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",
+      "requires": {
+        "currently-unhandled": "^0.4.1",
+        "signal-exit": "^3.0.0"
+      }
+    },
+    "lower-case": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz",
+      "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=",
+      "dev": true
+    },
+    "lower-case-first": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/lower-case-first/-/lower-case-first-1.0.2.tgz",
+      "integrity": "sha1-5dp8JvKacHO+AtUrrJmA5ZIq36E=",
+      "dev": true,
+      "requires": {
+        "lower-case": "^1.1.2"
+      }
+    },
+    "lru-cache": {
+      "version": "4.1.5",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
+      "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
+      "requires": {
+        "pseudomap": "^1.0.2",
+        "yallist": "^2.1.2"
+      }
+    },
+    "make-dir": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
+      "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
+      "dev": true,
+      "requires": {
+        "pify": "^3.0.0"
+      }
+    },
+    "map-cache": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+      "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
+      "dev": true
+    },
+    "map-obj": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
+      "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0="
+    },
+    "map-visit": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+      "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
+      "dev": true,
+      "requires": {
+        "object-visit": "^1.0.0"
+      }
+    },
+    "markdown-it": {
+      "version": "8.4.2",
+      "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz",
+      "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==",
+      "requires": {
+        "argparse": "^1.0.7",
+        "entities": "~1.1.1",
+        "linkify-it": "^2.0.0",
+        "mdurl": "^1.0.1",
+        "uc.micro": "^1.0.5"
+      },
+      "dependencies": {
+        "entities": {
+          "version": "1.1.2",
+          "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
+          "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w=="
+        }
+      }
+    },
+    "math-expression-evaluator": {
+      "version": "1.3.7",
+      "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.3.7.tgz",
+      "integrity": "sha512-nrbaifCl42w37hYd6oRLvoymFK42tWB+WQTMFtksDGQMi5GvlJwnz/CsS30FFAISFLtX+A0csJ0xLiuuyyec7w==",
+      "dev": true
+    },
+    "md5.js": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
+      "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
+      "dev": true,
+      "requires": {
+        "hash-base": "^3.0.0",
+        "inherits": "^2.0.1",
+        "safe-buffer": "^5.1.2"
+      }
+    },
+    "mdn-data": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz",
+      "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==",
+      "dev": true
+    },
+    "mdurl": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
+      "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4="
+    },
+    "media-typer": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+      "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
+      "dev": true
+    },
+    "mem": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz",
+      "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=",
+      "dev": true,
+      "requires": {
+        "mimic-fn": "^1.0.0"
+      }
+    },
+    "memory-fs": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
+      "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=",
+      "dev": true,
+      "requires": {
+        "errno": "^0.1.3",
+        "readable-stream": "^2.0.1"
+      }
+    },
+    "meow": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
+      "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
+      "requires": {
+        "camelcase-keys": "^2.0.0",
+        "decamelize": "^1.1.2",
+        "loud-rejection": "^1.0.0",
+        "map-obj": "^1.0.1",
+        "minimist": "^1.1.3",
+        "normalize-package-data": "^2.3.4",
+        "object-assign": "^4.0.1",
+        "read-pkg-up": "^1.0.1",
+        "redent": "^1.0.0",
+        "trim-newlines": "^1.0.0"
+      },
+      "dependencies": {
+        "find-up": {
+          "version": "1.1.2",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
+          "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
+          "requires": {
+            "path-exists": "^2.0.0",
+            "pinkie-promise": "^2.0.0"
+          }
+        },
+        "load-json-file": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
+          "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
+          "requires": {
+            "graceful-fs": "^4.1.2",
+            "parse-json": "^2.2.0",
+            "pify": "^2.0.0",
+            "pinkie-promise": "^2.0.0",
+            "strip-bom": "^2.0.0"
+          }
+        },
+        "path-exists": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
+          "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
+          "requires": {
+            "pinkie-promise": "^2.0.0"
+          }
+        },
+        "path-type": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
+          "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
+          "requires": {
+            "graceful-fs": "^4.1.2",
+            "pify": "^2.0.0",
+            "pinkie-promise": "^2.0.0"
+          }
+        },
+        "pify": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
+        },
+        "read-pkg": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
+          "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
+          "requires": {
+            "load-json-file": "^1.0.0",
+            "normalize-package-data": "^2.3.2",
+            "path-type": "^1.0.0"
+          }
+        },
+        "read-pkg-up": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
+          "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
+          "requires": {
+            "find-up": "^1.0.0",
+            "read-pkg": "^1.0.0"
+          }
+        },
+        "strip-bom": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
+          "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
+          "requires": {
+            "is-utf8": "^0.2.0"
+          }
+        }
+      }
+    },
+    "merge-descriptors": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+      "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=",
+      "dev": true
+    },
+    "methods": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+      "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
+      "dev": true
+    },
+    "micromatch": {
+      "version": "3.1.10",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+      "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+      "dev": true,
+      "requires": {
+        "arr-diff": "^4.0.0",
+        "array-unique": "^0.3.2",
+        "braces": "^2.3.1",
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "extglob": "^2.0.4",
+        "fragment-cache": "^0.2.1",
+        "kind-of": "^6.0.2",
+        "nanomatch": "^1.2.9",
+        "object.pick": "^1.3.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.2"
+      },
+      "dependencies": {
+        "braces": {
+          "version": "2.3.2",
+          "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+          "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+          "dev": true,
+          "requires": {
+            "arr-flatten": "^1.1.0",
+            "array-unique": "^0.3.2",
+            "extend-shallow": "^2.0.1",
+            "fill-range": "^4.0.0",
+            "isobject": "^3.0.1",
+            "repeat-element": "^1.1.2",
+            "snapdragon": "^0.8.1",
+            "snapdragon-node": "^2.0.1",
+            "split-string": "^3.0.2",
+            "to-regex": "^3.0.1"
+          },
+          "dependencies": {
+            "extend-shallow": {
+              "version": "2.0.1",
+              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+              "dev": true,
+              "requires": {
+                "is-extendable": "^0.1.0"
+              }
+            }
+          }
+        },
+        "fill-range": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+          "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+          "dev": true,
+          "requires": {
+            "extend-shallow": "^2.0.1",
+            "is-number": "^3.0.0",
+            "repeat-string": "^1.6.1",
+            "to-regex-range": "^2.1.0"
+          },
+          "dependencies": {
+            "extend-shallow": {
+              "version": "2.0.1",
+              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+              "dev": true,
+              "requires": {
+                "is-extendable": "^0.1.0"
+              }
+            }
+          }
+        },
+        "is-number": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+          "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+          "dev": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "3.2.2",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+              "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+              "dev": true,
+              "requires": {
+                "is-buffer": "^1.1.5"
+              }
+            }
+          }
+        },
+        "kind-of": {
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+          "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+          "dev": true
+        },
+        "to-regex-range": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+          "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
+          "dev": true,
+          "requires": {
+            "is-number": "^3.0.0",
+            "repeat-string": "^1.6.1"
+          }
+        }
+      }
+    },
+    "miller-rabin": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
+      "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==",
+      "dev": true,
+      "requires": {
+        "bn.js": "^4.0.0",
+        "brorand": "^1.0.1"
+      },
+      "dependencies": {
+        "bn.js": {
+          "version": "4.11.9",
+          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
+          "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
+          "dev": true
+        }
+      }
+    },
+    "mime": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+      "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+      "dev": true
+    },
+    "mime-db": {
+      "version": "1.45.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz",
+      "integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w=="
+    },
+    "mime-types": {
+      "version": "2.1.28",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz",
+      "integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==",
+      "requires": {
+        "mime-db": "1.45.0"
+      }
+    },
+    "mimic-fn": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
+      "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
+      "dev": true
+    },
+    "minimalistic-assert": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
+      "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
+      "dev": true
+    },
+    "minimalistic-crypto-utils": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
+      "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=",
+      "dev": true
+    },
+    "minimatch": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+      "requires": {
+        "brace-expansion": "^1.1.7"
+      }
+    },
+    "minimist": {
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+      "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
+    },
+    "mississippi": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz",
+      "integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==",
+      "dev": true,
+      "requires": {
+        "concat-stream": "^1.5.0",
+        "duplexify": "^3.4.2",
+        "end-of-stream": "^1.1.0",
+        "flush-write-stream": "^1.0.0",
+        "from2": "^2.1.0",
+        "parallel-transform": "^1.1.0",
+        "pump": "^2.0.1",
+        "pumpify": "^1.3.3",
+        "stream-each": "^1.1.0",
+        "through2": "^2.0.0"
+      }
+    },
+    "mixin-deep": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+      "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
+      "dev": true,
+      "requires": {
+        "for-in": "^1.0.2",
+        "is-extendable": "^1.0.1"
+      },
+      "dependencies": {
+        "is-extendable": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+          "dev": true,
+          "requires": {
+            "is-plain-object": "^2.0.4"
+          }
+        }
+      }
+    },
+    "mkdirp": {
+      "version": "0.5.5",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
+      "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
+      "requires": {
+        "minimist": "^1.2.5"
+      }
+    },
+    "moment": {
+      "version": "2.29.1",
+      "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
+      "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
+    },
+    "move-concurrently": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
+      "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=",
+      "dev": true,
+      "requires": {
+        "aproba": "^1.1.1",
+        "copy-concurrently": "^1.0.0",
+        "fs-write-stream-atomic": "^1.0.8",
+        "mkdirp": "^0.5.1",
+        "rimraf": "^2.5.4",
+        "run-queue": "^1.0.3"
+      }
+    },
+    "ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+      "dev": true
+    },
+    "multicast-dns": {
+      "version": "6.2.3",
+      "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz",
+      "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==",
+      "dev": true,
+      "requires": {
+        "dns-packet": "^1.3.1",
+        "thunky": "^1.0.2"
+      }
+    },
+    "multicast-dns-service-types": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz",
+      "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=",
+      "dev": true
+    },
+    "mute-stream": {
+      "version": "0.0.7",
+      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
+      "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
+      "dev": true
+    },
+    "nan": {
+      "version": "2.14.2",
+      "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz",
+      "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ=="
+    },
+    "nanomatch": {
+      "version": "1.2.13",
+      "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+      "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+      "dev": true,
+      "requires": {
+        "arr-diff": "^4.0.0",
+        "array-unique": "^0.3.2",
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "fragment-cache": "^0.2.1",
+        "is-windows": "^1.0.2",
+        "kind-of": "^6.0.2",
+        "object.pick": "^1.3.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+          "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+          "dev": true
+        }
+      }
+    },
+    "native-request": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/native-request/-/native-request-1.0.8.tgz",
+      "integrity": "sha512-vU2JojJVelUGp6jRcLwToPoWGxSx23z/0iX+I77J3Ht17rf2INGjrhOoQnjVo60nQd8wVsgzKkPfRXBiVdD2ag==",
+      "dev": true,
+      "optional": true
+    },
+    "natives": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.6.tgz",
+      "integrity": "sha512-6+TDFewD4yxY14ptjKaS63GVdtKiES1pTPyxn9Jb0rBqPMZ7VcCiooEhPNsr+mqHtMGxa/5c/HhcC4uPEUw/nA==",
+      "dev": true
+    },
+    "natural-compare": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+      "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
+      "dev": true
+    },
+    "ncname": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/ncname/-/ncname-1.0.0.tgz",
+      "integrity": "sha1-W1etGLHKCShk72Kwse2BlPODtxw=",
+      "dev": true,
+      "requires": {
+        "xml-char-classes": "^1.0.0"
+      }
+    },
+    "negotiator": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
+      "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
+      "dev": true
+    },
+    "neo-async": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
+      "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
+      "dev": true
+    },
+    "next-tick": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
+      "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=",
+      "dev": true
+    },
+    "no-case": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz",
+      "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==",
+      "dev": true,
+      "requires": {
+        "lower-case": "^1.1.1"
+      }
+    },
+    "node-forge": {
+      "version": "0.10.0",
+      "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
+      "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==",
+      "dev": true
+    },
+    "node-gyp": {
+      "version": "3.8.0",
+      "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz",
+      "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==",
+      "requires": {
+        "fstream": "^1.0.0",
+        "glob": "^7.0.3",
+        "graceful-fs": "^4.1.2",
+        "mkdirp": "^0.5.0",
+        "nopt": "2 || 3",
+        "npmlog": "0 || 1 || 2 || 3 || 4",
+        "osenv": "0",
+        "request": "^2.87.0",
+        "rimraf": "2",
+        "semver": "~5.3.0",
+        "tar": "^2.0.0",
+        "which": "1"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "5.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
+          "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8="
+        }
+      }
+    },
+    "node-libs-browser": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz",
+      "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==",
+      "dev": true,
+      "requires": {
+        "assert": "^1.1.1",
+        "browserify-zlib": "^0.2.0",
+        "buffer": "^4.3.0",
+        "console-browserify": "^1.1.0",
+        "constants-browserify": "^1.0.0",
+        "crypto-browserify": "^3.11.0",
+        "domain-browser": "^1.1.1",
+        "events": "^3.0.0",
+        "https-browserify": "^1.0.0",
+        "os-browserify": "^0.3.0",
+        "path-browserify": "0.0.1",
+        "process": "^0.11.10",
+        "punycode": "^1.2.4",
+        "querystring-es3": "^0.2.0",
+        "readable-stream": "^2.3.3",
+        "stream-browserify": "^2.0.1",
+        "stream-http": "^2.7.2",
+        "string_decoder": "^1.0.0",
+        "timers-browserify": "^2.0.4",
+        "tty-browserify": "0.0.0",
+        "url": "^0.11.0",
+        "util": "^0.11.0",
+        "vm-browserify": "^1.0.1"
+      },
+      "dependencies": {
+        "punycode": {
+          "version": "1.4.1",
+          "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+          "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
+          "dev": true
+        }
+      }
+    },
+    "node-notifier": {
+      "version": "5.4.3",
+      "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.3.tgz",
+      "integrity": "sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q==",
+      "dev": true,
+      "requires": {
+        "growly": "^1.3.0",
+        "is-wsl": "^1.1.0",
+        "semver": "^5.5.0",
+        "shellwords": "^0.1.1",
+        "which": "^1.3.0"
+      }
+    },
+    "node-releases": {
+      "version": "1.1.69",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.69.tgz",
+      "integrity": "sha512-DGIjo79VDEyAnRlfSqYTsy+yoHd2IOjJiKUozD2MV2D85Vso6Bug56mb9tT/fY5Urt0iqk01H7x+llAruDR2zA==",
+      "dev": true
+    },
+    "node-sass": {
+      "version": "4.14.1",
+      "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.14.1.tgz",
+      "integrity": "sha512-sjCuOlvGyCJS40R8BscF5vhVlQjNN069NtQ1gSxyK1u9iqvn6tf7O1R4GNowVZfiZUCRt5MmMs1xd+4V/7Yr0g==",
+      "requires": {
+        "async-foreach": "^0.1.3",
+        "chalk": "^1.1.1",
+        "cross-spawn": "^3.0.0",
+        "gaze": "^1.0.0",
+        "get-stdin": "^4.0.1",
+        "glob": "^7.0.3",
+        "in-publish": "^2.0.0",
+        "lodash": "^4.17.15",
+        "meow": "^3.7.0",
+        "mkdirp": "^0.5.1",
+        "nan": "^2.13.2",
+        "node-gyp": "^3.8.0",
+        "npmlog": "^4.0.0",
+        "request": "^2.88.0",
+        "sass-graph": "2.2.5",
+        "stdout-stream": "^1.4.0",
+        "true-case-path": "^1.0.2"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          }
+        },
+        "cross-spawn": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz",
+          "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=",
+          "requires": {
+            "lru-cache": "^4.0.1",
+            "which": "^1.2.9"
+          }
+        },
+        "supports-color": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+          "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
+        }
+      }
+    },
+    "nopt": {
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
+      "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
+      "requires": {
+        "abbrev": "1"
+      }
+    },
+    "normalize-package-data": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+      "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+      "requires": {
+        "hosted-git-info": "^2.1.4",
+        "resolve": "^1.10.0",
+        "semver": "2 || 3 || 4 || 5",
+        "validate-npm-package-license": "^3.0.1"
+      }
+    },
+    "normalize-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+      "dev": true
+    },
+    "normalize-range": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+      "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=",
+      "dev": true
+    },
+    "normalize-url": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz",
+      "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=",
+      "dev": true,
+      "requires": {
+        "object-assign": "^4.0.1",
+        "prepend-http": "^1.0.0",
+        "query-string": "^4.1.0",
+        "sort-keys": "^1.0.0"
+      }
+    },
+    "normalize-wheel": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/normalize-wheel/-/normalize-wheel-1.0.1.tgz",
+      "integrity": "sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU="
+    },
+    "npm-run-path": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
+      "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
+      "dev": true,
+      "requires": {
+        "path-key": "^2.0.0"
+      }
+    },
+    "npmlog": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
+      "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+      "requires": {
+        "are-we-there-yet": "~1.1.2",
+        "console-control-strings": "~1.1.0",
+        "gauge": "~2.7.3",
+        "set-blocking": "~2.0.0"
+      }
+    },
+    "nprogress": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz",
+      "integrity": "sha1-y480xTIT2JVyP8urkH6UIq28r7E="
+    },
+    "nth-check": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
+      "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==",
+      "dev": true,
+      "requires": {
+        "boolbase": "~1.0.0"
+      }
+    },
+    "num2fraction": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
+      "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=",
+      "dev": true
+    },
+    "number-is-nan": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+      "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
+    },
+    "oauth-sign": {
+      "version": "0.9.0",
+      "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+      "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
+    },
+    "object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+    },
+    "object-copy": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+      "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
+      "dev": true,
+      "requires": {
+        "copy-descriptor": "^0.1.0",
+        "define-property": "^0.2.5",
+        "kind-of": "^3.0.3"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        }
+      }
+    },
+    "object-hash": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz",
+      "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==",
+      "dev": true
+    },
+    "object-inspect": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz",
+      "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==",
+      "dev": true
+    },
+    "object-is": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.4.tgz",
+      "integrity": "sha512-1ZvAZ4wlF7IyPVOcE1Omikt7UpaFlOQq0HlSti+ZvDH3UiD2brwGMwDbyV43jao2bKJ+4+WdPJHSd7kgzKYVqg==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.0",
+        "define-properties": "^1.1.3"
+      }
+    },
+    "object-keys": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+      "dev": true
+    },
+    "object-visit": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+      "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
+      "dev": true,
+      "requires": {
+        "isobject": "^3.0.0"
+      }
+    },
+    "object.assign": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
+      "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.0",
+        "define-properties": "^1.1.3",
+        "has-symbols": "^1.0.1",
+        "object-keys": "^1.1.1"
+      }
+    },
+    "object.getownpropertydescriptors": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.1.tgz",
+      "integrity": "sha512-6DtXgZ/lIZ9hqx4GtZETobXLR/ZLaa0aqV0kzbn80Rf8Z2e/XFnhA0I7p07N2wH8bBBltr2xQPi6sbKWAY2Eng==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.0",
+        "define-properties": "^1.1.3",
+        "es-abstract": "^1.18.0-next.1"
+      }
+    },
+    "object.pick": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+      "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+      "dev": true,
+      "requires": {
+        "isobject": "^3.0.1"
+      }
+    },
+    "object.values": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.2.tgz",
+      "integrity": "sha512-MYC0jvJopr8EK6dPBiO8Nb9mvjdypOachO5REGk6MXzujbBrAisKo3HmdEI6kZDL6fC31Mwee/5YbtMebixeag==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.0",
+        "define-properties": "^1.1.3",
+        "es-abstract": "^1.18.0-next.1",
+        "has": "^1.0.3"
+      }
+    },
+    "obuf": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
+      "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==",
+      "dev": true
+    },
+    "on-finished": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+      "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+      "dev": true,
+      "requires": {
+        "ee-first": "1.1.1"
+      }
+    },
+    "on-headers": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
+      "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
+      "dev": true
+    },
+    "once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+      "requires": {
+        "wrappy": "1"
+      }
+    },
+    "onetime": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
+      "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
+      "dev": true,
+      "requires": {
+        "mimic-fn": "^1.0.0"
+      }
+    },
+    "opener": {
+      "version": "1.5.2",
+      "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz",
+      "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==",
+      "dev": true
+    },
+    "opn": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz",
+      "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==",
+      "dev": true,
+      "requires": {
+        "is-wsl": "^1.1.0"
+      }
+    },
+    "optimize-css-assets-webpack-plugin": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-3.2.1.tgz",
+      "integrity": "sha512-FSoF15xKSEM2qCE3/y2gH92PysJSBY58Wx/hmSdIzVSOd0vg+FRS28NWZADId1wh6PDlbVt0lfPduV0IBufItQ==",
+      "dev": true,
+      "requires": {
+        "cssnano": "^4.1.10",
+        "last-call-webpack-plugin": "^2.1.2"
+      },
+      "dependencies": {
+        "cssnano": {
+          "version": "4.1.10",
+          "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz",
+          "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==",
+          "dev": true,
+          "requires": {
+            "cosmiconfig": "^5.0.0",
+            "cssnano-preset-default": "^4.0.7",
+            "is-resolvable": "^1.0.0",
+            "postcss": "^7.0.0"
+          }
+        },
+        "postcss": {
+          "version": "7.0.35",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz",
+          "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^2.4.2",
+            "source-map": "^0.6.1",
+            "supports-color": "^6.1.0"
+          }
+        },
+        "supports-color": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+          "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
+      }
+    },
+    "optionator": {
+      "version": "0.8.3",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
+      "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
+      "dev": true,
+      "requires": {
+        "deep-is": "~0.1.3",
+        "fast-levenshtein": "~2.0.6",
+        "levn": "~0.3.0",
+        "prelude-ls": "~1.1.2",
+        "type-check": "~0.3.2",
+        "word-wrap": "~1.2.3"
+      }
+    },
+    "ora": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/ora/-/ora-1.4.0.tgz",
+      "integrity": "sha512-iMK1DOQxzzh2MBlVsU42G80mnrvUhqsMh74phHtDlrcTZPK0pH6o7l7DRshK+0YsxDyEuaOkziVdvM3T0QTzpw==",
+      "dev": true,
+      "requires": {
+        "chalk": "^2.1.0",
+        "cli-cursor": "^2.1.0",
+        "cli-spinners": "^1.0.1",
+        "log-symbols": "^2.1.0"
+      }
+    },
+    "original": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz",
+      "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==",
+      "dev": true,
+      "requires": {
+        "url-parse": "^1.4.3"
+      }
+    },
+    "os-browserify": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
+      "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=",
+      "dev": true
+    },
+    "os-homedir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+      "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
+    },
+    "os-locale": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz",
+      "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==",
+      "dev": true,
+      "requires": {
+        "execa": "^0.7.0",
+        "lcid": "^1.0.0",
+        "mem": "^1.1.0"
+      }
+    },
+    "os-tmpdir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+      "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
+    },
+    "osenv": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
+      "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
+      "requires": {
+        "os-homedir": "^1.0.0",
+        "os-tmpdir": "^1.0.0"
+      }
+    },
+    "p-finally": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
+      "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
+      "dev": true
+    },
+    "p-limit": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
+      "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
+      "dev": true,
+      "requires": {
+        "p-try": "^1.0.0"
+      }
+    },
+    "p-locate": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
+      "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
+      "dev": true,
+      "requires": {
+        "p-limit": "^1.1.0"
+      }
+    },
+    "p-map": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz",
+      "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==",
+      "dev": true
+    },
+    "p-try": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
+      "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
+      "dev": true
+    },
+    "pako": {
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+      "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
+      "dev": true
+    },
+    "parallel-transform": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz",
+      "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==",
+      "dev": true,
+      "requires": {
+        "cyclist": "^1.0.1",
+        "inherits": "^2.0.3",
+        "readable-stream": "^2.1.5"
+      }
+    },
+    "param-case": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz",
+      "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=",
+      "dev": true,
+      "requires": {
+        "no-case": "^2.2.0"
+      }
+    },
+    "parse-asn1": {
+      "version": "5.1.6",
+      "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz",
+      "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==",
+      "dev": true,
+      "requires": {
+        "asn1.js": "^5.2.0",
+        "browserify-aes": "^1.0.0",
+        "evp_bytestokey": "^1.0.0",
+        "pbkdf2": "^3.0.3",
+        "safe-buffer": "^5.1.1"
+      }
+    },
+    "parse-json": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+      "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
+      "requires": {
+        "error-ex": "^1.2.0"
+      }
+    },
+    "parseurl": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+      "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+      "dev": true
+    },
+    "pascal-case": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-2.0.1.tgz",
+      "integrity": "sha1-LVeNNFX2YNpl7KGO+VtODekSdh4=",
+      "dev": true,
+      "requires": {
+        "camel-case": "^3.0.0",
+        "upper-case-first": "^1.1.0"
+      }
+    },
+    "pascalcase": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+      "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
+      "dev": true
+    },
+    "path-browserify": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz",
+      "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==",
+      "dev": true
+    },
+    "path-case": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/path-case/-/path-case-2.1.1.tgz",
+      "integrity": "sha1-lLgDfDctP+KQbkZbtF4l0ibo7qU=",
+      "dev": true,
+      "requires": {
+        "no-case": "^2.2.0"
+      }
+    },
+    "path-dirname": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
+      "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=",
+      "dev": true
+    },
+    "path-exists": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+      "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
+    },
+    "path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+    },
+    "path-is-inside": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
+      "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
+      "dev": true
+    },
+    "path-key": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+      "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
+      "dev": true
+    },
+    "path-parse": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+      "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw=="
+    },
+    "path-to-regexp": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+      "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=",
+      "dev": true
+    },
+    "path-type": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
+      "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
+      "dev": true,
+      "requires": {
+        "pify": "^3.0.0"
+      }
+    },
+    "pbkdf2": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz",
+      "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==",
+      "dev": true,
+      "requires": {
+        "create-hash": "^1.1.2",
+        "create-hmac": "^1.1.4",
+        "ripemd160": "^2.0.1",
+        "safe-buffer": "^5.0.1",
+        "sha.js": "^2.4.8"
+      }
+    },
+    "performance-now": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+      "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
+    },
+    "picomatch": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
+      "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
+      "dev": true,
+      "optional": true
+    },
+    "pify": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+      "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+      "dev": true
+    },
+    "pinkie": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+      "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA="
+    },
+    "pinkie-promise": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+      "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+      "requires": {
+        "pinkie": "^2.0.0"
+      }
+    },
+    "pkg-dir": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz",
+      "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=",
+      "dev": true,
+      "requires": {
+        "find-up": "^2.1.0"
+      }
+    },
+    "pluralize": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz",
+      "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==",
+      "dev": true
+    },
+    "portfinder": {
+      "version": "1.0.28",
+      "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
+      "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==",
+      "dev": true,
+      "requires": {
+        "async": "^2.6.2",
+        "debug": "^3.1.1",
+        "mkdirp": "^0.5.5"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "3.2.7",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+          "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+          "dev": true,
+          "requires": {
+            "ms": "^2.1.1"
+          }
+        },
+        "ms": {
+          "version": "2.1.3",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+          "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+          "dev": true
+        }
+      }
+    },
+    "posix-character-classes": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+      "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
+      "dev": true
+    },
+    "postcss": {
+      "version": "6.0.23",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
+      "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
+      "dev": true,
+      "requires": {
+        "chalk": "^2.4.1",
+        "source-map": "^0.6.1",
+        "supports-color": "^5.4.0"
+      }
+    },
+    "postcss-calc": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-5.3.1.tgz",
+      "integrity": "sha1-d7rnypKK2FcW4v2kLyYb98HWW14=",
+      "dev": true,
+      "requires": {
+        "postcss": "^5.0.2",
+        "postcss-message-helpers": "^2.0.0",
+        "reduce-css-calc": "^1.2.6"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "postcss-colormin": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-2.2.2.tgz",
+      "integrity": "sha1-ZjFBfV8OkJo9fsJrJMio0eT5bks=",
+      "dev": true,
+      "requires": {
+        "colormin": "^1.0.5",
+        "postcss": "^5.0.13",
+        "postcss-value-parser": "^3.2.3"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "postcss-convert-values": {
+      "version": "2.6.1",
+      "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz",
+      "integrity": "sha1-u9hZPFwf0uPRwyK7kl3K6Nrk1i0=",
+      "dev": true,
+      "requires": {
+        "postcss": "^5.0.11",
+        "postcss-value-parser": "^3.1.2"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "postcss-discard-comments": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz",
+      "integrity": "sha1-vv6J+v1bPazlzM5Rt2uBUUvgDj0=",
+      "dev": true,
+      "requires": {
+        "postcss": "^5.0.14"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "postcss-discard-duplicates": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz",
+      "integrity": "sha1-uavye4isGIFYpesSq8riAmO5GTI=",
+      "dev": true,
+      "requires": {
+        "postcss": "^5.0.4"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "postcss-discard-empty": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz",
+      "integrity": "sha1-0rS9nVztXr2Nyt52QMfXzX9PkrU=",
+      "dev": true,
+      "requires": {
+        "postcss": "^5.0.14"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "postcss-discard-overridden": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz",
+      "integrity": "sha1-ix6vVU9ob7KIzYdMVWZ7CqNmjVg=",
+      "dev": true,
+      "requires": {
+        "postcss": "^5.0.16"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "postcss-discard-unused": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz",
+      "integrity": "sha1-vOMLLMWR/8Y0Mitfs0ZLbZNPRDM=",
+      "dev": true,
+      "requires": {
+        "postcss": "^5.0.14",
+        "uniqs": "^2.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "postcss-filter-plugins": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/postcss-filter-plugins/-/postcss-filter-plugins-2.0.3.tgz",
+      "integrity": "sha512-T53GVFsdinJhgwm7rg1BzbeBRomOg9y5MBVhGcsV0CxurUdVj1UlPdKtn7aqYA/c/QVkzKMjq2bSV5dKG5+AwQ==",
+      "dev": true,
+      "requires": {
+        "postcss": "^5.0.4"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "postcss-import": {
+      "version": "11.1.0",
+      "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-11.1.0.tgz",
+      "integrity": "sha512-5l327iI75POonjxkXgdRCUS+AlzAdBx4pOvMEhTKTCjb1p8IEeVR9yx3cPbmN7LIWJLbfnIXxAhoB4jpD0c/Cw==",
+      "dev": true,
+      "requires": {
+        "postcss": "^6.0.1",
+        "postcss-value-parser": "^3.2.3",
+        "read-cache": "^1.0.0",
+        "resolve": "^1.1.7"
+      }
+    },
+    "postcss-load-config": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.2.tgz",
+      "integrity": "sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw==",
+      "dev": true,
+      "requires": {
+        "cosmiconfig": "^5.0.0",
+        "import-cwd": "^2.0.0"
+      }
+    },
+    "postcss-load-options": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/postcss-load-options/-/postcss-load-options-1.2.0.tgz",
+      "integrity": "sha1-sJixVZ3awt8EvAuzdfmaXP4rbYw=",
+      "dev": true,
+      "requires": {
+        "cosmiconfig": "^2.1.0",
+        "object-assign": "^4.1.0"
+      },
+      "dependencies": {
+        "cosmiconfig": {
+          "version": "2.2.2",
+          "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz",
+          "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==",
+          "dev": true,
+          "requires": {
+            "is-directory": "^0.3.1",
+            "js-yaml": "^3.4.3",
+            "minimist": "^1.2.0",
+            "object-assign": "^4.1.0",
+            "os-homedir": "^1.0.1",
+            "parse-json": "^2.2.0",
+            "require-from-string": "^1.1.0"
+          }
+        }
+      }
+    },
+    "postcss-load-plugins": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/postcss-load-plugins/-/postcss-load-plugins-2.3.0.tgz",
+      "integrity": "sha1-dFdoEWWZrKLwCfrUJrABdQSdjZI=",
+      "dev": true,
+      "requires": {
+        "cosmiconfig": "^2.1.1",
+        "object-assign": "^4.1.0"
+      },
+      "dependencies": {
+        "cosmiconfig": {
+          "version": "2.2.2",
+          "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz",
+          "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==",
+          "dev": true,
+          "requires": {
+            "is-directory": "^0.3.1",
+            "js-yaml": "^3.4.3",
+            "minimist": "^1.2.0",
+            "object-assign": "^4.1.0",
+            "os-homedir": "^1.0.1",
+            "parse-json": "^2.2.0",
+            "require-from-string": "^1.1.0"
+          }
+        }
+      }
+    },
+    "postcss-loader": {
+      "version": "2.1.6",
+      "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-2.1.6.tgz",
+      "integrity": "sha512-hgiWSc13xVQAq25cVw80CH0l49ZKlAnU1hKPOdRrNj89bokRr/bZF2nT+hebPPF9c9xs8c3gw3Fr2nxtmXYnNg==",
+      "dev": true,
+      "requires": {
+        "loader-utils": "^1.1.0",
+        "postcss": "^6.0.0",
+        "postcss-load-config": "^2.0.0",
+        "schema-utils": "^0.4.0"
+      },
+      "dependencies": {
+        "ajv": {
+          "version": "6.12.6",
+          "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+          "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+          "dev": true,
+          "requires": {
+            "fast-deep-equal": "^3.1.1",
+            "fast-json-stable-stringify": "^2.0.0",
+            "json-schema-traverse": "^0.4.1",
+            "uri-js": "^4.2.2"
+          }
+        },
+        "ajv-keywords": {
+          "version": "3.5.2",
+          "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
+          "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
+          "dev": true
+        },
+        "fast-deep-equal": {
+          "version": "3.1.3",
+          "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+          "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+          "dev": true
+        },
+        "json-schema-traverse": {
+          "version": "0.4.1",
+          "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+          "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+          "dev": true
+        },
+        "schema-utils": {
+          "version": "0.4.7",
+          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz",
+          "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==",
+          "dev": true,
+          "requires": {
+            "ajv": "^6.1.0",
+            "ajv-keywords": "^3.1.0"
+          }
+        }
+      }
+    },
+    "postcss-merge-idents": {
+      "version": "2.1.7",
+      "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz",
+      "integrity": "sha1-TFUwMTwI4dWzu/PSu8dH4njuonA=",
+      "dev": true,
+      "requires": {
+        "has": "^1.0.1",
+        "postcss": "^5.0.10",
+        "postcss-value-parser": "^3.1.1"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "postcss-merge-longhand": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz",
+      "integrity": "sha1-I9kM0Sewp3mUkVMyc5A0oaTz1lg=",
+      "dev": true,
+      "requires": {
+        "postcss": "^5.0.4"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "postcss-merge-rules": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz",
+      "integrity": "sha1-0d9d+qexrMO+VT8OnhDofGG19yE=",
+      "dev": true,
+      "requires": {
+        "browserslist": "^1.5.2",
+        "caniuse-api": "^1.5.2",
+        "postcss": "^5.0.4",
+        "postcss-selector-parser": "^2.2.2",
+        "vendors": "^1.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "browserslist": {
+          "version": "1.7.7",
+          "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz",
+          "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=",
+          "dev": true,
+          "requires": {
+            "caniuse-db": "^1.0.30000639",
+            "electron-to-chromium": "^1.2.7"
+          }
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "postcss-message-helpers": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz",
+      "integrity": "sha1-pPL0+rbk/gAvCu0ABHjN9S+bpg4=",
+      "dev": true
+    },
+    "postcss-minify-font-values": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz",
+      "integrity": "sha1-S1jttWZB66fIR0qzUmyv17vey2k=",
+      "dev": true,
+      "requires": {
+        "object-assign": "^4.0.1",
+        "postcss": "^5.0.4",
+        "postcss-value-parser": "^3.0.2"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "postcss-minify-gradients": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz",
+      "integrity": "sha1-Xb2hE3NwP4PPtKPqOIHY11/15uE=",
+      "dev": true,
+      "requires": {
+        "postcss": "^5.0.12",
+        "postcss-value-parser": "^3.3.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "postcss-minify-params": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz",
+      "integrity": "sha1-rSzgcTc7lDs9kwo/pZo1jCjW8fM=",
+      "dev": true,
+      "requires": {
+        "alphanum-sort": "^1.0.1",
+        "postcss": "^5.0.2",
+        "postcss-value-parser": "^3.0.2",
+        "uniqs": "^2.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "postcss-minify-selectors": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz",
+      "integrity": "sha1-ssapjAByz5G5MtGkllCBFDEXNb8=",
+      "dev": true,
+      "requires": {
+        "alphanum-sort": "^1.0.2",
+        "has": "^1.0.1",
+        "postcss": "^5.0.14",
+        "postcss-selector-parser": "^2.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "postcss-modules-extract-imports": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.1.tgz",
+      "integrity": "sha512-6jt9XZwUhwmRUhb/CkyJY020PYaPJsCyt3UjbaWo6XEbH/94Hmv6MP7fG2C5NDU/BcHzyGYxNtHvM+LTf9HrYw==",
+      "dev": true,
+      "requires": {
+        "postcss": "^6.0.1"
+      }
+    },
+    "postcss-modules-local-by-default": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz",
+      "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=",
+      "dev": true,
+      "requires": {
+        "css-selector-tokenizer": "^0.7.0",
+        "postcss": "^6.0.1"
+      }
+    },
+    "postcss-modules-scope": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz",
+      "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=",
+      "dev": true,
+      "requires": {
+        "css-selector-tokenizer": "^0.7.0",
+        "postcss": "^6.0.1"
+      }
+    },
+    "postcss-modules-values": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz",
+      "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=",
+      "dev": true,
+      "requires": {
+        "icss-replace-symbols": "^1.1.0",
+        "postcss": "^6.0.1"
+      }
+    },
+    "postcss-normalize-charset": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz",
+      "integrity": "sha1-757nEhLX/nWceO0WL2HtYrXLk/E=",
+      "dev": true,
+      "requires": {
+        "postcss": "^5.0.5"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "postcss-normalize-display-values": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz",
+      "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==",
+      "dev": true,
+      "requires": {
+        "cssnano-util-get-match": "^4.0.0",
+        "postcss": "^7.0.0",
+        "postcss-value-parser": "^3.0.0"
+      },
+      "dependencies": {
+        "postcss": {
+          "version": "7.0.35",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz",
+          "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^2.4.2",
+            "source-map": "^0.6.1",
+            "supports-color": "^6.1.0"
+          }
+        },
+        "supports-color": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+          "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
+      }
+    },
+    "postcss-normalize-positions": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz",
+      "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==",
+      "dev": true,
+      "requires": {
+        "cssnano-util-get-arguments": "^4.0.0",
+        "has": "^1.0.0",
+        "postcss": "^7.0.0",
+        "postcss-value-parser": "^3.0.0"
+      },
+      "dependencies": {
+        "postcss": {
+          "version": "7.0.35",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz",
+          "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^2.4.2",
+            "source-map": "^0.6.1",
+            "supports-color": "^6.1.0"
+          }
+        },
+        "supports-color": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+          "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
+      }
+    },
+    "postcss-normalize-repeat-style": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz",
+      "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==",
+      "dev": true,
+      "requires": {
+        "cssnano-util-get-arguments": "^4.0.0",
+        "cssnano-util-get-match": "^4.0.0",
+        "postcss": "^7.0.0",
+        "postcss-value-parser": "^3.0.0"
+      },
+      "dependencies": {
+        "postcss": {
+          "version": "7.0.35",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz",
+          "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^2.4.2",
+            "source-map": "^0.6.1",
+            "supports-color": "^6.1.0"
+          }
+        },
+        "supports-color": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+          "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
+      }
+    },
+    "postcss-normalize-string": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz",
+      "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==",
+      "dev": true,
+      "requires": {
+        "has": "^1.0.0",
+        "postcss": "^7.0.0",
+        "postcss-value-parser": "^3.0.0"
+      },
+      "dependencies": {
+        "postcss": {
+          "version": "7.0.35",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz",
+          "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^2.4.2",
+            "source-map": "^0.6.1",
+            "supports-color": "^6.1.0"
+          }
+        },
+        "supports-color": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+          "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
+      }
+    },
+    "postcss-normalize-timing-functions": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz",
+      "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==",
+      "dev": true,
+      "requires": {
+        "cssnano-util-get-match": "^4.0.0",
+        "postcss": "^7.0.0",
+        "postcss-value-parser": "^3.0.0"
+      },
+      "dependencies": {
+        "postcss": {
+          "version": "7.0.35",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz",
+          "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^2.4.2",
+            "source-map": "^0.6.1",
+            "supports-color": "^6.1.0"
+          }
+        },
+        "supports-color": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+          "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
+      }
+    },
+    "postcss-normalize-unicode": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz",
+      "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==",
+      "dev": true,
+      "requires": {
+        "browserslist": "^4.0.0",
+        "postcss": "^7.0.0",
+        "postcss-value-parser": "^3.0.0"
+      },
+      "dependencies": {
+        "browserslist": {
+          "version": "4.16.1",
+          "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.1.tgz",
+          "integrity": "sha512-UXhDrwqsNcpTYJBTZsbGATDxZbiVDsx6UjpmRUmtnP10pr8wAYr5LgFoEFw9ixriQH2mv/NX2SfGzE/o8GndLA==",
+          "dev": true,
+          "requires": {
+            "caniuse-lite": "^1.0.30001173",
+            "colorette": "^1.2.1",
+            "electron-to-chromium": "^1.3.634",
+            "escalade": "^3.1.1",
+            "node-releases": "^1.1.69"
+          }
+        },
+        "postcss": {
+          "version": "7.0.35",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz",
+          "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^2.4.2",
+            "source-map": "^0.6.1",
+            "supports-color": "^6.1.0"
+          }
+        },
+        "supports-color": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+          "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
+      }
+    },
+    "postcss-normalize-url": {
+      "version": "3.0.8",
+      "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz",
+      "integrity": "sha1-EI90s/L82viRov+j6kWSJ5/HgiI=",
+      "dev": true,
+      "requires": {
+        "is-absolute-url": "^2.0.0",
+        "normalize-url": "^1.4.0",
+        "postcss": "^5.0.14",
+        "postcss-value-parser": "^3.2.3"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "postcss-normalize-whitespace": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz",
+      "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==",
+      "dev": true,
+      "requires": {
+        "postcss": "^7.0.0",
+        "postcss-value-parser": "^3.0.0"
+      },
+      "dependencies": {
+        "postcss": {
+          "version": "7.0.35",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz",
+          "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^2.4.2",
+            "source-map": "^0.6.1",
+            "supports-color": "^6.1.0"
+          }
+        },
+        "supports-color": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+          "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
+      }
+    },
+    "postcss-ordered-values": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz",
+      "integrity": "sha1-7sbCpntsQSqNsgQud/6NpD+VwR0=",
+      "dev": true,
+      "requires": {
+        "postcss": "^5.0.4",
+        "postcss-value-parser": "^3.0.1"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "postcss-reduce-idents": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz",
+      "integrity": "sha1-wsbSDMlYKE9qv75j92Cb9AkFmtM=",
+      "dev": true,
+      "requires": {
+        "postcss": "^5.0.4",
+        "postcss-value-parser": "^3.0.2"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "postcss-reduce-initial": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz",
+      "integrity": "sha1-aPgGlfBF0IJjqHmtJA343WT2ROo=",
+      "dev": true,
+      "requires": {
+        "postcss": "^5.0.4"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "postcss-reduce-transforms": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz",
+      "integrity": "sha1-/3b02CEkN7McKYpC0uFEQCV3GuE=",
+      "dev": true,
+      "requires": {
+        "has": "^1.0.1",
+        "postcss": "^5.0.8",
+        "postcss-value-parser": "^3.0.1"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "postcss-selector-parser": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz",
+      "integrity": "sha1-+UN3iGBsPJrO4W/+jYsWKX8nu5A=",
+      "dev": true,
+      "requires": {
+        "flatten": "^1.0.2",
+        "indexes-of": "^1.0.1",
+        "uniq": "^1.0.1"
+      }
+    },
+    "postcss-svgo": {
+      "version": "2.1.6",
+      "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-2.1.6.tgz",
+      "integrity": "sha1-tt8YqmE7Zm4TPwittSGcJoSsEI0=",
+      "dev": true,
+      "requires": {
+        "is-svg": "^2.0.0",
+        "postcss": "^5.0.14",
+        "postcss-value-parser": "^3.2.3",
+        "svgo": "^0.7.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "postcss-unique-selectors": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz",
+      "integrity": "sha1-mB1X0p3csz57Hf4f1DuGSfkzyh0=",
+      "dev": true,
+      "requires": {
+        "alphanum-sort": "^1.0.1",
+        "postcss": "^5.0.4",
+        "uniqs": "^2.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "postcss-url": {
+      "version": "7.3.2",
+      "resolved": "https://registry.npmjs.org/postcss-url/-/postcss-url-7.3.2.tgz",
+      "integrity": "sha512-QMV5mA+pCYZQcUEPQkmor9vcPQ2MT+Ipuu8qdi1gVxbNiIiErEGft+eny1ak19qALoBkccS5AHaCaCDzh7b9MA==",
+      "dev": true,
+      "requires": {
+        "mime": "^1.4.1",
+        "minimatch": "^3.0.4",
+        "mkdirp": "^0.5.0",
+        "postcss": "^6.0.1",
+        "xxhashjs": "^0.2.1"
+      }
+    },
+    "postcss-value-parser": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+      "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+      "dev": true
+    },
+    "postcss-zindex": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-2.2.0.tgz",
+      "integrity": "sha1-0hCd3AVbka9n/EyzsCWUZjnSryI=",
+      "dev": true,
+      "requires": {
+        "has": "^1.0.1",
+        "postcss": "^5.0.4",
+        "uniqs": "^2.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "preact": {
+      "version": "10.5.10",
+      "resolved": "https://registry.npmjs.org/preact/-/preact-10.5.10.tgz",
+      "integrity": "sha512-A6SITnHaj5CS4JPLVroQDNOEozq4Y0B4yQSGHLznxHe66Jb2DvoeTEibLjXmfeofgQE3BZ2zurltBIapzCMlwg=="
+    },
+    "prelude-ls": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+      "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+      "dev": true
+    },
+    "prepend-http": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
+      "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=",
+      "dev": true
+    },
+    "prettier": {
+      "version": "1.19.1",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz",
+      "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==",
+      "dev": true
+    },
+    "pretty-error": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz",
+      "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==",
+      "dev": true,
+      "requires": {
+        "lodash": "^4.17.20",
+        "renderkid": "^2.0.4"
+      }
+    },
+    "printj": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz",
+      "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ=="
+    },
+    "private": {
+      "version": "0.1.8",
+      "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
+      "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==",
+      "dev": true
+    },
+    "process": {
+      "version": "0.11.10",
+      "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+      "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=",
+      "dev": true
+    },
+    "process-nextick-args": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
+    },
+    "progress": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+      "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+      "dev": true
+    },
+    "promise-inflight": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
+      "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=",
+      "dev": true
+    },
+    "proxy-addr": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
+      "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
+      "dev": true,
+      "requires": {
+        "forwarded": "~0.1.2",
+        "ipaddr.js": "1.9.1"
+      }
+    },
+    "prr": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
+      "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=",
+      "dev": true
+    },
+    "pseudomap": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+      "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
+    },
+    "psl": {
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
+      "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
+    },
+    "public-encrypt": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
+      "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==",
+      "dev": true,
+      "requires": {
+        "bn.js": "^4.1.0",
+        "browserify-rsa": "^4.0.0",
+        "create-hash": "^1.1.0",
+        "parse-asn1": "^5.0.0",
+        "randombytes": "^2.0.1",
+        "safe-buffer": "^5.1.2"
+      },
+      "dependencies": {
+        "bn.js": {
+          "version": "4.11.9",
+          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
+          "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
+          "dev": true
+        }
+      }
+    },
+    "pump": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
+      "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
+      "dev": true,
+      "requires": {
+        "end-of-stream": "^1.1.0",
+        "once": "^1.3.1"
+      }
+    },
+    "pumpify": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz",
+      "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==",
+      "dev": true,
+      "requires": {
+        "duplexify": "^3.6.0",
+        "inherits": "^2.0.3",
+        "pump": "^2.0.0"
+      }
+    },
+    "punycode": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+      "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
+    },
+    "px2rem": {
+      "version": "0.5.0",
+      "resolved": "https://registry.npmjs.org/px2rem/-/px2rem-0.5.0.tgz",
+      "integrity": "sha1-JLOmz3TRSttO13byB4cdmJPkEOI=",
+      "dev": true,
+      "requires": {
+        "chalk": "~0.5.1",
+        "commander": "~2.6.0",
+        "css": "~2.2.0",
+        "extend": "~3.0.0",
+        "fs-extra": "~0.16.3"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "0.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz",
+          "integrity": "sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk=",
+          "dev": true
+        },
+        "ansi-styles": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz",
+          "integrity": "sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "0.5.1",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz",
+          "integrity": "sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^1.1.0",
+            "escape-string-regexp": "^1.0.0",
+            "has-ansi": "^0.1.0",
+            "strip-ansi": "^0.3.0",
+            "supports-color": "^0.2.0"
+          }
+        },
+        "commander": {
+          "version": "2.6.0",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-2.6.0.tgz",
+          "integrity": "sha1-nfflL7Kgyw+4kFjugMMQQiXzfh0=",
+          "dev": true
+        },
+        "has-ansi": {
+          "version": "0.1.0",
+          "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz",
+          "integrity": "sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4=",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^0.2.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "0.3.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz",
+          "integrity": "sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^0.2.1"
+          }
+        },
+        "supports-color": {
+          "version": "0.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz",
+          "integrity": "sha1-2S3iaU6z9nMjlz1649i1W0wiGQo=",
+          "dev": true
+        }
+      }
+    },
+    "px2rem-loader": {
+      "version": "0.1.9",
+      "resolved": "https://registry.npmjs.org/px2rem-loader/-/px2rem-loader-0.1.9.tgz",
+      "integrity": "sha512-3Ew8At5W/HHIIUe/KZk+FBRRb20KtgP1N1c/BnMlXk6LNkqrFmUIUF35GF/evzNdj/Q63iWJpkmn/c5qSMplRg==",
+      "dev": true,
+      "requires": {
+        "loader-utils": "^1.1.0",
+        "px2rem": "^0.5.0"
+      }
+    },
+    "q": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
+      "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=",
+      "dev": true
+    },
+    "qs": {
+      "version": "6.7.0",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+      "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
+      "dev": true
+    },
+    "query-string": {
+      "version": "4.3.4",
+      "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
+      "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
+      "dev": true,
+      "requires": {
+        "object-assign": "^4.1.0",
+        "strict-uri-encode": "^1.0.0"
+      }
+    },
+    "querystring": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
+      "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
+      "dev": true
+    },
+    "querystring-es3": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
+      "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=",
+      "dev": true
+    },
+    "querystringify": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
+      "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
+      "dev": true
+    },
+    "randombytes": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+      "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "^5.1.0"
+      }
+    },
+    "randomfill": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",
+      "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==",
+      "dev": true,
+      "requires": {
+        "randombytes": "^2.0.5",
+        "safe-buffer": "^5.1.0"
+      }
+    },
+    "range-parser": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+      "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+      "dev": true
+    },
+    "raw-body": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
+      "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
+      "dev": true,
+      "requires": {
+        "bytes": "3.1.0",
+        "http-errors": "1.7.2",
+        "iconv-lite": "0.4.24",
+        "unpipe": "1.0.0"
+      }
+    },
+    "read-cache": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
+      "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=",
+      "dev": true,
+      "requires": {
+        "pify": "^2.3.0"
+      },
+      "dependencies": {
+        "pify": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+          "dev": true
+        }
+      }
+    },
+    "read-pkg": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",
+      "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=",
+      "dev": true,
+      "requires": {
+        "load-json-file": "^2.0.0",
+        "normalize-package-data": "^2.3.2",
+        "path-type": "^2.0.0"
+      },
+      "dependencies": {
+        "path-type": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz",
+          "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=",
+          "dev": true,
+          "requires": {
+            "pify": "^2.0.0"
+          }
+        },
+        "pify": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+          "dev": true
+        }
+      }
+    },
+    "read-pkg-up": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz",
+      "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=",
+      "dev": true,
+      "requires": {
+        "find-up": "^2.0.0",
+        "read-pkg": "^2.0.0"
+      }
+    },
+    "readable-stream": {
+      "version": "2.3.7",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+      "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+      "requires": {
+        "core-util-is": "~1.0.0",
+        "inherits": "~2.0.3",
+        "isarray": "~1.0.0",
+        "process-nextick-args": "~2.0.0",
+        "safe-buffer": "~5.1.1",
+        "string_decoder": "~1.1.1",
+        "util-deprecate": "~1.0.1"
+      }
+    },
+    "readdirp": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
+      "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "picomatch": "^2.2.1"
+      }
+    },
+    "recast": {
+      "version": "0.11.23",
+      "resolved": "https://registry.npmjs.org/recast/-/recast-0.11.23.tgz",
+      "integrity": "sha1-RR/TAEqx5N+bTktmN2sqIZEkYtM=",
+      "dev": true,
+      "requires": {
+        "ast-types": "0.9.6",
+        "esprima": "~3.1.0",
+        "private": "~0.1.5",
+        "source-map": "~0.5.0"
+      },
+      "dependencies": {
+        "esprima": {
+          "version": "3.1.3",
+          "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz",
+          "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=",
+          "dev": true
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        }
+      }
+    },
+    "rechoir": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
+      "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
+      "dev": true,
+      "requires": {
+        "resolve": "^1.1.6"
+      }
+    },
+    "redent": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
+      "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=",
+      "requires": {
+        "indent-string": "^2.1.0",
+        "strip-indent": "^1.0.1"
+      }
+    },
+    "reduce-css-calc": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz",
+      "integrity": "sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=",
+      "dev": true,
+      "requires": {
+        "balanced-match": "^0.4.2",
+        "math-expression-evaluator": "^1.2.14",
+        "reduce-function-call": "^1.0.1"
+      },
+      "dependencies": {
+        "balanced-match": {
+          "version": "0.4.2",
+          "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz",
+          "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=",
+          "dev": true
+        }
+      }
+    },
+    "reduce-function-call": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.3.tgz",
+      "integrity": "sha512-Hl/tuV2VDgWgCSEeWMLwxLZqX7OK59eU1guxXsRKTAyeYimivsKdtcV4fu3r710tpG5GmDKDhQ0HSZLExnNmyQ==",
+      "dev": true,
+      "requires": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "regenerate": {
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
+      "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==",
+      "dev": true
+    },
+    "regenerator-runtime": {
+      "version": "0.11.1",
+      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
+      "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
+    },
+    "regenerator-transform": {
+      "version": "0.10.1",
+      "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz",
+      "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "^6.18.0",
+        "babel-types": "^6.19.0",
+        "private": "^0.1.6"
+      }
+    },
+    "regex-not": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+      "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+      "dev": true,
+      "requires": {
+        "extend-shallow": "^3.0.2",
+        "safe-regex": "^1.1.0"
+      }
+    },
+    "regexp.prototype.flags": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz",
+      "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==",
+      "dev": true,
+      "requires": {
+        "define-properties": "^1.1.3",
+        "es-abstract": "^1.17.0-next.1"
+      },
+      "dependencies": {
+        "es-abstract": {
+          "version": "1.17.7",
+          "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
+          "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
+          "dev": true,
+          "requires": {
+            "es-to-primitive": "^1.2.1",
+            "function-bind": "^1.1.1",
+            "has": "^1.0.3",
+            "has-symbols": "^1.0.1",
+            "is-callable": "^1.2.2",
+            "is-regex": "^1.1.1",
+            "object-inspect": "^1.8.0",
+            "object-keys": "^1.1.1",
+            "object.assign": "^4.1.1",
+            "string.prototype.trimend": "^1.0.1",
+            "string.prototype.trimstart": "^1.0.1"
+          }
+        }
+      }
+    },
+    "regexpp": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz",
+      "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==",
+      "dev": true
+    },
+    "regexpu-core": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz",
+      "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=",
+      "dev": true,
+      "requires": {
+        "regenerate": "^1.2.1",
+        "regjsgen": "^0.2.0",
+        "regjsparser": "^0.1.4"
+      }
+    },
+    "regjsgen": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz",
+      "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=",
+      "dev": true
+    },
+    "regjsparser": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz",
+      "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=",
+      "dev": true,
+      "requires": {
+        "jsesc": "~0.5.0"
+      },
+      "dependencies": {
+        "jsesc": {
+          "version": "0.5.0",
+          "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
+          "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
+          "dev": true
+        }
+      }
+    },
+    "relateurl": {
+      "version": "0.2.7",
+      "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
+      "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=",
+      "dev": true
+    },
+    "remove-trailing-separator": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+      "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
+      "dev": true
+    },
+    "renderkid": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.5.tgz",
+      "integrity": "sha512-ccqoLg+HLOHq1vdfYNm4TBeaCDIi1FLt3wGojTDSvdewUv65oTmI3cnT2E4hRjl1gzKZIPK+KZrXzlUYKnR+vQ==",
+      "dev": true,
+      "requires": {
+        "css-select": "^2.0.2",
+        "dom-converter": "^0.2",
+        "htmlparser2": "^3.10.1",
+        "lodash": "^4.17.20",
+        "strip-ansi": "^3.0.0"
+      }
+    },
+    "repeat-element": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
+      "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==",
+      "dev": true
+    },
+    "repeat-string": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+      "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
+      "dev": true
+    },
+    "repeating": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
+      "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
+      "requires": {
+        "is-finite": "^1.0.0"
+      }
+    },
+    "request": {
+      "version": "2.88.2",
+      "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
+      "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
+      "requires": {
+        "aws-sign2": "~0.7.0",
+        "aws4": "^1.8.0",
+        "caseless": "~0.12.0",
+        "combined-stream": "~1.0.6",
+        "extend": "~3.0.2",
+        "forever-agent": "~0.6.1",
+        "form-data": "~2.3.2",
+        "har-validator": "~5.1.3",
+        "http-signature": "~1.2.0",
+        "is-typedarray": "~1.0.0",
+        "isstream": "~0.1.2",
+        "json-stringify-safe": "~5.0.1",
+        "mime-types": "~2.1.19",
+        "oauth-sign": "~0.9.0",
+        "performance-now": "^2.1.0",
+        "qs": "~6.5.2",
+        "safe-buffer": "^5.1.2",
+        "tough-cookie": "~2.5.0",
+        "tunnel-agent": "^0.6.0",
+        "uuid": "^3.3.2"
+      },
+      "dependencies": {
+        "qs": {
+          "version": "6.5.2",
+          "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+          "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
+        }
+      }
+    },
+    "require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
+    },
+    "require-from-string": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz",
+      "integrity": "sha1-UpyczvJzgK3+yaL5ZbZJu+5jZBg=",
+      "dev": true
+    },
+    "require-main-filename": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
+      "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
+      "dev": true
+    },
+    "require-uncached": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz",
+      "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=",
+      "dev": true,
+      "requires": {
+        "caller-path": "^0.1.0",
+        "resolve-from": "^1.0.0"
+      }
+    },
+    "requires-port": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+      "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
+      "dev": true
+    },
+    "resize-observer-polyfill": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
+      "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="
+    },
+    "resolve": {
+      "version": "1.19.0",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz",
+      "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==",
+      "requires": {
+        "is-core-module": "^2.1.0",
+        "path-parse": "^1.0.6"
+      }
+    },
+    "resolve-cwd": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz",
+      "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=",
+      "dev": true,
+      "requires": {
+        "resolve-from": "^3.0.0"
+      },
+      "dependencies": {
+        "resolve-from": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
+          "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=",
+          "dev": true
+        }
+      }
+    },
+    "resolve-from": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz",
+      "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=",
+      "dev": true
+    },
+    "resolve-url": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+      "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
+      "dev": true
+    },
+    "restore-cursor": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
+      "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
+      "dev": true,
+      "requires": {
+        "onetime": "^2.0.0",
+        "signal-exit": "^3.0.2"
+      }
+    },
+    "ret": {
+      "version": "0.1.15",
+      "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+      "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
+      "dev": true
+    },
+    "rgb-regex": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz",
+      "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=",
+      "dev": true
+    },
+    "rgba-regex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz",
+      "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=",
+      "dev": true
+    },
+    "right-align": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
+      "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=",
+      "dev": true,
+      "requires": {
+        "align-text": "^0.1.1"
+      }
+    },
+    "rimraf": {
+      "version": "2.7.1",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+      "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+      "requires": {
+        "glob": "^7.1.3"
+      }
+    },
+    "ripemd160": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
+      "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
+      "dev": true,
+      "requires": {
+        "hash-base": "^3.0.0",
+        "inherits": "^2.0.1"
+      }
+    },
+    "run-async": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
+      "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
+      "dev": true
+    },
+    "run-queue": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz",
+      "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=",
+      "dev": true,
+      "requires": {
+        "aproba": "^1.1.1"
+      }
+    },
+    "rx-lite": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz",
+      "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=",
+      "dev": true
+    },
+    "rx-lite-aggregates": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz",
+      "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=",
+      "dev": true,
+      "requires": {
+        "rx-lite": "*"
+      }
+    },
+    "safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+    },
+    "safe-regex": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+      "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
+      "dev": true,
+      "requires": {
+        "ret": "~0.1.10"
+      }
+    },
+    "safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+    },
+    "sass-graph": {
+      "version": "2.2.5",
+      "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.5.tgz",
+      "integrity": "sha512-VFWDAHOe6mRuT4mZRd4eKE+d8Uedrk6Xnh7Sh9b4NGufQLQjOrvf/MQoOdx+0s92L89FeyUUNfU597j/3uNpag==",
+      "requires": {
+        "glob": "^7.0.0",
+        "lodash": "^4.0.0",
+        "scss-tokenizer": "^0.2.3",
+        "yargs": "^13.3.2"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
+        },
+        "camelcase": {
+          "version": "5.3.1",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+          "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
+        },
+        "cliui": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
+          "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
+          "requires": {
+            "string-width": "^3.1.0",
+            "strip-ansi": "^5.2.0",
+            "wrap-ansi": "^5.1.0"
+          }
+        },
+        "find-up": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+          "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+          "requires": {
+            "locate-path": "^3.0.0"
+          }
+        },
+        "get-caller-file": {
+          "version": "2.0.5",
+          "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+          "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
+        },
+        "locate-path": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+          "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+          "requires": {
+            "p-locate": "^3.0.0",
+            "path-exists": "^3.0.0"
+          }
+        },
+        "p-limit": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+          "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+          "requires": {
+            "p-try": "^2.0.0"
+          }
+        },
+        "p-locate": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+          "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+          "requires": {
+            "p-limit": "^2.0.0"
+          }
+        },
+        "p-try": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+          "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
+        },
+        "require-main-filename": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+          "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
+        },
+        "string-width": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+          "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+          "requires": {
+            "emoji-regex": "^7.0.1",
+            "is-fullwidth-code-point": "^2.0.0",
+            "strip-ansi": "^5.1.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+          "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+          "requires": {
+            "ansi-regex": "^4.1.0"
+          }
+        },
+        "wrap-ansi": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
+          "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
+          "requires": {
+            "ansi-styles": "^3.2.0",
+            "string-width": "^3.0.0",
+            "strip-ansi": "^5.0.0"
+          }
+        },
+        "yargs": {
+          "version": "13.3.2",
+          "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
+          "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
+          "requires": {
+            "cliui": "^5.0.0",
+            "find-up": "^3.0.0",
+            "get-caller-file": "^2.0.1",
+            "require-directory": "^2.1.1",
+            "require-main-filename": "^2.0.0",
+            "set-blocking": "^2.0.0",
+            "string-width": "^3.0.0",
+            "which-module": "^2.0.0",
+            "y18n": "^4.0.0",
+            "yargs-parser": "^13.1.2"
+          }
+        },
+        "yargs-parser": {
+          "version": "13.1.2",
+          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
+          "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
+          "requires": {
+            "camelcase": "^5.0.0",
+            "decamelize": "^1.2.0"
+          }
+        }
+      }
+    },
+    "sass-loader": {
+      "version": "7.3.1",
+      "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.3.1.tgz",
+      "integrity": "sha512-tuU7+zm0pTCynKYHpdqaPpe+MMTQ76I9TPZ7i4/5dZsigE350shQWe5EZNl5dBidM49TPET75tNqRbcsUZWeNA==",
+      "dev": true,
+      "requires": {
+        "clone-deep": "^4.0.1",
+        "loader-utils": "^1.0.1",
+        "neo-async": "^2.5.0",
+        "pify": "^4.0.1",
+        "semver": "^6.3.0"
+      },
+      "dependencies": {
+        "pify": {
+          "version": "4.0.1",
+          "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
+          "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
+          "dev": true
+        },
+        "semver": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+          "dev": true
+        }
+      }
+    },
+    "sax": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+      "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
+      "dev": true
+    },
+    "schema-utils": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz",
+      "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=",
+      "dev": true,
+      "requires": {
+        "ajv": "^5.0.0"
+      }
+    },
+    "scss-tokenizer": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz",
+      "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=",
+      "requires": {
+        "js-base64": "^2.1.8",
+        "source-map": "^0.4.2"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.4.4",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
+          "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
+          "requires": {
+            "amdefine": ">=0.0.4"
+          }
+        }
+      }
+    },
+    "select-hose": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
+      "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=",
+      "dev": true
+    },
+    "selfsigned": {
+      "version": "1.10.8",
+      "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.8.tgz",
+      "integrity": "sha512-2P4PtieJeEwVgTU9QEcwIRDQ/mXJLX8/+I3ur+Pg16nS8oNbrGxEso9NyYWy8NAmXiNl4dlAp5MwoNeCWzON4w==",
+      "dev": true,
+      "requires": {
+        "node-forge": "^0.10.0"
+      }
+    },
+    "semver": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+      "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
+    },
+    "send": {
+      "version": "0.17.1",
+      "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
+      "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
+      "dev": true,
+      "requires": {
+        "debug": "2.6.9",
+        "depd": "~1.1.2",
+        "destroy": "~1.0.4",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "etag": "~1.8.1",
+        "fresh": "0.5.2",
+        "http-errors": "~1.7.2",
+        "mime": "1.6.0",
+        "ms": "2.1.1",
+        "on-finished": "~2.3.0",
+        "range-parser": "~1.2.1",
+        "statuses": "~1.5.0"
+      },
+      "dependencies": {
+        "ms": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
+          "dev": true
+        }
+      }
+    },
+    "sentence-case": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-2.1.1.tgz",
+      "integrity": "sha1-H24t2jnBaL+S0T+G1KkYkz9mftQ=",
+      "dev": true,
+      "requires": {
+        "no-case": "^2.2.0",
+        "upper-case-first": "^1.1.2"
+      }
+    },
+    "serialize-javascript": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.9.1.tgz",
+      "integrity": "sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A==",
+      "dev": true
+    },
+    "serve-index": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
+      "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=",
+      "dev": true,
+      "requires": {
+        "accepts": "~1.3.4",
+        "batch": "0.6.1",
+        "debug": "2.6.9",
+        "escape-html": "~1.0.3",
+        "http-errors": "~1.6.2",
+        "mime-types": "~2.1.17",
+        "parseurl": "~1.3.2"
+      },
+      "dependencies": {
+        "http-errors": {
+          "version": "1.6.3",
+          "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
+          "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
+          "dev": true,
+          "requires": {
+            "depd": "~1.1.2",
+            "inherits": "2.0.3",
+            "setprototypeof": "1.1.0",
+            "statuses": ">= 1.4.0 < 2"
+          }
+        },
+        "inherits": {
+          "version": "2.0.3",
+          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+          "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+          "dev": true
+        },
+        "setprototypeof": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
+          "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==",
+          "dev": true
+        }
+      }
+    },
+    "serve-static": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
+      "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
+      "dev": true,
+      "requires": {
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "parseurl": "~1.3.3",
+        "send": "0.17.1"
+      }
+    },
+    "set-blocking": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+      "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
+    },
+    "set-value": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
+      "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
+      "dev": true,
+      "requires": {
+        "extend-shallow": "^2.0.1",
+        "is-extendable": "^0.1.1",
+        "is-plain-object": "^2.0.3",
+        "split-string": "^3.0.1"
+      },
+      "dependencies": {
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        }
+      }
+    },
+    "setimmediate": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+      "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=",
+      "dev": true
+    },
+    "setprototypeof": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
+      "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==",
+      "dev": true
+    },
+    "sha.js": {
+      "version": "2.4.11",
+      "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
+      "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.1",
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "shallow-clone": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
+      "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==",
+      "dev": true,
+      "requires": {
+        "kind-of": "^6.0.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+          "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+          "dev": true
+        }
+      }
+    },
+    "shebang-command": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+      "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+      "dev": true,
+      "requires": {
+        "shebang-regex": "^1.0.0"
+      }
+    },
+    "shebang-regex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+      "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
+      "dev": true
+    },
+    "shelljs": {
+      "version": "0.7.8",
+      "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz",
+      "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=",
+      "dev": true,
+      "requires": {
+        "glob": "^7.0.0",
+        "interpret": "^1.0.0",
+        "rechoir": "^0.6.2"
+      }
+    },
+    "shellwords": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz",
+      "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==",
+      "dev": true
+    },
+    "signal-exit": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
+      "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA=="
+    },
+    "simple-swizzle": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
+      "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=",
+      "dev": true,
+      "requires": {
+        "is-arrayish": "^0.3.1"
+      },
+      "dependencies": {
+        "is-arrayish": {
+          "version": "0.3.2",
+          "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
+          "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
+          "dev": true
+        }
+      }
+    },
+    "slash": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
+      "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=",
+      "dev": true
+    },
+    "slice-ansi": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz",
+      "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==",
+      "dev": true,
+      "requires": {
+        "is-fullwidth-code-point": "^2.0.0"
+      }
+    },
+    "snake-case": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-2.1.0.tgz",
+      "integrity": "sha1-Qb2xtz8w7GagTU4srRt2OH1NbZ8=",
+      "dev": true,
+      "requires": {
+        "no-case": "^2.2.0"
+      }
+    },
+    "snapdragon": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+      "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+      "dev": true,
+      "requires": {
+        "base": "^0.11.1",
+        "debug": "^2.2.0",
+        "define-property": "^0.2.5",
+        "extend-shallow": "^2.0.1",
+        "map-cache": "^0.2.2",
+        "source-map": "^0.5.6",
+        "source-map-resolve": "^0.5.0",
+        "use": "^3.1.0"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        },
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        }
+      }
+    },
+    "snapdragon-node": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+      "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+      "dev": true,
+      "requires": {
+        "define-property": "^1.0.0",
+        "isobject": "^3.0.0",
+        "snapdragon-util": "^3.0.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^1.0.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        },
+        "kind-of": {
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+          "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+          "dev": true
+        }
+      }
+    },
+    "snapdragon-util": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+      "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.2.0"
+      }
+    },
+    "sockjs": {
+      "version": "0.3.19",
+      "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz",
+      "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==",
+      "dev": true,
+      "requires": {
+        "faye-websocket": "^0.10.0",
+        "uuid": "^3.0.1"
+      }
+    },
+    "sockjs-client": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.1.5.tgz",
+      "integrity": "sha1-G7fA9yIsQPQq3xT0RCy9Eml3GoM=",
+      "dev": true,
+      "requires": {
+        "debug": "^2.6.6",
+        "eventsource": "0.1.6",
+        "faye-websocket": "~0.11.0",
+        "inherits": "^2.0.1",
+        "json3": "^3.3.2",
+        "url-parse": "^1.1.8"
+      },
+      "dependencies": {
+        "faye-websocket": {
+          "version": "0.11.3",
+          "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz",
+          "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==",
+          "dev": true,
+          "requires": {
+            "websocket-driver": ">=0.5.1"
+          }
+        }
+      }
+    },
+    "sort-keys": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
+      "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=",
+      "dev": true,
+      "requires": {
+        "is-plain-obj": "^1.0.0"
+      }
+    },
+    "sortablejs": {
+      "version": "1.10.2",
+      "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.10.2.tgz",
+      "integrity": "sha512-YkPGufevysvfwn5rfdlGyrGjt7/CRHwvRPogD/lC+TnvcN29jDpCifKP+rBqf+LRldfXSTh+0CGLcSg0VIxq3A=="
+    },
+    "source-list-map": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
+      "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==",
+      "dev": true
+    },
+    "source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true
+    },
+    "source-map-resolve": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
+      "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
+      "dev": true,
+      "requires": {
+        "atob": "^2.1.2",
+        "decode-uri-component": "^0.2.0",
+        "resolve-url": "^0.2.1",
+        "source-map-url": "^0.4.0",
+        "urix": "^0.1.0"
+      }
+    },
+    "source-map-support": {
+      "version": "0.4.18",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
+      "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==",
+      "dev": true,
+      "requires": {
+        "source-map": "^0.5.6"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        }
+      }
+    },
+    "source-map-url": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
+      "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
+      "dev": true
+    },
+    "spdx-correct": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
+      "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
+      "requires": {
+        "spdx-expression-parse": "^3.0.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "spdx-exceptions": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
+      "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A=="
+    },
+    "spdx-expression-parse": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
+      "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
+      "requires": {
+        "spdx-exceptions": "^2.1.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "spdx-license-ids": {
+      "version": "3.0.7",
+      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz",
+      "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ=="
+    },
+    "spdy": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz",
+      "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==",
+      "dev": true,
+      "requires": {
+        "debug": "^4.1.0",
+        "handle-thing": "^2.0.0",
+        "http-deceiver": "^1.2.7",
+        "select-hose": "^2.0.0",
+        "spdy-transport": "^3.0.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "4.3.1",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+          "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+          "dev": true,
+          "requires": {
+            "ms": "2.1.2"
+          }
+        },
+        "ms": {
+          "version": "2.1.2",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+          "dev": true
+        }
+      }
+    },
+    "spdy-transport": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz",
+      "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==",
+      "dev": true,
+      "requires": {
+        "debug": "^4.1.0",
+        "detect-node": "^2.0.4",
+        "hpack.js": "^2.1.6",
+        "obuf": "^1.1.2",
+        "readable-stream": "^3.0.6",
+        "wbuf": "^1.7.3"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "4.3.1",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+          "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+          "dev": true,
+          "requires": {
+            "ms": "2.1.2"
+          }
+        },
+        "ms": {
+          "version": "2.1.2",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+          "dev": true,
+          "requires": {
+            "inherits": "^2.0.3",
+            "string_decoder": "^1.1.1",
+            "util-deprecate": "^1.0.1"
+          }
+        }
+      }
+    },
+    "split-string": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+      "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+      "dev": true,
+      "requires": {
+        "extend-shallow": "^3.0.0"
+      }
+    },
+    "sprintf-js": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
+    },
+    "ssf": {
+      "version": "0.10.3",
+      "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.10.3.tgz",
+      "integrity": "sha512-pRuUdW0WwyB2doSqqjWyzwCD6PkfxpHAHdZp39K3dp/Hq7f+xfMwNAWIi16DyrRg4gg9c/RvLYkJTSawTPTm1w==",
+      "requires": {
+        "frac": "~1.1.2"
+      }
+    },
+    "sshpk": {
+      "version": "1.16.1",
+      "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
+      "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
+      "requires": {
+        "asn1": "~0.2.3",
+        "assert-plus": "^1.0.0",
+        "bcrypt-pbkdf": "^1.0.0",
+        "dashdash": "^1.12.0",
+        "ecc-jsbn": "~0.1.1",
+        "getpass": "^0.1.1",
+        "jsbn": "~0.1.0",
+        "safer-buffer": "^2.0.2",
+        "tweetnacl": "~0.14.0"
+      }
+    },
+    "ssri": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.3.0.tgz",
+      "integrity": "sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "^5.1.1"
+      }
+    },
+    "stable": {
+      "version": "0.1.8",
+      "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
+      "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==",
+      "dev": true
+    },
+    "stackframe": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz",
+      "integrity": "sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA==",
+      "dev": true
+    },
+    "static-extend": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+      "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
+      "dev": true,
+      "requires": {
+        "define-property": "^0.2.5",
+        "object-copy": "^0.1.0"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        }
+      }
+    },
+    "statuses": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+      "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
+      "dev": true
+    },
+    "stdout-stream": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz",
+      "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==",
+      "requires": {
+        "readable-stream": "^2.0.1"
+      }
+    },
+    "stream-browserify": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz",
+      "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==",
+      "dev": true,
+      "requires": {
+        "inherits": "~2.0.1",
+        "readable-stream": "^2.0.2"
+      }
+    },
+    "stream-each": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz",
+      "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==",
+      "dev": true,
+      "requires": {
+        "end-of-stream": "^1.1.0",
+        "stream-shift": "^1.0.0"
+      }
+    },
+    "stream-http": {
+      "version": "2.8.3",
+      "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz",
+      "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==",
+      "dev": true,
+      "requires": {
+        "builtin-status-codes": "^3.0.0",
+        "inherits": "^2.0.1",
+        "readable-stream": "^2.3.6",
+        "to-arraybuffer": "^1.0.0",
+        "xtend": "^4.0.0"
+      }
+    },
+    "stream-shift": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz",
+      "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==",
+      "dev": true
+    },
+    "strict-uri-encode": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
+      "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=",
+      "dev": true
+    },
+    "string-width": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+      "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+      "requires": {
+        "is-fullwidth-code-point": "^2.0.0",
+        "strip-ansi": "^4.0.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
+        },
+        "strip-ansi": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+          "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+          "requires": {
+            "ansi-regex": "^3.0.0"
+          }
+        }
+      }
+    },
+    "string.prototype.trimend": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz",
+      "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.0",
+        "define-properties": "^1.1.3"
+      }
+    },
+    "string.prototype.trimstart": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz",
+      "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.0",
+        "define-properties": "^1.1.3"
+      }
+    },
+    "string_decoder": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "requires": {
+        "safe-buffer": "~5.1.0"
+      }
+    },
+    "strip-ansi": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+      "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+      "requires": {
+        "ansi-regex": "^2.0.0"
+      }
+    },
+    "strip-bom": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+      "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
+      "dev": true
+    },
+    "strip-eof": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
+      "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
+      "dev": true
+    },
+    "strip-indent": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
+      "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=",
+      "requires": {
+        "get-stdin": "^4.0.1"
+      }
+    },
+    "strip-json-comments": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+      "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
+      "dev": true
+    },
+    "stylehacks": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz",
+      "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==",
+      "dev": true,
+      "requires": {
+        "browserslist": "^4.0.0",
+        "postcss": "^7.0.0",
+        "postcss-selector-parser": "^3.0.0"
+      },
+      "dependencies": {
+        "browserslist": {
+          "version": "4.16.1",
+          "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.1.tgz",
+          "integrity": "sha512-UXhDrwqsNcpTYJBTZsbGATDxZbiVDsx6UjpmRUmtnP10pr8wAYr5LgFoEFw9ixriQH2mv/NX2SfGzE/o8GndLA==",
+          "dev": true,
+          "requires": {
+            "caniuse-lite": "^1.0.30001173",
+            "colorette": "^1.2.1",
+            "electron-to-chromium": "^1.3.634",
+            "escalade": "^3.1.1",
+            "node-releases": "^1.1.69"
+          }
+        },
+        "postcss": {
+          "version": "7.0.35",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz",
+          "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^2.4.2",
+            "source-map": "^0.6.1",
+            "supports-color": "^6.1.0"
+          }
+        },
+        "postcss-selector-parser": {
+          "version": "3.1.2",
+          "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz",
+          "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==",
+          "dev": true,
+          "requires": {
+            "dot-prop": "^5.2.0",
+            "indexes-of": "^1.0.1",
+            "uniq": "^1.0.1"
+          }
+        },
+        "supports-color": {
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+          "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
+      }
+    },
+    "supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dev": true,
+      "requires": {
+        "has-flag": "^3.0.0"
+      }
+    },
+    "svgo": {
+      "version": "0.7.2",
+      "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.2.tgz",
+      "integrity": "sha1-n1dyQTlSE1xv779Ar+ak+qiLS7U=",
+      "dev": true,
+      "requires": {
+        "coa": "~1.0.1",
+        "colors": "~1.1.2",
+        "csso": "~2.3.1",
+        "js-yaml": "~3.7.0",
+        "mkdirp": "~0.5.1",
+        "sax": "~1.2.1",
+        "whet.extend": "~0.9.9"
+      }
+    },
+    "swap-case": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/swap-case/-/swap-case-1.1.2.tgz",
+      "integrity": "sha1-w5IDpFhzhfrTyFCgvRvK+ggZdOM=",
+      "dev": true,
+      "requires": {
+        "lower-case": "^1.1.1",
+        "upper-case": "^1.1.1"
+      }
+    },
+    "table": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz",
+      "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==",
+      "dev": true,
+      "requires": {
+        "ajv": "^5.2.3",
+        "ajv-keywords": "^2.1.0",
+        "chalk": "^2.1.0",
+        "lodash": "^4.17.4",
+        "slice-ansi": "1.0.0",
+        "string-width": "^2.1.1"
+      }
+    },
+    "tapable": {
+      "version": "0.2.9",
+      "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.9.tgz",
+      "integrity": "sha512-2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A==",
+      "dev": true
+    },
+    "tar": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz",
+      "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==",
+      "requires": {
+        "block-stream": "*",
+        "fstream": "^1.0.12",
+        "inherits": "2"
+      }
+    },
+    "text-table": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+      "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+      "dev": true
+    },
+    "throttle-debounce": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-1.1.0.tgz",
+      "integrity": "sha512-XH8UiPCQcWNuk2LYePibW/4qL97+ZQ1AN3FNXwZRBNPPowo/NRU5fAlDCSNBJIYCKbioZfuYtMhG4quqoJhVzg=="
+    },
+    "through": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+      "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
+      "dev": true
+    },
+    "through2": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
+      "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
+      "dev": true,
+      "requires": {
+        "readable-stream": "~2.3.6",
+        "xtend": "~4.0.1"
+      }
+    },
+    "thunky": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz",
+      "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==",
+      "dev": true
+    },
+    "time-stamp": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-2.2.0.tgz",
+      "integrity": "sha512-zxke8goJQpBeEgD82CXABeMh0LSJcj7CXEd0OHOg45HgcofF7pxNwZm9+RknpxpDhwN4gFpySkApKfFYfRQnUA==",
+      "dev": true
+    },
+    "timers-browserify": {
+      "version": "2.0.12",
+      "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz",
+      "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==",
+      "dev": true,
+      "requires": {
+        "setimmediate": "^1.0.4"
+      }
+    },
+    "timsort": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
+      "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=",
+      "dev": true
+    },
+    "title-case": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/title-case/-/title-case-2.1.1.tgz",
+      "integrity": "sha1-PhJyFtpY0rxb7PE3q5Ha46fNj6o=",
+      "dev": true,
+      "requires": {
+        "no-case": "^2.2.0",
+        "upper-case": "^1.0.3"
+      }
+    },
+    "tmp": {
+      "version": "0.0.33",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+      "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+      "dev": true,
+      "requires": {
+        "os-tmpdir": "~1.0.2"
+      }
+    },
+    "to-arraybuffer": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
+      "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=",
+      "dev": true
+    },
+    "to-fast-properties": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
+      "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=",
+      "dev": true
+    },
+    "to-object-path": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+      "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.0.2"
+      }
+    },
+    "to-regex": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+      "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+      "dev": true,
+      "requires": {
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "regex-not": "^1.0.2",
+        "safe-regex": "^1.1.0"
+      }
+    },
+    "to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "is-number": "^7.0.0"
+      }
+    },
+    "toidentifier": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
+      "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
+      "dev": true
+    },
+    "toposort": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.7.tgz",
+      "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=",
+      "dev": true
+    },
+    "tough-cookie": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
+      "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
+      "requires": {
+        "psl": "^1.1.28",
+        "punycode": "^2.1.1"
+      }
+    },
+    "trim-newlines": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
+      "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM="
+    },
+    "trim-right": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
+      "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
+      "dev": true
+    },
+    "true-case-path": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz",
+      "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==",
+      "requires": {
+        "glob": "^7.1.2"
+      }
+    },
+    "tryer": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz",
+      "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==",
+      "dev": true
+    },
+    "tsconfig-paths": {
+      "version": "3.9.0",
+      "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz",
+      "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==",
+      "dev": true,
+      "requires": {
+        "@types/json5": "^0.0.29",
+        "json5": "^1.0.1",
+        "minimist": "^1.2.0",
+        "strip-bom": "^3.0.0"
+      },
+      "dependencies": {
+        "json5": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
+          "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
+          "dev": true,
+          "requires": {
+            "minimist": "^1.2.0"
+          }
+        }
+      }
+    },
+    "tslib": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+      "dev": true
+    },
+    "tty-browserify": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
+      "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=",
+      "dev": true
+    },
+    "tunnel-agent": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+      "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+      "requires": {
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "tweetnacl": {
+      "version": "0.14.5",
+      "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+      "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
+    },
+    "type": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
+      "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==",
+      "dev": true
+    },
+    "type-check": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+      "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+      "dev": true,
+      "requires": {
+        "prelude-ls": "~1.1.2"
+      }
+    },
+    "type-is": {
+      "version": "1.6.18",
+      "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+      "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+      "dev": true,
+      "requires": {
+        "media-typer": "0.3.0",
+        "mime-types": "~2.1.24"
+      }
+    },
+    "typedarray": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+      "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
+      "dev": true
+    },
+    "uc.micro": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
+      "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
+    },
+    "uglify-js": {
+      "version": "3.4.10",
+      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz",
+      "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==",
+      "dev": true,
+      "requires": {
+        "commander": "~2.19.0",
+        "source-map": "~0.6.1"
+      },
+      "dependencies": {
+        "commander": {
+          "version": "2.19.0",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz",
+          "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==",
+          "dev": true
+        }
+      }
+    },
+    "uglify-to-browserify": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
+      "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=",
+      "dev": true
+    },
+    "uglifyjs-webpack-plugin": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.3.0.tgz",
+      "integrity": "sha512-ovHIch0AMlxjD/97j9AYovZxG5wnHOPkL7T1GKochBADp/Zwc44pEWNqpKl1Loupp1WhFg7SlYmHZRUfdAacgw==",
+      "dev": true,
+      "requires": {
+        "cacache": "^10.0.4",
+        "find-cache-dir": "^1.0.0",
+        "schema-utils": "^0.4.5",
+        "serialize-javascript": "^1.4.0",
+        "source-map": "^0.6.1",
+        "uglify-es": "^3.3.4",
+        "webpack-sources": "^1.1.0",
+        "worker-farm": "^1.5.2"
+      },
+      "dependencies": {
+        "ajv": {
+          "version": "6.12.6",
+          "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+          "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+          "dev": true,
+          "requires": {
+            "fast-deep-equal": "^3.1.1",
+            "fast-json-stable-stringify": "^2.0.0",
+            "json-schema-traverse": "^0.4.1",
+            "uri-js": "^4.2.2"
+          }
+        },
+        "ajv-keywords": {
+          "version": "3.5.2",
+          "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
+          "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
+          "dev": true
+        },
+        "commander": {
+          "version": "2.13.0",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz",
+          "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==",
+          "dev": true
+        },
+        "fast-deep-equal": {
+          "version": "3.1.3",
+          "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+          "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+          "dev": true
+        },
+        "json-schema-traverse": {
+          "version": "0.4.1",
+          "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+          "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+          "dev": true
+        },
+        "schema-utils": {
+          "version": "0.4.7",
+          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz",
+          "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==",
+          "dev": true,
+          "requires": {
+            "ajv": "^6.1.0",
+            "ajv-keywords": "^3.1.0"
+          }
+        },
+        "uglify-es": {
+          "version": "3.3.9",
+          "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz",
+          "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==",
+          "dev": true,
+          "requires": {
+            "commander": "~2.13.0",
+            "source-map": "~0.6.1"
+          }
+        }
+      }
+    },
+    "union-value": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+      "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
+      "dev": true,
+      "requires": {
+        "arr-union": "^3.1.0",
+        "get-value": "^2.0.6",
+        "is-extendable": "^0.1.1",
+        "set-value": "^2.0.1"
+      }
+    },
+    "uniq": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
+      "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=",
+      "dev": true
+    },
+    "uniqs": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz",
+      "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=",
+      "dev": true
+    },
+    "unique-filename": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",
+      "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==",
+      "dev": true,
+      "requires": {
+        "unique-slug": "^2.0.0"
+      }
+    },
+    "unique-slug": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz",
+      "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==",
+      "dev": true,
+      "requires": {
+        "imurmurhash": "^0.1.4"
+      }
+    },
+    "unpipe": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+      "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
+      "dev": true
+    },
+    "unquote": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz",
+      "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=",
+      "dev": true
+    },
+    "unset-value": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+      "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
+      "dev": true,
+      "requires": {
+        "has-value": "^0.3.1",
+        "isobject": "^3.0.0"
+      },
+      "dependencies": {
+        "has-value": {
+          "version": "0.3.1",
+          "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+          "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
+          "dev": true,
+          "requires": {
+            "get-value": "^2.0.3",
+            "has-values": "^0.1.4",
+            "isobject": "^2.0.0"
+          },
+          "dependencies": {
+            "isobject": {
+              "version": "2.1.0",
+              "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+              "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+              "dev": true,
+              "requires": {
+                "isarray": "1.0.0"
+              }
+            }
+          }
+        },
+        "has-values": {
+          "version": "0.1.4",
+          "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+          "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=",
+          "dev": true
+        }
+      }
+    },
+    "upath": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
+      "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==",
+      "dev": true
+    },
+    "upper-case": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz",
+      "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=",
+      "dev": true
+    },
+    "upper-case-first": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-1.1.2.tgz",
+      "integrity": "sha1-XXm+3P8UQZUY/S7bCgUHybaFkRU=",
+      "dev": true,
+      "requires": {
+        "upper-case": "^1.1.1"
+      }
+    },
+    "uri-js": {
+      "version": "4.4.1",
+      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+      "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+      "requires": {
+        "punycode": "^2.1.0"
+      }
+    },
+    "urix": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+      "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
+      "dev": true
+    },
+    "url": {
+      "version": "0.11.0",
+      "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
+      "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
+      "dev": true,
+      "requires": {
+        "punycode": "1.3.2",
+        "querystring": "0.2.0"
+      },
+      "dependencies": {
+        "punycode": {
+          "version": "1.3.2",
+          "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
+          "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=",
+          "dev": true
+        }
+      }
+    },
+    "url-loader": {
+      "version": "0.5.9",
+      "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-0.5.9.tgz",
+      "integrity": "sha512-B7QYFyvv+fOBqBVeefsxv6koWWtjmHaMFT6KZWti4KRw8YUD/hOU+3AECvXuzyVawIBx3z7zQRejXCDSO5kk1Q==",
+      "dev": true,
+      "requires": {
+        "loader-utils": "^1.0.2",
+        "mime": "1.3.x"
+      },
+      "dependencies": {
+        "mime": {
+          "version": "1.3.6",
+          "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.6.tgz",
+          "integrity": "sha1-WR2E02U6awtKO5343lqoEI5y5eA=",
+          "dev": true
+        }
+      }
+    },
+    "url-parse": {
+      "version": "1.4.7",
+      "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz",
+      "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==",
+      "dev": true,
+      "requires": {
+        "querystringify": "^2.1.1",
+        "requires-port": "^1.0.0"
+      }
+    },
+    "use": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+      "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
+      "dev": true
+    },
+    "util": {
+      "version": "0.11.1",
+      "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
+      "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==",
+      "dev": true,
+      "requires": {
+        "inherits": "2.0.3"
+      },
+      "dependencies": {
+        "inherits": {
+          "version": "2.0.3",
+          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+          "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+          "dev": true
+        }
+      }
+    },
+    "util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+    },
+    "util.promisify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz",
+      "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==",
+      "dev": true,
+      "requires": {
+        "define-properties": "^1.1.3",
+        "es-abstract": "^1.17.2",
+        "has-symbols": "^1.0.1",
+        "object.getownpropertydescriptors": "^2.1.0"
+      },
+      "dependencies": {
+        "es-abstract": {
+          "version": "1.17.7",
+          "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
+          "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
+          "dev": true,
+          "requires": {
+            "es-to-primitive": "^1.2.1",
+            "function-bind": "^1.1.1",
+            "has": "^1.0.3",
+            "has-symbols": "^1.0.1",
+            "is-callable": "^1.2.2",
+            "is-regex": "^1.1.1",
+            "object-inspect": "^1.8.0",
+            "object-keys": "^1.1.1",
+            "object.assign": "^4.1.1",
+            "string.prototype.trimend": "^1.0.1",
+            "string.prototype.trimstart": "^1.0.1"
+          }
+        }
+      }
+    },
+    "utila": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz",
+      "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=",
+      "dev": true
+    },
+    "utils-merge": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+      "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
+      "dev": true
+    },
+    "uuid": {
+      "version": "3.4.0",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
+      "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
+    },
+    "v-distpicker": {
+      "version": "1.2.9",
+      "resolved": "https://registry.npmjs.org/v-distpicker/-/v-distpicker-1.2.9.tgz",
+      "integrity": "sha512-3tXove1dRSK35ipvuZ/HBVrQhQ3XPh+KSVsgc9Y+QsIBV2bTGol+hklhoYyVcgvSCuTrhPQ8XGWUHPQshHzGUA==",
+      "requires": {
+        "vue": "^2.6.10"
+      }
+    },
+    "validate-npm-package-license": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+      "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+      "requires": {
+        "spdx-correct": "^3.0.0",
+        "spdx-expression-parse": "^3.0.0"
+      }
+    },
+    "vary": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+      "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
+      "dev": true
+    },
+    "vendors": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz",
+      "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==",
+      "dev": true
+    },
+    "verror": {
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+      "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+      "requires": {
+        "assert-plus": "^1.0.0",
+        "core-util-is": "1.0.2",
+        "extsprintf": "^1.2.0"
+      }
+    },
+    "vm-browserify": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
+      "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==",
+      "dev": true
+    },
+    "vue": {
+      "version": "2.6.12",
+      "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.12.tgz",
+      "integrity": "sha512-uhmLFETqPPNyuLLbsKz6ioJ4q7AZHzD8ZVFNATNyICSZouqP2Sz0rotWQC8UNBF6VGSCs5abnKJoStA6JbCbfg=="
+    },
+    "vue-baidu-map": {
+      "version": "0.21.22",
+      "resolved": "https://registry.npmjs.org/vue-baidu-map/-/vue-baidu-map-0.21.22.tgz",
+      "integrity": "sha512-WQMPCih4UTh0AZCKKH/OVOYnyAWjfRNeK6BIeoLmscyY5aF8zzlJhz/NOHLb3mdztIpB0Z6aohn4Jd9mfCSjQw==",
+      "requires": {
+        "bmaplib.curveline": "^1.0.0",
+        "bmaplib.heatmap": "^1.0.4",
+        "bmaplib.lushu": "^1.0.7",
+        "bmaplib.markerclusterer": "^1.0.13",
+        "markdown-it": "^8.4.0"
+      }
+    },
+    "vue-bus": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/vue-bus/-/vue-bus-1.2.1.tgz",
+      "integrity": "sha512-uCSJEWFWoDZz+GV/Pj/wXAC7WVBLD18V62l+2ezd4UCsZWZB27Hz3K0M9WUcbNum/yKBoN+OkOCIrU6A9xqWhw=="
+    },
+    "vue-calendar-component": {
+      "version": "2.8.2",
+      "resolved": "https://registry.npmjs.org/vue-calendar-component/-/vue-calendar-component-2.8.2.tgz",
+      "integrity": "sha512-BJh7xOBzM7QVcapcN4EbPQ1eZ8Pii1/oy+dzqjZTilRSIDD7SRPdFpnUJwZvs8lCrhtBAyJbYFsdm2SogXWHVQ=="
+    },
+    "vue-eslint-parser": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-2.0.3.tgz",
+      "integrity": "sha512-ZezcU71Owm84xVF6gfurBQUGg8WQ+WZGxgDEQu1IHFBZNx7BFZg3L1yHxrCBNNwbwFtE1GuvfJKMtb6Xuwc/Bw==",
+      "dev": true,
+      "requires": {
+        "debug": "^3.1.0",
+        "eslint-scope": "^3.7.1",
+        "eslint-visitor-keys": "^1.0.0",
+        "espree": "^3.5.2",
+        "esquery": "^1.0.0",
+        "lodash": "^4.17.4"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "3.2.7",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+          "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+          "dev": true,
+          "requires": {
+            "ms": "^2.1.1"
+          }
+        },
+        "ms": {
+          "version": "2.1.3",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+          "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+          "dev": true
+        }
+      }
+    },
+    "vue-fullcalendar": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/vue-fullcalendar/-/vue-fullcalendar-1.0.9.tgz",
+      "integrity": "sha1-qFO7JZRiUid1M7mZTvUDz6ywEjM=",
+      "requires": {
+        "es6-promise": "^4.0.5",
+        "vue": "^2.1.8",
+        "vue-fullcalendar": "^1.0.5"
+      }
+    },
+    "vue-hot-reload-api": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-1.3.2.tgz",
+      "integrity": "sha1-1kTWdMGVSuHlFooaSvmkhSOQnWA=",
+      "dev": true
+    },
+    "vue-html-loader": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/vue-html-loader/-/vue-html-loader-1.2.4.tgz",
+      "integrity": "sha1-VM5Im+BgZckdwqEXMSLz4ATgolM=",
+      "dev": true,
+      "requires": {
+        "es6-templates": "^0.2.2",
+        "fastparse": "^1.0.0",
+        "html-minifier": "^2.1.5",
+        "loader-utils": "^1.0.2",
+        "object-assign": "^4.1.0"
+      },
+      "dependencies": {
+        "async": {
+          "version": "0.2.10",
+          "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz",
+          "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=",
+          "dev": true
+        },
+        "clean-css": {
+          "version": "3.4.28",
+          "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz",
+          "integrity": "sha1-vxlF6C/ICPVWlebd6uwBQA79A/8=",
+          "dev": true,
+          "requires": {
+            "commander": "2.8.x",
+            "source-map": "0.4.x"
+          },
+          "dependencies": {
+            "commander": {
+              "version": "2.8.1",
+              "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
+              "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=",
+              "dev": true,
+              "requires": {
+                "graceful-readlink": ">= 1.0.0"
+              }
+            }
+          }
+        },
+        "commander": {
+          "version": "2.9.0",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
+          "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=",
+          "dev": true,
+          "requires": {
+            "graceful-readlink": ">= 1.0.0"
+          }
+        },
+        "he": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
+          "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=",
+          "dev": true
+        },
+        "html-minifier": {
+          "version": "2.1.7",
+          "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-2.1.7.tgz",
+          "integrity": "sha1-kFHW/LvPIU7TB+GtdPQyu5rWVcw=",
+          "dev": true,
+          "requires": {
+            "change-case": "3.0.x",
+            "clean-css": "3.4.x",
+            "commander": "2.9.x",
+            "he": "1.1.x",
+            "ncname": "1.0.x",
+            "relateurl": "0.2.x",
+            "uglify-js": "2.6.x"
+          }
+        },
+        "source-map": {
+          "version": "0.4.4",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
+          "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
+          "dev": true,
+          "requires": {
+            "amdefine": ">=0.0.4"
+          }
+        },
+        "uglify-js": {
+          "version": "2.6.4",
+          "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.6.4.tgz",
+          "integrity": "sha1-ZeovswWck5RpLxX+2HwrNsFrmt8=",
+          "dev": true,
+          "requires": {
+            "async": "~0.2.6",
+            "source-map": "~0.5.1",
+            "uglify-to-browserify": "~1.0.0",
+            "yargs": "~3.10.0"
+          },
+          "dependencies": {
+            "source-map": {
+              "version": "0.5.7",
+              "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+              "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+              "dev": true
+            }
+          }
+        },
+        "yargs": {
+          "version": "3.10.0",
+          "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
+          "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
+          "dev": true,
+          "requires": {
+            "camelcase": "^1.0.2",
+            "cliui": "^2.1.0",
+            "decamelize": "^1.0.0",
+            "window-size": "0.1.0"
+          }
+        }
+      }
+    },
+    "vue-lazyload": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/vue-lazyload/-/vue-lazyload-1.3.3.tgz",
+      "integrity": "sha512-uHnq0FTEeNmqnbBC2aRKlmtd9LofMZ6Q3mWvgfLa+i9vhxU8fDK+nGs9c1iVT85axSua/AUnMttIq3xPaU9G3A=="
+    },
+    "vue-loader": {
+      "version": "13.7.3",
+      "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-13.7.3.tgz",
+      "integrity": "sha512-ACCwbfeC6HjY2pnDii+Zer+MZ6sdOtwvLmDXRK/BoD3WNR551V22R6KEagwHoTRJ0ZlIhpCBkptpCU6+Ri/05w==",
+      "dev": true,
+      "requires": {
+        "consolidate": "^0.14.0",
+        "hash-sum": "^1.0.2",
+        "loader-utils": "^1.1.0",
+        "lru-cache": "^4.1.1",
+        "postcss": "^6.0.8",
+        "postcss-load-config": "^1.1.0",
+        "postcss-selector-parser": "^2.0.0",
+        "prettier": "^1.7.0",
+        "resolve": "^1.4.0",
+        "source-map": "^0.6.1",
+        "vue-hot-reload-api": "^2.2.0",
+        "vue-style-loader": "^3.0.0",
+        "vue-template-es2015-compiler": "^1.6.0"
+      },
+      "dependencies": {
+        "cosmiconfig": {
+          "version": "2.2.2",
+          "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz",
+          "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==",
+          "dev": true,
+          "requires": {
+            "is-directory": "^0.3.1",
+            "js-yaml": "^3.4.3",
+            "minimist": "^1.2.0",
+            "object-assign": "^4.1.0",
+            "os-homedir": "^1.0.1",
+            "parse-json": "^2.2.0",
+            "require-from-string": "^1.1.0"
+          }
+        },
+        "postcss-load-config": {
+          "version": "1.2.0",
+          "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-1.2.0.tgz",
+          "integrity": "sha1-U56a/J3chiASHr+djDZz4M5Q0oo=",
+          "dev": true,
+          "requires": {
+            "cosmiconfig": "^2.1.0",
+            "object-assign": "^4.1.0",
+            "postcss-load-options": "^1.2.0",
+            "postcss-load-plugins": "^2.3.0"
+          }
+        },
+        "vue-hot-reload-api": {
+          "version": "2.3.4",
+          "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz",
+          "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==",
+          "dev": true
+        }
+      }
+    },
+    "vue-moment": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/vue-moment/-/vue-moment-4.1.0.tgz",
+      "integrity": "sha512-Gzisqpg82ItlrUyiD9d0Kfru+JorW2o4mQOH06lEDZNgxci0tv/fua1Hl0bo4DozDV2JK1r52Atn/8QVCu8qQw==",
+      "requires": {
+        "moment": "^2.19.2"
+      }
+    },
+    "vue-router": {
+      "version": "3.4.9",
+      "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.4.9.tgz",
+      "integrity": "sha512-CGAKWN44RqXW06oC+u4mPgHLQQi2t6vLD/JbGRDAXm0YpMv0bgpKuU5bBd7AvMgfTz9kXVRIWKHqRwGEb8xFkA=="
+    },
+    "vue-style-loader": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-3.1.2.tgz",
+      "integrity": "sha512-ICtVdK/p+qXWpdSs2alWtsXt9YnDoYjQe0w5616j9+/EhjoxZkbun34uWgsMFnC1MhrMMwaWiImz3K2jK1Yp2Q==",
+      "dev": true,
+      "requires": {
+        "hash-sum": "^1.0.2",
+        "loader-utils": "^1.0.2"
+      }
+    },
+    "vue-template-compiler": {
+      "version": "2.6.12",
+      "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.12.tgz",
+      "integrity": "sha512-OzzZ52zS41YUbkCBfdXShQTe69j1gQDZ9HIX8miuC9C3rBCk9wIRjLiZZLrmX9V+Ftq/YEyv1JaVr5Y/hNtByg==",
+      "dev": true,
+      "requires": {
+        "de-indent": "^1.0.2",
+        "he": "^1.1.0"
+      }
+    },
+    "vue-template-es2015-compiler": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz",
+      "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==",
+      "dev": true
+    },
+    "vuedraggable": {
+      "version": "2.24.3",
+      "resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-2.24.3.tgz",
+      "integrity": "sha512-6/HDXi92GzB+Hcs9fC6PAAozK1RLt1ewPTLjK0anTYguXLAeySDmcnqE8IC0xa7shvSzRjQXq3/+dsZ7ETGF3g==",
+      "requires": {
+        "sortablejs": "1.10.2"
+      }
+    },
+    "vuex": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/vuex/-/vuex-3.6.0.tgz",
+      "integrity": "sha512-W74OO2vCJPs9/YjNjW8lLbj+jzT24waTo2KShI8jLvJW8OaIkgb3wuAMA7D+ZiUxDOx3ubwSZTaJBip9G8a3aQ=="
+    },
+    "watchpack": {
+      "version": "1.7.5",
+      "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz",
+      "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==",
+      "dev": true,
+      "requires": {
+        "chokidar": "^3.4.1",
+        "graceful-fs": "^4.1.2",
+        "neo-async": "^2.5.0",
+        "watchpack-chokidar2": "^2.0.1"
+      }
+    },
+    "watchpack-chokidar2": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz",
+      "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "chokidar": "^2.1.8"
+      },
+      "dependencies": {
+        "anymatch": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
+          "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "micromatch": "^3.1.4",
+            "normalize-path": "^2.1.1"
+          },
+          "dependencies": {
+            "normalize-path": {
+              "version": "2.1.1",
+              "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+              "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+              "dev": true,
+              "optional": true,
+              "requires": {
+                "remove-trailing-separator": "^1.0.1"
+              }
+            }
+          }
+        },
+        "binary-extensions": {
+          "version": "1.13.1",
+          "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
+          "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
+          "dev": true,
+          "optional": true
+        },
+        "braces": {
+          "version": "2.3.2",
+          "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+          "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "arr-flatten": "^1.1.0",
+            "array-unique": "^0.3.2",
+            "extend-shallow": "^2.0.1",
+            "fill-range": "^4.0.0",
+            "isobject": "^3.0.1",
+            "repeat-element": "^1.1.2",
+            "snapdragon": "^0.8.1",
+            "snapdragon-node": "^2.0.1",
+            "split-string": "^3.0.2",
+            "to-regex": "^3.0.1"
+          }
+        },
+        "chokidar": {
+          "version": "2.1.8",
+          "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
+          "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "anymatch": "^2.0.0",
+            "async-each": "^1.0.1",
+            "braces": "^2.3.2",
+            "fsevents": "^1.2.7",
+            "glob-parent": "^3.1.0",
+            "inherits": "^2.0.3",
+            "is-binary-path": "^1.0.0",
+            "is-glob": "^4.0.0",
+            "normalize-path": "^3.0.0",
+            "path-is-absolute": "^1.0.0",
+            "readdirp": "^2.2.1",
+            "upath": "^1.1.1"
+          }
+        },
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        },
+        "fill-range": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+          "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "extend-shallow": "^2.0.1",
+            "is-number": "^3.0.0",
+            "repeat-string": "^1.6.1",
+            "to-regex-range": "^2.1.0"
+          }
+        },
+        "fsevents": {
+          "version": "1.2.13",
+          "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
+          "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "nan": "^2.12.1"
+          }
+        },
+        "glob-parent": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+          "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "is-glob": "^3.1.0",
+            "path-dirname": "^1.0.0"
+          },
+          "dependencies": {
+            "is-glob": {
+              "version": "3.1.0",
+              "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+              "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+              "dev": true,
+              "optional": true,
+              "requires": {
+                "is-extglob": "^2.1.0"
+              }
+            }
+          }
+        },
+        "is-binary-path": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
+          "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "binary-extensions": "^1.0.0"
+          }
+        },
+        "is-number": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+          "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          }
+        },
+        "readdirp": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
+          "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "graceful-fs": "^4.1.11",
+            "micromatch": "^3.1.10",
+            "readable-stream": "^2.0.2"
+          }
+        },
+        "to-regex-range": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+          "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "is-number": "^3.0.0",
+            "repeat-string": "^1.6.1"
+          }
+        }
+      }
+    },
+    "wbuf": {
+      "version": "1.7.3",
+      "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz",
+      "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==",
+      "dev": true,
+      "requires": {
+        "minimalistic-assert": "^1.0.0"
+      }
+    },
+    "webpack": {
+      "version": "3.12.0",
+      "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.12.0.tgz",
+      "integrity": "sha512-Sw7MdIIOv/nkzPzee4o0EdvCuPmxT98+vVpIvwtcwcF1Q4SDSNp92vwcKc4REe7NItH9f1S4ra9FuQ7yuYZ8bQ==",
+      "dev": true,
+      "requires": {
+        "acorn": "^5.0.0",
+        "acorn-dynamic-import": "^2.0.0",
+        "ajv": "^6.1.0",
+        "ajv-keywords": "^3.1.0",
+        "async": "^2.1.2",
+        "enhanced-resolve": "^3.4.0",
+        "escope": "^3.6.0",
+        "interpret": "^1.0.0",
+        "json-loader": "^0.5.4",
+        "json5": "^0.5.1",
+        "loader-runner": "^2.3.0",
+        "loader-utils": "^1.1.0",
+        "memory-fs": "~0.4.1",
+        "mkdirp": "~0.5.0",
+        "node-libs-browser": "^2.0.0",
+        "source-map": "^0.5.3",
+        "supports-color": "^4.2.1",
+        "tapable": "^0.2.7",
+        "uglifyjs-webpack-plugin": "^0.4.6",
+        "watchpack": "^1.4.0",
+        "webpack-sources": "^1.0.1",
+        "yargs": "^8.0.2"
+      },
+      "dependencies": {
+        "ajv": {
+          "version": "6.12.6",
+          "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+          "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+          "dev": true,
+          "requires": {
+            "fast-deep-equal": "^3.1.1",
+            "fast-json-stable-stringify": "^2.0.0",
+            "json-schema-traverse": "^0.4.1",
+            "uri-js": "^4.2.2"
+          }
+        },
+        "ajv-keywords": {
+          "version": "3.5.2",
+          "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
+          "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
+          "dev": true
+        },
+        "fast-deep-equal": {
+          "version": "3.1.3",
+          "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+          "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+          "dev": true
+        },
+        "has-flag": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
+          "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
+          "dev": true
+        },
+        "json-schema-traverse": {
+          "version": "0.4.1",
+          "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+          "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+          "dev": true
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "4.5.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",
+          "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^2.0.0"
+          }
+        },
+        "uglify-js": {
+          "version": "2.8.29",
+          "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
+          "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=",
+          "dev": true,
+          "requires": {
+            "source-map": "~0.5.1",
+            "uglify-to-browserify": "~1.0.0",
+            "yargs": "~3.10.0"
+          },
+          "dependencies": {
+            "yargs": {
+              "version": "3.10.0",
+              "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
+              "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
+              "dev": true,
+              "requires": {
+                "camelcase": "^1.0.2",
+                "cliui": "^2.1.0",
+                "decamelize": "^1.0.0",
+                "window-size": "0.1.0"
+              }
+            }
+          }
+        },
+        "uglifyjs-webpack-plugin": {
+          "version": "0.4.6",
+          "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz",
+          "integrity": "sha1-uVH0q7a9YX5m9j64kUmOORdj4wk=",
+          "dev": true,
+          "requires": {
+            "source-map": "^0.5.6",
+            "uglify-js": "^2.8.29",
+            "webpack-sources": "^1.0.1"
+          }
+        }
+      }
+    },
+    "webpack-bundle-analyzer": {
+      "version": "2.13.1",
+      "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.13.1.tgz",
+      "integrity": "sha512-rwxyfecTAxoarCC9VlHlIpfQCmmJ/qWD5bpbjkof+7HrNhTNZIwZITxN6CdlYL2axGmwNUQ+tFgcSOiNXMf/sQ==",
+      "dev": true,
+      "requires": {
+        "acorn": "^5.3.0",
+        "bfj-node4": "^5.2.0",
+        "chalk": "^2.3.0",
+        "commander": "^2.13.0",
+        "ejs": "^2.5.7",
+        "express": "^4.16.2",
+        "filesize": "^3.5.11",
+        "gzip-size": "^4.1.0",
+        "lodash": "^4.17.4",
+        "mkdirp": "^0.5.1",
+        "opener": "^1.4.3",
+        "ws": "^4.0.0"
+      }
+    },
+    "webpack-dev-middleware": {
+      "version": "1.12.2",
+      "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-1.12.2.tgz",
+      "integrity": "sha512-FCrqPy1yy/sN6U/SaEZcHKRXGlqU0DUaEBL45jkUYoB8foVb6wCnbIJ1HKIx+qUFTW+3JpVcCJCxZ8VATL4e+A==",
+      "dev": true,
+      "requires": {
+        "memory-fs": "~0.4.1",
+        "mime": "^1.5.0",
+        "path-is-absolute": "^1.0.0",
+        "range-parser": "^1.0.3",
+        "time-stamp": "^2.0.0"
+      }
+    },
+    "webpack-dev-server": {
+      "version": "2.11.5",
+      "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-2.11.5.tgz",
+      "integrity": "sha512-7TdOKKt7G3sWEhPKV0zP+nD0c4V9YKUJ3wDdBwQsZNo58oZIRoVIu66pg7PYkBW8A74msP9C2kLwmxGHndz/pw==",
+      "dev": true,
+      "requires": {
+        "ansi-html": "0.0.7",
+        "array-includes": "^3.0.3",
+        "bonjour": "^3.5.0",
+        "chokidar": "^2.1.2",
+        "compression": "^1.7.3",
+        "connect-history-api-fallback": "^1.3.0",
+        "debug": "^3.1.0",
+        "del": "^3.0.0",
+        "express": "^4.16.2",
+        "html-entities": "^1.2.0",
+        "http-proxy-middleware": "^0.19.1",
+        "import-local": "^1.0.0",
+        "internal-ip": "1.2.0",
+        "ip": "^1.1.5",
+        "killable": "^1.0.0",
+        "loglevel": "^1.4.1",
+        "opn": "^5.1.0",
+        "portfinder": "^1.0.9",
+        "selfsigned": "^1.9.1",
+        "serve-index": "^1.9.1",
+        "sockjs": "0.3.19",
+        "sockjs-client": "1.1.5",
+        "spdy": "^4.0.0",
+        "strip-ansi": "^3.0.0",
+        "supports-color": "^5.1.0",
+        "webpack-dev-middleware": "1.12.2",
+        "yargs": "6.6.0"
+      },
+      "dependencies": {
+        "anymatch": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
+          "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
+          "dev": true,
+          "requires": {
+            "micromatch": "^3.1.4",
+            "normalize-path": "^2.1.1"
+          },
+          "dependencies": {
+            "normalize-path": {
+              "version": "2.1.1",
+              "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+              "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+              "dev": true,
+              "requires": {
+                "remove-trailing-separator": "^1.0.1"
+              }
+            }
+          }
+        },
+        "binary-extensions": {
+          "version": "1.13.1",
+          "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
+          "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
+          "dev": true
+        },
+        "braces": {
+          "version": "2.3.2",
+          "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+          "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+          "dev": true,
+          "requires": {
+            "arr-flatten": "^1.1.0",
+            "array-unique": "^0.3.2",
+            "extend-shallow": "^2.0.1",
+            "fill-range": "^4.0.0",
+            "isobject": "^3.0.1",
+            "repeat-element": "^1.1.2",
+            "snapdragon": "^0.8.1",
+            "snapdragon-node": "^2.0.1",
+            "split-string": "^3.0.2",
+            "to-regex": "^3.0.1"
+          }
+        },
+        "camelcase": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
+          "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
+          "dev": true
+        },
+        "chokidar": {
+          "version": "2.1.8",
+          "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
+          "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
+          "dev": true,
+          "requires": {
+            "anymatch": "^2.0.0",
+            "async-each": "^1.0.1",
+            "braces": "^2.3.2",
+            "fsevents": "^1.2.7",
+            "glob-parent": "^3.1.0",
+            "inherits": "^2.0.3",
+            "is-binary-path": "^1.0.0",
+            "is-glob": "^4.0.0",
+            "normalize-path": "^3.0.0",
+            "path-is-absolute": "^1.0.0",
+            "readdirp": "^2.2.1",
+            "upath": "^1.1.1"
+          }
+        },
+        "cliui": {
+          "version": "3.2.0",
+          "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
+          "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
+          "dev": true,
+          "requires": {
+            "string-width": "^1.0.1",
+            "strip-ansi": "^3.0.1",
+            "wrap-ansi": "^2.0.0"
+          }
+        },
+        "debug": {
+          "version": "3.2.7",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+          "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+          "dev": true,
+          "requires": {
+            "ms": "^2.1.1"
+          }
+        },
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        },
+        "fill-range": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+          "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+          "dev": true,
+          "requires": {
+            "extend-shallow": "^2.0.1",
+            "is-number": "^3.0.0",
+            "repeat-string": "^1.6.1",
+            "to-regex-range": "^2.1.0"
+          }
+        },
+        "find-up": {
+          "version": "1.1.2",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
+          "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
+          "dev": true,
+          "requires": {
+            "path-exists": "^2.0.0",
+            "pinkie-promise": "^2.0.0"
+          }
+        },
+        "fsevents": {
+          "version": "1.2.13",
+          "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
+          "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "nan": "^2.12.1"
+          }
+        },
+        "glob-parent": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+          "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
+          "dev": true,
+          "requires": {
+            "is-glob": "^3.1.0",
+            "path-dirname": "^1.0.0"
+          },
+          "dependencies": {
+            "is-glob": {
+              "version": "3.1.0",
+              "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+              "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+              "dev": true,
+              "requires": {
+                "is-extglob": "^2.1.0"
+              }
+            }
+          }
+        },
+        "is-binary-path": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
+          "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
+          "dev": true,
+          "requires": {
+            "binary-extensions": "^1.0.0"
+          }
+        },
+        "is-fullwidth-code-point": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+          "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+          "dev": true,
+          "requires": {
+            "number-is-nan": "^1.0.0"
+          }
+        },
+        "is-number": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+          "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+          "dev": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          }
+        },
+        "load-json-file": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
+          "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
+          "dev": true,
+          "requires": {
+            "graceful-fs": "^4.1.2",
+            "parse-json": "^2.2.0",
+            "pify": "^2.0.0",
+            "pinkie-promise": "^2.0.0",
+            "strip-bom": "^2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.1.3",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+          "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+          "dev": true
+        },
+        "os-locale": {
+          "version": "1.4.0",
+          "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
+          "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
+          "dev": true,
+          "requires": {
+            "lcid": "^1.0.0"
+          }
+        },
+        "path-exists": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
+          "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
+          "dev": true,
+          "requires": {
+            "pinkie-promise": "^2.0.0"
+          }
+        },
+        "path-type": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
+          "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
+          "dev": true,
+          "requires": {
+            "graceful-fs": "^4.1.2",
+            "pify": "^2.0.0",
+            "pinkie-promise": "^2.0.0"
+          }
+        },
+        "pify": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+          "dev": true
+        },
+        "read-pkg": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
+          "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
+          "dev": true,
+          "requires": {
+            "load-json-file": "^1.0.0",
+            "normalize-package-data": "^2.3.2",
+            "path-type": "^1.0.0"
+          }
+        },
+        "read-pkg-up": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
+          "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
+          "dev": true,
+          "requires": {
+            "find-up": "^1.0.0",
+            "read-pkg": "^1.0.0"
+          }
+        },
+        "readdirp": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
+          "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
+          "dev": true,
+          "requires": {
+            "graceful-fs": "^4.1.11",
+            "micromatch": "^3.1.10",
+            "readable-stream": "^2.0.2"
+          }
+        },
+        "string-width": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+          "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+          "dev": true,
+          "requires": {
+            "code-point-at": "^1.0.0",
+            "is-fullwidth-code-point": "^1.0.0",
+            "strip-ansi": "^3.0.0"
+          }
+        },
+        "strip-bom": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
+          "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
+          "dev": true,
+          "requires": {
+            "is-utf8": "^0.2.0"
+          }
+        },
+        "to-regex-range": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+          "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
+          "dev": true,
+          "requires": {
+            "is-number": "^3.0.0",
+            "repeat-string": "^1.6.1"
+          }
+        },
+        "which-module": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
+          "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=",
+          "dev": true
+        },
+        "y18n": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz",
+          "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==",
+          "dev": true
+        },
+        "yargs": {
+          "version": "6.6.0",
+          "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz",
+          "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=",
+          "dev": true,
+          "requires": {
+            "camelcase": "^3.0.0",
+            "cliui": "^3.2.0",
+            "decamelize": "^1.1.1",
+            "get-caller-file": "^1.0.1",
+            "os-locale": "^1.4.0",
+            "read-pkg-up": "^1.0.1",
+            "require-directory": "^2.1.1",
+            "require-main-filename": "^1.0.1",
+            "set-blocking": "^2.0.0",
+            "string-width": "^1.0.2",
+            "which-module": "^1.0.0",
+            "y18n": "^3.2.1",
+            "yargs-parser": "^4.2.0"
+          }
+        },
+        "yargs-parser": {
+          "version": "4.2.1",
+          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz",
+          "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=",
+          "dev": true,
+          "requires": {
+            "camelcase": "^3.0.0"
+          }
+        }
+      }
+    },
+    "webpack-merge": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz",
+      "integrity": "sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==",
+      "dev": true,
+      "requires": {
+        "lodash": "^4.17.15"
+      }
+    },
+    "webpack-sources": {
+      "version": "1.4.3",
+      "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz",
+      "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==",
+      "dev": true,
+      "requires": {
+        "source-list-map": "^2.0.0",
+        "source-map": "~0.6.1"
+      }
+    },
+    "websocket-driver": {
+      "version": "0.7.4",
+      "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
+      "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
+      "dev": true,
+      "requires": {
+        "http-parser-js": ">=0.5.1",
+        "safe-buffer": ">=5.1.0",
+        "websocket-extensions": ">=0.1.1"
+      }
+    },
+    "websocket-extensions": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
+      "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
+      "dev": true
+    },
+    "whet.extend": {
+      "version": "0.9.9",
+      "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz",
+      "integrity": "sha1-+HfVv2SMl+WqVC+twW1qJZucEaE=",
+      "dev": true
+    },
+    "which": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+      "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+      "requires": {
+        "isexe": "^2.0.0"
+      }
+    },
+    "which-module": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+      "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
+    },
+    "wide-align": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
+      "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
+      "requires": {
+        "string-width": "^1.0.2 || 2"
+      }
+    },
+    "window-size": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
+      "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=",
+      "dev": true
+    },
+    "word-wrap": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+      "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+      "dev": true
+    },
+    "wordwrap": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
+      "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=",
+      "dev": true
+    },
+    "worker-farm": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz",
+      "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==",
+      "dev": true,
+      "requires": {
+        "errno": "~0.1.7"
+      }
+    },
+    "wrap-ansi": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+      "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
+      "dev": true,
+      "requires": {
+        "string-width": "^1.0.1",
+        "strip-ansi": "^3.0.1"
+      },
+      "dependencies": {
+        "is-fullwidth-code-point": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+          "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+          "dev": true,
+          "requires": {
+            "number-is-nan": "^1.0.0"
+          }
+        },
+        "string-width": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+          "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+          "dev": true,
+          "requires": {
+            "code-point-at": "^1.0.0",
+            "is-fullwidth-code-point": "^1.0.0",
+            "strip-ansi": "^3.0.0"
+          }
+        }
+      }
+    },
+    "wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+    },
+    "write": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz",
+      "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=",
+      "dev": true,
+      "requires": {
+        "mkdirp": "^0.5.1"
+      }
+    },
+    "ws": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-4.1.0.tgz",
+      "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==",
+      "dev": true,
+      "requires": {
+        "async-limiter": "~1.0.0",
+        "safe-buffer": "~5.1.0"
+      }
+    },
+    "xlsx": {
+      "version": "0.14.5",
+      "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.14.5.tgz",
+      "integrity": "sha512-s/5f4/mjeWREmIWZ+HtDfh/rnz51ar+dZ4LWKZU3u9VBx2zLdSIWTdXgoa52/pnZ9Oe/Vu1W1qzcKzLVe+lq4w==",
+      "requires": {
+        "adler-32": "~1.2.0",
+        "cfb": "^1.1.2",
+        "codepage": "~1.14.0",
+        "commander": "~2.17.1",
+        "crc-32": "~1.2.0",
+        "exit-on-epipe": "~1.0.1",
+        "ssf": "~0.10.2"
+      }
+    },
+    "xml-char-classes": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/xml-char-classes/-/xml-char-classes-1.0.0.tgz",
+      "integrity": "sha1-ZGV4SKIP/F31g6Qq2KJ3tFErvE0=",
+      "dev": true
+    },
+    "xss": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/xss/-/xss-1.0.8.tgz",
+      "integrity": "sha512-3MgPdaXV8rfQ/pNn16Eio6VXYPTkqwa0vc7GkiymmY/DqR1SE/7VPAAVZz1GJsJFrllMYO3RHfEaiUGjab6TNw==",
+      "requires": {
+        "commander": "^2.20.3",
+        "cssfilter": "0.0.10"
+      },
+      "dependencies": {
+        "commander": {
+          "version": "2.20.3",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+          "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
+        }
+      }
+    },
+    "xtend": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+      "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+      "dev": true
+    },
+    "xxhashjs": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz",
+      "integrity": "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==",
+      "dev": true,
+      "requires": {
+        "cuint": "^0.2.2"
+      }
+    },
+    "y18n": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz",
+      "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ=="
+    },
+    "yallist": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+      "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
+    },
+    "yargs": {
+      "version": "8.0.2",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz",
+      "integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=",
+      "dev": true,
+      "requires": {
+        "camelcase": "^4.1.0",
+        "cliui": "^3.2.0",
+        "decamelize": "^1.1.1",
+        "get-caller-file": "^1.0.1",
+        "os-locale": "^2.0.0",
+        "read-pkg-up": "^2.0.0",
+        "require-directory": "^2.1.1",
+        "require-main-filename": "^1.0.1",
+        "set-blocking": "^2.0.0",
+        "string-width": "^2.0.0",
+        "which-module": "^2.0.0",
+        "y18n": "^3.2.1",
+        "yargs-parser": "^7.0.0"
+      },
+      "dependencies": {
+        "camelcase": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
+          "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
+          "dev": true
+        },
+        "cliui": {
+          "version": "3.2.0",
+          "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
+          "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
+          "dev": true,
+          "requires": {
+            "string-width": "^1.0.1",
+            "strip-ansi": "^3.0.1",
+            "wrap-ansi": "^2.0.0"
+          },
+          "dependencies": {
+            "string-width": {
+              "version": "1.0.2",
+              "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+              "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+              "dev": true,
+              "requires": {
+                "code-point-at": "^1.0.0",
+                "is-fullwidth-code-point": "^1.0.0",
+                "strip-ansi": "^3.0.0"
+              }
+            }
+          }
+        },
+        "is-fullwidth-code-point": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+          "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+          "dev": true,
+          "requires": {
+            "number-is-nan": "^1.0.0"
+          }
+        },
+        "y18n": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz",
+          "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==",
+          "dev": true
+        }
+      }
+    },
+    "yargs-parser": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz",
+      "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=",
+      "dev": true,
+      "requires": {
+        "camelcase": "^4.1.0"
+      },
+      "dependencies": {
+        "camelcase": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
+          "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
+          "dev": true
+        }
+      }
+    }
+  }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..1312ea4
--- /dev/null
+++ b/package.json
@@ -0,0 +1,104 @@
+{
+  "name": "myproject",
+  "version": "1.0.0",
+  "description": "DCGY-CRM",
+  "author": "gjj <Ganjj@probim.com.cn>",
+  "private": true,
+  "scripts": {
+    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
+    "start": "npm run dev",
+    "lint": "eslint --ext .js,.vue src",
+    "build": "node build/build.js"
+  },
+  "dependencies": {
+    "@fullcalendar/core": "^5.5.1",
+    "@fullcalendar/daygrid": "^5.5.0",
+    "@fullcalendar/vue": "^5.5.0",
+    "axios": "^0.21.1",
+    "element-ui": "^2.14.1",
+    "es6-promise": "^4.2.8",
+    "js-cookie": "^2.2.1",
+    "lib-flexible": "^0.3.2",
+    "lockr": "^0.8.5",
+    "moment": "^2.29.1",
+    "node-sass": "^4.14.1",
+    "nprogress": "^0.2.0",
+    "v-distpicker": "^1.2.9",
+    "vue": "^2.6.12",
+    "vue-baidu-map": "^0.21.22",
+    "vue-bus": "^1.2.1",
+    "vue-calendar-component": "^2.8.2",
+    "vue-fullcalendar": "^1.0.9",
+    "vue-lazyload": "^1.3.3",
+    "vue-moment": "^4.1.0",
+    "vue-router": "^3.4.9",
+    "vuedraggable": "^2.24.3",
+    "vuex": "^3.6.0",
+    "xlsx": "^0.14.1",
+    "xss": "^1.0.6"
+  },
+  "devDependencies": {
+    "autoprefixer": "^7.1.2",
+    "babel-core": "^6.26.3",
+    "babel-eslint": "^8.2.1",
+    "babel-helper-vue-jsx-merge-props": "^2.0.3",
+    "babel-loader": "^7.1.5",
+    "babel-plugin-syntax-jsx": "^6.18.0",
+    "babel-plugin-transform-runtime": "^6.23.0",
+    "babel-plugin-transform-vue-jsx": "^3.5.0",
+    "babel-preset-env": "^1.3.2",
+    "babel-preset-es2015": "^6.24.1",
+    "babel-preset-stage-2": "^6.22.0",
+    "babel-runtime": "^6.26.0",
+    "chalk": "^2.0.1",
+    "copy-webpack-plugin": "^4.0.1",
+    "css-loader": "^0.28.11",
+    "eslint": "^4.15.0",
+    "eslint-config-standard": "^10.2.1",
+    "eslint-friendly-formatter": "^3.0.0",
+    "eslint-loader": "^1.7.1",
+    "eslint-plugin-import": "^2.7.0",
+    "eslint-plugin-node": "^5.2.0",
+    "eslint-plugin-promise": "^3.4.0",
+    "eslint-plugin-standard": "^3.0.1",
+    "eslint-plugin-vue": "^4.0.0",
+    "extract-text-webpack-plugin": "^3.0.0",
+    "file-loader": "^1.1.4",
+    "friendly-errors-webpack-plugin": "^1.6.1",
+    "html-webpack-plugin": "^2.30.1",
+    "less": "^3.9",
+    "less-loader": "^5.0.0",
+    "node-notifier": "^5.1.2",
+    "optimize-css-assets-webpack-plugin": "^3.2.0",
+    "ora": "^1.2.0",
+    "portfinder": "^1.0.13",
+    "postcss-import": "^11.0.0",
+    "postcss-loader": "^2.0.8",
+    "postcss-url": "^7.2.1",
+    "px2rem-loader": "^0.1.9",
+    "rimraf": "^2.6.0",
+    "sass-loader": "^7.3.1",
+    "semver": "^5.3.0",
+    "shelljs": "^0.7.6",
+    "uglifyjs-webpack-plugin": "^1.1.1",
+    "url-loader": "^0.5.8",
+    "vue-hot-reload-api": "^1.3.2",
+    "vue-html-loader": "^1.2.4",
+    "vue-loader": "^13.7.3",
+    "vue-style-loader": "^3.1.2",
+    "vue-template-compiler": "^2.5.2",
+    "webpack": "^3.12.0",
+    "webpack-bundle-analyzer": "^2.9.0",
+    "webpack-dev-server": "^2.9.1",
+    "webpack-merge": "^4.1.0"
+  },
+  "engines": {
+    "node": ">= 6.0.0",
+    "npm": ">= 3.0.0"
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not ie <= 8"
+  ]
+}
diff --git a/src/App.vue b/src/App.vue
new file mode 100644
index 0000000..4959f0b
--- /dev/null
+++ b/src/App.vue
@@ -0,0 +1,19 @@
+<template>
+  <div id="app">
+     <router-view/>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'App'
+}
+</script>
+
+<style>
+#app {
+  width: 100%;
+  position: relative;
+  height: 100%;
+}
+</style>
diff --git a/src/api/businessIntelligence/index.js b/src/api/businessIntelligence/index.js
new file mode 100644
index 0000000..e2e27ca
--- /dev/null
+++ b/src/api/businessIntelligence/index.js
@@ -0,0 +1,72 @@
+import request from '@/utils/request'
+
+export function GetOtherCustomerPageList (data) {
+  return request({
+    url: '/Customer/GetOtherCustomerPageList?PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize +
+    '&SelectOwnedType=' + data.SelectOwnedType +
+    '&Name=' + data.Name +
+    '&CreateStartTime=' + data.CreateStartTime +
+    '&CreateEndTime=' + data.CreateEndTime +
+    '&StartFollowTime=' + data.StartFollowTime +
+    '&EndFolowTime=' + data.EndFolowTime +
+    (data.ProvinceCode ? '&ProvinceCode=' + data.ProvinceCode : '') +
+    (data.CustomerBusinessStatus
+      ? '&CustomerBusinessStatus=' + data.CustomerBusinessStatus : '') +
+    (data.CustomerSource ? '&CustomerSource=' + data.CustomerSource : '') + (data.CustomerType ? '&CustomerType=' + data.CustomerType : '') +
+    (data.CostomerCategory ? '&CostomerCategory=' + data.CostomerCategory : '') +
+    (data.CustomerIndustry ? '&CustomerIndustry=' + data.CustomerIndustry : '') +
+    (data.CompanyType ? '&CompanyType=' + data.CompanyType : '') + (data.DepartmentUserType
+      ? '&DepartmentUserType=' + data.DepartmentUserType : '') +
+      (data.Id
+        ? '&Id=' + data.Id : ''),
+    method: 'get'
+  })
+}
+export function GetOtherSalesChanceList (data) {
+  return request({
+    url: '/SalesChance/GetOtherSalesChanceList?PageIndex=' + data.PageIndex +
+    '&PageSize=' + data.PageSize +
+    '&SelectOwnedType=' + data.SelectOwnedType +
+    '&Name=' + data.Name +
+    (data.SalesChanceStage
+      ? '&SalesChanceStage=' + data.SalesChanceStage : '') +
+    (data.ProvinceCode
+      ? '&ProvinceCode=' + data.ProvinceCode : '') +
+    (data.SalesChanceType
+      ? '&SalesChanceType=' + data.SalesChanceType : '') +
+    (data.ChanceUploadStatus
+      ? '&ChanceUploadStatus=' + data.ChanceUploadStatus : '') +
+    (data.ChanceReportStatus
+      ? '&ChanceReportStatus=' + data.ChanceReportStatus : '') +
+    (data.SalesChanceSubmissionMethod
+      ? '&SalesChanceSubmissionMethod=' + data.SalesChanceSubmissionMethod : '') +
+    (data.ProjectProperty
+      ? '&ProjectProperty=' + data.ProjectProperty : '') +
+    (data.UploadStatusName
+      ? '&UploadStatusName=' + data.UploadStatusName : '') +
+    (data.ReportStatusName
+      ? '&ReportStatusName=' + data.ReportStatusName : '') +
+    '&CreateStartTime=' + data.CreateStartTime +
+    '&CreateEndTime=' + data.CreateEndTime + (data.DepartmentUserType
+      ? '&DepartmentUserType=' + data.DepartmentUserType : '') +
+      (data.Id
+        ? '&Id=' + data.Id : ''),
+    method: 'get'
+  })
+}
+export function GetOtherAgreementList (data) {
+  return request({
+    url: '/Agreement/GetOtherAgreementList?SelectOwnedType=' + data.SelectOwnedType + '&AuditStatus=' + data.AuditStatus +
+    '&PageIndex=' + data.PageIndex +
+    '&PageSize=' + data.PageSize +
+    '&SealStatus=' + data.SealStatus +
+    '&Name=' + data.Name +
+    '&CreateStartTime=' + data.CreateStartTime +
+    '&CreateEndTime=' + data.CreateEndTime + (data.SealType
+      ? '&SealType=' + data.SealType : '') + (data.DepartmentUserType
+      ? '&DepartmentUserType=' + data.DepartmentUserType : '') +
+        (data.Id
+          ? '&Id=' + data.Id : ''),
+    method: 'get'
+  })
+}
diff --git a/src/api/common.js b/src/api/common.js
new file mode 100644
index 0000000..ed9309f
--- /dev/null
+++ b/src/api/common.js
@@ -0,0 +1,314 @@
+import request from '@/utils/request'
+import { ResouceUrl } from '@/utils/baseconfig'
+/**
+ *
+ * @param {*} data
+ */
+export function UploadFileAsync (data) {
+  var param = new FormData()
+  param.append('file', data.file)
+  return request({
+    url: ResouceUrl + '/api/File/UploadFileAsync',
+    method: 'post',
+    data: param,
+    headers: {
+      'Content-Type': 'multipart/form-data'
+    }
+  })
+}
+export function UploadImageAsync (data) {
+  var param = new FormData()
+  param.append('file', data.file)
+  return request({
+    url: ResouceUrl + '/api/File/UploadImageAsync',
+    method: 'post',
+    data: param,
+    headers: {
+      'Content-Type': 'multipart/form-data'
+    }
+  })
+}
+export function GetBusinessFollowRecordList (data) {
+  return request({
+    url: '/FollowRecord/GetBusinessFollowRecordList?SourceId=' + data.SourceId + '&PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize + '&BusinessOperationType=' + data.BusinessOperationType,
+    method: 'get'
+  })
+}
+export function DeleteFollowRecord (data) {
+  return request({
+    url: '/FollowRecord/DeleteFollowRecord',
+    method: 'post',
+    data: data
+  })
+}
+// 获取省
+export function GetProvincesList (data) {
+  return request({
+    url: '/ProvinceCity/GetProvincesList',
+    method: 'get'
+  })
+}
+// 获取市
+export function GetCityList (data) {
+  return request({
+    url: '/ProvinceCity/GetCityList?provinceId=' + data.provinceId,
+    method: 'get'
+  })
+}
+// 获取区
+export function GetAreaList (data) {
+  return request({
+    url: '/ProvinceCity/GetAreaList?cityId=' + data.cityId,
+    method: 'get'
+  })
+}
+
+export function GetCusomterNumber (data) {
+  return request({
+    url: '/Number/GetCusomterNumber',
+    method: 'get'
+  })
+}
+export function GetSalesChanceNumber (data) {
+  return request({
+    url: '/Number/GetSalesChanceNumber',
+    method: 'get'
+  })
+}
+export function GetContacterNumber (data) {
+  return request({
+    url: '/Number/GetContacterNumber',
+    method: 'get'
+  })
+}
+export function GetAgreementNumber (data) {
+  return request({
+    url: '/Number/GetAgreementNumber',
+    method: 'get'
+  })
+}
+export function GetQuotationName (data) {
+  return request({
+    url: '/Number/GetQuotationName?salesChanceId=' + data.salesChanceId,
+    method: 'get'
+  })
+}
+export function GetAgreenmentName (data) {
+  return request({
+    url: '/Number/GetAgreenmentName?salesChanceId=' + data.salesChanceId,
+    method: 'get'
+  })
+}
+export function GetQuotationNumber (data) {
+  return request({
+    url: '/Number/GetQuotationNumber',
+    method: 'get'
+  })
+}
+export function GetSalesChanceName (data) {
+  return request({
+    url: '/Number/GetSalesChanceName?customerId=' + data.customerId,
+    method: 'get'
+  })
+}
+
+export function CustomerRepeatCheck (data) {
+  return request({
+    url: '/Customer/CustomerRepeatCheck?Name=' + data.Name,
+    method: 'get'
+  })
+}
+export function GetIndustryListChildrenData (data) {
+  return request({
+    url: '/Data/GetIndustryListChildrenData',
+    method: 'get'
+  })
+}
+export function ImportCustomerExcel (data) {
+  var param = new FormData()
+  // Object.keys(data).forEach(key => {
+  param.append('file', data.file)
+  // })
+  return request({
+    url: '/Excel/ImportCustomerExcel?excelImportType=' + data.excelImportType,
+    method: 'post',
+    data: param,
+    headers: {
+      'Content-Type': 'multipart/form-data'
+    }
+  })
+}
+export function ImportContacterExcel (data) {
+  var param = new FormData()
+  // Object.keys(data).forEach(key => {
+  param.append('file', data.file)
+  // })
+  return request({
+    url: '/Excel/ImportContacterExcel?excelImportType=' + data.excelImportType,
+    method: 'post',
+    data: param,
+    headers: {
+      'Content-Type': 'multipart/form-data'
+    }
+  })
+}
+export function ImportSalesChanceExcel (data) {
+  var param = new FormData()
+  // Object.keys(data).forEach(key => {
+  param.append('file', data.file)
+  // })
+  return request({
+    url: '/Excel/ImportSalesChanceExcel?excelImportType=' + data.excelImportType,
+    method: 'post',
+    data: param,
+    headers: {
+      'Content-Type': 'multipart/form-data'
+    }
+  })
+}
+export function DownloadCustomerExcelModel (data) {
+  return request({
+    url: '/Excel/DownloadCustomerExcelModel',
+    method: 'get',
+    responseType: 'blob'
+  })
+}
+export function DownloadContacgerExcelModel (data) {
+  return request({
+    url: '/Excel/DownloadContacgerExcelModel',
+    method: 'get',
+    responseType: 'blob'
+  })
+}
+export function DownloadSalesChanceExcelModel (data) {
+  return request({
+    url: '/Excel/DownloadSalesChanceExcelModel',
+    method: 'get',
+    responseType: 'blob'
+  })
+}
+export function OutputCustomerToExcel (data) {
+  return request({
+    url: '/Excel/OutputCustomerToExcel?PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize +
+    '&SelectOwnedType=' + data.SelectOwnedType +
+    '&Name=' + data.Name +
+    '&CreateStartTime=' + data.CreateStartTime +
+    '&CreateEndTime=' + data.CreateEndTime +
+    '&StartFollowTime=' + data.StartFollowTime +
+    '&EndFolowTime=' + data.EndFolowTime,
+    method: 'get',
+    responseType: 'blob'
+  })
+}
+export function OutputContacterToExcel (data) {
+  return request({
+    url: '/Excel/OutputContacterToExcel?PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize +
+    '&SelectOwnedType=' + data.SelectOwnedType +
+    (data.BrachUserId
+      ? '&BrachUserId=' + data.BrachUserId : '') +
+    '&Name=' + data.Name,
+    method: 'get',
+    responseType: 'blob'
+  })
+}
+
+export function OutputSalesChanceToExcel (data) {
+  return request({
+    url: '/Excel/OutputSalesChanceToExcel?PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize +
+    '&SelectOwnedType=' + data.SelectOwnedType +
+    '&Name=' + data.Name +
+    (data.BrachUserId
+      ? '&BrachUserId=' + data.BrachUserId : '') +
+    (data.SalesChanceStage
+      ? '&SalesChanceStage=' + data.SalesChanceStage : '') +
+    (data.ProvinceCode
+      ? '&ProvinceCode=' + data.ProvinceCode : '') +
+    (data.SalesChanceType
+      ? '&SalesChanceType=' + data.SalesChanceType : '') +
+    (data.ChanceUploadStatus
+      ? '&ChanceUploadStatus=' + data.ChanceUploadStatus : '') +
+    (data.ChanceReportStatus
+      ? '&ChanceReportStatus=' + data.ChanceReportStatus : '') +
+    (data.SalesChanceSubmissionMethod
+      ? '&SalesChanceSubmissionMethod=' + data.SalesChanceSubmissionMethod : '') +
+    (data.ProjectProperty
+      ? '&ProjectProperty=' + data.ProjectProperty : '') +
+    (data.UploadStatusName
+      ? '&UploadStatusName=' + data.UploadStatusName : '') +
+    (data.ReportStatusName
+      ? '&ReportStatusName=' + data.ReportStatusName : '') +
+    (data.CreateStartTime
+      ? '&CreateStartTime=' + data.CreateStartTime : '') +
+    (data.CreateEndTime
+      ? '&CreateEndTime=' + data.CreateEndTime : '') +
+    (data.DepartmentUserType
+      ? '&DepartmentUserType=' + data.DepartmentUserType : '') +
+      (data.Id
+        ? '&Id=' + data.Id : ''),
+    method: 'get',
+    responseType: 'blob'
+  })
+}
+export function OutputOtherSalesChanceToExcel (data) {
+  return request({
+    url: '/Excel/OutputOtherSalesChanceToExcel?PageIndex=' + data.PageIndex +
+    '&PageSize=' + data.PageSize +
+    '&SelectOwnedType=' + data.SelectOwnedType +
+    '&Name=' + data.Name +
+    (data.BrachUserId
+      ? '&BrachUserId=' + data.BrachUserId : '') +
+    (data.SalesChanceStage
+      ? '&SalesChanceStage=' + data.SalesChanceStage : '') +
+    (data.ProvinceCode
+      ? '&ProvinceCode=' + data.ProvinceCode : '') +
+    (data.SalesChanceType
+      ? '&SalesChanceType=' + data.SalesChanceType : '') +
+    (data.ChanceUploadStatus
+      ? '&ChanceUploadStatus=' + data.ChanceUploadStatus : '') +
+    (data.ChanceReportStatus
+      ? '&ChanceReportStatus=' + data.ChanceReportStatus : '') +
+    (data.SalesChanceSubmissionMethod
+      ? '&SalesChanceSubmissionMethod=' + data.SalesChanceSubmissionMethod : '') +
+    (data.ProjectProperty
+      ? '&ProjectProperty=' + data.ProjectProperty : '') +
+    (data.UploadStatusName
+      ? '&UploadStatusName=' + data.UploadStatusName : '') +
+    (data.ReportStatusName
+      ? '&ReportStatusName=' + data.ReportStatusName : '') +
+    (data.CreateStartTime
+      ? '&CreateStartTime=' + data.CreateStartTime : '') +
+      (data.CreateEndTime
+        ? '&CreateEndTime=' + data.CreateEndTime : '') +
+   (data.DepartmentUserType
+     ? '&DepartmentUserType=' + data.DepartmentUserType : '') +
+      (data.Id
+        ? '&Id=' + data.Id : ''),
+    method: 'get',
+    responseType: 'blob'
+  })
+}
+export function DownloadSubscriptions (data) {
+  return request({
+    url: '/AutoDesk/download/subscriptions/' + data.taskId,
+    method: 'get',
+    responseType: 'blob'
+  })
+}
+export function GetProjectPropertyData (data) {
+  return request({
+    url: '/Data/GetProjectPropertyData',
+    method: 'get'
+  })
+}
+export function GetExtendProjectPropertyData (data) {
+  return request({
+    url: '/Data/GetExtendProjectPropertyData',
+    method: 'get'
+  })
+}
+export function GetWxSpUserList (data) {
+  return request({
+    url: '/Data/GetWxSpUserList',
+    method: 'get'
+  })
+}
diff --git a/src/api/customermanagement/business.js b/src/api/customermanagement/business.js
new file mode 100644
index 0000000..3ee98ba
--- /dev/null
+++ b/src/api/customermanagement/business.js
@@ -0,0 +1,129 @@
+import request from '@/utils/request'
+
+export function GetSalesChanceList (data) {
+  return request({
+    url: '/SalesChance/GetSalesChanceList?PageIndex=' + data.PageIndex +
+    '&PageSize=' + data.PageSize +
+    '&SelectOwnedType=' + data.SelectOwnedType +
+     (data.BrachUserId
+       ? '&BrachUserId=' + data.BrachUserId : '') +
+    '&Name=' + data.Name +
+    (data.SalesChanceStage
+      ? '&SalesChanceStage=' + data.SalesChanceStage : '') +
+    (data.ProvinceCode
+      ? '&ProvinceCode=' + data.ProvinceCode : '') +
+    (data.SalesChanceType
+      ? '&SalesChanceType=' + data.SalesChanceType : '') +
+    (data.ChanceUploadStatus
+      ? '&ChanceUploadStatus=' + data.ChanceUploadStatus : '') +
+    (data.ChanceReportStatus
+      ? '&ChanceReportStatus=' + data.ChanceReportStatus : '') +
+    (data.SalesChanceSubmissionMethod
+      ? '&SalesChanceSubmissionMethod=' + data.SalesChanceSubmissionMethod : '') +
+    (data.ProjectProperty
+      ? '&ProjectProperty=' + data.ProjectProperty : '') +
+    (data.UploadStatusName
+      ? '&UploadStatusName=' + data.UploadStatusName : '') +
+    (data.ReportStatusName
+      ? '&ReportStatusName=' + data.ReportStatusName : '') +
+    '&CreateStartTime=' + data.CreateStartTime +
+    '&CreateEndTime=' + data.CreateEndTime,
+    method: 'get'
+  })
+}
+export function AddSalesChance (data) {
+  return request({
+    url: '/SalesChance/AddSalesChance',
+    method: 'post',
+    data: data
+  })
+}
+export function UpdateSalesChance (data) {
+  return request({
+    url: '/SalesChance/UpdateSalesChance',
+    method: 'post',
+    data: data
+  })
+}
+export function DeleteSalesChance (data) {
+  return request({
+    url: '/SalesChance/DeleteSalesChance',
+    method: 'post',
+    data: data
+  })
+}
+export function GetSalesChanceDetail (data) {
+  return request({
+    url: '/SalesChance/GetSalesChanceDetail?Id=' + data.Id,
+    method: 'get'
+  })
+}
+export function GetSalesChanceFollowList (data) {
+  return request({
+    url: '/SalesChance/GetSalesChanceFollowList?Id=' + data.Id + '&Name=' + data.Name + '&PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize,
+    method: 'get'
+  })
+}
+export function GetSalesChanceAgreementList (data) {
+  return request({
+    url: '/SalesChance/GetSalesChanceAgreementList?Id=' + data.Id + '&PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize,
+    method: 'get'
+  })
+}
+export function GetSalesChanceProductList (data) {
+  return request({
+    url: '/SalesChance/GetSalesChanceProductList?Id=' + data.Id + '&PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize,
+    method: 'get'
+  })
+}
+export function GetSalesDocumentFileList (data) {
+  return request({
+    url: '/SalesChance/GetSalesDocumentFileList?Id=' + data.Id + '&PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize,
+    method: 'get'
+  })
+}
+export function GetSalesChanceOperationLogList (data) {
+  return request({
+    url: '/SalesChance/GetSalesChanceOperationLogList?Id=' + data.Id + '&PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize,
+    method: 'get'
+  })
+}
+export function GetSalesChanceQuotationSheetList (data) {
+  return request({
+    url: '/SalesChance/GetSalesChanceQuotationSheetList?Id=' + data.Id + '&PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize,
+    method: 'get'
+  })
+}
+export function GetSalesChanceJobScheduleList (data) {
+  return request({
+    url: '/SalesChance/GetSalesChanceJobScheduleList?Id=' + data.Id + '&PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize,
+    method: 'get'
+  })
+}
+export function ChangeSalesChanceStage (data) {
+  return request({
+    url: '/SalesChance/ChangeSalesChanceStage',
+    method: 'post',
+    data: data
+  })
+}
+export function GetAutoSalesChanceLogList (data) {
+  return request({
+    url: '/SalesChance/GetAutoSalesChanceLogList?Id=' + data.Id + '&PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize,
+    method: 'get'
+  })
+}
+export function DeleteSalesChanceProduct (data) {
+  return request({
+    url: '/SalesChance/DeleteSalesChanceProduct',
+    method: 'post',
+    data: data
+  })
+}
+export function SubmitSalesChance (data) {
+  return request({
+    url: '/SalesChance/SubmitSalesChance',
+    method: 'post',
+    data: data
+  })
+}
diff --git a/src/api/customermanagement/contacts.js b/src/api/customermanagement/contacts.js
new file mode 100644
index 0000000..140f320
--- /dev/null
+++ b/src/api/customermanagement/contacts.js
@@ -0,0 +1,62 @@
+import request from '@/utils/request'
+
+export function GetContacterList (data) {
+  return request({
+    url: '/Contacter/GetContacterList?PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize +
+    '&SelectOwnedType=' + data.SelectOwnedType +
+     (data.BrachUserId
+       ? '&BrachUserId=' + data.BrachUserId : '') +
+    '&Name=' + data.Name +
+    (data.ProvinceCode
+      ? '&ProvinceCode=' + data.ProvinceCode : '') +
+      (data.SelectOwnedType
+        ? '&SelectOwnedType=' + data.SelectOwnedType : ''),
+    method: 'get'
+  })
+}
+export function AddContacter (data) {
+  return request({
+    url: '/Contacter/AddContacter',
+    method: 'post',
+    data: data
+  })
+}
+export function UpdateContacter (data) {
+  return request({
+    url: '/Contacter/UpdateContacter',
+    method: 'post',
+    data: data
+  })
+}
+export function DeleteContacter (data) {
+  return request({
+    url: '/Contacter/DeleteContacter',
+    method: 'post',
+    data: data
+  })
+}
+
+export function GetPersonalContacterList (data) {
+  return request({
+    url: '/Contacter/GetPersonalContacterList?CustomerId=' + data.CustomerId + '&Name=' + data.Name + '&PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize,
+    method: 'get'
+  })
+}
+export function GetContacterDetail (data) {
+  return request({
+    url: '/Contacter/GetContacterDetail?Id=' + data.Id,
+    method: 'get'
+  })
+}
+export function GetContacterDocumentFileList (data) {
+  return request({
+    url: '/Contacter/GetContacterDocumentFileList?Id=' + data.Id + '&PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize,
+    method: 'get'
+  })
+}
+export function GetContacterOperationLogList (data) {
+  return request({
+    url: '/Contacter/GetContacterOperationLogList?Id=' + data.Id + '&PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize,
+    method: 'get'
+  })
+}
diff --git a/src/api/customermanagement/contract.js b/src/api/customermanagement/contract.js
new file mode 100644
index 0000000..2e42164
--- /dev/null
+++ b/src/api/customermanagement/contract.js
@@ -0,0 +1,62 @@
+import request from '@/utils/request'
+
+export function AddAgreement (data) {
+  return request({
+    url: '/Agreement/AddAgreement',
+    method: 'post',
+    data: data
+  })
+}
+export function UpdateAgreement (data) {
+  return request({
+    url: '/Agreement/UpdateAgreement',
+    method: 'post',
+    data: data
+  })
+}
+export function GetAgreementList (data) {
+  return request({
+    url: '/Agreement/GetAgreementList?SelectOwnedType=' + data.SelectOwnedType + '&AuditStatus=' + data.AuditStatus +
+     (data.BrachUserId
+       ? '&BrachUserId=' + data.BrachUserId : '') +
+    '&PageIndex=' + data.PageIndex +
+    '&PageSize=' + data.PageSize +
+    '&SealStatus=' + data.SealStatus +
+    '&Name=' + data.Name +
+    '&CreateStartTime=' + data.CreateStartTime +
+    '&CreateEndTime=' + data.CreateEndTime + (data.SealType
+      ? '&SealType=' + data.SealType : ''),
+    method: 'get'
+  })
+}
+export function DeleteAgreenment (data) {
+  return request({
+    url: '/Agreement/DeleteAgreenment',
+    method: 'post',
+    data: data
+  })
+}
+export function GetManagementAgreementList (data) {
+  return request({
+    url: '/Agreement/GetManagementAgreementList?SelectOwnedType=' + data.SelectOwnedType + '&AuditStatus=' + data.AuditStatus +
+    '&PageIndex=' + data.PageIndex +
+    '&PageSize=' + data.PageSize +
+    '&SealStatus=' + data.SealStatus +
+    '&Name=' + data.Name +
+    '&CreateStartTime=' + data.CreateStartTime +
+    '&CreateEndTime=' + data.CreateEndTime + (data.DepartmentUserType
+      ? '&DepartmentUserType=' + data.DepartmentUserType : '') +
+      (data.Id
+        ? '&Id=' + data.Id : '') +
+        (data.SealType
+          ? '&SealType=' + data.SealType : ''),
+    method: 'get'
+  })
+}
+export function AgreementToSeal (data) {
+  return request({
+    url: '/Agreement/AgreementToSeal',
+    method: 'post',
+    data: data
+  })
+}
diff --git a/src/api/customermanagement/customerManage.js b/src/api/customermanagement/customerManage.js
new file mode 100644
index 0000000..fe072ad
--- /dev/null
+++ b/src/api/customermanagement/customerManage.js
@@ -0,0 +1,125 @@
+import request from '@/utils/request'
+
+export function GetCustomerPageList (data) {
+  return request({
+    url: '/Customer/GetCustomerPageList?PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize +
+    '&SelectOwnedType=' + data.SelectOwnedType +
+     (data.BrachUserId
+       ? '&BrachUserId=' + data.BrachUserId : '') +
+    '&Name=' + data.Name +
+    '&CreateStartTime=' + data.CreateStartTime +
+    '&CreateEndTime=' + data.CreateEndTime +
+    '&StartFollowTime=' + data.StartFollowTime +
+    '&EndFolowTime=' + data.EndFolowTime +
+    (data.ProvinceCode ? '&ProvinceCode=' + data.ProvinceCode : '') +
+    (data.CustomerBusinessStatus
+      ? '&CustomerBusinessStatus=' + data.CustomerBusinessStatus : '') +
+    (data.CustomerSource ? '&CustomerSource=' + data.CustomerSource : '') + (data.CustomerType ? '&CustomerType=' + data.CustomerType : '') +
+    (data.CostomerCategory ? '&CostomerCategory=' + data.CostomerCategory : '') +
+    (data.CustomerIndustry ? '&CustomerIndustry=' + data.CustomerIndustry : '') +
+    (data.CompanyType ? '&CompanyType=' + data.CompanyType : ''),
+    method: 'get'
+  })
+}
+export function AddCustomer (data) {
+  return request({
+    url: '/Customer/AddCustomer',
+    method: 'post',
+    data: data
+  })
+}
+export function UpdateCustomer (data) {
+  return request({
+    url: '/Customer/UpdateCustomer',
+    method: 'post',
+    data: data
+  })
+}
+export function DeleteCustomer (data) {
+  return request({
+    url: '/Customer/DeleteCustomer',
+    method: 'post',
+    data: data
+  })
+}
+export function GetPersonalCustomerPageList (data) {
+  return request({
+    url: '/Customer/GetPersonalCustomerPageList?Name=' + data.Name + '&PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize,
+    method: 'get'
+  })
+}
+export function GetCustomerDetail (data) {
+  return request({
+    url: '/Customer/GetCustomerDetail?Id=' + data.Id,
+    method: 'get'
+  })
+}
+export function GetCustomerFollowRecordList (data) {
+  return request({
+    url: '/Customer/GetCustomerFollowRecordList?Id=' + data.Id + '&PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize,
+    method: 'get'
+  })
+}
+
+export function AddFollowRecord (data) {
+  return request({
+    url: '/FollowRecord/AddCustomerFollowRecord',
+    method: 'post',
+    data: data
+  })
+}
+export function MakeFollowRecordCompleted (data) {
+  return request({
+    url: '/FollowRecord/MakeFollowRecordCompleted',
+    method: 'post',
+    data: data
+  })
+}
+export function GetCustomerContacterList (data) {
+  return request({
+    url: '/Customer/GetCustomerContacterList?Id=' + data.Id + '&PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize,
+    method: 'get'
+  })
+}
+export function GetCustomerSalesChanceList (data) {
+  return request({
+    url: '/Customer/GetCustomerSalesChanceList?Id=' + data.Id + '&PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize,
+    method: 'get'
+  })
+}
+export function GetCustomerOrderList (data) {
+  return request({
+    url: '/Customer/GetCustomerOrderList?Id=' + data.Id + '&PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize,
+    method: 'get'
+  })
+}
+export function GetCustomerAgreenmentList (data) {
+  return request({
+    url: '/Customer/GetCustomerAgreenmentList?Id=' + data.Id + '&PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize,
+    method: 'get'
+  })
+}
+export function GetCustomerPaymentRecordList (data) {
+  return request({
+    url: '/Customer/GetCustomerPaymentRecordList?Id=' + data.Id + '&PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize,
+    method: 'get'
+  })
+}
+export function GetCustomerPaymentPlanList (data) {
+  return request({
+    url: '/Customer/GetCustomerPaymentPlanList?Id=' + data.Id + '&PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize,
+    method: 'get'
+  })
+}
+export function GetCustomerDocumentFileList (data) {
+  return request({
+    url: '/Customer/GetCustomerDocumentFileList?Id=' + data.Id + '&PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize,
+    method: 'get'
+  })
+}
+export function GetCustomerOperationLogList (data) {
+  return request({
+    url: '/Customer/GetCustomerOperationLogList?Id=' + data.Id + '&PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize,
+    method: 'get'
+  })
+}
diff --git a/src/api/customermanagement/offer.js b/src/api/customermanagement/offer.js
new file mode 100644
index 0000000..02cfb7c
--- /dev/null
+++ b/src/api/customermanagement/offer.js
@@ -0,0 +1,62 @@
+import request from '@/utils/request'
+
+export function AddQuatotationSheet (data) {
+  return request({
+    url: '/QuotationSheet/AddQuatotationSheet',
+    method: 'post',
+    data: data
+  })
+}
+export function UpdateQuotationSheet (data) {
+  return request({
+    url: '/QuotationSheet/UpdateQuotationSheet',
+    method: 'post',
+    data: data
+  })
+}
+
+export function GetQuotationSheetList (data) {
+  return request({
+    url: '/QuotationSheet/GetQuotationSheetList?SelectOwnedType=' + data.SelectOwnedType +
+     (data.BrachUserId
+       ? '&BrachUserId=' + data.BrachUserId : '') +
+    '&AuditStatus=' + data.AuditStatus +
+    '&PageIndex=' + data.PageIndex +
+    '&PageSize=' + data.PageSize +
+    '&SealStatus=' + data.SealStatus +
+    '&Name=' + data.Name +
+    '&CreateStartTime=' + data.CreateStartTime +
+    '&CreateEndTime=' + data.CreateEndTime,
+    method: 'get'
+  })
+}
+export function DeleteQuotationSheet (data) {
+  return request({
+    url: '/QuotationSheet/DeleteQuotationSheet',
+    method: 'post',
+    data: data
+  })
+}
+export function GetManagementQuotationSheetList (data) {
+  return request({
+    url: 'QuotationSheet/GetManagementQuotationSheetList?AuditStatus=' + data.AuditStatus +
+    '&PageIndex=' + data.PageIndex +
+    '&PageSize=' + data.PageSize +
+    '&SealStatus=' + data.SealStatus +
+    '&Name=' + data.Name +
+    '&CreateStartTime=' + data.CreateStartTime +
+    '&CreateEndTime=' + data.CreateEndTime +
+    (data.DepartmentUserType
+      ? '&DepartmentUserType=' + data.DepartmentUserType : '') +
+      (data.Id
+        ? '&Id=' + data.Id : ''),
+    method: 'get'
+  })
+}
+export function QuotationSheetToSeal (data) {
+  return request({
+    url: '/QuotationSheet/QuotationSheetToSeal',
+    method: 'post',
+    data: data
+  })
+}
diff --git a/src/api/customermanagement/product.js b/src/api/customermanagement/product.js
new file mode 100644
index 0000000..c0fd209
--- /dev/null
+++ b/src/api/customermanagement/product.js
@@ -0,0 +1,14 @@
+import request from '@/utils/request'
+
+export function GetAutoProductTypeList (data) {
+  return request({
+    url: '/Product/GetAutoProductTypeList',
+    method: 'get'
+  })
+}
+export function GetAutoProductListAsync (data) {
+  return request({
+    url: '/Product/GetAutoProductListAsync?' + (data.TypeName ? data.TypeName + '&' : '') + 'Name=' + data.Name + '&PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize,
+    method: 'get'
+  })
+}
diff --git a/src/api/login.js b/src/api/login.js
new file mode 100644
index 0000000..9265779
--- /dev/null
+++ b/src/api/login.js
@@ -0,0 +1,62 @@
+import request from '@/utils/request'
+
+export function requestverify (data) {
+  return request({
+    url: '/Account/Verify',
+    method: 'get'
+  })
+}
+
+export function CreateVerifyCode (token) {
+  return request({
+    url: '/Account/CreateVerifyCode?verify=' + token,
+    method: 'get',
+    responseType: 'arraybuffer'
+  })
+}
+
+export function requestLogin (data) {
+  return request({
+    url: '/Account/Login',
+    method: 'post',
+    data: data
+  })
+}
+
+export function FindPassword (data) {
+  return request({
+    url: '/Account/FindPassword',
+    method: 'post',
+    data: data
+  })
+}
+
+export function FindPasswordStep2 (data) {
+  return request({
+    url: '/Account/FindPasswordStep2',
+    method: 'post',
+    data: data
+  })
+}
+
+export function FindPasswordStep3 (data) {
+  return request({
+    url: '/Account/FindPasswordStep3',
+    method: 'post',
+    data: data
+  })
+}
+export function WxLogin (code) {
+  return request({
+    url: '/Account/WxLogin?code=' + code,
+    method: 'get'
+  })
+}
+
+export function CheckLogin (token) {
+  return request({
+    url: '/Account/CheckLogin',
+    method: 'post',
+    data: token
+  })
+}
diff --git a/src/api/moduleManage/moduleManage.js b/src/api/moduleManage/moduleManage.js
new file mode 100644
index 0000000..9366746
--- /dev/null
+++ b/src/api/moduleManage/moduleManage.js
@@ -0,0 +1,35 @@
+import request from '@/utils/request'
+
+export function GetSysModuleList (data) {
+  return request({
+    url: '/Module/GetSysModuleList',
+    method: 'get'
+  })
+}
+export function DeleteSysModule (data) {
+  return request({
+    url: '/Module/DeleteSysModule',
+    method: 'post',
+    data: data
+  })
+}
+export function AddSysModule (data) {
+  return request({
+    url: '/Module/AddSysModule',
+    method: 'post',
+    data: data
+  })
+}
+export function UpdateSysModule (data) {
+  return request({
+    url: '/Module/UpdateSysModule',
+    method: 'post',
+    data: data
+  })
+}
+export function GetCurrentUserModules (data) {
+  return request({
+    url: '/User/GetCurrentUserModules',
+    method: 'get'
+  })
+}
diff --git a/src/api/pwsApi/ewsAnalyze.js b/src/api/pwsApi/ewsAnalyze.js
new file mode 100644
index 0000000..0760c4d
--- /dev/null
+++ b/src/api/pwsApi/ewsAnalyze.js
@@ -0,0 +1,11 @@
+import request from '@/utils/request'
+
+export function InsightsMetrics (data) {
+  return request({
+    url: '/AutoDesk/insightsMetrics/query?' +
+    (data.CustomerCSN ? '&CustomerCSN=' + data.CustomerCSN : '') +
+    (data.ContractNumber ? '&ContractNumber=' + data.ContractNumber : '') +
+    (data.Plc ? '&Plc=' + data.Plc : ''),
+    method: 'get'
+  })
+}
diff --git a/src/api/pwsApi/subscriptions.js b/src/api/pwsApi/subscriptions.js
new file mode 100644
index 0000000..d2f4635
--- /dev/null
+++ b/src/api/pwsApi/subscriptions.js
@@ -0,0 +1,18 @@
+import request from '@/utils/request'
+
+export function ExportSubscriptionsTask (data) {
+  return request({
+    url: '/AutoDesk/create/export-subscriptions-task',
+    method: 'post',
+    data: data
+  })
+}
+export function GetSubscriptionsTask (data) {
+  return request({
+    url: '/AutoDesk/export-subscriptions-task/paged?PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize +
+    (data.StartTime ? '&StartTime=' + data.StartTime : '') +
+    (data.EndTime ? '&EndTime=' + data.EndTime : '') +
+    (data.TaskStatus ? '&TaskStatus=' + data.TaskStatus : ''),
+    method: 'get'
+  })
+}
diff --git a/src/api/systemManagement/departmentManage.js b/src/api/systemManagement/departmentManage.js
new file mode 100644
index 0000000..377372c
--- /dev/null
+++ b/src/api/systemManagement/departmentManage.js
@@ -0,0 +1,63 @@
+import request from '@/utils/request'
+
+// export function GetDepartmentList (data) {
+//   return request({
+//     url: '/Department/GetDepartmentList',
+//     method: 'get'
+//   })
+// }
+export function AddDepartment (data) {
+  return request({
+    url: '/Department/AddDepartment',
+    method: 'post',
+    data: data
+  })
+}
+export function DeleteDepartment (data) {
+  return request({
+    url: '/Department/DeleteDepartment',
+    method: 'post',
+    data: data
+  })
+}
+export function UpdateDepartment (data) {
+  return request({
+    url: '/Department/UpdateDepartment',
+    method: 'post',
+    data: data
+  })
+}
+
+export function GetDepartmentAreaList (data) {
+  return request({
+    url: '/Department/GetDepartmentAreaList',
+    method: 'get'
+  })
+}
+
+export function GetDepartmentUserChildList (data) {
+  return request({
+    url: '/Department/GetDepartmentUserChildList',
+    method: 'get'
+  })
+}
+export function GetSalesDepartmentUserChildList (data) {
+  return request({
+    url: '/Department/GetSalesDepartmentUserChildList',
+    method: 'get'
+  })
+}
+
+export function GetCurrentBranches (data) {
+  return request({
+    url: '/UserManager/GetCurrentBranches',
+    method: 'get'
+  })
+}
+
+export function GetDepartmentList (data) {
+  return request({
+    url: '/WxWork/GetDepartmentList',
+    method: 'get'
+  })
+}
diff --git a/src/api/systemManagement/employeeManage.js b/src/api/systemManagement/employeeManage.js
new file mode 100644
index 0000000..15716e6
--- /dev/null
+++ b/src/api/systemManagement/employeeManage.js
@@ -0,0 +1,62 @@
+import request from '@/utils/request'
+
+export function GetUserInfoPageList (data) {
+  return request({
+    url: '/UserManager/GetUserInfoPageList?PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize + '&DepartmentId=' + data.DepartmentId + '&PositionId=' + data.PositionId + '&RealName=' + data.RealName + '&MobilePhone=' + data.MobilePhone,
+    method: 'get'
+  })
+}
+export function GetUserInfoDepartmentList (data) {
+  return request({
+    url: '/UserManager/GetUserInfoDepartmentList',
+    method: 'get'
+  })
+}
+export function GetUserInfoPositionList (data) {
+  return request({
+    url: '/UserManager/GetUserInfoPositionList',
+    method: 'get'
+  })
+}
+export function AddUserInfo (data) {
+  return request({
+    url: '/UserManager/AddUserInfo',
+    method: 'post',
+    data: data
+  })
+}
+export function UpdateUserInfo (data) {
+  return request({
+    url: '/UserManager/UpdateUserInfo',
+    method: 'post',
+    data: data
+  })
+}
+export function DeleteUserInfo (data) {
+  return request({
+    url: '/UserManager/DeleteUserInfo',
+    method: 'post',
+    data: data
+  })
+}
+
+export function GetUserInfoList (data) {
+  return request({
+    url: '/WxWork/GetUserInfoList?DepartmentId=' + data.DepartmentId + '&RealName=' + data.RealName + '&MobilePhone=' + data.MobilePhone + '&PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize,
+    method: 'get'
+  })
+}
+export function UpdateUserPostion (data) {
+  return request({
+    url: '/UserManager/UpdateUserPostion',
+    method: 'post',
+    data: data
+  })
+}
+export function BindUserSalesArea (data) {
+  return request({
+    url: '/UserManager/BindUserSalesArea',
+    method: 'post',
+    data: data
+  })
+}
diff --git a/src/api/systemManagement/log.js b/src/api/systemManagement/log.js
new file mode 100644
index 0000000..6683838
--- /dev/null
+++ b/src/api/systemManagement/log.js
@@ -0,0 +1,14 @@
+import request from '@/utils/request'
+
+export function GetOperationLogList (data) {
+  return request({
+    url: '/Log/GetOperationLogList?StartTime=' + data.StartTime + '&EndTime=' + data.EndTime + '&RealName=' + data.RealName + '&BusinessOperationType=' + data.BusinessOperationType + '&PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize,
+    method: 'get'
+  })
+}
+export function GetLoginRecordList (data) {
+  return request({
+    url: '/Log/GetLoginRecordList?StartTime=' + data.StartTime + '&EndTime=' + data.EndTime + '&RealName=' + data.RealName + '&PageIndex=' + data.PageIndex + '&PageSize=' + data.PageSize,
+    method: 'get'
+  })
+}
diff --git a/src/api/systemManagement/officalAuthority.js b/src/api/systemManagement/officalAuthority.js
new file mode 100644
index 0000000..4a49166
--- /dev/null
+++ b/src/api/systemManagement/officalAuthority.js
@@ -0,0 +1,42 @@
+import request from '@/utils/request'
+
+export function GetPositionList (data) {
+  return request({
+    url: '/Position/GetPositionList',
+    method: 'get'
+  })
+}
+export function AddPosition (data) {
+  return request({
+    url: '/Position/AddPosition',
+    method: 'post',
+    data: data
+  })
+}
+export function DeletePosition (data) {
+  return request({
+    url: '/Position/DeletePosition',
+    method: 'post',
+    data: data
+  })
+}
+export function UpdatePosition (data) {
+  return request({
+    url: '/Position/UpdatePosition',
+    method: 'post',
+    data: data
+  })
+}
+export function GetPositionModules (data) {
+  return request({
+    url: '/PositionModule/GetPositionModules?positionId=' + data.Id,
+    method: 'get'
+  })
+}
+export function UpdatePositionModules (data) {
+  return request({
+    url: '/PositionModule/UpdatePositionModules',
+    method: 'post',
+    data: data
+  })
+}
diff --git a/src/assets/401_images/1.gif b/src/assets/401_images/1.gif
new file mode 100644
index 0000000..06d3573
--- /dev/null
+++ b/src/assets/401_images/1.gif
Binary files differ
diff --git a/src/assets/401_images/401.gif b/src/assets/401_images/401.gif
new file mode 100644
index 0000000..cd6e0d9
--- /dev/null
+++ b/src/assets/401_images/401.gif
Binary files differ
diff --git a/src/assets/404_images/404.png b/src/assets/404_images/404.png
new file mode 100644
index 0000000..4516c49
--- /dev/null
+++ b/src/assets/404_images/404.png
Binary files differ
diff --git a/src/assets/404_images/404_cloud.png b/src/assets/404_images/404_cloud.png
new file mode 100644
index 0000000..c6281d0
--- /dev/null
+++ b/src/assets/404_images/404_cloud.png
Binary files differ
diff --git a/src/assets/aside/business.png b/src/assets/aside/business.png
new file mode 100644
index 0000000..88d0a6e
--- /dev/null
+++ b/src/assets/aside/business.png
Binary files differ
diff --git a/src/assets/aside/business_active.png b/src/assets/aside/business_active.png
new file mode 100644
index 0000000..51e1878
--- /dev/null
+++ b/src/assets/aside/business_active.png
Binary files differ
diff --git a/src/assets/aside/check.png b/src/assets/aside/check.png
new file mode 100644
index 0000000..200f1e9
--- /dev/null
+++ b/src/assets/aside/check.png
Binary files differ
diff --git a/src/assets/aside/company.png b/src/assets/aside/company.png
new file mode 100644
index 0000000..28ef38d
--- /dev/null
+++ b/src/assets/aside/company.png
Binary files differ
diff --git a/src/assets/aside/company_active.png b/src/assets/aside/company_active.png
new file mode 100644
index 0000000..efc1c1c
--- /dev/null
+++ b/src/assets/aside/company_active.png
Binary files differ
diff --git a/src/assets/aside/customer.png b/src/assets/aside/customer.png
new file mode 100644
index 0000000..54cba14
--- /dev/null
+++ b/src/assets/aside/customer.png
Binary files differ
diff --git a/src/assets/aside/customer_active.png b/src/assets/aside/customer_active.png
new file mode 100644
index 0000000..9ecd87b
--- /dev/null
+++ b/src/assets/aside/customer_active.png
Binary files differ
diff --git a/src/assets/aside/delete.png b/src/assets/aside/delete.png
new file mode 100644
index 0000000..5bcddcc
--- /dev/null
+++ b/src/assets/aside/delete.png
Binary files differ
diff --git a/src/assets/aside/dilivery.png b/src/assets/aside/dilivery.png
new file mode 100644
index 0000000..23a18d5
--- /dev/null
+++ b/src/assets/aside/dilivery.png
Binary files differ
diff --git a/src/assets/aside/export.png b/src/assets/aside/export.png
new file mode 100644
index 0000000..07f1cfe
--- /dev/null
+++ b/src/assets/aside/export.png
Binary files differ
diff --git a/src/assets/aside/financial.png b/src/assets/aside/financial.png
new file mode 100644
index 0000000..aaa7f04
--- /dev/null
+++ b/src/assets/aside/financial.png
Binary files differ
diff --git a/src/assets/aside/financial_active.png b/src/assets/aside/financial_active.png
new file mode 100644
index 0000000..52c1f3d
--- /dev/null
+++ b/src/assets/aside/financial_active.png
Binary files differ
diff --git a/src/assets/aside/import.png b/src/assets/aside/import.png
new file mode 100644
index 0000000..7a4f86c
--- /dev/null
+++ b/src/assets/aside/import.png
Binary files differ
diff --git a/src/assets/aside/order.png b/src/assets/aside/order.png
new file mode 100644
index 0000000..066d0ab
--- /dev/null
+++ b/src/assets/aside/order.png
Binary files differ
diff --git a/src/assets/aside/order_active.png b/src/assets/aside/order_active.png
new file mode 100644
index 0000000..275374b
--- /dev/null
+++ b/src/assets/aside/order_active.png
Binary files differ
diff --git a/src/assets/aside/personnel.png b/src/assets/aside/personnel.png
new file mode 100644
index 0000000..e1977fe
--- /dev/null
+++ b/src/assets/aside/personnel.png
Binary files differ
diff --git a/src/assets/aside/personnel_active.png b/src/assets/aside/personnel_active.png
new file mode 100644
index 0000000..b3057dd
--- /dev/null
+++ b/src/assets/aside/personnel_active.png
Binary files differ
diff --git a/src/assets/aside/product.png b/src/assets/aside/product.png
new file mode 100644
index 0000000..260e8d6
--- /dev/null
+++ b/src/assets/aside/product.png
Binary files differ
diff --git a/src/assets/aside/product_active.png b/src/assets/aside/product_active.png
new file mode 100644
index 0000000..e50fdfa
--- /dev/null
+++ b/src/assets/aside/product_active.png
Binary files differ
diff --git a/src/assets/aside/system.png b/src/assets/aside/system.png
new file mode 100644
index 0000000..eaeee7c
--- /dev/null
+++ b/src/assets/aside/system.png
Binary files differ
diff --git a/src/assets/aside/system_active.png b/src/assets/aside/system_active.png
new file mode 100644
index 0000000..8ed382b
--- /dev/null
+++ b/src/assets/aside/system_active.png
Binary files differ
diff --git a/src/assets/aside/total.png b/src/assets/aside/total.png
new file mode 100644
index 0000000..6650573
--- /dev/null
+++ b/src/assets/aside/total.png
Binary files differ
diff --git a/src/assets/aside/total_active.png b/src/assets/aside/total_active.png
new file mode 100644
index 0000000..5478304
--- /dev/null
+++ b/src/assets/aside/total_active.png
Binary files differ
diff --git a/src/assets/aside/workbench.png b/src/assets/aside/workbench.png
new file mode 100644
index 0000000..d713ea1
--- /dev/null
+++ b/src/assets/aside/workbench.png
Binary files differ
diff --git a/src/assets/aside/workbench_active.png b/src/assets/aside/workbench_active.png
new file mode 100644
index 0000000..f16f534
--- /dev/null
+++ b/src/assets/aside/workbench_active.png
Binary files differ
diff --git a/src/assets/css/normalize.css b/src/assets/css/normalize.css
new file mode 100644
index 0000000..36fe817
--- /dev/null
+++ b/src/assets/css/normalize.css
@@ -0,0 +1,460 @@
+/*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */
+
+
+/* Document
+   ========================================================================== */
+
+html,
+body,
+#app {
+    height: 100%;
+    margin: 0;
+    padding: 0;
+}
+
+#app {
+    /*min-width: 1366px;*/
+}
+
+.el-breadcrumb {
+    margin-bottom: 15px;
+    font-size: 12px;
+}
+
+.el-card {
+    box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15) !important;
+}
+
+.el-table {
+    margin-top: 15px;
+    font-size: 12px;
+}
+
+.el-pagination {
+    margin-top: 15px;
+}
+
+.ql-editor {
+    min-height: 300px;
+}
+
+.el-scrollbar__wrap {
+    overflow-x: hidden;
+}
+
+.el-scrollbar .el-scrollbar__wrap {
+    overflow-x: hidden;
+}
+
+
+/**
+ * 1. Correct the line height in all browsers.
+ * 2. Prevent adjustments of font size after orientation changes in iOS.
+ */
+
+html {
+    line-height: 1.15;
+    /* 1 */
+    -webkit-text-size-adjust: 100%;
+    /* 2 */
+}
+
+
+/* Sections
+   ========================================================================== */
+
+
+/**
+ * Remove the margin in all browsers.
+ */
+
+body {
+    margin: 0;
+}
+
+ul,
+li {
+    padding: 0;
+    margin: 0;
+    list-style: none;
+}
+
+
+/**
+ * Correct the font size and margin on `h1` elements within `section` and
+ * `article` contexts in Chrome, Firefox, and Safari.
+ */
+
+h1 {
+    font-size: 2em;
+    margin: 0.67em 0;
+}
+
+
+/* Grouping content
+   ========================================================================== */
+
+
+/**
+ * 1. Add the correct box sizing in Firefox.
+ * 2. Show the overflow in Edge and IE.
+ */
+
+hr {
+    box-sizing: content-box;
+    /* 1 */
+    height: 0;
+    /* 1 */
+    overflow: visible;
+    /* 2 */
+}
+
+
+/**
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
+ */
+
+pre {
+    font-family: monospace, monospace;
+    /* 1 */
+    font-size: 1em;
+    /* 2 */
+}
+
+
+/* Text-level semantics
+   ========================================================================== */
+
+
+/**
+ * Remove the gray background on active links in IE 10.
+ */
+
+a {
+    background-color: transparent;
+    text-decoration: none;
+}
+
+
+/**
+ * 1. Remove the bottom border in Chrome 57-
+ * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
+ */
+
+abbr[title] {
+    border-bottom: none;
+    /* 1 */
+    text-decoration: underline;
+    /* 2 */
+    text-decoration: underline dotted;
+    /* 2 */
+}
+
+
+/**
+ * Add the correct font weight in Chrome, Edge, and Safari.
+ */
+
+b,
+strong {
+    font-weight: bolder;
+}
+
+
+/**
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
+ */
+
+code,
+kbd,
+samp {
+    font-family: monospace, monospace;
+    /* 1 */
+    font-size: 1em;
+    /* 2 */
+}
+
+
+/**
+ * Add the correct font size in all browsers.
+ */
+
+small {
+    font-size: 80%;
+}
+
+
+/**
+ * Prevent `sub` and `sup` elements from affecting the line height in
+ * all browsers.
+ */
+
+sub,
+sup {
+    font-size: 75%;
+    line-height: 0;
+    position: relative;
+    vertical-align: baseline;
+}
+
+sub {
+    bottom: -0.25em;
+}
+
+sup {
+    top: -0.5em;
+}
+
+
+/* Embedded content
+   ========================================================================== */
+
+
+/**
+ * Remove the border on images inside links in IE 10.
+ */
+
+img {
+    border-style: none;
+}
+
+
+/* Forms
+   ========================================================================== */
+
+
+/**
+ * 1. Change the font styles in all browsers.
+ * 2. Remove the margin in Firefox and Safari.
+ */
+
+button,
+input,
+optgroup,
+select,
+textarea {
+    font-family: inherit;
+    /* 1 */
+    font-size: 100%;
+    /* 1 */
+    line-height: 1.15;
+    /* 1 */
+    margin: 0;
+    /* 2 */
+}
+
+
+/**
+ * Show the overflow in IE.
+ * 1. Show the overflow in Edge.
+ */
+
+button,
+input {
+    /* 1 */
+    overflow: visible;
+}
+
+
+/**
+ * Remove the inheritance of text transform in Edge, Firefox, and IE.
+ * 1. Remove the inheritance of text transform in Firefox.
+ */
+
+button,
+select {
+    /* 1 */
+    text-transform: none;
+}
+
+
+/**
+ * Correct the inability to style clickable types in iOS and Safari.
+ */
+
+button,
+[type="button"],
+[type="reset"],
+[type="submit"] {
+    -webkit-appearance: button;
+}
+
+
+/**
+ * Remove the inner border and padding in Firefox.
+ */
+
+button::-moz-focus-inner,
+[type="button"]::-moz-focus-inner,
+[type="reset"]::-moz-focus-inner,
+[type="submit"]::-moz-focus-inner {
+    border-style: none;
+    padding: 0;
+}
+
+
+/**
+ * Restore the focus styles unset by the previous rule.
+ */
+
+button:-moz-focusring,
+[type="button"]:-moz-focusring,
+[type="reset"]:-moz-focusring,
+[type="submit"]:-moz-focusring {
+    outline: 1px dotted ButtonText;
+}
+
+
+/**
+ * Correct the padding in Firefox.
+ */
+
+fieldset {
+    padding: 0.35em 0.75em 0.625em;
+}
+
+
+/**
+ * 1. Correct the text wrapping in Edge and IE.
+ * 2. Correct the color inheritance from `fieldset` elements in IE.
+ * 3. Remove the padding so developers are not caught out when they zero out
+ *    `fieldset` elements in all browsers.
+ */
+
+legend {
+    box-sizing: border-box;
+    /* 1 */
+    color: inherit;
+    /* 2 */
+    display: table;
+    /* 1 */
+    max-width: 100%;
+    /* 1 */
+    padding: 0;
+    /* 3 */
+    white-space: normal;
+    /* 1 */
+}
+
+
+/**
+ * Add the correct vertical alignment in Chrome, Firefox, and Opera.
+ */
+
+progress {
+    vertical-align: baseline;
+}
+
+
+/**
+ * Remove the default vertical scrollbar in IE 10+.
+ */
+
+textarea {
+    overflow: auto;
+}
+
+
+/**
+ * 1. Add the correct box sizing in IE 10.
+ * 2. Remove the padding in IE 10.
+ */
+
+[type="checkbox"],
+[type="radio"] {
+    box-sizing: border-box;
+    /* 1 */
+    padding: 0;
+    /* 2 */
+}
+
+
+/**
+ * Correct the cursor style of increment and decrement buttons in Chrome.
+ */
+
+[type="number"]::-webkit-inner-spin-button,
+[type="number"]::-webkit-outer-spin-button {
+    height: auto;
+}
+
+
+/**
+ * 1. Correct the odd appearance in Chrome and Safari.
+ * 2. Correct the outline style in Safari.
+ */
+
+[type="search"] {
+    -webkit-appearance: textfield;
+    /* 1 */
+    outline-offset: -2px;
+    /* 2 */
+}
+
+
+/**
+ * Remove the inner padding in Chrome and Safari on macOS.
+ */
+
+[type="search"]::-webkit-search-decoration {
+    -webkit-appearance: none;
+}
+
+
+/**
+ * 1. Correct the inability to style clickable types in iOS and Safari.
+ * 2. Change font properties to `inherit` in Safari.
+ */
+
+::-webkit-file-upload-button {
+    -webkit-appearance: button;
+    /* 1 */
+    font: inherit;
+    /* 2 */
+}
+
+
+/* Interactive
+   ========================================================================== */
+
+
+/*
+ * Add the correct display in Edge, IE 10+, and Firefox.
+ */
+
+details {
+    display: block;
+}
+
+
+/*
+ * Add the correct display in all browsers.
+ */
+
+summary {
+    display: list-item;
+}
+
+
+/* Misc
+   ========================================================================== */
+
+
+/**
+ * Add the correct display in IE 10+.
+ */
+
+template {
+    display: none;
+}
+
+
+/**
+ * Add the correct display in IE 10.
+ */
+
+[hidden] {
+    display: none;
+}
\ No newline at end of file
diff --git a/src/assets/fonts/demo.css b/src/assets/fonts/demo.css
new file mode 100644
index 0000000..a67054a
--- /dev/null
+++ b/src/assets/fonts/demo.css
@@ -0,0 +1,539 @@
+/* Logo 字体 */
+@font-face {
+  font-family: "iconfont logo";
+  src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
+  src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
+}
+
+.logo {
+  font-family: "iconfont logo";
+  font-size: 160px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+/* tabs */
+.nav-tabs {
+  position: relative;
+}
+
+.nav-tabs .nav-more {
+  position: absolute;
+  right: 0;
+  bottom: 0;
+  height: 42px;
+  line-height: 42px;
+  color: #666;
+}
+
+#tabs {
+  border-bottom: 1px solid #eee;
+}
+
+#tabs li {
+  cursor: pointer;
+  width: 100px;
+  height: 40px;
+  line-height: 40px;
+  text-align: center;
+  font-size: 16px;
+  border-bottom: 2px solid transparent;
+  position: relative;
+  z-index: 1;
+  margin-bottom: -1px;
+  color: #666;
+}
+
+
+#tabs .active {
+  border-bottom-color: #f00;
+  color: #222;
+}
+
+.tab-container .content {
+  display: none;
+}
+
+/* 页面布局 */
+.main {
+  padding: 30px 100px;
+  width: 960px;
+  margin: 0 auto;
+}
+
+.main .logo {
+  color: #333;
+  text-align: left;
+  margin-bottom: 30px;
+  line-height: 1;
+  height: 110px;
+  margin-top: -50px;
+  overflow: hidden;
+  *zoom: 1;
+}
+
+.main .logo a {
+  font-size: 160px;
+  color: #333;
+}
+
+.helps {
+  margin-top: 40px;
+}
+
+.helps pre {
+  padding: 20px;
+  margin: 10px 0;
+  border: solid 1px #e7e1cd;
+  background-color: #fffdef;
+  overflow: auto;
+}
+
+.icon_lists {
+  width: 100% !important;
+  overflow: hidden;
+  *zoom: 1;
+}
+
+.icon_lists li {
+  width: 100px;
+  margin-bottom: 10px;
+  margin-right: 20px;
+  text-align: center;
+  list-style: none !important;
+  cursor: default;
+}
+
+.icon_lists li .code-name {
+  line-height: 1.2;
+}
+
+.icon_lists .icon {
+  display: block;
+  height: 100px;
+  line-height: 100px;
+  font-size: 42px;
+  margin: 10px auto;
+  color: #333;
+  -webkit-transition: font-size 0.25s linear, width 0.25s linear;
+  -moz-transition: font-size 0.25s linear, width 0.25s linear;
+  transition: font-size 0.25s linear, width 0.25s linear;
+}
+
+.icon_lists .icon:hover {
+  font-size: 100px;
+}
+
+.icon_lists .svg-icon {
+  /* 通过设置 font-size 来改变图标大小 */
+  width: 1em;
+  /* 图标和文字相邻时,垂直对齐 */
+  vertical-align: -0.15em;
+  /* 通过设置 color 来改变 SVG 的颜色/fill */
+  fill: currentColor;
+  /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
+      normalize.css 中也包含这行 */
+  overflow: hidden;
+}
+
+.icon_lists li .name,
+.icon_lists li .code-name {
+  color: #666;
+}
+
+/* markdown 样式 */
+.markdown {
+  color: #666;
+  font-size: 14px;
+  line-height: 1.8;
+}
+
+.highlight {
+  line-height: 1.5;
+}
+
+.markdown img {
+  vertical-align: middle;
+  max-width: 100%;
+}
+
+.markdown h1 {
+  color: #404040;
+  font-weight: 500;
+  line-height: 40px;
+  margin-bottom: 24px;
+}
+
+.markdown h2,
+.markdown h3,
+.markdown h4,
+.markdown h5,
+.markdown h6 {
+  color: #404040;
+  margin: 1.6em 0 0.6em 0;
+  font-weight: 500;
+  clear: both;
+}
+
+.markdown h1 {
+  font-size: 28px;
+}
+
+.markdown h2 {
+  font-size: 22px;
+}
+
+.markdown h3 {
+  font-size: 16px;
+}
+
+.markdown h4 {
+  font-size: 14px;
+}
+
+.markdown h5 {
+  font-size: 12px;
+}
+
+.markdown h6 {
+  font-size: 12px;
+}
+
+.markdown hr {
+  height: 1px;
+  border: 0;
+  background: #e9e9e9;
+  margin: 16px 0;
+  clear: both;
+}
+
+.markdown p {
+  margin: 1em 0;
+}
+
+.markdown>p,
+.markdown>blockquote,
+.markdown>.highlight,
+.markdown>ol,
+.markdown>ul {
+  width: 80%;
+}
+
+.markdown ul>li {
+  list-style: circle;
+}
+
+.markdown>ul li,
+.markdown blockquote ul>li {
+  margin-left: 20px;
+  padding-left: 4px;
+}
+
+.markdown>ul li p,
+.markdown>ol li p {
+  margin: 0.6em 0;
+}
+
+.markdown ol>li {
+  list-style: decimal;
+}
+
+.markdown>ol li,
+.markdown blockquote ol>li {
+  margin-left: 20px;
+  padding-left: 4px;
+}
+
+.markdown code {
+  margin: 0 3px;
+  padding: 0 5px;
+  background: #eee;
+  border-radius: 3px;
+}
+
+.markdown strong,
+.markdown b {
+  font-weight: 600;
+}
+
+.markdown>table {
+  border-collapse: collapse;
+  border-spacing: 0px;
+  empty-cells: show;
+  border: 1px solid #e9e9e9;
+  width: 95%;
+  margin-bottom: 24px;
+}
+
+.markdown>table th {
+  white-space: nowrap;
+  color: #333;
+  font-weight: 600;
+}
+
+.markdown>table th,
+.markdown>table td {
+  border: 1px solid #e9e9e9;
+  padding: 8px 16px;
+  text-align: left;
+}
+
+.markdown>table th {
+  background: #F7F7F7;
+}
+
+.markdown blockquote {
+  font-size: 90%;
+  color: #999;
+  border-left: 4px solid #e9e9e9;
+  padding-left: 0.8em;
+  margin: 1em 0;
+}
+
+.markdown blockquote p {
+  margin: 0;
+}
+
+.markdown .anchor {
+  opacity: 0;
+  transition: opacity 0.3s ease;
+  margin-left: 8px;
+}
+
+.markdown .waiting {
+  color: #ccc;
+}
+
+.markdown h1:hover .anchor,
+.markdown h2:hover .anchor,
+.markdown h3:hover .anchor,
+.markdown h4:hover .anchor,
+.markdown h5:hover .anchor,
+.markdown h6:hover .anchor {
+  opacity: 1;
+  display: inline-block;
+}
+
+.markdown>br,
+.markdown>p>br {
+  clear: both;
+}
+
+
+.hljs {
+  display: block;
+  background: white;
+  padding: 0.5em;
+  color: #333333;
+  overflow-x: auto;
+}
+
+.hljs-comment,
+.hljs-meta {
+  color: #969896;
+}
+
+.hljs-string,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-strong,
+.hljs-emphasis,
+.hljs-quote {
+  color: #df5000;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-type {
+  color: #a71d5d;
+}
+
+.hljs-literal,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-attribute {
+  color: #0086b3;
+}
+
+.hljs-section,
+.hljs-name {
+  color: #63a35c;
+}
+
+.hljs-tag {
+  color: #333333;
+}
+
+.hljs-title,
+.hljs-attr,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-selector-attr,
+.hljs-selector-pseudo {
+  color: #795da3;
+}
+
+.hljs-addition {
+  color: #55a532;
+  background-color: #eaffea;
+}
+
+.hljs-deletion {
+  color: #bd2c00;
+  background-color: #ffecec;
+}
+
+.hljs-link {
+  text-decoration: underline;
+}
+
+/* 代码高亮 */
+/* PrismJS 1.15.0
+https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
+/**
+ * prism.js default theme for JavaScript, CSS and HTML
+ * Based on dabblet (http://dabblet.com)
+ * @author Lea Verou
+ */
+code[class*="language-"],
+pre[class*="language-"] {
+  color: black;
+  background: none;
+  text-shadow: 0 1px white;
+  font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
+  text-align: left;
+  white-space: pre;
+  word-spacing: normal;
+  word-break: normal;
+  word-wrap: normal;
+  line-height: 1.5;
+
+  -moz-tab-size: 4;
+  -o-tab-size: 4;
+  tab-size: 4;
+
+  -webkit-hyphens: none;
+  -moz-hyphens: none;
+  -ms-hyphens: none;
+  hyphens: none;
+}
+
+pre[class*="language-"]::-moz-selection,
+pre[class*="language-"] ::-moz-selection,
+code[class*="language-"]::-moz-selection,
+code[class*="language-"] ::-moz-selection {
+  text-shadow: none;
+  background: #b3d4fc;
+}
+
+pre[class*="language-"]::selection,
+pre[class*="language-"] ::selection,
+code[class*="language-"]::selection,
+code[class*="language-"] ::selection {
+  text-shadow: none;
+  background: #b3d4fc;
+}
+
+@media print {
+
+  code[class*="language-"],
+  pre[class*="language-"] {
+    text-shadow: none;
+  }
+}
+
+/* Code blocks */
+pre[class*="language-"] {
+  padding: 1em;
+  margin: .5em 0;
+  overflow: auto;
+}
+
+:not(pre)>code[class*="language-"],
+pre[class*="language-"] {
+  background: #f5f2f0;
+}
+
+/* Inline code */
+:not(pre)>code[class*="language-"] {
+  padding: .1em;
+  border-radius: .3em;
+  white-space: normal;
+}
+
+.token.comment,
+.token.prolog,
+.token.doctype,
+.token.cdata {
+  color: slategray;
+}
+
+.token.punctuation {
+  color: #999;
+}
+
+.namespace {
+  opacity: .7;
+}
+
+.token.property,
+.token.tag,
+.token.boolean,
+.token.number,
+.token.constant,
+.token.symbol,
+.token.deleted {
+  color: #905;
+}
+
+.token.selector,
+.token.attr-name,
+.token.string,
+.token.char,
+.token.builtin,
+.token.inserted {
+  color: #690;
+}
+
+.token.operator,
+.token.entity,
+.token.url,
+.language-css .token.string,
+.style .token.string {
+  color: #9a6e3a;
+  background: hsla(0, 0%, 100%, .5);
+}
+
+.token.atrule,
+.token.attr-value,
+.token.keyword {
+  color: #07a;
+}
+
+.token.function,
+.token.class-name {
+  color: #DD4A68;
+}
+
+.token.regex,
+.token.important,
+.token.variable {
+  color: #e90;
+}
+
+.token.important,
+.token.bold {
+  font-weight: bold;
+}
+
+.token.italic {
+  font-style: italic;
+}
+
+.token.entity {
+  cursor: help;
+}
diff --git a/src/assets/fonts/demo_index.html b/src/assets/fonts/demo_index.html
new file mode 100644
index 0000000..4547c70
--- /dev/null
+++ b/src/assets/fonts/demo_index.html
@@ -0,0 +1,329 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8"/>
+  <title>IconFont Demo</title>
+  <link rel="shortcut icon" href="https://img.alicdn.com/tps/i4/TB1_oz6GVXXXXaFXpXXJDFnIXXX-64-64.ico" type="image/x-icon"/>
+  <link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
+  <link rel="stylesheet" href="demo.css">
+  <link rel="stylesheet" href="iconfont.css">
+  <script src="iconfont.js"></script>
+  <!-- jQuery -->
+  <script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
+  <!-- 代码高亮 -->
+  <script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
+</head>
+<body>
+  <div class="main">
+    <h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">&#xe86b;</a></h1>
+    <div class="nav-tabs">
+      <ul id="tabs" class="dib-box">
+        <li class="dib active"><span>Unicode</span></li>
+        <li class="dib"><span>Font class</span></li>
+        <li class="dib"><span>Symbol</span></li>
+      </ul>
+      
+    </div>
+    <div class="tab-container">
+      <div class="content unicode" style="display: block;">
+          <ul class="icon_lists dib-box">
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xea3f;</span>
+                <div class="name">show-password </div>
+                <div class="code-name">&amp;#xea3f;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe830;</span>
+                <div class="name">user</div>
+                <div class="code-name">&amp;#xe830;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xa;</span>
+                <div class="name">users</div>
+                <div class="code-name">&amp;#xa;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe8c9;</span>
+                <div class="name">225默认头像</div>
+                <div class="code-name">&amp;#xe8c9;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe902;</span>
+                <div class="name">406报表</div>
+                <div class="code-name">&amp;#xe902;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe734;</span>
+                <div class="name">password</div>
+                <div class="code-name">&amp;#xe734;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe6af;</span>
+                <div class="name">lock-fill</div>
+                <div class="code-name">&amp;#xe6af;</div>
+              </li>
+          
+          </ul>
+          <div class="article markdown">
+          <h2 id="unicode-">Unicode 引用</h2>
+          <hr>
+
+          <p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
+          <ul>
+            <li>兼容性最好,支持 IE6+,及所有现代浏览器。</li>
+            <li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
+            <li>但是因为是字体,所以不支持多色。只能使用平台里单色的图标,就算项目里有多色图标也会自动去色。</li>
+          </ul>
+          <blockquote>
+            <p>注意:新版 iconfont 支持多色图标,这些多色图标在 Unicode 模式下将不能使用,如果有需求建议使用symbol 的引用方式</p>
+          </blockquote>
+          <p>Unicode 使用步骤如下:</p>
+          <h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3>
+<pre><code class="language-css"
+>@font-face {
+  font-family: 'iconfont';
+  src: url('iconfont.eot');
+  src: url('iconfont.eot?#iefix') format('embedded-opentype'),
+      url('iconfont.woff2') format('woff2'),
+      url('iconfont.woff') format('woff'),
+      url('iconfont.ttf') format('truetype'),
+      url('iconfont.svg#iconfont') format('svg');
+}
+</code></pre>
+          <h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
+<pre><code class="language-css"
+>.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+</code></pre>
+          <h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
+<pre>
+<code class="language-html"
+>&lt;span class="iconfont"&gt;&amp;#x33;&lt;/span&gt;
+</code></pre>
+          <blockquote>
+            <p>"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
+          </blockquote>
+          </div>
+      </div>
+      <div class="content font-class">
+        <ul class="icon_lists dib-box">
+          
+          <li class="dib">
+            <span class="icon iconfont icon-showpassword"></span>
+            <div class="name">
+              show-password 
+            </div>
+            <div class="code-name">.icon-showpassword
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-user"></span>
+            <div class="name">
+              user
+            </div>
+            <div class="code-name">.icon-user
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-users"></span>
+            <div class="name">
+              users
+            </div>
+            <div class="code-name">.icon-users
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-morentouxiang"></span>
+            <div class="name">
+              225默认头像
+            </div>
+            <div class="code-name">.icon-morentouxiang
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-baobiao"></span>
+            <div class="name">
+              406报表
+            </div>
+            <div class="code-name">.icon-baobiao
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-password"></span>
+            <div class="name">
+              password
+            </div>
+            <div class="code-name">.icon-password
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont icon-lock-fill"></span>
+            <div class="name">
+              lock-fill
+            </div>
+            <div class="code-name">.icon-lock-fill
+            </div>
+          </li>
+          
+        </ul>
+        <div class="article markdown">
+        <h2 id="font-class-">font-class 引用</h2>
+        <hr>
+
+        <p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p>
+        <p>与 Unicode 使用方式相比,具有如下特点:</p>
+        <ul>
+          <li>兼容性良好,支持 IE8+,及所有现代浏览器。</li>
+          <li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li>
+          <li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li>
+          <li>不过因为本质上还是使用的字体,所以多色图标还是不支持的。</li>
+        </ul>
+        <p>使用步骤如下:</p>
+        <h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3>
+<pre><code class="language-html">&lt;link rel="stylesheet" href="./iconfont.css"&gt;
+</code></pre>
+        <h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
+<pre><code class="language-html">&lt;span class="iconfont icon-xxx"&gt;&lt;/span&gt;
+</code></pre>
+        <blockquote>
+          <p>"
+            iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
+        </blockquote>
+      </div>
+      </div>
+      <div class="content symbol">
+          <ul class="icon_lists dib-box">
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-showpassword"></use>
+                </svg>
+                <div class="name">show-password </div>
+                <div class="code-name">#icon-showpassword</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-user"></use>
+                </svg>
+                <div class="name">user</div>
+                <div class="code-name">#icon-user</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-users"></use>
+                </svg>
+                <div class="name">users</div>
+                <div class="code-name">#icon-users</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-morentouxiang"></use>
+                </svg>
+                <div class="name">225默认头像</div>
+                <div class="code-name">#icon-morentouxiang</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-baobiao"></use>
+                </svg>
+                <div class="name">406报表</div>
+                <div class="code-name">#icon-baobiao</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-password"></use>
+                </svg>
+                <div class="name">password</div>
+                <div class="code-name">#icon-password</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-lock-fill"></use>
+                </svg>
+                <div class="name">lock-fill</div>
+                <div class="code-name">#icon-lock-fill</div>
+            </li>
+          
+          </ul>
+          <div class="article markdown">
+          <h2 id="symbol-">Symbol 引用</h2>
+          <hr>
+
+          <p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
+            这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p>
+          <ul>
+            <li>支持多色图标了,不再受单色限制。</li>
+            <li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li>
+            <li>兼容性较差,支持 IE9+,及现代浏览器。</li>
+            <li>浏览器渲染 SVG 的性能一般,还不如 png。</li>
+          </ul>
+          <p>使用步骤如下:</p>
+          <h3 id="-symbol-">第一步:引入项目下面生成的 symbol 代码:</h3>
+<pre><code class="language-html">&lt;script src="./iconfont.js"&gt;&lt;/script&gt;
+</code></pre>
+          <h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3>
+<pre><code class="language-html">&lt;style&gt;
+.icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+&lt;/style&gt;
+</code></pre>
+          <h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
+<pre><code class="language-html">&lt;svg class="icon" aria-hidden="true"&gt;
+  &lt;use xlink:href="#icon-xxx"&gt;&lt;/use&gt;
+&lt;/svg&gt;
+</code></pre>
+          </div>
+      </div>
+
+    </div>
+  </div>
+  <script>
+  $(document).ready(function () {
+      $('.tab-container .content:first').show()
+
+      $('#tabs li').click(function (e) {
+        var tabContent = $('.tab-container .content')
+        var index = $(this).index()
+
+        if ($(this).hasClass('active')) {
+          return
+        } else {
+          $('#tabs li').removeClass('active')
+          $(this).addClass('active')
+
+          tabContent.hide().eq(index).fadeIn()
+        }
+      })
+    })
+  </script>
+</body>
+</html>
diff --git a/src/assets/fonts/iconfont.css b/src/assets/fonts/iconfont.css
new file mode 100644
index 0000000..e9ed551
--- /dev/null
+++ b/src/assets/fonts/iconfont.css
@@ -0,0 +1,341 @@
+@font-face {font-family: "wukong";
+  src: url('iconfont.eot?t=1565078640369'); /* IE9 */
+  src: url('iconfont.eot?t=1565078640369#iefix') format('embedded-opentype'), /* IE6-IE8 */
+  url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAADJoAAsAAAAAXbQAADIWAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCMcAqBmHT3DQE2AiQDgkQLgSQABCAFhFUHiTwbY0tlBGwcAGjbvoKiKImqGkXFppb9/9fk5HCF2uC/hwSOdMVcG2qjwSdWJOwjcCjn4yM+6YLV8EIlccvH1H1dFIjPSiWmaGIevJL6zGG2qESllo89YKIwk4Zxw33pP6JJjXtIUjSJiP347fuu0okMiZTxjNdIPgz+bdv7sLGBqJ52Q7JkzybP166d3geJtAAkoSTyO8YNgCFeN//eyNxAGCEghCVhDSUkhLEDCVNhJ5awFcI0cTBcCOIgaDXuEjr84thE/S2lBqVLRcHSiqMLcXVr4J86MxfFMIAdL+UwzepGsOKdgNT+vt/z/svtkz9JxV065FQSr0SkFe0yadPHoYV25ds5siynBsRl9+30qZI2Px/475fO/LMz3E+5omguli5/Tu3NIp5ARtIyuws28839tgdpv4oKonaCida/UDGLGvEofrcLGR61ucDgBGWZ9dylrlzNd9JPKq3WkLAh4YqgzfQPzG6s1m6PntgQID7MaWkM7d1IspPFA4AXIBgWMJtNDqmbj/2Vv5IcarptsHSYHBA6zuN9FwF/r6quhOhWJLtvZmodFl/WDGPGbMmw4H0AFB9AyAIoygIhngW6gnAhKCtHkC4qKZLCXKsVIOVCSckBKndiqpgqpbapDUsdc3umNeuWy5Y1y7iGJ34nSYIfwKJ6JydJoJPBQGjqhtjUC/znYGpTt83Pf8ZcPWltI3KlX0QcuC5vr2Fsa3b8HECJeWdkCqhxm1OcvU9Vgipmu7cCitdBUwqqAhEmqSlkXSMGLaOrv8plyZbxVXkrfvriv1XgASW8FGxH9fRKXgGOsqyBjX1elM7+/EYG5VAKcyhDySdybfGmSh1jTqmxVMuKsuCHMaTMzDiXBiUqrVHN6PXTh0+fPH0dppoaGyytjAorTvMrnrhIGQ2tWt/Cyfrv7NnGC8/uxEs2bNnxjvpwUj//N3mUOBUubdp16NSlW49effoNGDRk2IhRY8ZNmDRl2oxZc+YtWLRk2YpVa9Zt2LRl245de/YdOHRkw7ETp86cu1TqVcY1IX2u3bhz616134MnNRbTarM7NFNUAOy/daD0F3ueyTIbJYgnWkg2CqQIraQYbaQE7aQMHaQcnaQCXaQS3USDHrIGvUSLPlKNflKLAVKHQVKPIdKAYdKIEbIWo2QdxkgTxkkzJogOk6QFU6QV06QNM6Qds6QDc6QT82Q9Fogei8SAJbIBy2QjVsgmrJLNWCNdWCfd2CA92CS92CJbsE22Yodswy7Zjj2yA/ukDwdkJw5JP47IwCw/u4BjMogTshunZA/OyF6ck324JEMoRYy4IDdQhjxEObKACuQJKpHXqEL+wxV5h2vyHjfEhjt+A9zyG8I9v2FU4zeCR36jeOA3Bk/8Jm4iNFQt4oKqQyJQ9UgUqgGJw6aTYlQTosHRfGv+x3fFy4Wuzwbeb0fJGu9yVTDrBg8sg+kQiiO0e1McjBCEUyWeQkFwHaF7RJ/VUI2FiRqRsrkEdTA8lFXTOStj8xXMvpIrYU+GiNiNMUTLJxFiSyQYoO3sMqU2RfxlJpZBIhkqlJokKhKjnDetFCLRoBCndfYXicb1ihufSegmnbaAE05IwzloMHITRcIIoZDkmIzG3V5MG/OHw8HSSQ8vvOwHr3IsQAQItxQZiBkxA5wE+fSqFxj7Xb+RfL/43LqvdN22MVODcR9ETQ0hE44mxFApPSsskp+njNsIeBVAr7uYzSZR7ifHYM0IiZO3WegxkxVEMBgilGTeb0iyH50U8n6ynUk8RD8ZfjRS6biffPSnzRTbBsi6cKgo4A+B6Tg/i2yqHgQl0mFSGdMrzIEOXOZYmfTkhCU71z3JnmD6grMPzt+LOWhmPE0wU3NCmRmTqACGxLWokjjXWZTMIyT4ImQCBMebR43F7Cr/sDhhdvIekesv8afwYzODrir5PllC/scCBQPiJKM6kttQGX0V0k5aU4HnRL5s1x2mDGLet7hn8/jvZT+7YmaUA8aHPhLE3L5vhgBMGk5njxmkkbi0U4rtgL5/kvXST1onfvDbaC/9SaGTXwar/bNdBGBFiaBJjdkx4Qsitw503qSEwyX8uH3/4stETz7WhmcKtZ8KHQ5oS99HwXWuccMkTOq8fDqpaKNTJFlEoqS4GjdJBZ6AMwQME7bGxuYXEsykW5bqjJfkZ37e3qsFo3ARHDci12Y31HDUCK3hI1BmA5AJaWdnfkRYgXbzGP0wzQk64bw/aIYyL7iuksYpuyCrN7hHbWQ+05Wf1hp2WW/LizM8Kayb+9AdpdjphnKIN+2iNqprry08KngKxTThKTDkUlfOrAEfq5GbNKVwUfg/6yrv5oiNuVAlEDKKnPUFtgLFH3y8vYBo7tznksNejyI44MGgcEXOHag4lK5U/9lcVpFVbphv67r6ZUGNfSezFTVvyoww7ff7DR/+MdkxtEVMVviwBp7jyUjpkt0qfN7PwDrA2KGKYyAe1JuVURgP3xG8Ur4RoiTOCQ4rW8V0EOJ7QbXGMgFjWRYxLi5P+uW+ildXVPCjbWbOKC8DOlAJc9ChC3O0u8G1qzpv7Tkcl9OCAbwaOU0IbKkpDNM4xaQXaC8J0UdJs3XkSiAKs2iOARN9FzHv/CVER6QJUDpNYprxuCw4PKVWoK2+6bA8AhzklomyiV78zr99KeIN5iGMsRR5gU7kjO41zx5dEbYE2pNliN5y5VM1dUdQR8yOY3IVBoIr8SpB53eyM/6ptxZ/JdGkpkvDTJTDZfzyNUOq6I9F5Bc7CBycAhbQHRMsTncpp9p0jR7jYOQnXrRu1uPgeEuFmyRgXF8VW0J3hC41KzILtT/IJAqLyFOqS7XBcwCoYiPtuIFHxMMIVVTvxGD4BqG2sS9945XDk6YE5HtuQ5PzkHCdMkan4kvVUh8PgzSYtiC1OXslBbf34olPhdNDuBxKjyZTxpMyaKJJYngB9tGKphBrbGCUpUk8yoSAcWISBucN5UqVe8NCf44+hp/GuQwXPHXc3Aj0NcqZgt9GLU4aIHExJJN7m+opwQqc8Klj0do/sbb8mXP3c/9+lf0yy9LLNFW/9J87O3fKf8X6f0KD7w/JRjidcPXfUF81WC3fidCxE2O2XGoT3ExJdfZgg8uMWDMlaLsWAjXZc4QazKSAlmvXou1lNh60sgY8xIWgifQcXX24jpz8Z4B6qwDoNp3UN5ukQYhzT23QluXfvaoyzmvNUxkVA/DW5x4IIR1wKuA3mBf8pmUhajN9S66RK4mgaX9rJC1o8CiMtedPJCaT3mtv2mj+Rpod9PuFsyevAxOoumSqNsWgKlbWOH5H8gCMWEI6NpP2R/tYNMfvh6jQ7UsZTZQrXaEK7RHgu32GeXUVJKJq5dDkVCqDbno9PCOYsZt7Ztl7CNMkhKH1eWtdexJ7jH3A0pApTBW7yf2djGj12lWN94zXmf83CW8nWgg87UnkHKHQygTBmnf21ZHmGTMRDne9sa4mq37ZC/03bqy7peyjr5x+CpsDoPj4dsERSSlDaf9M5HfHpT9DHFjAPN9wZZjeyMwglK0m/V7C4Unfume08A25zhufK9fLg06fp0wfNHDolDJOEMwNzmlU5whJ1ESXBU1wjTd6Vz40gfAt1L5PV2uDHFChZVWRaAjflSJLSEds+NO9EhBVAiNQiK/k4BLxsz9jWZmB8jbXLwj3eoLTYep9R6NZ6CXfBdo9lcrI/iEEvsK468AJ9JklSC7NOfMvbKg5dM1Zxnzn9yjhUA6JGcfSNWWqNZeSs42GdFAi2Vc+EoZMxzD5FVAVVGPH3lyaoCtn3qRMFH4b0rW1Ay4hpUTTmEL0ekiiCORYcGXzossyNipXGxmqitwQyoy4fd44nIhinKoV0K4B+mG966cz9g20Na2q2Gi5VhOSNeGov7eaN8JG+ABWGMGosfMbOM+NMdmewwjjNqRd5Fie5NsMVIa21NYa/H7jQfdlFai9/qNk5lBrwurknubqjAG7NmJBTBmg7IhCWdubxxpI9Zx+8t1fMqIq2OIeCUWRghfAI+aoIP2TsB04URA2lQbGSF+gaXIsKcGUD8rlvSYpAoMBESnQuq5RmtIMaWt3gnEKCe7KwRVoF2/lGVVMibIuAu9K1ZTKeQxGXRXZK5XauDKcUboaTDEg1NdKSyVc9tOkm8a3pIk0ROZ2TTWoMdNpTRD0nUSVDMcp4JVEiaB5gZT+G8kTo7W6bzw78tIbcjc/qTaFQDPJ20LhxlCiYP4AdRZR2HI3drwyvkgeHLIOH7F3HSqZRw4/KwkeFAnxRQbevmdX+2fsZ+tX/G6OzC+IDj/v4q0jHKio8MvWSTFSZw4bcAtQ2mnV6KZySbq0i0byN7F1WTEmiKnnAJKMACQSTaCyDStjRItQItQ1MYcI/awGJxIQG0bDmdt+QOrIKAElehNhs0eaiSsV4dgRlcJFi1XNWYRPpNkozJtf6+a3+DtYZM1158PjqlErjzQjMDs7K7Utg8Zhs1Z4KRpLPikQZcbaI5KHS1SNpyxojBh3BFfHjOUQOUgLizk9NiS8N9Xwme0jVvtuH182vqy2XROmvQ6lbyPWmHJRrkBDaiIXnNhhLaWDWOFhYZezWTmaNBu+70589gcR+mA7UdSUEXAUGPqWH73SHKgM+sy/3GuyqLCYu3bssLOAf8oxm8UGh7hwLFhr794QgpMT7UAFe/sHvqNShksu/XOqUpSGyrP6KtVcu4pxSuGy1F1v9pHr/R++dIZa1fNrb934CZTq9zfnxxpz5x7LBNqSm5Ml7kT5Tqm2lhCoa6RjSlR4KxVJDwPtFUL0JQLsNRcFHa1CK9VDSllcDRJpIY0do6a2cEuOtzPqo88+uXTaZT3xS8aXC1swiUwyfQLG5s51/KTPfHjjUkDatOoJ9upmI0G5W64yG7NORsxkWcLJXww5ysGwfeoPhtPUbg2T0tSBHylxwc8Eb6uUDztTxR07Gw7GUwYazmTNETD1tCFGGmk4D9ov3du2axsybQqJFOCg/QBKST173vYE6rR1hlMx0K7V/T+nZULef3n1w30HsfbtJMtmo39Zpm3HdWCq9WRxRl/5VorqYdq5oUzD1lZV1da5Bv5wE4WD7I7yPZ494HQH/NlektqGNJgWpsOeXrT59ehgr7I8ZXUuR6lEhxHbTaQUizWrSX/O94LdV8Sj6Q2BpCeTrFWY0gb1zoEm1Uwww3D61pot3vsOGUKfYuKRMBr+oVOgTM/35G5vYzYlW4NIXSIZGduQFmbj2pK2Y5qy/amttLW1QBDu1YYgIn+Q4ZL0Vzw90uC1+nJaA6cmNd6uulD/baJiPZpRGRpNRJnbsZ1QuoHGOV1Id0T9Qbqtwr1h+JSDKtHWapPXCREDmdrkXaLK8lfB4WQNj3oVPc0gbAWRSeQoJv0L4brrPEpgMiCtIXfVjYQ+YzTVRaYbB87EFyImcZ6qBMpxRDhG3mhyfMywGphX2Ad585QqKpUdM9CTdZhSmAzuIG45xseUIx+VXknTLavnclC8YIeflhuPY6cQqcf9kk+kfh26gVfl076daa4Vgbx542JafbR330xrbMaK0dISNm3mPo2PJSHSM9+a8U1VNxwjklRkjDfXgH2K75SseAULl9omqqCXQOTz5Q6hmIlHnCgE8IFJSw/Rp2Ea6/WgkyMS5+amSJ0N170ZRyxoAIizZDFwofD7x2pzZuSDoMuYQYr1CcRV9tq7R2AdF+0FrOnFOLVLoQhH8dCVeiZQ4oQF0JpASEwDyBlecszCL3NlayhC1NFEXvy23yIOJWN36knwL/V1FfkvyagREBdympO1Z1sff75caZf+NOLqJio5KA7/dCcQ0XNc6DhUUXPVAe/gvb3HN3L/R5r2eyRdebdueDKYyZZ/NKW837Craxj7KS7KtP47Vxqmy5VE9p4wODmZDSYDKY2D7yInV/NGZ7wJxOmvwCccDq6XwjjvIHm4y6O5lfMoF1zrdlc9BouvkrZj82K8JJIVov62RBhIW72kX0O9zMViDlAIvyoPE9B5nV54g7XDu28MdubKCEuQDiFNLOzkq82pMsF+Tc/YrqYOFAgIv7IptUWBelgQLj0S96kK2JDJ7bgs7+0uTItwkR5Iu0RktYNvYwkQFZ+WUIK4lnlofWKchKcyx1pVD+sq21l2AcLagJFBWEqFuDSROAL0AasMNGlxfHde2MX2vOAQulvMnfbSEu1Pba852KNhpTnTMEujhMIrDvmkRkZZGwsbcmPNdAMBY3avlA9bOj+djovCH7B21UpULqPmARvIA83n4KORXZliFk++PFxTOOgXSWDR0O40LcET+U0NBOP5z/+XCo3KwHxciGLJuWhziREeNnPPcMzeJj0qmetCIbxi2wi56Q7jWqMlEp0cmE+dFtDguBLWKkuQcOhYJTW0aKzkf6nsunJRIcpW6NIcikm9P5AF3ynzYuwkkbpkU5hVhsZxWXbFwcSQF2WyqO5mNcmPLOcK4hK/r7+4UDYZM8AK9K5BaIazdkOk+998MflATsVsbcTvTKO+Gr3vsp9+q70fCKRpOdtgduzCNQjavRZbStcbieTS1orqycslg7clk8EqczYlhImWhCQoh5dkUAmX9wVN4lW9cqAWCq/BOr+kUopur+PccTHvkSgTbjIj1sK0tPldMsId9dvp+rbaEIEbCOVgZ10zNtE4mgXKr8C+b2t25p2t4ey1M1g1Ntqxo35Z0oef3i/1y7tH15K1NflfZOPDoiM+318xm7caiHcrGBmQbQqnIK3qlv/inuwSobBfcAVpR2pddbtqWySSdQbIHlikLLTGMns9WYL6IZ8DVdygEGw2drdGeOnpd03+fDzz5cM4a+3TI3OuEhyOyzMakmuUNcAmqDrssK1+dyn8A4FdCk+ND3UgRvSRibpV3/oFMCZSSjLzbxUZmN4Z27ySKcaB0Mnastvvbgo/X2IC6CDxp7tLsKLZj3+FY0aEZshENXcE0I4SNneJLhiF4/SbHguH/rvQxWhARirwet6Jfxu+q2zb+k4/0oJDrZfJnnjmna3//+LeadL/f2vTlv/+8e/A6d/fkXDib/WGflKzsriV9zuhxJ0a5OwG2yDwjuWjhPKbdfmQ0egTylf6iF8gJ5AX4v+E4drmbku0MovasUpcUlJDw7TFAfVX8pDA3xnNDLwV/JlYa3276+2tjPgzxSc7a3r82ZNbxIxmJg4TBcR0NQPHVEuNNQV9sU5vGnTY7Q3RST+FNgYVX1SoOZ7gXpzcOzczKfB5KbTBABVDJRv0pXCjVRZUAhVvMHz+Jb0HxsM9dHPZMjLpxJF7lh4n0JzdHptBmcuJ+iBcNy6oXozH1HsyjdJNBuQTlCVyN8VG4SAkwZudJ+u6YgoOe7OD/0IG76ruwU9DblxxwGGf00f5J+uivK+bnKI+uytA8SEBleHIoPILUmybhQrbPIMeFBRQ/CAxqPAGvMowAgLEQqqEygYZSc7zaxaDKktl4JHn63UFC64EYsZL7ODLb4BUGvQWiwLMiBlTQLQIjmDl8RZngXkca0h8vyb5sOkGevGCbNy502gXZGdsbZn88pT84QejjJa+W0nNxJLE3UoAkgbRteYKjnz1S5fqgJE9XKKvCMb1owtSxn2yQt+FlIUTcY/BmNqIEuTGbCAb3+mbiGKNIh5Je0t7321Y15/pz4lvawbhQADGDJcoekhUU25lTY30j/NTvJYLs2SSbOf5XExrO5JHcs6wbNs2VVCaicr4PcZSJ1xajDZIWMiKz3fxz8l7Dc79PuzqFL/M070wUCKDklanJIwI1qpjFTniRnhVb9EVGS0GWtyVFKWMq//Z5w3AHxHMZyYmYpodv1ckM9zudP5sP9lexDfk4JpCExIJrymMaULFZEdNcOed9Se6qhPwzcQg07xJxm86HVzfSQBRwneFurOB1weP61Lce8roqsFH8nL/pB3pN6l0B0D5TLQqVnKK4tNQg8V9lPYiRb611IqK52VQfj4kM5GSVMMVkedz73afHK8RXK8713xPc7wiqj1JRTJBsvx8txXzi/R50zxehS9yq+tN9cZftYhZtGssYjmZwOZ/Dn39Gj0HWnCo9TJIa/n7kTt3EIT2N0AtK44MGCQGKoPPmC7Ize179Q31ZE5abm7BdCRSY1kR7NkkaX8gGJ7O4vr9LAkumXnHlXZfvQmTe88MoX+4LU2brj1wgJYYIRGcW6wlPjKjL/RQUxDRFDi8dEZfpp/JvJAtppdeQeFiuXlekHLI10tNby4dNpDay+tF4NbWXjuI17KzbxHirXHmQc/Mp2hkTwrtlKfFRvmXtGS/RPoXZUg8JRDqiQKJmbJkb2OC1eQluyWydGAHSNt8M+1tM2j2vu0Rmz25vT0NBCBAcHl4yyW4kAwKKOUrBJtqybxkdeJ690KiRybm17hyBJexnPkpl5suVpcoO1P7VxYehglRhBwIf5MA0Qmc2SZz/X76/vpRCsGIP4A3u0Tfj6b9l9egKP0AnoH/mD6Kj9x8V4X2Mkbpo0Pj/qs3zgQICBqljkALmFy1UczsZSZYz0ohqwVKgFpYsk3/PXIQBnNyXfshg2voKlKyxoQ0ADSzUIImoJLCTBSMxjDbGR6pTaxOoeK0XxYtiOR9lJvf/3MnTzPohMl3yLQ2LnTW6D7mRpLivIkTIBQBMbD14oWPqbTRiPDLP768deGCajVOQmX4pZhMFMrBg/Rxm2mHWoVA3Ss7eg/jGqOHLhKxbldq/Rqzh2lnk6iStdmrYyEd046lg64BnYAbtx+pm8AtltntPPfu43d/lntoVMg+WEB449d7BruUD7V2ED2fjsGYnVXO5jJfdFI57Vdmn0Okq97ert1debvzIiOHnVVOlyIiUjLuRHVGyh2pt3eeAWzianjnTjhD1R3QzivjpCQ7zLOUWZacVMYq9QzLRqHE4uIf3zF7GXFN/dUQaYXgtNG565hwv8XSjzjt+4H7mTowHiORGIAEWEwzWGLGfbrFYJBYQp5ABBTmGATDQeFura2BfJnjQ0ed/Wpk/KCWluD4haDw5nB1uKYeHN07adGRJ8k6i8h5wjPgJ/GGSZ73gRiHj6L/ogAHQPmLjAuRtvvyekvS48tezD99gL30G+8ApT7+zqFDd+LrKQd4v77gHMBnCfd7x/mZAoysQ8sH9e6ozJC9d8XlOPmKMVIpu+ub212MJNwWl3v/hNS7uDRKD3W4bMUlMrpvf93FPkIdC9y+A0DSBfGd18WMAscOwPo7KIeDTqN3hHdG4AFoZFBYe86ir16hGTrXAcCWIeeQs5b0p9jpLRpScNXHRKewn1mAAwRSREMgB2a5Suw9aXBVf181PBQTMtAHVdE8/g5AVfBXPgVwSxOURyP+InycDYmHArKgheuRDjQ4T9dUAKdmqeDGelgJq7RMBeVAyyAVpMzIKZdBBXlAShrkO6At+XmQ1GnPBDb9DCoQoDOgAYdaL4Ny9PJV9L//UISuNkAtWws9MJnuGbo8rgDvCjCao+YA8JahFjphmmO8GGoGafNm0qCiXk8lREkSUAsrgc9uyEoXgR/pt0AiUAkrGe99fSz9E+Jpp+UgBdqjZyQwdR+WgjU1OtofIEfIx4OhBuEb+xoabqX+SiIz7DFmhwCH45gGBon0CKTM9B05cvDgtF53Rzd3dvrToFvrJqO9sb4+hwD0Np8EqKQYJH7/vXCG9qGb9w3AZrVIqyVfmbZcIasy+7x8VD7f6Q3mEbPeB3zPTUggvVcBvWqdEi8JRs3+Kh+VtzI+E9ze9oY74jfCxZ2MfkZOl2/lG/uxJo4a1ITS0gCMkZvEmytmuUZeUiUwAaWlBLVh1NBMiCY0H3lFsppumqxcK+kmySrOListS9zlsEFa8pmS1aoBKY1PHwi+IUAPPbp+nKvjDZ6D2kFmTNPVO4yZ4trSxM0VKVErfgV3rsY0xb9YW+eOK/wrzL1a8OFf2X+tS/4rWeol2UxUULOa6rNIjfiD25AmIJc2PB94xRxmVda6cqJq/EJ5YeBmH78yNSmjmaUxDhj7WdqMFjXpMmSzn1+5hqjQcTQpiXvfP/4YefoM/ZjS06eHTeizp8jHeJ+fPbMLPH26TvtetCh6sbPvvef7u3dfeL5wAyE/3Z6oFK8V3xus+h8IWXv9onv6VFmyqEfUre2ZtlJEFOt0j0WkMv8NjQuVUWZV3N8zcF3rsKbhl/JyZw7DJcKT7Rl2EBc5HijiZ5pZkqIkOTIhSm6/NBrZGB24hI10j5rzerutpCVKGLfcadXDCnmr804jEo24vbrYXNiEKaQabn9HQ8HjCfcU3jIoV8ie5wLmrZVXWf+MDWqViU4ljTzVoM8CcSicxiJfpbP8w+hDCz6qwUYetH+m5vzba/nnSyCHH6EnIcoQLiWt/dxPqPuNFlyt3aXll/wvL7/sYzISSUaTPsMkohG43uS0lPybXe7MDnchq1jbkOxAAR1Z2HVrHn4xuLac/DFZ8nllvr+EeLKTH3otjPuoluR3MpFYGlqz6NXc4eS9Nlj/+8/GP257t6EpqPvjCzrVuhJqvfH7W3q91T2xOlfM/BOo8rEMew8U3yL2FeTUWlYjS6nxLCDocf/iKPoqT6WmkfUBE80Iowk0rq33K7jwqm4MmkcOyR7/A7ZV1rtlpYKaOe8lRQSJUEQPDdmOFe1HH3xSQEmMHn4DX1wPQ4hXiNeerAPhKbwDpGrtRezGTClJXI76rs3KEAnXGqLs0Rux7OCCzdRNKyWqH7kZuKwkp4A2T85rPUxiftzvp+rI5xJ8g+if8QrgXGWma5wrV7QmG4N2fJebk/nlvNCegbMvonuEtGNFw8jDq8mURF8D/rtnwVILwmQU/YVV+Ef6Cx2FrAg0IGf0cKpX8jhJtn3jnzeQfSJKM8Zx2RrYC3G6kaNKLk4ns0cHKZJ1iQ9ZriCej3LmqMm+9HsJHji0mJWpd1oifEz8nUz59HdpensR0yDX/NPLAaWeIJQFj//lnum85zsgQAzTNhBwaFl1e+23bDKt/RqH9bsNpa9Zkx6COoDxnqllMn4cXwbk+miD644LytxdXOG9/F4QhJYYrKeMxGCi8ZR1OHiYeYNv1tM1SzEa1CoZllhRTcyShv5TCNeLcSs4seiz2N//A3au/p22euzM76I53A8JS1a1FUigky30Poulj96S3pKaxULvO3XKXsL9omrq4G5qdfNXCsXHzxO3xA0l7ElMHIrbbr/5/pO6jxWKr5qp1YO7q0sSRRKM8m5/xA0ZGNQ2dczLM/Rw+Z/qyFROdjs+jZhWX9YGnuvKSGm4tOz2FE6k+s9wuYBvqxwiGXO37D4zxnfYQCPmkWAn/REGRLPYwqoaj1BtCMDUOFdFzVcf+dRBJjv8BIQ/NjguSSS0CZok5qXqcWP/XPAjhxyHR8Fz/Y2PVS8lMaRZ4v/eYdHBbIsq4R08kCZzh32NmcmZRi7rwM4Ac78a301Q9w8cCN14tddZrpGbjIZlXHlTovK5Er7D3Oca2v7z7rz7bORZYyJPAgHi5nV5cyVPNwoqtlOdlc9gDLIdwcDPrvGlbq9Uj1byNgeFV/3BUWAwySjCijn13BTITlcoMBXbwaZddza6sJ5JCAGt4KB/dmCT7UjZ2WdkDAxMb0D6TVhYygyfnw3u3+enJKSSrZa8R5+JdZUJy7+fDGDysHMlLzLnsKN5JgIvlHeXF8IDMae81mtOpHmHNklBRQblBJLqQe47PLMp0j4oi0xKkPTWJ8CbSGgnCF3FL+LBk0Z6GSVLLmMcERwpDmk/5Kz5CFOr2cRbpTGlRuIbvkGO9PVqouW1DLVqHmPIwTS7+iub3FecExBYH3J2gbzeDVYKYAVSBv6nxOx0ogfR2tKC0shzvDlyGs4uqLBSx37Pai7VEivVzWZl60pKgkloGkmGJJVNpDm7WdPaxLvsP8r7+w/g1CwZPw0cWC4BsSsFQgo+JDVyWdK/fx20JHg+TPXZcRVVi7ITd4s/RLugDv+m1WEZ5j2TP8gerbUJhye8vdKiU+V2FKGdyOWzktjSWO80p68EqUQBmfNVqzj/LVYqqVfJVV+AtlUCY43UUf8obD1SnufBzefT5Pd1j1ddO3PKM7oGI3mbL279kkcUEF1Tv0pzNrFY1kZsiYuI8W1aoNVxqUxUFtk8Wn7PTcpN1rGKuJi/lup5/vNTThRKAHufYzDt/Do8CnETGHkuMXLW+DaHUuCt3QDZSWX2xUwC/lLQ/i8C6xyypfYBJn/u5+kuoYs5zPwEKJ46LdVv5LqJY0FeLhxrT7h5KPuDNol/trb10P95Mru6TA9OxhGv1fDp/xzpUvbYwYIjf2/cuT3NJzO97QPZzpt4e0ialyeF7otS7mMEAvQ+adHn5yVrODBWnLyiR+nrpW3StAH/yvaqZh/f3qyuvBzhysGkFdEtBNyOpwt6xE8wIhoRyPK2HtqNfxD3Sd7O/K7U1abq8/ZVhb3h9JBWL18tGPE0s1b7I0aREfFfzTJ7EpuAXTaLMRZ2cBukf7Q+fuHMTQbubOCNm8NRw5euhb4qmb538Zr5M8ybNys3yhs4LWg9OsYt51xBy921378+/ZvkpIgb2L2cevfHxHLuGFqNtksaxCmccvZvQPCtsETz6TcpviH5H2rDtfDfkW7SWjUCIUH5QQhdQkd02ZN3cjA5gKsWhp8417f713vp6OqxyUHLd5Q53CUPdbyp6p/Qn7vd8g1uVcIHnWS+h4+btjJc6hm/8dQFiyhhH2cyqv7GuUTE60PcKgoSSCUWlJMT1ldkoqfKAr6oPfpFzRe2iZcTKu9FPq1xk24lR5SJEhbEfHGPVw+bz+7hgGHG/HWOzksnuS7uYUPDLd0ado9XL1vDafHSgdNdjNezUVELP0dF31nJPn8u6zKwgstuLinGGMlQ7NDz51sk3TExI+kuxC8EiwmL8fZuwHp6KmhqyHZ/z4r1zJvG43fv2nE6QjoqjcGNTBo6qohWm5ryDv61wTliIFDDBlgt+F4FxDbkLmIT54h0g2pxrG6I9WS24gmQy/aJHIaVrr6sYqguq+lT9JxFpbgA0umgQifs581GNV29uFjJsDJU42pGpUJO+aG7ArWHWsBPxDTfZak91azx2auiHbvByBYUQrpmqJCcyohOpoO4oiIggVPH4YZ9+xqgRsheLtzwHoorKIiDZFBhAYh7wLZP4CdLl2XQfvUiXdtxY7MAboRTbb7eiSk+qqDLxvf+K4dYZsLWlLakj+JgpXgkTqZmLbLUc2+e+kZe9AYKxck8Wb9Ec43YXW1zxdRWKl4Gz0pqyB0IC7y7VthaYsaUmj2WjZVnRSoG6mmQM8+VH7xtl3Q2toX71DvOLRM/FojRYmznyoAEGPqADTzmEWgGXmNjRL0NF94XjrPVR2zOPAONwHsMJDH+I33gHB1jTDtGHkc8XrAPp2pYiFhYmGELt0TsMOc05jSYHROInnYY5j0dlHjDd4ItlwLqNVXPAzN1/hM24I0+CQM7hR315xexYOcDZZ+Z6NiC6P75Dsi47fzw+W1l2xHvkdkFMsuSy0Dm4e4bmrNN89FIe/MSBd9sfAIpamqyINJyBynOKUFmRne8Rzs0vPX8/pPDYFi7SRnd6dwluSUa1FmabE2WeugJlFVTnQUpIP+Ow1kfsDA/BS/nLZP/+dmFu+4/7XbmkEppH4GjH+LAaYP/qsJVxItSaCDgxMG/6Icb/EtqDnwnc/ZyTyR+vGfizOYATavg+n0QIK2LOyAfydddLHts0CwlDal+uZKTKzC2qnWxjnVqhsA11i1Dxi+ej5HawwmuckpPL50hYNAH8dhNVkp1rnBJprkfJHSvJBembCKZLgzg+toO/5l/Y2OX4d/tXDrvS9QrWfbYVS6MzHGVMuO8ktAvuXTutv+Uys+7GxuF3jIMmo1iPhHc6z/fG6dMvkiUHNQikAoJXxUziYWrinN7yhqXvCRY1KujEu7tgSohtUyVsBru6TmEKvGp+Nw6TrFRIsnf7z127I/nPd3nB9YpkGwE97NH8UhBQveqvR8RHfgeDg6+3+917I7LKzYTH1iUjpXTJd8Ggdd/HT92CkeJTA0ZhMhraE/27j729jWYGKh0VFqehBaN5CdsYq+P5ODBd3D83K7IjL9nUTlWTGMXzEx5+/euo1/8XXaaTdshg/JetIdkQtkIPACNSQXfaoPm1M5zEtlUnNz1FcdIH6QbOaGv4vp6VIIuu6W7KoBdw3FsipqVT8lHp+KmgC0GKCCtFlJY3uBE8NZmkwVS7FGG07vNwfeuL0mMy9tJfMf7pTAUM4UrkORqYMzOpGz5++5s7Xzvyt752tl3ypaUmdmBVS+XtU6qLUrnwWSSIP1RhsD3/NcKhdOsU3r5+rxvhuCRIJ2UPOis3KICUfWGlFuotc5mZ+GRHVTrPuv+cBfFOF2bXDttpCRTe+eTBxMDfuVchQpbWwthUSHU2gYVXi3M9volvDaqeqakxbHFZeAy6EiN7rnxMCojasuvInGyZG3YJneBbiotBH0ax1z73PATySH5UflWKOKEQ65j7g4NsOkfZN9TzH116sWExPXtGb7DqqGCDeHeo/5m8hQhG7N471v1is7FJ7W+x33hYdEw7HtC6/fd3JTHpWWzj9L8tFW+j6gVZPlofavTfp/zuLxsbvF77fKTvuwRTyPic7zad+H0VbcrD4UPF2uX12j9xI+39WLf9bJqjB5vmHJGxQfr8hi7RDskCUxXEK4v+X357yX/8DES4XzonnwCyocn5Pdk9jcxt+QPMTfRWblVxlpEt8gtFDYgetqgYWdY37ANPmVT2FOax5cwONOn2EXWJ5THBWtx2GmgxlgzgWQKVYMpdIoDuNxRM2wcvmXlzKHBmuBwOVbrdMcEf6KTaqR23uPf65gG0fUG1ZIkBjg+6cYlp0VCcwT7/q5gJyb22AG7x3ZLODNuaf3R2tvs1+l0qpQUVVxGhryr68jRFY2OTo06GkORoerqfqsp5ePzyJs3SIbOd0Ct9ynJ+l5i4FOVVC4rLPF2ImBcN/JdFRu+Xuedvcw+vlJuX0Zf4LcC9JcXbf+z86cJ/Ok0fxCYaQDOcqPSabCGHuciW0pKujbhQ9ualDwvc4mj1Q72PItok9sgxTgPelKJwXMDSQ+T3AfowdRZanCsMUuLC6YdBZfzNHBJf3W883qOktHqTImjySPHJbcek94yfmVcdhMivpBkNR588N458AvE2D58ofGJb9H32vEZ/7Nztvsfg4/r7fUFLfQzBQSG4YSBQSgAkT8WKaj/+/H9p26nnJYPp5sSj6ak9jRuq1MSBjQf5Kx05MGN2VGBOveYMfjNr/gzYOzJ32OUMYzthzkGmR2KIwbChQPrYHIMMy423b+CW+5RroyoNrroq77C/2mjZGYkHxzZYjLm8hO5hc9+Y80AdL1FFZljEVrUkZWWEasjKyeWLySkpfUH8dmVAY5CfoCaxQ8KVBudmk+ZLWqykax2Mjuph0re+72v0hCEI1/+9PgLMw33m24t1dcqadt/BQOvJsyZacWraL5Ab7O9+97++bft1gEA2MZMIUoAbP+XjUSv1WkzIvCdC4ivs4UBkQAAAGJBSnCHeSZEQDEQy2QUWHhTHXkzFRkwZvQj4jz5U4KoROCvsXAj/KdwSidw1S5EmhwffyOxWG4DggT2OYOsCbx1FcEZD+UggajZgEC4lLdAD9Zo4d90k6dIlWUYvEDyrJp0JDJwzQkk3vjBccRRpjxHDCjcKxXZZBvrWMSGWFgkI5SqRyGGS10gBKj6v2knfFOS7R3CcJDDIZPOI2EzbDYpy/MmQkWQTvixgdPuInWB9WgMsnHrb/bDD/Jkmix26ArRVlyPPCujuQzZ0PSZ8NkDP3ENqVZXw2+ZaFERB5sggqqq5cgupvKRQYhVeU8JnoMmS3qp1s+6CgVIl4ySs3800Rf4a+boqmJa9Fs86f8oNszUqeoE6T7oNkAS4AEMts0QAH8iIaGHJb4ntasgQ8X6rw3sHt7BjbaxHPbysKlfwPZOztm8n1pnqr2tZGKIbGrDuZXm29uuIKXFIIjhoJJWSapgPEuczdahByogAIgyDBwyaffnGGuY4FG3hzkXheGIDbDjg2GAA3xEqKlCRDFVdDAGkMByxGJqxMFE4ANiXpgEWKAKIABCCQAAb9CJgyFABicPhgEVjCGCqdcRxdSpgzGAC2YQi6kvDiaCHPCvSxLwgBTKpUxAhqaq5yo4zj4Gs1I39pzb32jHSOJjeV//IRo4V7v19mzrB2SIbgmd2r2Zr7xwqt5nMjrEyNUgfA1n685suNpsPFXG2nFalDIBGZqqnvmJg+Psc63UjX1Ab38DDz5GErKDl/sfomH14NVuvZVSH4Ss0GnZVp3ave0UX9m6cHLE95VREJnB1UAXu4azdaehD1cbqzevKqwbJaabd7DHdbEdAknhUZXJ1RRKdf2u57s0tWrTrsPnDwRD4Ug0Fk8kU+lMNpcvFEvlSrVWbzRb7U631x8MR+PJdDZfLFfrzXb3jHyyjqfz5Xq7P56v9+f7C/j3IgUp5AZyGtn1Z66D65/iliIcsXJkaFnmVQ70/mzxkBHazl6OHh5PEAsp8akpJuTTI03IJPNpjqAJT65Gw231bs6HCexqeJS5Uo8avBrVV+TTYRG+Cbl9MVJCjOMuTLkau2GzT8k6QZIzithlmLN5E88i1YiXOtYrI+1PfYg4HRVSCCImyg7LOpLrV4ly75KzMAWbFXPuOE4J2Xx80dqM03o5QJTzpO1dappgYbL9skGEQRURyQAv5HsRqJ7WzP1lq8hLd/lkH+bDuHScTcjZpRvVOEFCMMzSssFAYiaY7+ishkQmfGgfbvr5A1MjC2rB6WmIf8YSbzgNo3a0eNFBD/TAjzkjrvdU3LD0NbLrLu59nC4SVKnFeeZYK84SZ8yPkNsVecZIuB/ZPnvQndmMpBgoOvvEqD2J3J721J/1LIIaPRlovlTXoRkjykrrCtLy8nDF932isAuBm13EnZbWHLJlsX3LPNrldN/aqA+7sW7VZqWKhrSrmaS59/rT4WuBEYifKsw/vA8Ozx3xXUPwkLHuWRLNBis6xOFgYdAycru6iHzhFhQMcS4SSQ/rs16C43wQKOxAzvGY7ZCk35CXTAfKFGcNugAAAA==') format('woff2'),
+  url('iconfont.woff?t=1565078640369') format('woff'),
+  url('iconfont.ttf?t=1565078640369') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
+  url('iconfont.svg?t=1565078640369#wukong') format('svg'); /* iOS 4.1- */
+}
+
+.wukong {
+  font-family: "wukong" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+.wukong-reminder:before {
+  content: "\e653";
+}
+
+.wukong-lock:before {
+  content: "\e625";
+}
+
+.wukong-check:before {
+  content: "\e698";
+}
+
+.wukong-examine-category-nine:before {
+  content: "\e6c2";
+}
+
+.wukong-examine-category-eight:before {
+  content: "\e6db";
+}
+
+.wukong-examine-category-overtime:before {
+  content: "\e6e4";
+}
+
+.wukong-examine-category-seven:before {
+  content: "\e6e5";
+}
+
+.wukong-examine-category-ordinary:before {
+  content: "\e6f3";
+}
+
+.wukong-examine-category-leave:before {
+  content: "\e702";
+}
+
+.wukong-examine-category-six:before {
+  content: "\e70a";
+}
+
+.wukong-examine-category-five:before {
+  content: "\e70f";
+}
+
+.wukong-examine-category-four:before {
+  content: "\e71f";
+}
+
+.wukong-examine-category-business:before {
+  content: "\e739";
+}
+
+.wukong-examine-category-borrowing:before {
+  content: "\e73b";
+}
+
+.wukong-examine-category-billing:before {
+  content: "\e744";
+}
+
+.wukong-examine-category-two:before {
+  content: "\e75f";
+}
+
+.wukong-examine-category-three:before {
+  content: "\e767";
+}
+
+.wukong-examine-category-one:before {
+  content: "\e627";
+}
+
+.wukong-lightning:before {
+  content: "\e65e";
+}
+
+.wukong-label:before {
+  content: "\e65f";
+}
+
+.wukong-sub-task:before {
+  content: "\e660";
+}
+
+.wukong-file:before {
+  content: "\e662";
+}
+
+.wukong-user:before {
+  content: "\e663";
+}
+
+.wukong-relevance:before {
+  content: "\e664";
+}
+
+.wukong-black-label:before {
+  content: "\e665";
+}
+
+.wukong-activity-task:before {
+  content: "\e667";
+}
+
+.wukong-comment-task:before {
+  content: "\e668";
+}
+
+.wukong-time-task:before {
+  content: "\e66b";
+}
+
+.wukong-person-task:before {
+  content: "\e66c";
+}
+
+.wukong-addition-task:before {
+  content: "\e66e";
+}
+
+.wukong-delete-task:before {
+  content: "\e66f";
+}
+
+.wukong-edit-task:before {
+  content: "\e670";
+}
+
+.wukong-address:before {
+  content: "\e671";
+}
+
+.wukong-book:before {
+  content: "\e672";
+}
+
+.wukong-business:before {
+  content: "\e673";
+}
+
+.wukong-certificate:before {
+  content: "\e674";
+}
+
+.wukong-contract:before {
+  content: "\e675";
+}
+
+.wukong-customer:before {
+  content: "\e676";
+}
+
+.wukong-contacts:before {
+  content: "\e677";
+}
+
+.wukong-department:before {
+  content: "\e678";
+}
+
+.wukong-systemconfig:before {
+  content: "\e679";
+}
+
+.wukong-taskSetstatistics:before {
+  content: "\e67a";
+}
+
+.wukong-task:before {
+  content: "\e67b";
+}
+
+.wukong-taskCompletestatistics:before {
+  content: "\e67c";
+}
+
+.wukong-examine:before {
+  content: "\e67d";
+}
+
+.wukong-funnelstatistics:before {
+  content: "\e67e";
+}
+
+.wukong-workbench:before {
+  content: "\e67f";
+}
+
+.wukong-project:before {
+  content: "\e680";
+}
+
+.wukong-message:before {
+  content: "\e681";
+}
+
+.wukong-notice:before {
+  content: "\e682";
+}
+
+.wukong-money:before {
+  content: "\e683";
+}
+
+.wukong-employeestatistics:before {
+  content: "\e684";
+}
+
+.wukong-moneystatistics:before {
+  content: "\e685";
+}
+
+.wukong-product:before {
+  content: "\e686";
+}
+
+.wukong-example:before {
+  content: "\e687";
+}
+
+.wukong-tag:before {
+  content: "\e688";
+}
+
+.wukong-log:before {
+  content: "\e689";
+}
+
+.wukong-over:before {
+  content: "\e68a";
+}
+
+.wukong-leads:before {
+  content: "\e68b";
+}
+
+.wukong-pay:before {
+  content: "\e68c";
+}
+
+.wukong-schedule:before {
+  content: "\e68d";
+}
+
+.wukong-statistics:before {
+  content: "\e68e";
+}
+
+.wukong-seas:before {
+  content: "\e68f";
+}
+
+.wukong-subproject:before {
+  content: "\e690";
+}
+
+.wukong-productstatistics:before {
+  content: "\e691";
+}
+
+.wukong-set:before {
+  content: "\e692";
+}
+
+.wukong-recycle:before {
+  content: "\e693";
+}
+
+.wukong-personcenter:before {
+  content: "\e694";
+}
+
+.wukong-goout:before {
+  content: "\e695";
+}
+
+.wukong-versions:before {
+  content: "\e696";
+}
+
+.wukong-business-customer:before {
+  content: "\e699";
+}
+
+.wukong-dashboard:before {
+  content: "\e697";
+}
+
+.wukong-BI_Leaderboard:before {
+  content: "\e6fc";
+}
+
+.wukong-BI_Office:before {
+  content: "\e6fd";
+}
+
+.wukong-BI_Employee_performance:before {
+  content: "\e6fe";
+}
+
+.wukong-help_tips:before {
+  content: "\e700";
+}
+
+.wukong-log-delete:before {
+  content: "\e6ff";
+}
+
+.wukong-log-reply:before {
+  content: "\e701";
+}
+
+.wukong-marketing:before {
+  content: "\e704";
+}
+
+.wukong-icon_reset_account_login:before {
+  content: "\e703";
+}
+
+.wukong-oa_analysis:before {
+  content: "\e705";
+}
+
diff --git a/src/assets/fonts/iconfont.eot b/src/assets/fonts/iconfont.eot
new file mode 100644
index 0000000..2abd5ec
--- /dev/null
+++ b/src/assets/fonts/iconfont.eot
Binary files differ
diff --git a/src/assets/fonts/iconfont.js b/src/assets/fonts/iconfont.js
new file mode 100644
index 0000000..0af7eff
--- /dev/null
+++ b/src/assets/fonts/iconfont.js
@@ -0,0 +1 @@
+!function(t){var e,c,o,n,i,s,l,a='<svg><symbol id="icon-showpassword" viewBox="0 0 1024 1024"><path d="M1024 512c0 96-211.2 307.2-512 307.2-294.4 0-512-204.8-512-307.2s217.6-307.2 512-307.2c300.8 0 512 204.8 512 307.2l0 0zM512 262.4c-134.4 0-243.2 108.8-243.2 249.6s108.8 249.6 249.6 249.6c134.4 0 249.6-115.2 249.6-249.6-6.4-140.8-121.6-249.6-256-249.6l0 0zM512 352c-89.6 0-160 70.4-160 160s70.4 160 160 160c89.6 0 160-70.4 160-160s-70.4-160-160-160l0 0z"  ></path></symbol><symbol id="icon-user" viewBox="0 0 1024 1024"><path d="M867.328 790.592c-61.12-41.664-191.68-77.824-211.136-88.96s-38.848-19.456-38.848-55.488c0-36.096 19.776-55.232 47.232-80.64 51.52-47.488 41.6-101.376 74.944-126.4 27.328-20.416 40.96-36.16 45.248-66.752 0.704-4.544 1.152-9.728 1.344-15.488 0.064-2.368 0.576-3.968 0.576-6.656 0-47.232-38.848-47.232-38.848-47.232s0 1.344-13.888-76.352c-13.376-75.136-89.152-155.264-194.368-160.64L539.584 65.472c-2.112 0-3.968 0.192-6.016 0.256C531.84 65.664 530.112 65.472 528.32 65.472L528.32 65.92c-0.512 0-0.96 0.128-1.472 0.192C526.336 66.048 525.888 65.92 525.376 65.92L525.376 65.472c-1.792 0-3.52 0.192-5.248 0.256C518.144 65.664 516.224 65.472 514.112 65.472l0 0.512c-105.28 5.376-180.992 85.504-194.368 160.64C305.856 304.384 305.856 302.976 305.856 302.976s-38.848 0-38.848 47.232c0 2.624 0.512 4.224 0.576 6.656 0.256 5.76 0.704 10.944 1.344 15.488 4.288 30.592 17.92 46.336 45.248 66.752C347.52 464.128 337.6 518.016 389.12 565.504c27.52 25.344 47.232 44.48 47.232 80.64 0 36.032-19.456 44.352-38.848 55.488s-150.016 47.232-211.136 88.96S128 854.464 128 890.496C128 951.616 205.824 960 205.824 960l246.464 0 68.544 0 12.032 0 68.544 0 246.464 0c0 0 77.824-8.384 77.824-69.504C925.696 854.464 928.448 832.256 867.328 790.592z"  ></path></symbol><symbol id="icon-users" viewBox="0 0 1152 1024"><path d="M767.952003 770.575839v-52.7967c70.523592-39.741516 127.992-138.743329 127.992-237.809137C895.944003 320.939941 895.944003 191.988001 703.956003 191.988001S511.968002 320.939941 511.968002 479.970002c0 99.065808 57.468408 198.067621 127.992 237.809137v52.7967c-217.074433 17.726892-383.976001 124.408224-383.976001 253.360165h895.944003c0-128.951941-166.901569-235.633273-383.976001-253.360165z" fill="" ></path><path d="M327.147553 795.278295c55.292544-36.15774 124.088244-63.612024 199.795513-80.378976a362.665333 362.665333 0 0 1-40.509468-59.004312 366.441097 366.441097 0 0 1-46.461096-175.861009c0-86.010624 0-167.285545 30.590088-233.777389 29.694144-64.507968 83.130804-104.505468 159.222048-119.480533C612.889694 50.300856 567.83651 0.063996 447.972002 0.063996c-191.988001 0-191.988001 128.951941-191.988001 287.982001 0 99.065808 57.468408 198.067621 127.992 237.809137v52.7967c-217.074433 17.726892-383.976001 124.408224-383.976001 253.360165h278.958565c14.527092-12.927192 30.590088-25.150428 48.188988-36.669708z" fill="" ></path></symbol><symbol id="icon-morentouxiang" viewBox="0 0 1024 1024"><path d="M512 64C264.8 64 64 264.8 64 512s200.8 448 448 448 448-200.8 448-448S759.2 64 512 64zM384.8 376c4-64 56-115.2 120-119.2 74.4-4 135.2 55.2 135.2 128 0 70.4-57.6 128-128 128-73.6 0-132-62.4-127.2-136.8zM768 746.4c0 12-9.6 21.6-21.6 21.6H278.4c-12 0-21.6-9.6-21.6-21.6v-64c0-84.8 170.4-128 255.2-128 84.8 0 255.2 42.4 255.2 128l0.8 64z"  ></path></symbol><symbol id="icon-baobiao" viewBox="0 0 1024 1024"><path d="M960 672V160c0-17.6-14.4-32-32-32H544V64h-64v64H96c-17.6 0-32 14.4-32 32v512c0 17.6 14.4 32 32 32h384v50.4l-152.8 89.6 32 56 144-84h19.2l144 84 32-56L544 754.4V704h384c17.6 0 32-14.4 32-32zM790.4 256l41.6 48.8-316.8 270.4L352 437.6 233.6 536.8 192.8 488l160-133.6 163.2 137.6L790.4 256z"  ></path></symbol><symbol id="icon-password" viewBox="0 0 1024 1024"><path d="M807.049 391.258c0.946-9.62 1.45-19.37 1.45-29.239 0-163.7-132.706-296.406-296.406-296.406S215.687 198.318 215.687 362.02c0 9.802 0.498 19.486 1.432 29.043-43.925 18.95-74.675 62.638-74.675 113.516v330.363c0 68.25 55.328 123.58 123.58 123.58h491.672c68.25 0 123.578-55.328 123.578-123.58V504.578c0-50.704-30.54-94.267-74.225-113.32zM510.917 165.905c109.134 0 197.604 88.47 197.604 197.603 0 5.895-0.275 11.726-0.782 17.49H314.094a200.097 200.097 0 0 1-0.782-17.49c0.002-109.132 88.472-197.603 197.605-197.603z"  ></path></symbol><symbol id="icon-lock-fill" viewBox="0 0 1024 1024"><path d="M810.666667 426.666667h42.666666a42.666667 42.666667 0 0 1 42.666667 42.666666v426.666667a42.666667 42.666667 0 0 1-42.666667 42.666667H170.666667a42.666667 42.666667 0 0 1-42.666667-42.666667V469.333333a42.666667 42.666667 0 0 1 42.666667-42.666666h42.666666V384a298.666667 298.666667 0 1 1 597.333334 0v42.666667z m-85.333334 0V384A213.333333 213.333333 0 0 0 298.666667 384v42.666667h426.666666z m-256 170.666666v170.666667h85.333334v-170.666667h-85.333334z"  ></path></symbol></svg>',d=(e=document.getElementsByTagName("script"))[e.length-1].getAttribute("data-injectcss");if(d&&!t.__iconfont__svg__cssinject__){t.__iconfont__svg__cssinject__=!0;try{document.write("<style>.svgfont {display: inline-block;width: 1em;height: 1em;fill: currentColor;vertical-align: -0.1em;font-size:16px;}</style>")}catch(t){console&&console.log(t)}}function h(){s||(s=!0,n())}c=function(){var t,e,c,o,n,i=document.createElement("div");i.innerHTML=a,a=null,(t=i.getElementsByTagName("svg")[0])&&(t.setAttribute("aria-hidden","true"),t.style.position="absolute",t.style.width=0,t.style.height=0,t.style.overflow="hidden",e=t,(c=document.body).firstChild?(o=e,(n=c.firstChild).parentNode.insertBefore(o,n)):c.appendChild(e))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(c,0):(o=function(){document.removeEventListener("DOMContentLoaded",o,!1),c()},document.addEventListener("DOMContentLoaded",o,!1)):document.attachEvent&&(n=c,i=t.document,s=!1,(l=function(){try{i.documentElement.doScroll("left")}catch(t){return void setTimeout(l,50)}h()})(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,h())})}(window);
\ No newline at end of file
diff --git a/src/assets/fonts/iconfont.json b/src/assets/fonts/iconfont.json
new file mode 100644
index 0000000..6149187
--- /dev/null
+++ b/src/assets/fonts/iconfont.json
@@ -0,0 +1,58 @@
+{
+  "id": "",
+  "name": "",
+  "font_family": "iconfont",
+  "css_prefix_text": "icon-",
+  "description": "",
+  "glyphs": [
+    {
+      "icon_id": "212782",
+      "name": "show-password ",
+      "font_class": "showpassword",
+      "unicode": "ea3f",
+      "unicode_decimal": 59967
+    },
+    {
+      "icon_id": "587162",
+      "name": "user",
+      "font_class": "user",
+      "unicode": "e830",
+      "unicode_decimal": 59440
+    },
+    {
+      "icon_id": "1199149",
+      "name": "users",
+      "font_class": "users",
+      "unicode": "a",
+      "unicode_decimal": 10
+    },
+    {
+      "icon_id": "1727461",
+      "name": "225默认头像",
+      "font_class": "morentouxiang",
+      "unicode": "e8c9",
+      "unicode_decimal": 59593
+    },
+    {
+      "icon_id": "1727589",
+      "name": "406报表",
+      "font_class": "baobiao",
+      "unicode": "e902",
+      "unicode_decimal": 59650
+    },
+    {
+      "icon_id": "7712708",
+      "name": "password",
+      "font_class": "password",
+      "unicode": "e734",
+      "unicode_decimal": 59188
+    },
+    {
+      "icon_id": "16035104",
+      "name": "lock-fill",
+      "font_class": "lock-fill",
+      "unicode": "e6af",
+      "unicode_decimal": 59055
+    }
+  ]
+}
diff --git a/src/assets/fonts/iconfont.svg b/src/assets/fonts/iconfont.svg
new file mode 100644
index 0000000..3a47f2b
--- /dev/null
+++ b/src/assets/fonts/iconfont.svg
@@ -0,0 +1,47 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<!--
+2013-9-30: Created.
+-->
+<svg>
+<metadata>
+Created by iconfont
+</metadata>
+<defs>
+
+<font id="iconfont" horiz-adv-x="1024" >
+  <font-face
+    font-family="iconfont"
+    font-weight="500"
+    font-stretch="normal"
+    units-per-em="1024"
+    ascent="896"
+    descent="-128"
+  />
+    <missing-glyph />
+    
+    <glyph glyph-name="showpassword" unicode="&#59967;" d="M1024 300c0-96-211.2-307.2-512-307.2-294.4 0-512 204.8-512 307.2s217.6 307.2 512 307.2c300.8 0 512-204.8 512-307.2l0 0zM512 549.6c-134.4 0-243.2-108.8-243.2-249.6s108.8-249.6 249.6-249.6c134.4 0 249.6 115.2 249.6 249.6-6.4 140.8-121.6 249.6-256 249.6l0 0zM512 460c-89.6 0-160-70.4-160-160s70.4-160 160-160c89.6 0 160 70.4 160 160s-70.4 160-160 160l0 0z"  horiz-adv-x="1024" />
+
+    
+    <glyph glyph-name="user" unicode="&#59440;" d="M867.328 105.408c-61.12 41.664-191.68 77.824-211.136 88.96s-38.848 19.456-38.848 55.488c0 36.096 19.776 55.232 47.232 80.64 51.52 47.488 41.6 101.376 74.944 126.4 27.328 20.416 40.96 36.16 45.248 66.752 0.704 4.544 1.152 9.728 1.344 15.488 0.064 2.368 0.576 3.968 0.576 6.656 0 47.232-38.848 47.232-38.848 47.232s0-1.344-13.888 76.352c-13.376 75.136-89.152 155.264-194.368 160.64L539.584 830.528c-2.112 0-3.968-0.192-6.016-0.256C531.84 830.336 530.112 830.528 528.32 830.528L528.32 830.08c-0.512 0-0.96-0.128-1.472-0.192C526.336 829.952 525.888 830.08 525.376 830.08L525.376 830.528c-1.792 0-3.52-0.192-5.248-0.256C518.144 830.336 516.224 830.528 514.112 830.528l0-0.512c-105.28-5.376-180.992-85.504-194.368-160.64C305.856 591.616 305.856 593.024 305.856 593.024s-38.848 0-38.848-47.232c0-2.624 0.512-4.224 0.576-6.656 0.256-5.76 0.704-10.944 1.344-15.488 4.288-30.592 17.92-46.336 45.248-66.752C347.52 431.872 337.6 377.984 389.12 330.496c27.52-25.344 47.232-44.48 47.232-80.64 0-36.032-19.456-44.352-38.848-55.488s-150.016-47.232-211.136-88.96S128 41.536 128 5.504C128-55.616 205.824-64 205.824-64l246.464 0 68.544 0 12.032 0 68.544 0 246.464 0c0 0 77.824 8.384 77.824 69.504C925.696 41.536 928.448 63.744 867.328 105.408z"  horiz-adv-x="1024" />
+
+    
+    <glyph glyph-name="users" unicode="&#10;" d="M767.952003 125.424161v52.7967c70.523592 39.741516 127.992 138.743329 127.992 237.809137C895.944003 575.060059 895.944003 704.011999 703.956003 704.011999S511.968002 575.060059 511.968002 416.029998c0-99.065808 57.468408-198.067621 127.992-237.809137v-52.7967c-217.074433-17.726892-383.976001-124.408224-383.976001-253.360165h895.944003c0 128.951941-166.901569 235.633273-383.976001 253.360165zM327.147553 100.721705c55.292544 36.15774 124.088244 63.612024 199.795513 80.378976a362.665333 362.665333 0 0 0-40.509468 59.004312 366.441097 366.441097 0 0 0-46.461096 175.861009c0 86.010624 0 167.285545 30.590088 233.777389 29.694144 64.507968 83.130804 104.505468 159.222048 119.480533C612.889694 845.699144 567.83651 895.936004 447.972002 895.936004c-191.988001 0-191.988001-128.951941-191.988001-287.982001 0-99.065808 57.468408-198.067621 127.992-237.809137v-52.7967c-217.074433-17.726892-383.976001-124.408224-383.976001-253.360165h278.958565c14.527092 12.927192 30.590088 25.150428 48.188988 36.669708z"  horiz-adv-x="1152" />
+
+    
+    <glyph glyph-name="morentouxiang" unicode="&#59593;" d="M512 832C264.8 832 64 631.2 64 384s200.8-448 448-448 448 200.8 448 448S759.2 832 512 832zM384.8 520c4 64 56 115.2 120 119.2 74.4 4 135.2-55.2 135.2-128 0-70.4-57.6-128-128-128-73.6 0-132 62.4-127.2 136.8zM768 149.6c0-12-9.6-21.6-21.6-21.6H278.4c-12 0-21.6 9.6-21.6 21.6v64c0 84.8 170.4 128 255.2 128 84.8 0 255.2-42.4 255.2-128l0.8-64z"  horiz-adv-x="1024" />
+
+    
+    <glyph glyph-name="baobiao" unicode="&#59650;" d="M960 224V736c0 17.6-14.4 32-32 32H544V832h-64v-64H96c-17.6 0-32-14.4-32-32v-512c0-17.6 14.4-32 32-32h384v-50.4l-152.8-89.6 32-56 144 84h19.2l144-84 32 56L544 141.6V192h384c17.6 0 32 14.4 32 32zM790.4 640l41.6-48.8-316.8-270.4L352 458.4 233.6 359.2 192.8 408l160 133.6 163.2-137.6L790.4 640z"  horiz-adv-x="1024" />
+
+    
+    <glyph glyph-name="password" unicode="&#59188;" d="M807.049 504.742c0.946 9.62 1.45 19.37 1.45 29.239 0 163.7-132.706 296.406-296.406 296.406S215.687 697.682 215.687 533.98c0-9.802 0.498-19.486 1.432-29.043-43.925-18.95-74.675-62.638-74.675-113.516v-330.363c0-68.25 55.328-123.58 123.58-123.58h491.672c68.25 0 123.578 55.328 123.578 123.58V391.422c0 50.704-30.54 94.267-74.225 113.32zM510.917 730.095c109.134 0 197.604-88.47 197.604-197.603 0-5.895-0.275-11.726-0.782-17.49H314.094a200.097 200.097 0 0 0-0.782 17.49c0.002 109.132 88.472 197.603 197.605 197.603z"  horiz-adv-x="1024" />
+
+    
+    <glyph glyph-name="lock-fill" unicode="&#59055;" d="M810.666667 469.333333h42.666666a42.666667 42.666667 0 0 0 42.666667-42.666666v-426.666667a42.666667 42.666667 0 0 0-42.666667-42.666667H170.666667a42.666667 42.666667 0 0 0-42.666667 42.666667V426.666667a42.666667 42.666667 0 0 0 42.666667 42.666666h42.666666V512a298.666667 298.666667 0 1 0 597.333334 0v-42.666667z m-85.333334 0V512A213.333333 213.333333 0 0 1 298.666667 512v-42.666667h426.666666z m-256-170.666666v-170.666667h85.333334v170.666667h-85.333334z"  horiz-adv-x="1024" />
+
+    
+
+
+  </font>
+</defs></svg>
diff --git a/src/assets/fonts/iconfont.ttf b/src/assets/fonts/iconfont.ttf
new file mode 100644
index 0000000..808aa01
--- /dev/null
+++ b/src/assets/fonts/iconfont.ttf
Binary files differ
diff --git a/src/assets/fonts/iconfont.woff b/src/assets/fonts/iconfont.woff
new file mode 100644
index 0000000..95de749
--- /dev/null
+++ b/src/assets/fonts/iconfont.woff
Binary files differ
diff --git a/src/assets/fonts/iconfont.woff2 b/src/assets/fonts/iconfont.woff2
new file mode 100644
index 0000000..1a998b9
--- /dev/null
+++ b/src/assets/fonts/iconfont.woff2
Binary files differ
diff --git a/src/assets/img/accessory.png b/src/assets/img/accessory.png
new file mode 100644
index 0000000..bed8faf
--- /dev/null
+++ b/src/assets/img/accessory.png
Binary files differ
diff --git a/src/assets/img/add_examine.png b/src/assets/img/add_examine.png
new file mode 100644
index 0000000..2aeb460
--- /dev/null
+++ b/src/assets/img/add_examine.png
Binary files differ
diff --git a/src/assets/img/add_journal.png b/src/assets/img/add_journal.png
new file mode 100644
index 0000000..42a07e0
--- /dev/null
+++ b/src/assets/img/add_journal.png
Binary files differ
diff --git a/src/assets/img/add_notice.png b/src/assets/img/add_notice.png
new file mode 100644
index 0000000..043cae3
--- /dev/null
+++ b/src/assets/img/add_notice.png
Binary files differ
diff --git a/src/assets/img/add_schedule.png b/src/assets/img/add_schedule.png
new file mode 100644
index 0000000..3120c54
--- /dev/null
+++ b/src/assets/img/add_schedule.png
Binary files differ
diff --git a/src/assets/img/add_task.png b/src/assets/img/add_task.png
new file mode 100644
index 0000000..60484c6
--- /dev/null
+++ b/src/assets/img/add_task.png
Binary files differ
diff --git a/src/assets/img/archive_project.png b/src/assets/img/archive_project.png
new file mode 100644
index 0000000..c2638af
--- /dev/null
+++ b/src/assets/img/archive_project.png
Binary files differ
diff --git a/src/assets/img/business_detail.png b/src/assets/img/business_detail.png
new file mode 100644
index 0000000..9dfdfb0
--- /dev/null
+++ b/src/assets/img/business_detail.png
Binary files differ
diff --git a/src/assets/img/business_dot.png b/src/assets/img/business_dot.png
new file mode 100644
index 0000000..c375906
--- /dev/null
+++ b/src/assets/img/business_dot.png
Binary files differ
diff --git a/src/assets/img/button_add_black.png b/src/assets/img/button_add_black.png
new file mode 100644
index 0000000..e3aae65
--- /dev/null
+++ b/src/assets/img/button_add_black.png
Binary files differ
diff --git a/src/assets/img/button_add_white.png b/src/assets/img/button_add_white.png
new file mode 100644
index 0000000..573994b
--- /dev/null
+++ b/src/assets/img/button_add_white.png
Binary files differ
diff --git a/src/assets/img/c_business.png b/src/assets/img/c_business.png
new file mode 100644
index 0000000..613b51a
--- /dev/null
+++ b/src/assets/img/c_business.png
Binary files differ
diff --git a/src/assets/img/c_contact.png b/src/assets/img/c_contact.png
new file mode 100644
index 0000000..c535fd1
--- /dev/null
+++ b/src/assets/img/c_contact.png
Binary files differ
diff --git a/src/assets/img/c_contract.png b/src/assets/img/c_contract.png
new file mode 100644
index 0000000..0e7e381
--- /dev/null
+++ b/src/assets/img/c_contract.png
Binary files differ
diff --git a/src/assets/img/c_curomer.png b/src/assets/img/c_curomer.png
new file mode 100644
index 0000000..f2b7096
--- /dev/null
+++ b/src/assets/img/c_curomer.png
Binary files differ
diff --git a/src/assets/img/c_filtrate.png b/src/assets/img/c_filtrate.png
new file mode 100644
index 0000000..94a04e4
--- /dev/null
+++ b/src/assets/img/c_filtrate.png
Binary files differ
diff --git a/src/assets/img/c_log.png b/src/assets/img/c_log.png
new file mode 100644
index 0000000..9c28405
--- /dev/null
+++ b/src/assets/img/c_log.png
Binary files differ
diff --git a/src/assets/img/c_receivables.png b/src/assets/img/c_receivables.png
new file mode 100644
index 0000000..78e198a
--- /dev/null
+++ b/src/assets/img/c_receivables.png
Binary files differ
diff --git a/src/assets/img/cancel_associated.png b/src/assets/img/cancel_associated.png
new file mode 100644
index 0000000..3531ae0
--- /dev/null
+++ b/src/assets/img/cancel_associated.png
Binary files differ
diff --git a/src/assets/img/check_cancel.png b/src/assets/img/check_cancel.png
new file mode 100644
index 0000000..7589fb6
--- /dev/null
+++ b/src/assets/img/check_cancel.png
Binary files differ
diff --git a/src/assets/img/check_create.png b/src/assets/img/check_create.png
new file mode 100644
index 0000000..f0fff9f
--- /dev/null
+++ b/src/assets/img/check_create.png
Binary files differ
diff --git a/src/assets/img/check_fail.png b/src/assets/img/check_fail.png
new file mode 100644
index 0000000..4d3bd54
--- /dev/null
+++ b/src/assets/img/check_fail.png
Binary files differ
diff --git a/src/assets/img/check_revoke.png b/src/assets/img/check_revoke.png
new file mode 100644
index 0000000..c15324b
--- /dev/null
+++ b/src/assets/img/check_revoke.png
Binary files differ
diff --git a/src/assets/img/check_suc.png b/src/assets/img/check_suc.png
new file mode 100644
index 0000000..d188a4d
--- /dev/null
+++ b/src/assets/img/check_suc.png
Binary files differ
diff --git a/src/assets/img/check_wait.png b/src/assets/img/check_wait.png
new file mode 100644
index 0000000..49f815b
--- /dev/null
+++ b/src/assets/img/check_wait.png
Binary files differ
diff --git a/src/assets/img/close.png b/src/assets/img/close.png
new file mode 100644
index 0000000..96c4219
--- /dev/null
+++ b/src/assets/img/close.png
Binary files differ
diff --git a/src/assets/img/close2x.png b/src/assets/img/close2x.png
new file mode 100644
index 0000000..7010b37
--- /dev/null
+++ b/src/assets/img/close2x.png
Binary files differ
diff --git a/src/assets/img/clue_detail.png b/src/assets/img/clue_detail.png
new file mode 100644
index 0000000..5c75adc
--- /dev/null
+++ b/src/assets/img/clue_detail.png
Binary files differ
diff --git a/src/assets/img/collapse_gray.png b/src/assets/img/collapse_gray.png
new file mode 100644
index 0000000..40a37a5
--- /dev/null
+++ b/src/assets/img/collapse_gray.png
Binary files differ
diff --git a/src/assets/img/collapse_right.png b/src/assets/img/collapse_right.png
new file mode 100644
index 0000000..41a9387
--- /dev/null
+++ b/src/assets/img/collapse_right.png
Binary files differ
diff --git a/src/assets/img/collapse_white.png b/src/assets/img/collapse_white.png
new file mode 100644
index 0000000..68b2205
--- /dev/null
+++ b/src/assets/img/collapse_white.png
Binary files differ
diff --git a/src/assets/img/comment.png b/src/assets/img/comment.png
new file mode 100644
index 0000000..3470b27
--- /dev/null
+++ b/src/assets/img/comment.png
Binary files differ
diff --git a/src/assets/img/contacts_detail.png b/src/assets/img/contacts_detail.png
new file mode 100644
index 0000000..e0f3c8b
--- /dev/null
+++ b/src/assets/img/contacts_detail.png
Binary files differ
diff --git a/src/assets/img/contract_detail.png b/src/assets/img/contract_detail.png
new file mode 100644
index 0000000..b1c83fd
--- /dev/null
+++ b/src/assets/img/contract_detail.png
Binary files differ
diff --git a/src/assets/img/crm_multiuser.png b/src/assets/img/crm_multiuser.png
new file mode 100644
index 0000000..e93c6e8
--- /dev/null
+++ b/src/assets/img/crm_multiuser.png
Binary files differ
diff --git a/src/assets/img/customer_detail.png b/src/assets/img/customer_detail.png
new file mode 100644
index 0000000..444b858
--- /dev/null
+++ b/src/assets/img/customer_detail.png
Binary files differ
diff --git a/src/assets/img/deadline.png b/src/assets/img/deadline.png
new file mode 100644
index 0000000..a32f9dd
--- /dev/null
+++ b/src/assets/img/deadline.png
Binary files differ
diff --git a/src/assets/img/delete_task.png b/src/assets/img/delete_task.png
new file mode 100644
index 0000000..c18528a
--- /dev/null
+++ b/src/assets/img/delete_task.png
Binary files differ
diff --git a/src/assets/img/empty.png b/src/assets/img/empty.png
new file mode 100644
index 0000000..c71b48e
--- /dev/null
+++ b/src/assets/img/empty.png
Binary files differ
diff --git a/src/assets/img/examine_head.png b/src/assets/img/examine_head.png
new file mode 100644
index 0000000..1486f2a
--- /dev/null
+++ b/src/assets/img/examine_head.png
Binary files differ
diff --git a/src/assets/img/field_business_manager.png b/src/assets/img/field_business_manager.png
new file mode 100644
index 0000000..669b327
--- /dev/null
+++ b/src/assets/img/field_business_manager.png
Binary files differ
diff --git a/src/assets/img/field_contacts_manager.png b/src/assets/img/field_contacts_manager.png
new file mode 100644
index 0000000..ff432c5
--- /dev/null
+++ b/src/assets/img/field_contacts_manager.png
Binary files differ
diff --git a/src/assets/img/field_contract_manager.png b/src/assets/img/field_contract_manager.png
new file mode 100644
index 0000000..01abe6f
--- /dev/null
+++ b/src/assets/img/field_contract_manager.png
Binary files differ
diff --git a/src/assets/img/field_customer_manager.png b/src/assets/img/field_customer_manager.png
new file mode 100644
index 0000000..3fb3c21
--- /dev/null
+++ b/src/assets/img/field_customer_manager.png
Binary files differ
diff --git a/src/assets/img/field_leads_manager.png b/src/assets/img/field_leads_manager.png
new file mode 100644
index 0000000..56cf614
--- /dev/null
+++ b/src/assets/img/field_leads_manager.png
Binary files differ
diff --git a/src/assets/img/field_other_manager.png b/src/assets/img/field_other_manager.png
new file mode 100644
index 0000000..9587a26
--- /dev/null
+++ b/src/assets/img/field_other_manager.png
Binary files differ
diff --git a/src/assets/img/field_product_manager.png b/src/assets/img/field_product_manager.png
new file mode 100644
index 0000000..ffe1ff5
--- /dev/null
+++ b/src/assets/img/field_product_manager.png
Binary files differ
diff --git a/src/assets/img/field_receivables_manager.png b/src/assets/img/field_receivables_manager.png
new file mode 100644
index 0000000..364b3c8
--- /dev/null
+++ b/src/assets/img/field_receivables_manager.png
Binary files differ
diff --git a/src/assets/img/file_excle.png b/src/assets/img/file_excle.png
new file mode 100644
index 0000000..ed79ad6
--- /dev/null
+++ b/src/assets/img/file_excle.png
Binary files differ
diff --git a/src/assets/img/file_img.png b/src/assets/img/file_img.png
new file mode 100644
index 0000000..ea8306e
--- /dev/null
+++ b/src/assets/img/file_img.png
Binary files differ
diff --git a/src/assets/img/file_pdf.png b/src/assets/img/file_pdf.png
new file mode 100644
index 0000000..b61e3f5
--- /dev/null
+++ b/src/assets/img/file_pdf.png
Binary files differ
diff --git a/src/assets/img/file_ppt.png b/src/assets/img/file_ppt.png
new file mode 100644
index 0000000..02b27d4
--- /dev/null
+++ b/src/assets/img/file_ppt.png
Binary files differ
diff --git a/src/assets/img/file_txt.png b/src/assets/img/file_txt.png
new file mode 100644
index 0000000..8a0b49c
--- /dev/null
+++ b/src/assets/img/file_txt.png
Binary files differ
diff --git a/src/assets/img/file_unknown.png b/src/assets/img/file_unknown.png
new file mode 100644
index 0000000..693395b
--- /dev/null
+++ b/src/assets/img/file_unknown.png
Binary files differ
diff --git a/src/assets/img/file_video.png b/src/assets/img/file_video.png
new file mode 100644
index 0000000..f595851
--- /dev/null
+++ b/src/assets/img/file_video.png
Binary files differ
diff --git a/src/assets/img/file_word.png b/src/assets/img/file_word.png
new file mode 100644
index 0000000..866b5a7
--- /dev/null
+++ b/src/assets/img/file_word.png
Binary files differ
diff --git a/src/assets/img/file_zip.png b/src/assets/img/file_zip.png
new file mode 100644
index 0000000..5fccba4
--- /dev/null
+++ b/src/assets/img/file_zip.png
Binary files differ
diff --git a/src/assets/img/fold.png b/src/assets/img/fold.png
new file mode 100644
index 0000000..1629254
--- /dev/null
+++ b/src/assets/img/fold.png
Binary files differ
diff --git a/src/assets/img/follow_log.png b/src/assets/img/follow_log.png
new file mode 100644
index 0000000..8bd23dd
--- /dev/null
+++ b/src/assets/img/follow_log.png
Binary files differ
diff --git a/src/assets/img/follow_record.png b/src/assets/img/follow_record.png
new file mode 100644
index 0000000..7259e1e
--- /dev/null
+++ b/src/assets/img/follow_record.png
Binary files differ
diff --git a/src/assets/img/goOut.png b/src/assets/img/goOut.png
new file mode 100644
index 0000000..24d1a7c
--- /dev/null
+++ b/src/assets/img/goOut.png
Binary files differ
diff --git a/src/assets/img/head.png b/src/assets/img/head.png
new file mode 100644
index 0000000..ff16f21
--- /dev/null
+++ b/src/assets/img/head.png
Binary files differ
diff --git a/src/assets/img/jd_business.png b/src/assets/img/jd_business.png
new file mode 100644
index 0000000..5e6682d
--- /dev/null
+++ b/src/assets/img/jd_business.png
Binary files differ
diff --git a/src/assets/img/jianbao.png b/src/assets/img/jianbao.png
new file mode 100644
index 0000000..18cef9a
--- /dev/null
+++ b/src/assets/img/jianbao.png
Binary files differ
diff --git a/src/assets/img/journal_comment.png b/src/assets/img/journal_comment.png
new file mode 100644
index 0000000..c2e9960
--- /dev/null
+++ b/src/assets/img/journal_comment.png
Binary files differ
diff --git a/src/assets/img/loading.gif b/src/assets/img/loading.gif
new file mode 100644
index 0000000..e8c2892
--- /dev/null
+++ b/src/assets/img/loading.gif
Binary files differ
diff --git a/src/assets/img/login/login.png b/src/assets/img/login/login.png
new file mode 100644
index 0000000..51ed192
--- /dev/null
+++ b/src/assets/img/login/login.png
Binary files differ
diff --git a/src/assets/img/login/login_bg.png b/src/assets/img/login/login_bg.png
new file mode 100644
index 0000000..2dd0718
--- /dev/null
+++ b/src/assets/img/login/login_bg.png
Binary files differ
diff --git a/src/assets/img/login/logo.png b/src/assets/img/login/logo.png
new file mode 100644
index 0000000..82a3b81
--- /dev/null
+++ b/src/assets/img/login/logo.png
Binary files differ
diff --git a/src/assets/img/logo.jpg b/src/assets/img/logo.jpg
new file mode 100644
index 0000000..c738cbd
--- /dev/null
+++ b/src/assets/img/logo.jpg
Binary files differ
diff --git a/src/assets/img/logo.png b/src/assets/img/logo.png
new file mode 100644
index 0000000..def45bb
--- /dev/null
+++ b/src/assets/img/logo.png
Binary files differ
diff --git a/src/assets/img/logo_bg.png b/src/assets/img/logo_bg.png
new file mode 100644
index 0000000..5434068
--- /dev/null
+++ b/src/assets/img/logo_bg.png
Binary files differ
diff --git a/src/assets/img/loudou.png b/src/assets/img/loudou.png
new file mode 100644
index 0000000..527b568
--- /dev/null
+++ b/src/assets/img/loudou.png
Binary files differ
diff --git a/src/assets/img/mobile.png b/src/assets/img/mobile.png
new file mode 100644
index 0000000..10f40fc
--- /dev/null
+++ b/src/assets/img/mobile.png
Binary files differ
diff --git a/src/assets/img/money_detail.png b/src/assets/img/money_detail.png
new file mode 100644
index 0000000..fbd78e8
--- /dev/null
+++ b/src/assets/img/money_detail.png
Binary files differ
diff --git a/src/assets/img/more_dot.png b/src/assets/img/more_dot.png
new file mode 100644
index 0000000..e4e3689
--- /dev/null
+++ b/src/assets/img/more_dot.png
Binary files differ
diff --git a/src/assets/img/no_data.png b/src/assets/img/no_data.png
new file mode 100644
index 0000000..98f0ae8
--- /dev/null
+++ b/src/assets/img/no_data.png
Binary files differ
diff --git a/src/assets/img/no_task.png b/src/assets/img/no_task.png
new file mode 100644
index 0000000..110f8b2
--- /dev/null
+++ b/src/assets/img/no_task.png
Binary files differ
diff --git a/src/assets/img/nopermission.png b/src/assets/img/nopermission.png
new file mode 100644
index 0000000..087de83
--- /dev/null
+++ b/src/assets/img/nopermission.png
Binary files differ
diff --git a/src/assets/img/person_dot.png b/src/assets/img/person_dot.png
new file mode 100644
index 0000000..bc2a52b
--- /dev/null
+++ b/src/assets/img/person_dot.png
Binary files differ
diff --git a/src/assets/img/post.png b/src/assets/img/post.png
new file mode 100644
index 0000000..82d240f
--- /dev/null
+++ b/src/assets/img/post.png
Binary files differ
diff --git a/src/assets/img/product_detail.png b/src/assets/img/product_detail.png
new file mode 100644
index 0000000..2551e33
--- /dev/null
+++ b/src/assets/img/product_detail.png
Binary files differ
diff --git a/src/assets/img/project/archive_project.png b/src/assets/img/project/archive_project.png
new file mode 100644
index 0000000..c2638af
--- /dev/null
+++ b/src/assets/img/project/archive_project.png
Binary files differ
diff --git a/src/assets/img/project/head.png b/src/assets/img/project/head.png
new file mode 100644
index 0000000..ff16f21
--- /dev/null
+++ b/src/assets/img/project/head.png
Binary files differ
diff --git a/src/assets/img/project/my_task.png b/src/assets/img/project/my_task.png
new file mode 100644
index 0000000..762e034
--- /dev/null
+++ b/src/assets/img/project/my_task.png
Binary files differ
diff --git a/src/assets/img/project/project_add.png b/src/assets/img/project/project_add.png
new file mode 100644
index 0000000..12f7e6c
--- /dev/null
+++ b/src/assets/img/project/project_add.png
Binary files differ
diff --git a/src/assets/img/project/project_filtrate.png b/src/assets/img/project/project_filtrate.png
new file mode 100644
index 0000000..120e68f
--- /dev/null
+++ b/src/assets/img/project/project_filtrate.png
Binary files differ
diff --git a/src/assets/img/project/relevance_file.png b/src/assets/img/project/relevance_file.png
new file mode 100644
index 0000000..c81fbb4
--- /dev/null
+++ b/src/assets/img/project/relevance_file.png
Binary files differ
diff --git a/src/assets/img/project/schedule.png b/src/assets/img/project/schedule.png
new file mode 100644
index 0000000..656ad9a
--- /dev/null
+++ b/src/assets/img/project/schedule.png
Binary files differ
diff --git a/src/assets/img/project/send_contacts.png b/src/assets/img/project/send_contacts.png
new file mode 100644
index 0000000..bbbfdb8
--- /dev/null
+++ b/src/assets/img/project/send_contacts.png
Binary files differ
diff --git a/src/assets/img/project/smiling_face.png b/src/assets/img/project/smiling_face.png
new file mode 100644
index 0000000..df83ca6
--- /dev/null
+++ b/src/assets/img/project/smiling_face.png
Binary files differ
diff --git a/src/assets/img/project/t_set.png b/src/assets/img/project/t_set.png
new file mode 100644
index 0000000..84414b6
--- /dev/null
+++ b/src/assets/img/project/t_set.png
Binary files differ
diff --git a/src/assets/img/project/task_accessory.png b/src/assets/img/project/task_accessory.png
new file mode 100644
index 0000000..d6f2ad1
--- /dev/null
+++ b/src/assets/img/project/task_accessory.png
Binary files differ
diff --git a/src/assets/img/project/task_add.png b/src/assets/img/project/task_add.png
new file mode 100644
index 0000000..ebc169a
--- /dev/null
+++ b/src/assets/img/project/task_add.png
Binary files differ
diff --git a/src/assets/img/project/task_circle.png b/src/assets/img/project/task_circle.png
new file mode 100644
index 0000000..275b174
--- /dev/null
+++ b/src/assets/img/project/task_circle.png
Binary files differ
diff --git a/src/assets/img/project/task_close.png b/src/assets/img/project/task_close.png
new file mode 100644
index 0000000..f6334b0
--- /dev/null
+++ b/src/assets/img/project/task_close.png
Binary files differ
diff --git a/src/assets/img/project/task_download.png b/src/assets/img/project/task_download.png
new file mode 100644
index 0000000..2b45441
--- /dev/null
+++ b/src/assets/img/project/task_download.png
Binary files differ
diff --git a/src/assets/img/project/task_ellipsis.png b/src/assets/img/project/task_ellipsis.png
new file mode 100644
index 0000000..12ecd50
--- /dev/null
+++ b/src/assets/img/project/task_ellipsis.png
Binary files differ
diff --git a/src/assets/img/project/task_end_time.png b/src/assets/img/project/task_end_time.png
new file mode 100644
index 0000000..2951600
--- /dev/null
+++ b/src/assets/img/project/task_end_time.png
Binary files differ
diff --git a/src/assets/img/project/task_priority.png b/src/assets/img/project/task_priority.png
new file mode 100644
index 0000000..7523d2c
--- /dev/null
+++ b/src/assets/img/project/task_priority.png
Binary files differ
diff --git a/src/assets/img/project/task_subtask.png b/src/assets/img/project/task_subtask.png
new file mode 100644
index 0000000..1259122
--- /dev/null
+++ b/src/assets/img/project/task_subtask.png
Binary files differ
diff --git a/src/assets/img/project/task_tag.png b/src/assets/img/project/task_tag.png
new file mode 100644
index 0000000..00bb157
--- /dev/null
+++ b/src/assets/img/project/task_tag.png
Binary files differ
diff --git a/src/assets/img/qushi.png b/src/assets/img/qushi.png
new file mode 100644
index 0000000..d99679b
--- /dev/null
+++ b/src/assets/img/qushi.png
Binary files differ
diff --git a/src/assets/img/relevance_business.png b/src/assets/img/relevance_business.png
new file mode 100644
index 0000000..cc99dd5
--- /dev/null
+++ b/src/assets/img/relevance_business.png
Binary files differ
diff --git a/src/assets/img/relevance_file.png b/src/assets/img/relevance_file.png
new file mode 100644
index 0000000..c81fbb4
--- /dev/null
+++ b/src/assets/img/relevance_file.png
Binary files differ
diff --git a/src/assets/img/scene_add.png b/src/assets/img/scene_add.png
new file mode 100644
index 0000000..4635ac2
--- /dev/null
+++ b/src/assets/img/scene_add.png
Binary files differ
diff --git a/src/assets/img/scene_set.png b/src/assets/img/scene_set.png
new file mode 100644
index 0000000..923cda9
--- /dev/null
+++ b/src/assets/img/scene_set.png
Binary files differ
diff --git a/src/assets/img/sea_detail.png b/src/assets/img/sea_detail.png
new file mode 100644
index 0000000..6aa7798
--- /dev/null
+++ b/src/assets/img/sea_detail.png
Binary files differ
diff --git a/src/assets/img/section_reset_name.png b/src/assets/img/section_reset_name.png
new file mode 100644
index 0000000..1b7c83b
--- /dev/null
+++ b/src/assets/img/section_reset_name.png
Binary files differ
diff --git a/src/assets/img/selection_add_user.png b/src/assets/img/selection_add_user.png
new file mode 100644
index 0000000..5b909ac
--- /dev/null
+++ b/src/assets/img/selection_add_user.png
Binary files differ
diff --git a/src/assets/img/selection_alloc.png b/src/assets/img/selection_alloc.png
new file mode 100644
index 0000000..7fd467d
--- /dev/null
+++ b/src/assets/img/selection_alloc.png
Binary files differ
diff --git a/src/assets/img/selection_convert_customer.png b/src/assets/img/selection_convert_customer.png
new file mode 100644
index 0000000..f8b95d8
--- /dev/null
+++ b/src/assets/img/selection_convert_customer.png
Binary files differ
diff --git a/src/assets/img/selection_deal_status.png b/src/assets/img/selection_deal_status.png
new file mode 100644
index 0000000..c7ae1dd
--- /dev/null
+++ b/src/assets/img/selection_deal_status.png
Binary files differ
diff --git a/src/assets/img/selection_delete.png b/src/assets/img/selection_delete.png
new file mode 100644
index 0000000..47a149a
--- /dev/null
+++ b/src/assets/img/selection_delete.png
Binary files differ
diff --git a/src/assets/img/selection_delete_user.png b/src/assets/img/selection_delete_user.png
new file mode 100644
index 0000000..7c2491f
--- /dev/null
+++ b/src/assets/img/selection_delete_user.png
Binary files differ
diff --git a/src/assets/img/selection_disable.png b/src/assets/img/selection_disable.png
new file mode 100644
index 0000000..bfc9469
--- /dev/null
+++ b/src/assets/img/selection_disable.png
Binary files differ
diff --git a/src/assets/img/selection_edit.png b/src/assets/img/selection_edit.png
new file mode 100644
index 0000000..83c3e54
--- /dev/null
+++ b/src/assets/img/selection_edit.png
Binary files differ
diff --git a/src/assets/img/selection_export.png b/src/assets/img/selection_export.png
new file mode 100644
index 0000000..ed21ef5
--- /dev/null
+++ b/src/assets/img/selection_export.png
Binary files differ
diff --git a/src/assets/img/selection_get.png b/src/assets/img/selection_get.png
new file mode 100644
index 0000000..664885d
--- /dev/null
+++ b/src/assets/img/selection_get.png
Binary files differ
diff --git a/src/assets/img/selection_lock.png b/src/assets/img/selection_lock.png
new file mode 100644
index 0000000..0919448
--- /dev/null
+++ b/src/assets/img/selection_lock.png
Binary files differ
diff --git a/src/assets/img/selection_putseas.png b/src/assets/img/selection_putseas.png
new file mode 100644
index 0000000..05c8bdb
--- /dev/null
+++ b/src/assets/img/selection_putseas.png
Binary files differ
diff --git a/src/assets/img/selection_reset.png b/src/assets/img/selection_reset.png
new file mode 100644
index 0000000..a7596fd
--- /dev/null
+++ b/src/assets/img/selection_reset.png
Binary files differ
diff --git a/src/assets/img/selection_start.png b/src/assets/img/selection_start.png
new file mode 100644
index 0000000..17b0491
--- /dev/null
+++ b/src/assets/img/selection_start.png
Binary files differ
diff --git a/src/assets/img/selection_transfer.png b/src/assets/img/selection_transfer.png
new file mode 100644
index 0000000..67e79d1
--- /dev/null
+++ b/src/assets/img/selection_transfer.png
Binary files differ
diff --git a/src/assets/img/selection_unlock.png b/src/assets/img/selection_unlock.png
new file mode 100644
index 0000000..afe6fb3
--- /dev/null
+++ b/src/assets/img/selection_unlock.png
Binary files differ
diff --git a/src/assets/img/send_business.png b/src/assets/img/send_business.png
new file mode 100644
index 0000000..853e41c
--- /dev/null
+++ b/src/assets/img/send_business.png
Binary files differ
diff --git a/src/assets/img/send_contacts.png b/src/assets/img/send_contacts.png
new file mode 100644
index 0000000..bbbfdb8
--- /dev/null
+++ b/src/assets/img/send_contacts.png
Binary files differ
diff --git a/src/assets/img/send_file.png b/src/assets/img/send_file.png
new file mode 100644
index 0000000..8210301
--- /dev/null
+++ b/src/assets/img/send_file.png
Binary files differ
diff --git a/src/assets/img/send_img.png b/src/assets/img/send_img.png
new file mode 100644
index 0000000..1e4edeb
--- /dev/null
+++ b/src/assets/img/send_img.png
Binary files differ
diff --git a/src/assets/img/setting.png b/src/assets/img/setting.png
new file mode 100644
index 0000000..c56fa39
--- /dev/null
+++ b/src/assets/img/setting.png
Binary files differ
diff --git a/src/assets/img/smiling_face.png b/src/assets/img/smiling_face.png
new file mode 100644
index 0000000..df83ca6
--- /dev/null
+++ b/src/assets/img/smiling_face.png
Binary files differ
diff --git a/src/assets/img/sprite/vue-emoji.png b/src/assets/img/sprite/vue-emoji.png
new file mode 100644
index 0000000..04337ad
--- /dev/null
+++ b/src/assets/img/sprite/vue-emoji.png
Binary files differ
diff --git a/src/assets/img/step_success.png b/src/assets/img/step_success.png
new file mode 100644
index 0000000..5d74f4d
--- /dev/null
+++ b/src/assets/img/step_success.png
Binary files differ
diff --git a/src/assets/img/step_wait.png b/src/assets/img/step_wait.png
new file mode 100644
index 0000000..bbd1dd0
--- /dev/null
+++ b/src/assets/img/step_wait.png
Binary files differ
diff --git a/src/assets/img/structure.png b/src/assets/img/structure.png
new file mode 100644
index 0000000..8e1465b
--- /dev/null
+++ b/src/assets/img/structure.png
Binary files differ
diff --git a/src/assets/img/system/app/call_disable.png b/src/assets/img/system/app/call_disable.png
new file mode 100644
index 0000000..46970e9
--- /dev/null
+++ b/src/assets/img/system/app/call_disable.png
Binary files differ
diff --git a/src/assets/img/system/app/call_enable.png b/src/assets/img/system/app/call_enable.png
new file mode 100644
index 0000000..38b4459
--- /dev/null
+++ b/src/assets/img/system/app/call_enable.png
Binary files differ
diff --git a/src/assets/img/system/app/crm_disable.png b/src/assets/img/system/app/crm_disable.png
new file mode 100644
index 0000000..b95a342
--- /dev/null
+++ b/src/assets/img/system/app/crm_disable.png
Binary files differ
diff --git a/src/assets/img/system/app/crm_enable.png b/src/assets/img/system/app/crm_enable.png
new file mode 100644
index 0000000..75f3e5e
--- /dev/null
+++ b/src/assets/img/system/app/crm_enable.png
Binary files differ
diff --git a/src/assets/img/system/app/hrm.png b/src/assets/img/system/app/hrm.png
new file mode 100644
index 0000000..96e7329
--- /dev/null
+++ b/src/assets/img/system/app/hrm.png
Binary files differ
diff --git a/src/assets/img/system/app/inventory.png b/src/assets/img/system/app/inventory.png
new file mode 100644
index 0000000..0d54578
--- /dev/null
+++ b/src/assets/img/system/app/inventory.png
Binary files differ
diff --git a/src/assets/img/system/app/oa_disable.png b/src/assets/img/system/app/oa_disable.png
new file mode 100644
index 0000000..dcec257
--- /dev/null
+++ b/src/assets/img/system/app/oa_disable.png
Binary files differ
diff --git a/src/assets/img/system/app/oa_enable.png b/src/assets/img/system/app/oa_enable.png
new file mode 100644
index 0000000..fa9ea4c
--- /dev/null
+++ b/src/assets/img/system/app/oa_enable.png
Binary files differ
diff --git a/src/assets/img/system/app/phone.png b/src/assets/img/system/app/phone.png
new file mode 100644
index 0000000..f38f74b
--- /dev/null
+++ b/src/assets/img/system/app/phone.png
Binary files differ
diff --git a/src/assets/img/system/app/project_disable.png b/src/assets/img/system/app/project_disable.png
new file mode 100644
index 0000000..5bfa9d2
--- /dev/null
+++ b/src/assets/img/system/app/project_disable.png
Binary files differ
diff --git a/src/assets/img/system/app/project_enable.png b/src/assets/img/system/app/project_enable.png
new file mode 100644
index 0000000..bda34d8
--- /dev/null
+++ b/src/assets/img/system/app/project_enable.png
Binary files differ
diff --git a/src/assets/img/system/customer_pool_module.png b/src/assets/img/system/customer_pool_module.png
new file mode 100644
index 0000000..5483581
--- /dev/null
+++ b/src/assets/img/system/customer_pool_module.png
Binary files differ
diff --git a/src/assets/img/system/examine_module.png b/src/assets/img/system/examine_module.png
new file mode 100644
index 0000000..753d392
--- /dev/null
+++ b/src/assets/img/system/examine_module.png
Binary files differ
diff --git a/src/assets/img/system/leads_module.png b/src/assets/img/system/leads_module.png
new file mode 100644
index 0000000..e6cad0d
--- /dev/null
+++ b/src/assets/img/system/leads_module.png
Binary files differ
diff --git a/src/assets/img/system/leads_pool_module.png b/src/assets/img/system/leads_pool_module.png
new file mode 100644
index 0000000..94ee9fd
--- /dev/null
+++ b/src/assets/img/system/leads_pool_module.png
Binary files differ
diff --git a/src/assets/img/system/log_module.png b/src/assets/img/system/log_module.png
new file mode 100644
index 0000000..c1c659b
--- /dev/null
+++ b/src/assets/img/system/log_module.png
Binary files differ
diff --git a/src/assets/img/system/notice_module.png b/src/assets/img/system/notice_module.png
new file mode 100644
index 0000000..73c50c2
--- /dev/null
+++ b/src/assets/img/system/notice_module.png
Binary files differ
diff --git a/src/assets/img/system/schedule_module.png b/src/assets/img/system/schedule_module.png
new file mode 100644
index 0000000..c590a48
--- /dev/null
+++ b/src/assets/img/system/schedule_module.png
Binary files differ
diff --git a/src/assets/img/system/task_module.png b/src/assets/img/system/task_module.png
new file mode 100644
index 0000000..6da12b1
--- /dev/null
+++ b/src/assets/img/system/task_module.png
Binary files differ
diff --git a/src/assets/img/t_set.png b/src/assets/img/t_set.png
new file mode 100644
index 0000000..84414b6
--- /dev/null
+++ b/src/assets/img/t_set.png
Binary files differ
diff --git a/src/assets/img/tablefilter.png b/src/assets/img/tablefilter.png
new file mode 100644
index 0000000..f4188dd
--- /dev/null
+++ b/src/assets/img/tablefilter.png
Binary files differ
diff --git a/src/assets/img/task_accessory.png b/src/assets/img/task_accessory.png
new file mode 100644
index 0000000..d6f2ad1
--- /dev/null
+++ b/src/assets/img/task_accessory.png
Binary files differ
diff --git a/src/assets/img/task_add.png b/src/assets/img/task_add.png
new file mode 100644
index 0000000..ebc169a
--- /dev/null
+++ b/src/assets/img/task_add.png
Binary files differ
diff --git a/src/assets/img/task_close.png b/src/assets/img/task_close.png
new file mode 100644
index 0000000..602b600
--- /dev/null
+++ b/src/assets/img/task_close.png
Binary files differ
diff --git a/src/assets/img/task_edit_def.png b/src/assets/img/task_edit_def.png
new file mode 100644
index 0000000..802808e
--- /dev/null
+++ b/src/assets/img/task_edit_def.png
Binary files differ
diff --git a/src/assets/img/task_ellipsis.png b/src/assets/img/task_ellipsis.png
new file mode 100644
index 0000000..12ecd50
--- /dev/null
+++ b/src/assets/img/task_ellipsis.png
Binary files differ
diff --git a/src/assets/img/unfold.png b/src/assets/img/unfold.png
new file mode 100644
index 0000000..c4b5e14
--- /dev/null
+++ b/src/assets/img/unfold.png
Binary files differ
diff --git a/src/assets/img/update_files.png b/src/assets/img/update_files.png
new file mode 100644
index 0000000..8210301
--- /dev/null
+++ b/src/assets/img/update_files.png
Binary files differ
diff --git a/src/assets/img/work_examine.png b/src/assets/img/work_examine.png
new file mode 100644
index 0000000..35063d2
--- /dev/null
+++ b/src/assets/img/work_examine.png
Binary files differ
diff --git a/src/assets/img/work_log.png b/src/assets/img/work_log.png
new file mode 100644
index 0000000..afe6e51
--- /dev/null
+++ b/src/assets/img/work_log.png
Binary files differ
diff --git a/src/assets/img/work_notice.png b/src/assets/img/work_notice.png
new file mode 100644
index 0000000..4051076
--- /dev/null
+++ b/src/assets/img/work_notice.png
Binary files differ
diff --git a/src/assets/img/work_schedule.png b/src/assets/img/work_schedule.png
new file mode 100644
index 0000000..8b37302
--- /dev/null
+++ b/src/assets/img/work_schedule.png
Binary files differ
diff --git a/src/assets/img/work_statistics.png b/src/assets/img/work_statistics.png
new file mode 100644
index 0000000..1d766d8
--- /dev/null
+++ b/src/assets/img/work_statistics.png
Binary files differ
diff --git a/src/assets/img/work_task.png b/src/assets/img/work_task.png
new file mode 100644
index 0000000..e39f040
--- /dev/null
+++ b/src/assets/img/work_task.png
Binary files differ
diff --git a/src/assets/img/zhibiao.png b/src/assets/img/zhibiao.png
new file mode 100644
index 0000000..8d52a31
--- /dev/null
+++ b/src/assets/img/zhibiao.png
Binary files differ
diff --git a/src/components/CreateCom/CrmRelative.vue b/src/components/CreateCom/CrmRelative.vue
new file mode 100644
index 0000000..5a72234
--- /dev/null
+++ b/src/components/CreateCom/CrmRelative.vue
@@ -0,0 +1,377 @@
+<template>
+  <div class="cr-contianer">
+      <div class="title" v-show="!isProduct">{{ getTitle() }}
+        <img
+          class="t-close"
+          src="@/assets/img/close.png"
+          @click="closeView" >
+      </div>
+    <div style="height: 100%;position: relative;">
+      <div
+        v-if="crmType === 'product'"
+        class="cr-body-side">
+        <el-tree
+          ref="tree"
+          :data="treeData"
+          :expand-on-click-node="false"
+          node-key="TypeName"
+          :props="defaultProps"
+          highlight-current
+          @node-click="changeDepClick">
+          <flexbox
+            slot-scope="{ node, data }"
+            class="node-data">
+            <el-tooltip :content="data.TypeName" placement="top">
+              <div class="node-label">{{ data.TypeName }}</div>
+            </el-tooltip>
+          </flexbox>
+        </el-tree>
+        <!--<div
+          v-for="(item, index) in leftSides"
+          :key="index"
+          :class="leftType===item.type? 'side-item-select' : 'side-item-default'"
+          class="side-item"
+          @click="sideClick(item)">{{ item.name }}</div>-->
+      </div>
+      <div :style="{ 'padding-left': crmType === 'product' ? '220px' : '0'}">
+        <crm-relative-table
+          v-for="(item, index) in leftSides"
+          v-show="item.type === leftType"
+          :isProduct="isProduct"
+          :key="index"
+          :ref="'crm'+item.type"
+          :show="show && item.type === leftType"
+          :radio="radio"
+          :crm-type="item.type"
+          :selected-data="currentSelectedData"
+          :action="action"
+          @closeView="closeView"
+          @changeCheckout="checkCrmTypeInfos"/>
+
+          <!--<div class="handle-bar">
+            <el-button @click="closeView">取消</el-button>
+            <el-button
+              type="primary"
+              @click="confirmClick">确定</el-button>
+          </div>-->
+      </div>
+    </div>
+  </div>
+</template>
+
+<script type="text/javascript">
+import { GetAutoProductTypeList } from '@/api/customermanagement/product'
+import CrmRelativeTable from './CrmRelativeTable'
+import { objDeepCopy } from '@/utils'
+
+export default {
+  name: 'CrmRelatieve', // 相关
+  components: {
+    CrmRelativeTable
+  },
+  props: {
+    /** 多选框 只能选一个 */
+    radio: {
+      type: Boolean,
+      default: true
+    },
+    isProduct: {
+      type: Boolean,
+      default: true
+    },
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    /** 需要展示哪些类型 默认关键字数组 */
+    showTypes: {
+      type: Array,
+      default: () => {
+        return [
+          'customer',
+          'contacts',
+          'leads',
+          'business',
+          'contract',
+          'product'
+        ]
+      }
+    },
+    /** 已选信息 */
+    selectedData: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    /** true 的时候 发请求 */
+    show: {
+      type: Boolean,
+      default: true
+    },
+    /**
+     * default 默认  condition 固定条件筛选 moduleType 下的
+     * relative: 相关 添加
+     */
+    action: {
+      type: Object,
+      default: () => {
+        return {
+          type: 'default',
+          data: {}
+        }
+      }
+    }
+  },
+  data () {
+    return {
+      leftType: 'customer',
+      leftSides: [],
+      treeData: [],
+      /** 各类型选择的值 */
+      currentSelectedData: {},
+      defaultProps: {
+        children: 'ProductResultList',
+        label: 'TypeName'
+      }
+    }
+  },
+  computed: {},
+  watch: {
+    selectedData: function (data) {
+      this.currentSelectedData = objDeepCopy(data)
+    },
+    // 刷新标记
+    show (val) {
+      if (val) {
+        this.currentSelectedData = objDeepCopy(this.selectedData)
+      }
+    }
+  },
+  mounted () {
+    var leftItems = {
+      customer: {
+        name: '客户',
+        type: 'customer'
+      },
+      contacts: {
+        name: '联系人',
+        type: 'contacts'
+      },
+      leads: {
+        name: '线索',
+        type: 'leads'
+      },
+      business: {
+        name: '商机',
+        type: 'business'
+      },
+      contract: {
+        name: '合同',
+        type: 'contract'
+      },
+      product: {
+        name: '产品',
+        type: 'product'
+      }
+    }
+    if (this.crmType) {
+      this.leftType = this.crmType
+      this.leftSides.push(leftItems[this.crmType])
+    } else {
+      for (let index = 0; index < this.showTypes.length; index++) {
+        const element = this.showTypes[index]
+        this.leftSides.push(leftItems[element])
+      }
+    }
+    this.currentSelectedData = objDeepCopy(this.selectedData)
+    this.getTreeList()
+  },
+  methods: {
+    /**
+     * 刷新列表
+     */
+    refreshList () {
+      this.$refs['crm' + this.crmType][0].refreshList()
+    },
+    getTreeList () {
+      GetAutoProductTypeList().then(res => {
+        console.log(res)
+        if (res.data.ErrorCode === 200) {
+          this.treeData = res.data.Result || []
+        }
+      })
+    },
+    changeDepClick (data) {
+      console.log(data)
+      this.$refs['crm' + this.crmType][0].getFieldList(data.ParameterLink)
+    },
+    sideClick (item) {
+      this.leftType = item.type
+    },
+    clearAll () {
+      if (this.crmType) {
+        this.$refs['crm' + this.crmType][0].clearAll()
+      }
+    },
+    // 当用户手动勾选全选 Checkbox 时触发的事件
+    selectAll () {},
+    // 关闭操作
+    closeView () {
+      this.$emit('close')
+    },
+    checkCrmTypeInfos (data) {
+      this.currentSelectedData[data.type] = data.data
+      if (this.crmType) {
+        // 以单类型传值
+        this.$emit('changeVal', this.currentSelectedData[this.crmType])
+      } else {
+        this.$emit('changeVal', this.currentSelectedData)
+      }
+
+      this.$emit('close')
+    },
+    // 根据类型获取标题展示名称
+    getTitle () {
+      if (this.crmType === 'leads') {
+        return '关联线索'
+      } else if (this.crmType === 'customer') {
+        return '关联客户'
+      } else if (this.crmType === 'contacts') {
+        return '关联联系人'
+      } else if (this.crmType === 'business') {
+        return '关联商机'
+      } else if (this.crmType === 'product') {
+        return '关联产品'
+      } else if (this.crmType === 'contract') {
+        return '关联合同'
+      } else {
+        return '关联业务'
+      }
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.cr-contianer {
+  // height: 600px;
+  position: relative;
+  // padding: 50px 0 50px 0;
+}
+
+.title {
+  padding: 0 30px;
+  font-size: 16px;
+  line-height: 50px;
+  font-weight: 550;
+  color: #333333;
+  height: 50px;
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  z-index: 3;
+  // border-bottom: 1px solid #e6e6e6;
+  .t-close{
+    position: absolute;
+    right: 30px;
+    top: 12px;
+    cursor: pointer;
+  }
+}
+
+.handle-bar {
+  height: 50px;
+  // position: absolute;
+  // bottom: 0;
+  // left: 0;
+  // right: 40%;
+  z-index: 2;
+  display: flex;
+  align-items: center;
+  align-content: center;
+  justify-content: center;
+  width: 100%;
+  button {
+    float: right;
+    margin-top: 10px;
+    margin-right: 10px;
+  }
+}
+
+.cr-body-side {
+  flex-shrink: 0;
+  z-index: 3;
+  position: absolute;
+  left: 0;
+  top: 0;
+  bottom: 0;
+  width: 220px;
+  font-size: 12px;
+  background-color: #F8F8F8;
+  border-right: 1px solid #e6e6e6;
+  height: 650px;
+  overflow: auto;
+  /deep/ .el-tree{
+    background-color: #F8F8F8;
+  }
+  .side-item {
+    height: 35px;
+    line-height: 35px;
+    padding: 0 20px;
+    cursor: pointer;
+  }
+}
+
+.side-item-default {
+  color: #333;
+}
+
+.side-item-select {
+  color: #409eff;
+  background-color: #ecf5ff;
+}
+.el-dialog /deep/ .el-dialog__headerbtn{
+  padding: 10px;
+}
+// tree
+.el-tree /deep/ .el-tree-node__content {
+  height: 30px;
+   &:hover{
+    color: #4D88FF;
+    background-color: #EBF1FF;
+  }
+  .node-data {
+    .node-label {
+      margin-right: 8px;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+      width: 150px;
+    }
+    .node-label-set {
+      display: none;
+    }
+  }
+
+  .node-data:hover .node-label-set {
+    display: block;
+  }
+}
+.el-tree /deep/ .el-tree-node.is-current > .el-tree-node__content {
+  background-color: #4D88FF;
+  color: #fff;
+  // border-right: 2px solid #4D88FF;
+  .node-label-set {
+    display: block;
+  }
+}
+.system-view-nav /deep/ .el-tree-node > .el-tree-node__children {
+  overflow: visible;
+}
+.system-view-nav /deep/ .el-tree > .el-tree-node {
+  min-width: 100%;
+  display: inline-block !important;
+}
+</style>
diff --git a/src/components/CreateCom/CrmRelativeCell.vue b/src/components/CreateCom/CrmRelativeCell.vue
new file mode 100644
index 0000000..6ee6760
--- /dev/null
+++ b/src/components/CreateCom/CrmRelativeCell.vue
@@ -0,0 +1,179 @@
+<template>
+  <el-popover
+    v-model="showPopover"
+    :disabled="disabled"
+    placement="bottom"
+    width="700"
+    popper-class="no-padding-popover"
+    trigger="click">
+    <crm-relative
+      v-if="!disabled&&showSelectView"
+      ref="crmrelative"
+      :crm-type="item.data.formType"
+      :action="relationAction"
+      @close="showPopover=false"
+      @changeCheckout="checkInfos"/>
+    <flexbox
+      slot="reference"
+      :class="[disabled ? 'is_disabled' : 'is_valid']"
+      wrap="wrap"
+      class="user-container"
+      @click.native="contentClick">
+      <div
+        v-for="(aitem, aindex) in dataValue"
+        :key="aindex"
+        class="user-item"
+        @click.stop="deleteinfo(aindex)">{{ getShowName(aitem) }}
+        <i class="delete-icon el-icon-close"/>
+      </div>
+      <div
+        v-if="dataValue.length === 0"
+        class="add-item">+添加</div>
+    </flexbox>
+  </el-popover>
+</template>
+<script type="text/javascript">
+import CrmRelative from './CrmRelative'
+import arrayMixin from './arrayMixin'
+
+export default {
+  name: 'CrmRelativeCell', // 相关模块CRMCell
+  components: {
+    CrmRelative
+  },
+  mixins: [arrayMixin],
+  props: {
+    relation: {
+      // 相关ID
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  data () {
+    return {
+      showPopover: false, // 展示popover
+      showSelectView: false, // 内容
+      radio: true, // 是否单选
+      relationAction: { type: 'default' }
+    }
+  },
+  computed: {
+    // 如果有相关ID  展示相关效果 例如客户下的商机和合同
+    isRelationShow () {
+      return this.item && this.item.data && this.item.data.relation_id
+    }
+  },
+  watch: {
+    relation: function (val) {
+      if (val.moduleType) {
+        this.relationAction = { type: 'condition', data: val }
+      } else {
+        this.relationAction = { type: 'default' }
+      }
+    }
+  },
+  mounted () {
+    if (this.relation && this.relation.moduleType) {
+      this.relationAction = { type: 'condition', data: this.relation }
+    } else {
+      this.relationAction = { type: 'default' }
+    }
+  },
+  methods: {
+    /** 选中 */
+    checkInfos (data) {
+      this.dataValue = data.data ? data.data : []
+      this.$emit('value-change', {
+        index: this.index,
+        value: data.data
+      })
+    },
+    /** 删除 */
+    deleteinfo (index) {
+      if (this.disabled) return
+      if (this.radio && this.$refs.crmrelative) {
+        // 如果单选告知删除
+        this.$refs.crmrelative.clearAll()
+      }
+      if (this.dataValue.length === 1) {
+        this.dataValue = []
+      } else {
+        this.dataValue.splice(index, 1)
+      }
+
+      this.$emit('value-change', {
+        index: this.index,
+        value: this.dataValue
+      })
+    },
+    contentClick () {
+      this.showSelectView = true
+    },
+    getShowName (data) {
+      if (this.item.data.formType === 'receivables') {
+        return data.number
+      } else if (this.item.data.formType === 'customer') {
+        return data.customerName
+      } else if (this.item.data.formType === 'business') {
+        return data.businessName
+      } else if (this.item.data.formType === 'contract') {
+        return data.contractNum || data.num
+      }
+      return data.name
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+.user-container {
+  min-height: 34px;
+  position: relative;
+  border-radius: 3px;
+  font-size: 12px;
+  border: 1px solid #ddd;
+  color: #333333;
+  padding: 5px;
+  line-height: 15px;
+  .user-item {
+    padding: 5px;
+    background-color: #e2ebf9;
+    border-radius: 3px;
+    margin: 3px;
+    cursor: pointer;
+  }
+  .add-item {
+    padding: 5px;
+    color: #4D88FF;
+    cursor: pointer;
+  }
+  .delete-icon {
+    color: #999;
+    cursor: pointer;
+  }
+}
+
+.user-container.is_disabled {
+  background-color: #f5f7fa;
+  border-color: #e4e7ed;
+  cursor: not-allowed;
+  .user-item {
+    background-color: #f0f4f8ea;
+    color: #c0c4cc;
+    cursor: not-allowed;
+  }
+  .delete-icon {
+    color: #c0c4cc;
+    cursor: not-allowed;
+  }
+  .add-item {
+    color: #c0c4cc;
+    cursor: not-allowed;
+  }
+}
+
+.user-container.is_valid:hover {
+  border-color: #c0c4cc;
+}
+</style>
diff --git a/src/components/CreateCom/CrmRelativeTable.vue b/src/components/CreateCom/CrmRelativeTable.vue
new file mode 100644
index 0000000..745a415
--- /dev/null
+++ b/src/components/CreateCom/CrmRelativeTable.vue
@@ -0,0 +1,590 @@
+<template>
+  <div class="cr-body-content">
+    <flexbox class="content-header">
+      <!--<Xh-inputSelect v-if="isProduct" :isProduct="isProduct" @getName="getName" :crm-type="crmType" />-->
+      <el-input
+        placeholder='请输入你要搜索的内容'
+        v-model="searchContent"
+        @keyup.enter.native="searchInput"
+        class="search-container">
+      </el-input>
+      <el-button class="searchBtn" type="primary" @click="searchInput">搜索</el-button>
+      <!--<el-button
+        class="create-button"
+        type="primary"
+        @click="isCreate=true">新建</el-button> -->
+    </flexbox>
+    <div class='content-table'>
+      <el-table
+        v-loading="loading"
+        id="crm-table"
+        ref="relativeTable"
+        :data="list"
+        :height="550"
+        :cell-style="cellStyle"
+        class="n-table--border"
+        border
+        highlight-current-row
+        style="width: 100%"
+        @selection-change="handleSelectionChange"
+        @row-click="handleRowClick">
+        <el-table-column
+          show-overflow-tooltip
+          type="selection"/>
+        <el-table-column
+          v-for="(item, index) in fieldList"
+          :key="index"
+          :prop="item.field"
+          :label="item.name"
+          :formatter="fieldFormatter"
+          show-overflow-tooltip>
+          <template
+            slot="header"
+            slot-scope="scope">
+            <div class="table-head-name">
+              {{ scope.column.label }}
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column/>
+      </el-table>
+    </div>
+    <div class="p-contianer" v-show='total>0'>
+      <el-pagination
+        :current-page="currentPage"
+        :page-sizes="pageSizes"
+        :page-size.sync="pageSize"
+        :total="total"
+        class="p-bar"
+        layout="total, sizes, prev, pager, next, jumper"
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"/>
+    </div>
+    <div class="handle-bar">
+      <el-button @click="closeView">取消</el-button>
+      <el-button
+        type="primary"
+        @click="confirmClick">确定</el-button>
+    </div>
+    <c-r-m-create-view
+      v-if="isCreate"
+      :crm-type="crmType"
+      @save-success="getList"
+      @hiden-view="isCreate=false"/>
+  </div>
+</template>
+<script type="text/javascript">
+// import crmTypeModel from '@/views/clients/model/crmTypeModel'
+import { GetSalesChanceList } from '@/api/customermanagement/business'
+import { XhInputSelect } from '@/components/CreateCom'
+import { GetAutoProductListAsync } from '@/api/customermanagement/product'
+
+export default {
+  name: 'CrmRelativeTable', // 相关模块CRMCell
+  components: {
+    XhInputSelect,
+    CRMCreateView: () =>
+      import('@/views/clients/components/CRMCreateView')
+  },
+  props: {
+    show: {
+      type: Boolean,
+      default: false
+    },
+    /** 多选框 只能选一个 */
+    radio: {
+      type: Boolean,
+      default: true
+    },
+    isProduct: {
+      type: Boolean,
+      default: true
+    },
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    /** 已选信息 */
+    selectedData: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    /**
+     * default 默认  condition 固定条件筛选
+     * relative: 相关 添加
+     */
+    action: {
+      type: Object,
+      default: () => {
+        return {
+          type: 'default',
+          data: {}
+        }
+      }
+    }
+  },
+  data () {
+    return {
+      loading: false, // 加载进度
+      searchContent: '', // 输入内容
+      isCreate: false, // 控制新建
+      scenesList: [], // 场景信息
+      sceneInfo: null,
+
+      list: [], // 表数据
+      fieldList: [], // 表头数据
+      currentPage: 1, // 当前页数
+      total: 0,
+      pageSize: 10,
+      pageSizes: [10, 30, 60, 100],
+      otherItems: [],
+      selectedItem: [] // 勾选的数据 点击确定 传递给父组件
+    }
+  },
+  computed: {
+    // 展示相关效果 去除场景
+    isRelationShow () {
+      return this.action.type === 'condition'
+    }
+  },
+  watch: {
+    crmType: function (newValue, oldValue) {
+      if (newValue !== oldValue) {
+        this.fieldList = []
+        this.getFieldList()
+      }
+    },
+    action: function (val) {
+      console.log(this.action, val)
+      if (this.action !== val) {
+        this.sceneInfo = null
+        this.list = [] // 表数据
+        this.fieldList = [] // 表头数据
+        this.currentPage = 1 // 当前页数
+        this.pageSize = 10
+        if (!this.isRelationShow) {
+          this.getSceneList()
+        } else {
+          this.getFieldList()
+        }
+      }
+    },
+    show: {
+      handler (val) {
+        if (val && this.fieldList.length === 0) {
+          // 相关列表展示时不需要场景 直接获取展示字段
+          if (!this.isRelationShow) {
+            this.getSceneList()
+          } else {
+            this.getFieldList()
+          }
+        }
+      },
+      deep: true,
+      immediate: true
+    },
+    // 选择
+    selectedData: function () {
+      // this.checkItemsWithSelectedData()
+    }
+  },
+  mounted () {
+  },
+  methods: {
+    /**
+     * 刷新列表
+     */
+    refreshList () {
+      this.currentPage = 1
+      this.pageSize = 10
+      this.getList()
+    },
+    getName (data) {
+      console.log('this is data of input-select: ', data)
+      // this.formInline.user = data.name
+      // this.inputSelectData = data
+    },
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      return { textAlign: 'left' }
+    },
+    getSceneList () {
+      // this.loading = true
+      // crmSceneIndex({
+      //   type: crmTypeModel[this.crmType]
+      // })
+      //   .then(res => {
+      //     var defaultScene = res.data.filter(function (item, index) {
+      //       return item.isDefault === 1
+      //     })
+      //     this.scenesList = res.data
+      //     if (defaultScene && defaultScene.length > 0) {
+      //       this.sceneInfo = defaultScene[0]
+      //     }
+      //     if (this.scenesList.length === 0) {
+      //       this.scenesList.push({ sceneId: '', name: '全部' })
+      //       this.sceneInfo = this.scenesList[0]
+      //     }
+      //     this.getFieldList()
+      //   })
+      //   .catch(() => {
+      //     this.loading = false
+      //   })
+    },
+    /** 获取字段 */
+    getFieldList (data) {
+      if (this.fieldList && this.fieldList.length === 0) {
+        this.fieldList = this.getDefaultField()
+      }
+      // 获取好字段开始请求数据
+      this.getList(data)
+    },
+    /** 获取列表请求 */
+    getDefaultField () {
+      console.log(this.crmType)
+      if (this.crmType === 'leads') {
+        return [
+          { name: '线索名称', field: 'name', formType: 'leads' },
+          { name: '下次联系时间', field: 'nextTime', formType: 'datetime' },
+          { name: '最后跟进时间', field: 'updateTime', formType: 'datetime' },
+          { name: '创建时间 ', field: 'createTime', formType: 'datetime' }
+        ]
+      } else if (this.crmType === 'customer') {
+        return [
+          { name: '客户名称', field: 'CustomerName', formType: 'customer' },
+          { name: '下次联系时间', field: 'nextTime', formType: 'datetime' },
+          { name: '最后跟进时间', field: 'updateTime', formType: 'datetime' },
+          { name: '创建时间 ', field: 'createTime', formType: 'datetime' }
+        ]
+      } else if (this.crmType === 'contacts') {
+        return [
+          { name: '姓名', field: 'name', formType: 'contacts' },
+          { name: '手机', field: 'mobile', formType: 'mobile' },
+          { name: '电话', field: 'telephone', formType: 'text' },
+          { name: '是否关键决策人', field: '是否关键决策人', formType: 'text' },
+          { name: '职务', field: 'post', formType: 'text' }
+        ]
+      } else if (this.crmType === 'business') {
+        return [
+          { field: 'ChanceName', name: '商机名称', formType: 'text' },
+          { field: 'CustomerName', name: '客户名称', formType: 'text' },
+          { field: 'ContacterName', name: '联系人', formType: 'text' },
+          { field: 'SalesChanceStage', name: '销售阶段', formType: 'text' },
+          { field: 'ExpectedDate', name: '预期成交日期', formType: 'text' },
+          { field: 'ExpectedAmount', name: '商机金额/元', formType: 'text' },
+          { field: 'OwerName', name: '销售负责人', formType: 'text' }
+        ]
+      } else if (this.crmType === 'contract') {
+        return [
+          { name: '合同编号', field: 'num', formType: 'text' },
+          {
+            name: '合同名称',
+            field: this.isRelationShow ? 'contractName' : 'name',
+            formType: 'text'
+          },
+          { name: '客户名称', field: 'customerName', formType: 'text' },
+          { name: '合同金额', field: 'money', formType: 'text' },
+          { name: '开始日期', field: 'startTime', formType: 'text' },
+          { name: '结束日期', field: 'endTime', formType: 'text' }
+        ]
+      } else if (this.crmType === 'product') {
+        return [
+          { name: '产品线', field: 'ProductLine', formType: 'text' },
+          { name: '产品类型', field: 'ProductType', formType: 'text' },
+          { name: 'SKU值', field: 'SKU', formType: 'text' },
+          { name: '产品名称', field: 'ProductName', formType: 'text' },
+          { name: '产品描述', field: 'ProductDesc', formType: 'text' },
+          { name: '产品更新时间', field: 'LastUpdateTime', formType: 'text' },
+          { name: '产品是否在线', field: 'Status', formType: 'text' },
+          { name: '市场参考价(¥)', field: 'ETP', formType: 'text' },
+          { name: '建议经销商转售价(¥)', field: 'RTP', formType: 'text' }
+        ]
+      }
+    },
+    /** 获取列表数据 */
+    getList (data) {
+      console.log(data)
+      this.loading = true
+      let crmIndexRequest
+      crmIndexRequest = this.getIndexRequest()
+      // const params = { search: this.searchContent }
+      let params
+      // 注入场景
+      if (this.sceneInfo) {
+        params.sceneId = this.sceneInfo.sceneId
+      }
+      // 注入关联ID
+      if (this.isRelationShow) {
+        // this.action.data.moduleType 下的 this.crmType 的列表
+        if (this.action.data.moduleType) {
+          crmIndexRequest = {
+            customer: {
+              business: GetSalesChanceList
+              // contacts: crmCustomerQueryContacts,
+              // contract: crmCustomerQueryContract
+            },
+            business: {
+              business: GetSalesChanceList
+              // contacts: crmCustomerQueryContacts,
+              // contract: crmCustomerQueryContract
+            }
+          }[this.action.data.moduleType][this.crmType]
+          params = {
+            'PageIndex': 1,
+            'PageSize': 20,
+            'SelectOwnedType': 0,
+            'Name': this.searchContent,
+            'SalesChanceType': '',
+            'CreateStartTime': '',
+            'CreateEndTime': ''
+          }
+          // params[this.action.data.moduleType + 'Id'] = this.action.data[
+          //   this.action.data.moduleType + 'Id'
+          // ]
+          if (this.action.data.params) {
+            for (const field in this.action.data.params) {
+              params[field] = this.action.data.params[field]
+            }
+          }
+        }
+      } else {
+        params = {
+          PageIndex: this.currentPage,
+          PageSize: this.pageSize,
+          TypeName: data || '',
+          Name: this.searchContent
+        }
+      }
+      crmIndexRequest(params)
+        .then(res => {
+          this.list = res.data.Result.List || []
+          console.log(this.list)
+          /**
+           *  如果已选择的有数据
+           */
+
+          // if (this.selectedData[this.crmType]) {
+          //   this.checkItemsWithSelectedData()
+          // } else {
+          //   this.list = res.data.Result.List
+          // }
+
+          // this.total = Math.ceil(res.data.totalRow / 10)
+          this.total = res.data.Result.Count
+          this.loading = false
+          this.$forceUpdate()
+        })
+        .catch(() => {
+          this.loading = false
+        })
+    },
+    // 标记选择数据
+    checkItemsWithSelectedData () {
+      const selectedArray = this.selectedData[this.crmType].map(item => {
+        item.has = false
+        return item
+      })
+
+      const selectedRows = []
+      this.otherItems = []
+
+      this.list.forEach((item, index) => {
+        selectedArray.forEach((selectedItem, selectedIndex) => {
+          if (item[this.crmType + 'Id'] === selectedItem[this.crmType + 'Id']) {
+            selectedItem.has = true
+            selectedRows.push(item)
+          }
+        })
+      })
+
+      selectedArray.forEach((selectedItem, selectedIndex) => {
+        if (!selectedItem.has) {
+          this.otherItems.push(selectedItem)
+        }
+      })
+
+      this.$nextTick(() => {
+        this.$refs.relativeTable.clearSelection()
+        selectedRows.forEach(row => {
+          this.$refs.relativeTable.toggleRowSelection(row, true)
+        })
+      })
+    },
+    /** 获取列表请求 */
+    getIndexRequest () {
+      // if (this.crmType === 'leads') {
+      //   return crmLeadsIndex
+      // } else if (this.crmType === 'customer') {
+      //   return crmCustomerIndex
+      // } else if (this.crmType === 'contacts') {
+      //   return crmContactsIndex
+      // } else if (this.crmType === 'business') {
+      //   return crmBusinessIndex
+      // } else if (this.crmType === 'contract') {
+      //   return crmContractIndex
+      // } else
+      if (this.crmType === 'product') {
+        return GetAutoProductListAsync
+      }
+    },
+    // 场景选择
+    handleTypeDrop (command) {
+      this.sceneInfo = command
+      this.getList()
+    },
+    /** 列表操作 */
+    // 当某一行被点击时会触发该事件
+    handleRowClick (row, column, event) {},
+    fieldFormatter (row, column) {
+      if (column.property === 'Status') {
+        switch (row[column.property]) {
+          case true:
+            row[column.property] = '是'
+            break
+          case false:
+            row[column.property] = '否'
+            break
+        }
+      }
+      return row[column.property] || '--'
+    },
+    // 当选择项发生变化时会触发该事件
+    handleSelectionChange (val) {
+      if (this.radio) {
+        // this.$refs.relativeTable.clearSelection();
+        val.forEach((row, index) => {
+          if (index === val.length - 1) return
+          this.$refs.relativeTable.toggleRowSelection(row, false)
+        })
+        if (val.length === 0) {
+          this.selectedItem = []
+        } else {
+          this.selectedItem = val.length === 1 ? val : [val[val.length - 1]]
+        }
+      } else {
+        this.selectedItem = this.otherItems.concat(val)
+      }
+    },
+    closeView () {
+      this.$emit('closeView')
+    },
+    // 确定选择
+    confirmClick () {
+      console.log(this.crmType)
+      this.$emit('changeCheckout', {
+        data: this.selectedItem,
+        type: this.crmType
+      })
+    },
+    clearAll () {
+      this.$refs.relativeTable.clearSelection()
+    },
+    // 当用户手动勾选全选 Checkbox 时触发的事件
+    selectAll () {},
+    // 进行搜索操作
+    searchInput () {
+      this.currentPage = 1
+      this.pageSize = 10
+      this.getFieldList()
+      // this.getList()
+    },
+    handleSizeChange (newSize) {
+      this.pageSize = newSize
+      this.getList()
+    },
+    handleCurrentChange (newPage) {
+      this.currentPage = newPage
+      this.getList()
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+@import '../../views/clients/styles/table.scss';
+.cr-body-content {
+  position: relative;
+  background-color: white;
+}
+
+.content-header {
+  position: relative;
+  padding: 10px 30px;
+  .search-container {
+    width: 224px;
+  }
+  .search-container /deep/ .el-input__inner{
+    height: 32px;
+  }
+  .search-container /deep/ .el-input-group__append{
+    background-color: #4D88FF;
+    border-radius: 0px 3px 3px 0px;
+    color: #fff;
+    border: 1px solid #4D88FF;
+  }
+  .create-button {
+    position: absolute;
+    right: 30px;
+    top: 15px;
+    width: 97px;
+    height: 32px;
+    background: #FF8800;
+    border-radius: 3px;
+    border: 1px solid #FF8800;
+  }
+}
+.content-table{
+  padding: 0 30px;
+  margin-bottom: 20px;
+}
+//表尾 上一页按钮
+.table-footer {
+  padding: 0px 30px;
+}
+
+.el-table /deep/ thead th {
+  font-weight: 400;
+  font-size: 12px;
+}
+
+.el-table /deep/ tbody tr td {
+  font-size: 12px;
+}
+.el-table /deep/ thead th,
+thead td {
+  padding: 0;
+  border-right: 1px solid #F7FAFF;
+}
+
+// .el-table /deep/ thead .el-checkbox {
+//   display: none;
+// }
+
+body .el-table th.gutter {
+  display: table-cell !important;
+}
+
+.el-table /deep/ .el-table__body-wrapper {
+  height: calc(100% - 48px) !important;
+}
+.searchBtn{
+  width: 58px;
+  height: 32px;
+  margin-left: 24px;
+}
+.handle-bar {
+  height: 50px;
+  z-index: 2;
+  display: flex;
+  align-items: center;
+  align-content: center;
+  justify-content: center;
+  width: 100%;
+  button {
+    float: right;
+    margin-top: 10px;
+    margin-right: 10px;
+  }
+}
+</style>
diff --git a/src/components/CreateCom/XhBusinessStatus.vue b/src/components/CreateCom/XhBusinessStatus.vue
new file mode 100644
index 0000000..1be8acd
--- /dev/null
+++ b/src/components/CreateCom/XhBusinessStatus.vue
@@ -0,0 +1,67 @@
+<template>
+  <el-select
+    v-model="dataValue"
+    :disabled="disabled"
+    style="width: 100%;"
+    placeholder="请选择"
+    @change="valueChange">
+    <el-option
+      v-for="item in options"
+      :key="item.typeId"
+      :label="item.name"
+      :value="item.typeId"/>
+  </el-select>
+</template>
+<script type="text/javascript">
+import stringMixin from './stringMixin'
+// import { crmBusinessStatusList } from '@/api/clients/business'
+
+export default {
+  name: 'XhBusinessStatus', // 商机状态
+  components: {},
+  mixins: [stringMixin],
+  props: {},
+  data () {
+    return {
+      options: []
+    }
+  },
+  computed: {},
+  mounted () {
+    this.getBusinessStatusList()
+  },
+  methods: {
+    /** 获取商机状态组 */
+    getBusinessStatusList () {
+      // crmBusinessStatusList({})
+      //   .then(res => {
+      //     this.options = res.data
+      //     if (this.dataValue) {
+      //       for (const item of this.options) {
+      //         if (item.typeId === this.dataValue) {
+      //           this.$emit('value-change', {
+      //             index: this.index,
+      //             value: this.dataValue,
+      //             data: this.options,
+      //             type: 'init' // 初始化下不更改阶段值
+      //           })
+      //         }
+      //       }
+      //     }
+      //   })
+      //   .catch(() => {})
+    },
+    // 输入的值
+    valueChange (val) {
+      /** 商机组顺便回调筛选数据 */
+      this.$emit('value-change', {
+        index: this.index,
+        value: val,
+        data: this.options
+      })
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+</style>
diff --git a/src/components/CreateCom/XhCustomerAddress.vue b/src/components/CreateCom/XhCustomerAddress.vue
new file mode 100644
index 0000000..03b8e33
--- /dev/null
+++ b/src/components/CreateCom/XhCustomerAddress.vue
@@ -0,0 +1,397 @@
+<template>
+  <flexbox align="stretch">
+    <el-row>
+      <el-col
+        :span="span">
+        <!--@focus="getProvinces" @focus="getCities"@focus="getAreas"-->
+        <el-select
+          ref="proSel"
+          class='selecInput'
+          size="small"
+          v-model="provinceCode"
+          @change="changeProvince"
+          placeholder="请选择省份"
+          :disabled='disabled'
+          filterable>
+          <el-option
+            v-for="item in provinceList"
+            :key="item.ProvinceID"
+            :label="item.ProvinceName"
+            :value="item.ProvinceID">
+          </el-option>
+        </el-select>
+      </el-col>
+      <el-col
+        :span="span"
+        v-if="!hideCity">
+        <el-select
+          ref="citySel"
+          class='selecInput'
+          size="small"
+          v-model="cityCode"
+          @change="changeCity"
+          placeholder="请选择市"
+          :disabled='disabled'
+          filterable>
+          <el-option
+            v-for="item in cityList"
+            :key="item.CityID"
+            :label="item.CityName"
+            :value="item.CityID">
+          </el-option>
+        </el-select>
+      </el-col>
+      <el-col
+        :span="span"
+        v-if="!hideCity && !hideArea">
+        <el-select
+          class='selecInput'
+          size="small"
+          v-model="areaCode"
+          @change="changeArea"
+          placeholder="请选择区/县"
+          :disabled='disabled'
+          filterable>
+          <el-option
+            v-for="item in areaList"
+            :key="item.AreaId"
+            :label="item.AreaName"
+            :value="item.AreaId">
+          </el-option>
+        </el-select>
+      </el-col>
+    </el-row>
+  </flexbox>
+</template>
+<script type="text/javascript">
+import {GetProvincesList, GetCityList, GetAreaList} from '@/api/common'
+export default {
+  name: 'XhCustomerAddress', // 新建 客户位置
+  components: {
+  },
+  props: {
+    disabled: { // 禁
+      type: Boolean,
+      default: false
+    },
+    hideCity: { // 隐藏市
+      type: Boolean,
+      default: false
+    },
+    hideArea: { // 隐藏区/县
+      type: Boolean,
+      default: false
+    },
+    province: {
+      type: String,
+      default: ''
+    },
+    city: {
+      type: String,
+      default: ''
+    },
+    area: {
+      type: String,
+      default: ''
+    },
+    addressCode: null // 地址编码
+  },
+  data () {
+    return {
+      provinceList: [], // 省份列表
+      cityList: [], // 城市列表
+      areaList: [], // 区/县列表
+      provinceCode: '', // 省份编码
+      cityCode: '', // 城市编码
+      areaCode: '', // 区/县编码
+      cityFlag: false, // 避免重复请求的标志
+      provinceFlag: false,
+      areaFlag: false
+    }
+  },
+  computed: {
+    span () {
+      if (this.hideCity) {
+        return 24
+      }
+      if (this.hideArea) {
+        return 12
+      }
+      return 8
+    }
+  },
+  watch: {
+    addressCode: {
+      deep: true,
+      immediate: true,
+      handler (newVal) {
+        if (newVal) {
+          this.addressCodeToList(newVal)
+        } else {
+          this.$nextTick(() => {
+            this.reset()
+          })
+        }
+      }
+    },
+    province: {
+      deep: true,
+      immediate: true,
+      handler (newVal) {
+        if (newVal) {
+          console.log(newVal)
+          this.editCodeToList(newVal, 'province')
+        } else {
+          this.$nextTick(() => {
+            this.reset()
+          })
+        }
+      }
+    },
+    city: {
+      deep: true,
+      immediate: true,
+      handler (newVal) {
+        if (newVal) {
+          this.editCityToList(newVal, 'city')
+        } else {
+          this.$nextTick(() => {
+            this.reset()
+          })
+        }
+      }
+    },
+    area: {
+      deep: true,
+      immediate: true,
+      handler (newVal) {
+        if (newVal) {
+          this.editAreaToList(newVal, 'area')
+        } else {
+          this.$nextTick(() => {
+            this.reset()
+          })
+        }
+      }
+    }
+  },
+  created () {
+    this.getProList()
+  },
+  mounted () {
+  },
+  methods: {
+    /**
+     * 获取数据
+     */
+    getProList () {
+      GetProvincesList().then(res => {
+        this.provinceList = res.data.Result || []
+        console.log(this.province)
+        if (!this.province) {
+          this.provinceCode = res.data.Result && res.data.Result.length > 0 ? res.data.Result[0].ProvinceID : ''
+          let selected = this.idFilter(this.provinceCode, this.provinceList, 'province')
+          this.$emit('province', selected.ProvinceName)
+        }
+        this.getCityList(this.provinceCode)
+      })
+    },
+    getCityList (val) {
+      let params = {
+        provinceId: val
+      }
+      GetCityList(params).then(res => {
+        this.cityList = res.data.Result || []
+        // this.cityCode = res.data.Result && res.data.Result.length > 0 ? res.data.Result[0].CityID : ''
+        if (this.city) {
+          console.log('11111111', this.city)
+          let selectedCity = this.nameFilter(this.city, this.cityList, 'city')
+          this.cityCode = selectedCity ? selectedCity.CityID : ''
+        } else {
+          this.cityCode = res.data.Result && res.data.Result.length > 0 ? res.data.Result[0].CityID : ''
+          let selected = this.idFilter(this.cityCode, this.cityList, 'city')
+          this.$emit('city', selected.CityName)
+        }
+      })
+    },
+    getAreaList (val) {
+      let params = {
+        cityId: val
+      }
+      GetAreaList(params).then(res => {
+        this.areaList = res.data.Result || []
+        this.areaCode = res.data.Result && res.data.Result.length > 0 ? res.data.Result[0].AreaID : ''
+      })
+    },
+    idFilter (e, list, name) {
+      if (name === 'province') {
+        return list.find((item) => {
+          return item.ProvinceID === e
+        })
+      }
+      if (name === 'city') {
+        return list.find((item) => {
+          return item.CityID === e
+        })
+      }
+      if (name === 'area') {
+        return list.find((item) => {
+          return item.AreaID === e
+        })
+      }
+    },
+    nameFilter (e, list, name) {
+      if (name === 'province') {
+        return list.find((item) => {
+          return item.ProvinceName === e
+        })
+      }
+      if (name === 'city') {
+        return list.find((item) => {
+          return item.CityName === e
+        })
+      }
+      if (name === 'area') {
+        return list.find((item) => {
+          return item.AreaName === e
+        })
+      }
+    },
+    // 根据国家编码获取省份列表
+    getProvinces () {
+      if (this.provinceFlag) {
+        return
+      }
+      this.getProList()
+      this.provinceFlag = true
+    },
+    // 省份修改,拉取对应城市列表
+    changeProvince (val) {
+      this.getCityList(this.provinceCode)
+      this.cityFlag = true
+      this.cityCode = ''
+      this.areaCode = ''
+      let selected = this.idFilter(val, this.provinceList, 'province')
+      this.$emit('province', selected.ProvinceName)
+    },
+    // 根据省份编码获取城市列表
+    getCities () {
+      if (this.cityFlag) {
+        return
+      }
+      if (this.provinceCode) {
+        this.getCityList(this.provinceCode)
+        this.cityFlag = true
+      }
+    },
+    // 城市修改,拉取对应区域列表
+    changeCity (val) {
+      this.getAreaList(this.cityCode)
+      this.areaFlag = true
+      this.areaCode = ''
+      let selected = this.idFilter(val, this.cityList, 'city')
+      this.$emit('city', selected.CityName)
+      // let selected = this.idFilter(this.cityCode, this.cityList, 'city')
+      // this.$emit('city', selected ? selected.CityName : '')
+    },
+    // 根据城市编码获取区域列表
+    getAreas () {
+      if (this.areaFlag) {
+        return
+      }
+      if (this.cityCode) {
+        this.getAreaList(this.cityCode)
+      }
+    },
+    // 区域修改
+    changeArea (val) {
+      let selected = this.idFilter(val, this.areaList, 'area')
+      this.$emit('area', selected.AreaName)
+    },
+    // 重置省市区/县编码
+    reset () {
+      this.provinceCode = ''
+      this.cityCode = ''
+      this.areaCode = ''
+    },
+    editCodeToList (code, name) {
+      if (!code) return false
+      if (name === 'province') {
+        let selectedPro = this.nameFilter(code, this.provinceList, name)
+        this.provinceCode = selectedPro ? selectedPro.ProvinceID : ''
+        this.getCityList(this.provinceCode)
+      }
+    },
+    editCityToList (code, name) {
+      if (!code) return false
+      if (name === 'city') {
+        if (this.cityList && this.cityList.length > 0) {
+          let selectedCity = this.nameFilter(code, this.cityList, name)
+          this.cityCode = selectedCity ? selectedCity.CityID : ''
+          if (!this.hideArea) {
+            this.getAreaList(this.cityCode)
+          }
+        }
+      }
+    },
+    editAreaToList (code, name) {
+      if (!code) return false
+      if (name === 'area') {
+        if (this.areaList && this.areaList.length > 0) {
+          let selectedArea = this.nameFilter(code, this.areaList, name)
+          this.areaCode = selectedArea ? selectedArea.AreaID : ''
+        }
+      }
+    },
+    // 地址编码转换成省市区列表
+    addressCodeToList (addressCode) {
+      if (!addressCode) return false
+      this.$http({
+        method: 'get',
+        url: this.API.addressCode + '/' + addressCode
+      })
+        .then(res => {
+          let data = res.data.body
+          if (!data) return
+          if (data.provinceCode) {
+            this.provinceCode = data.provinceCode
+            this.fetchData(this.cityList, this.API.city, this.provinceCode)
+          } else if (data.cityCode) {
+            this.cityCode = data.cityCode
+            this.fetchData(this.areaList, this.API.area, this.cityCode)
+          } else if (data.areaCode) {
+            this.areaCode = data.areaCode
+          }
+        })
+        .finally(res => {
+        })
+    }
+
+  }
+}
+</script>
+<style rel="stylesheet/scss" lang="scss" scoped>
+.map {
+  height: 150px;
+  width: 100%;
+  overflow: hidden;
+  margin-top: 5px;
+}
+
+.area-title {
+  font-size: 12px;
+  color: #aaa;
+  padding-left: 10px;
+}
+
+.distpicker-address-wrapper /deep/ select {
+  height: 34px;
+  font-size: 12px;
+  border-radius: 0.1rem;
+  padding: .5rem .2rem;
+}
+.selecInput{
+  min-width: 120px;
+  margin-left: 10px;
+}
+</style>
diff --git a/src/components/CreateCom/XhDate.vue b/src/components/CreateCom/XhDate.vue
new file mode 100644
index 0000000..d2033e7
--- /dev/null
+++ b/src/components/CreateCom/XhDate.vue
@@ -0,0 +1,29 @@
+<template>
+  <el-date-picker
+    v-model="dataValue"
+    :disabled="disabled"
+    style="width: 100%;"
+    type="date"
+    value-format="yyyy-MM-dd"
+    placeholder="选择日期"
+    @change="valueChange"/>
+</template>
+<script type="text/javascript">
+import stringMixin from './stringMixin'
+
+export default {
+  name: 'XhInput', // 新建 date
+  components: {},
+  mixins: [stringMixin],
+  props: {},
+  data () {
+    return {}
+  },
+  computed: {},
+  watch: {},
+  mounted () {},
+  methods: {}
+}
+</script>
+<style lang="less" scoped>
+</style>
diff --git a/src/components/CreateCom/XhDateTime.vue b/src/components/CreateCom/XhDateTime.vue
new file mode 100644
index 0000000..2012f64
--- /dev/null
+++ b/src/components/CreateCom/XhDateTime.vue
@@ -0,0 +1,43 @@
+<template>
+  <el-date-picker
+    v-model="dataValue"
+    :disabled="disabled"
+    style="width: 100%;"
+    type="datetime"
+    value-format="yyyy-MM-dd HH:mm:ss"
+    placeholder="选择日期"
+    @change="valueChange"/>
+</template>
+<script type="text/javascript">
+import stringMixin from './stringMixin'
+import { getDateFromTimestamp } from '@/utils'
+import moment from 'moment'
+
+export default {
+  name: 'XhInput', // 新建 datetime
+  components: {},
+  mixins: [stringMixin],
+  props: {
+    value: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {}
+  },
+  computed: {},
+  watch: {},
+  mounted () {
+    if (this.value && this.value.toString().length === 10) {
+      // 编辑的时候 值是时间戳
+      this.dataValue = moment(getDateFromTimestamp(this.value)).format(
+        'YYYY-MM-DD HH:mm:ss'
+      )
+    }
+  },
+  methods: {}
+}
+</script>
+<style lang="less" scoped>
+</style>
diff --git a/src/components/CreateCom/XhFiles.vue b/src/components/CreateCom/XhFiles.vue
new file mode 100644
index 0000000..4ae17ba
--- /dev/null
+++ b/src/components/CreateCom/XhFiles.vue
@@ -0,0 +1,203 @@
+<template>
+  <div
+    :class="[disabled ? 'is_disabled' : 'is_valid']"
+    class="xh-files-cont">
+    <flexbox
+      :class="[disabled ? 'is_disabled' : 'is_valid']"
+      class="f-header"
+      @click.native="selectImage">
+      <img
+        v-if="!disabled"
+        class="f-logo"
+        src="@/assets/img/relevance_file.png" >
+      <div class="f-name">附件</div>
+      <input
+        :id="'xhImageInput' + index||'0'"
+        type="file"
+        class="bar-iput"
+        accept="*.*"
+        multiple
+        @change="xhUploadFile" >
+    </flexbox>
+    <div class="f-body">
+      <flexbox
+        v-for="(item, index) in dataValue"
+        :key="index"
+        class="f-item">
+        <img
+          class="f-img"
+          src="@/assets/img/relevance_file.png" >
+        <div class="f-name">{{ item.name.length > 25 ? (item.name.substring(0, 25) + '...'): item.name+'('+item.size+')' }}</div>
+        <div
+          class="close-button"
+          @click="deleteFile(item, index)">×</div>
+      </flexbox>
+    </div>
+  </div>
+</template>
+<script type="text/javascript">
+import arrayMixin from './arrayMixin'
+// import { crmFileSave, crmFileDelete } from '@/api/common'
+// import { fileSize } from '@/utils/index'
+
+export default {
+  name: 'XhFiles', // 新建 file  以数组的形式上传
+  components: {},
+  mixins: [arrayMixin],
+  props: {},
+  data () {
+    return {
+      batchId: '' // 批次ID
+    }
+  },
+  computed: {},
+  watch: {},
+  mounted () {},
+  methods: {
+    selectImage () {
+      if (!this.disabled) {
+        document.getElementById('xhImageInput' + this.index || '0').click()
+      }
+    },
+    /** 图片选择出发 */
+    xhUploadFile (event) {
+      var files = event.target.files
+      var firstFile = files[0]
+      this.sendFileRequest(firstFile, () => {
+        for (let index = 1; index < files.length; index++) {
+          const file = files[index]
+          this.sendFileRequest(file)
+        }
+        event.target.value = ''
+      })
+    },
+    // 发送请求
+    sendFileRequest (file, result) {
+      var params = { file: file }
+      if (this.batchId) {
+        params.batchId = this.batchId
+      }
+      // crmFileSave(params)
+      //   .then(res => {
+      //     if (this.batchId === '') {
+      //       this.batchId = res.batchId
+      //     }
+      //     res.size = fileSize(res.size)
+      //     this.dataValue.push(res)
+      //     this.$emit('value-change', {
+      //       index: this.index,
+      //       value: this.dataValue
+      //     })
+      //     if (result) {
+      //       result()
+      //     }
+      //   })
+      //   .catch(() => {})
+    },
+    /** 删除图片 */
+    deleteFile (item, index) {
+      this.$confirm('您确定要删除该文件吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          // crmFileDelete({
+          //   id: item.fileId
+          // })
+          //   .then(res => {
+          //     this.dataValue.splice(index, 1)
+          //     this.$emit('value-change', {
+          //       index: this.index,
+          //       value: this.dataValue
+          //     })
+          //     this.$message.success('操作成功')
+          //   })
+          //   .catch(() => {})
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消操作'
+          })
+        })
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+/** 附件  */
+.xh-files-cont {
+  position: relative;
+  display: inline-block;
+  border-radius: 3px;
+  width: 100%;
+  border: 1px solid #ddd;
+  padding: 3.5px 5px;
+  margin: 3px;
+  line-height: 15px;
+}
+
+.xh-files-cont.is_disabled {
+  background-color: #f5f7fa;
+  border-color: #e4e7ed;
+  cursor: not-allowed;
+  .f-name {
+    background-color: #f0f4f8ea;
+    color: #c0c4cc;
+    cursor: not-allowed;
+  }
+}
+
+.xh-files-cont.is_valid:hover {
+  border-color: #c0c4cc;
+}
+
+.f-header {
+  cursor: pointer;
+  padding: 5px 0 5px;
+  .f-logo {
+    position: block;
+    width: 15px;
+    height: 15px;
+    margin-right: 8px;
+  }
+  .f-name {
+    color: #4D88FF;
+    font-size: 12px;
+  }
+}
+.f-header.is_disabled {
+  cursor: not-allowed;
+}
+
+.f-body {
+  .f-item {
+    padding: 3px 0;
+    height: 25px;
+    .f-img {
+      position: block;
+      width: 15px;
+      height: 15px;
+      padding: 0 1px;
+      margin-right: 8px;
+    }
+    .f-name {
+      color: #666;
+      font-size: 12px;
+    }
+    .close-button {
+      cursor: pointer;
+    }
+  }
+}
+
+.bar-iput {
+  position: absolute;
+  top: 0;
+  left: 0;
+  height: 0;
+  width: 0;
+  opacity: 0;
+}
+</style>
diff --git a/src/components/CreateCom/XhInput.vue b/src/components/CreateCom/XhInput.vue
new file mode 100644
index 0000000..01db9dd
--- /dev/null
+++ b/src/components/CreateCom/XhInput.vue
@@ -0,0 +1,36 @@
+<template>
+  <el-input
+    v-model="dataValue"
+    :type="type"
+    :disabled="disabled"
+    @input="valueChange"/>
+</template>
+<script type="text/javascript">
+import stringMixin from './stringMixin'
+
+export default {
+  name: 'XhInput', // 新建 input
+  components: {},
+  mixins: [stringMixin],
+  props: {},
+  data () {
+    return {}
+  },
+  computed: {
+    type () {
+      if (this.item && this.item.form_type === 'password') {
+        return this.item.form_type
+      } else {
+        return 'text'
+      }
+    }
+  },
+  watch: {},
+  mounted () {
+    console.log('123')
+  },
+  methods: {}
+}
+</script>
+<style lang="less" scoped>
+</style>
diff --git a/src/components/CreateCom/XhInputSelect.vue b/src/components/CreateCom/XhInputSelect.vue
new file mode 100644
index 0000000..ebc17e8
--- /dev/null
+++ b/src/components/CreateCom/XhInputSelect.vue
@@ -0,0 +1,201 @@
+<template>
+  <div :class="isProduct?'':'input-container'">
+      <el-autocomplete
+      ref="elautocomplete"
+      v-model="state"
+      :class="isProduct?'search-container':''"
+      :fetch-suggestions="querySearchAsync"
+      :placeholder="isProduct?'输入产品名称':'请输入内容'"
+      :trigger-on-focus="false"
+      @blur='blurInput'
+      @select="handleSelect"
+    ></el-autocomplete>
+    </div>
+</template>
+<script type="text/javascript">
+import { GetCustomerPageList } from '@/api/customermanagement/customerManage'
+import { GetSalesChanceList } from '@/api/customermanagement/business'
+import { GetContacterList } from '@/api/customermanagement/contacts'
+import { GetAgreementList, GetManagementAgreementList } from '@/api/customermanagement/contract'
+import { GetQuotationSheetList, GetManagementQuotationSheetList } from '@/api/customermanagement/offer'
+import { GetOtherCustomerPageList, GetOtherSalesChanceList, GetOtherAgreementList } from '@/api/businessIntelligence/index'
+export default {
+  name: 'XhInputSelect', // 新建 multiple select
+  components: {},
+  data () {
+    return {
+      options: [],
+      value: [],
+      inputVal: '',
+      list: [],
+      states: [],
+      allInfos: [],
+      state: '',
+      isSelect: false,
+      timeout: null
+    }
+  },
+  props: {
+    arrayList: { // 下拉列表的数据
+      type: Array
+    },
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    isProduct: {
+      type: Boolean,
+      default: true
+    }
+  },
+  watch: {
+    state: {
+      handler (val) {
+        console.log(val)
+        this.$emit('getName', {'name': val})
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+  mounted () {
+    console.log(this.isProduct)
+  },
+  methods: {
+    querySearchAsync (queryString, cb) {
+      this.getList(queryString)
+      clearTimeout(this.timeout)
+      this.timeout = setTimeout(() => {
+        cb(this.allInfos)
+      }, 3000 * Math.random())
+    },
+    handleSelect (item) {
+      this.isSelect = true
+      this.$emit('getName', {'name': item.value})
+    },
+    blurInput () {
+      if (!this.isSelect) {
+        console.log('blurrrrrrr')
+        this.$emit('getName', {'name': this.state})
+      }
+    },
+    resetInput () {
+      this.state = ''
+    },
+    getList (query) {
+      if (query !== '') {
+        let params = []
+        if (this.crmType === 'contract' || this.crmType === 'offers') {
+          params = {
+            'PageIndex': 1,
+            'PageSize': 20,
+            'SelectOwnedType': 0,
+            'AuditStatus': 0,
+            'SealStatus': 0,
+            'Name': query,
+            'CreateStartTime': '',
+            'CreateEndTime': ''
+          }
+        } else if (this.crmType === 'sealContract' || this.crmType === 'sealOffers') {
+          params = {
+            'PageIndex': 1,
+            'PageSize': 20,
+            'DepartmentUserType': 0,
+            'SelectOwnedType': 0,
+            'AuditStatus': 0,
+            'SealStatus': 0,
+            'Name': query,
+            'CreateStartTime': '',
+            'CreateEndTime': ''
+          }
+        } else {
+          params = {
+            'PageIndex': 1,
+            'PageSize': 20,
+            'SelectOwnedType': 0,
+            'Name': query,
+            'CreateStartTime': '',
+            'CreateEndTime': '',
+            'StartFollowTime': '',
+            'EndFolowTime': ''
+          }
+        }
+        const request = {
+          customer: GetCustomerPageList,
+          business: GetSalesChanceList,
+          contacts: GetContacterList,
+          contract: GetAgreementList,
+          offers: GetQuotationSheetList,
+          sealContract: GetManagementAgreementList,
+          sealOffers: GetManagementQuotationSheetList,
+          businessCustomer: GetOtherCustomerPageList,
+          businessContract: GetOtherAgreementList,
+          businessChances: GetOtherSalesChanceList
+        }[this.crmType]
+        setTimeout(() => {
+          if (!this.isProduct) {
+            request(params)
+              .then(res => {
+                console.log(res)
+                if (res.data.ErrorCode === 200) {
+                  this.options = res.data.Result.List || []
+                  this.allInfos = this.options.map((terminal) => {
+                    if (this.crmType === 'customer' || this.crmType === 'businessCustomer') {
+                      return {
+                        value: terminal.CustomerName,
+                        name: terminal.CustomerName
+                      }
+                    } else if (this.crmType === 'business' || this.crmType === 'businessChances') {
+                      return {
+                        value: terminal.ChanceName,
+                        name: terminal.ChanceName
+                      }
+                    } else if (this.crmType === 'contacts') {
+                      return {
+                        value: terminal.ChanceName,
+                        name: terminal.ChanceName
+                      }
+                    } else if (this.crmType === 'offers' || this.crmType === 'sealOffers') {
+                      return {
+                        value: terminal.QuotationName,
+                        name: terminal.QuotationName
+                      }
+                    } else if (this.crmType === 'contract' || this.crmType === 'sealContract' || this.crmType === 'businessContract') {
+                      return {
+                        value: terminal.AgreeName,
+                        name: terminal.AgreeName
+                      }
+                    }
+                  })
+                  console.log(this.allInfos)
+                } else {
+                  this.options = []
+                  this.allInfos = []
+                  this.$message.error(res.data.Message)
+                }
+              })
+          }
+        }, 300)
+      } else {
+        this.options = []
+      }
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.input-container {
+    width: 224px;
+    height: 32px;
+    border-radius: 4px;
+    margin-right: 40px
+}
+.search-container{
+  width: 224px;
+  height: 32px;
+}
+.search-container.el-autocomplete /deep/ .el-input__inner{
+  height: 32px;
+}
+</style>
diff --git a/src/components/CreateCom/XhMultipleSelect.vue b/src/components/CreateCom/XhMultipleSelect.vue
new file mode 100644
index 0000000..8c5352e
--- /dev/null
+++ b/src/components/CreateCom/XhMultipleSelect.vue
@@ -0,0 +1,45 @@
+<template>
+  <el-select
+    v-model="dataValue"
+    :disabled="disabled"
+    style="width: 100%;"
+    multiple
+    placeholder="请选择"
+    @change="valueChange">
+    <el-option
+      v-for="item in option"
+      :key="item.value"
+      :label="item.value"
+      :value="item.value"/>
+  </el-select>
+</template>
+<script type="text/javascript">
+import arrayMixin from './arrayMixin'
+
+export default {
+  name: 'XhMultipleSelect', // 新建 multiple select
+  components: {},
+  mixins: [arrayMixin],
+  props: {},
+  data () {
+    return {}
+  },
+  computed: {
+    option () {
+      var array = []
+      if (this.item && this.item.data.setting) {
+        for (let index = 0; index < this.item.data.setting.length; index++) {
+          const element = this.item.data.setting[index]
+          array.push({ value: element })
+        }
+      }
+      return array
+    }
+  },
+  watch: {},
+  mounted () {},
+  methods: {}
+}
+</script>
+<style lang="less" scoped>
+</style>
diff --git a/src/components/CreateCom/XhProduct.vue b/src/components/CreateCom/XhProduct.vue
new file mode 100644
index 0000000..4d5405f
--- /dev/null
+++ b/src/components/CreateCom/XhProduct.vue
@@ -0,0 +1,391 @@
+<template>
+  <div class='productWrap'>
+    <div class="handel-header">
+    <el-dialog title="添加产品" :visible.sync="showPopover" :modal-append-to-body="false" width="80%" top="4vh" class='productTitle'>
+      <crm-relative
+          v-if="showSelectView"
+          ref="crmrelative"
+          :isProduct="true"
+          :radio="false"
+          :show="showPopover"
+          :selected-data="selectedData"
+          crm-type="product"
+          @close="showPopover=false"
+          @changeVal="selectInfos"/>
+    </el-dialog>
+    <el-button
+      v-show='!isLcTbl'
+      slot="reference"
+      @click="showProduct">+ 添加产品</el-button>
+    <el-button
+      v-show='isLcTbl'
+      slot="reference"
+      @click="showProduct">+ 添加盗版产品</el-button>
+      <!--<el-popover
+        v-model="showPopover"
+        placement="bottom"
+        width="700"
+        style="padding: 0 !important;"
+        trigger="click">
+        <crm-relative
+          v-if="showSelectView"
+          ref="crmrelative"
+          :radio="false"
+          :show="showPopover"
+          :selected-data="selectedData"
+          crm-type="product"
+          @close="showPopover=false"
+          @changeVal="selectInfos"/>
+        <el-button
+          v-show='!isLC'
+          slot="reference"
+          @click="showSelectView=true">+ 添加产品</el-button>
+      </el-popover>
+      <el-popover
+        v-model="showSecondPopover"
+        placement="bottom"
+        width="200"
+        style="padding: 0 !important"
+        trigger="click">
+        <div style="height: 200px;">
+          <div class='el-scrollbar' style="height: 100%">
+            <div class='el-select-dropdown__wrap el-scrollbar__wrap' style="margin-bottom: -7px; margin-right: -7px;">
+              <ul class="el-scrollbar__view el-select-dropdown__list">
+                <li class='el-select-dropdown__item'
+                :class="item.value === proValue?'selected':''"
+                v-for="item in options"
+                :key="item.value"
+                @click="getItem(item.value)"
+                >{{item.label}}</li>
+               <flexbox class="popover-foot">
+                  <el-button @click="hidenPopoverView" style='margin-right:16px;'>取 消</el-button>
+                  <el-button
+                    type="primary"
+                    @click="setFakePro">确 定</el-button>
+                </flexbox>
+              </ul>
+            </div>
+          </div>
+        </div>
+        <el-button
+          v-show='isLC'
+          slot="reference">+ 添加盗版产品</el-button>
+      v-if='isTableShow'
+      </el-popover>-->
+    </div>
+    <el-table
+      id="crm-table"
+      :data="productList"
+      :cell-style="cellStyle"
+      class="n-table--border"
+      border
+      highlight-current-row
+      style="width: 100%;">
+      <el-table-column
+        v-for="(item, index) in fieldList"
+        :key="'crm'+index"
+        :prop="item.field"
+        :label="item.name"
+        :formatter="fieldFormatter"
+        show-overflow-tooltip/>
+      <el-table-column/>
+      <el-table-column prop="Amount" label="使用数量" :key='1+index'>
+       <template slot-scope="scope">
+           <el-input size="small" type="number" min='0' v-show="scope.row.show" v-model="scope.row.Amount" placeholder="请输入内容" @keyup.enter.native="getEditData(scope.row)" @keyup.esc.native="cancelEdit(scope.row)"></el-input>
+           <span v-show="!scope.row.show">{{scope.row.Amount}}</span>
+       </template>
+      </el-table-column>
+      <el-table-column prop="Department" label="使用部门" v-if="isLcTbl" :key='2+index'>
+       <template slot-scope="scope">
+           <el-input size="small" v-show="scope.row.show" v-model="scope.row.Department" placeholder="请输入使用部门" @keyup.enter.native="getEditData(scope.row)"></el-input>
+           <span v-show="!scope.row.show">{{scope.row.Department}}</span>
+       </template>
+      </el-table-column>
+      <el-table-column prop="Comment" label="说明" v-if="isLcTbl" :key='3+index'>
+       <template slot-scope="scope">
+           <el-input size="small" v-show="scope.row.show" v-model="scope.row.Comment" placeholder="请输入说明" @keyup.enter.native="getEditData(scope.row)"></el-input>
+           <!--@blur="getEditData(scope.row)"-->
+           <span v-show="!scope.row.show">{{scope.row.Comment}}</span>
+       </template>
+      </el-table-column>
+      <el-table-column label="操作" width="150">
+        <template slot-scope="scope">
+          <el-button type="text" v-show="!scope.row.show" @click="scope.row.show=true">编辑 |</el-button>
+          <el-button type="text" v-show="scope.row.show" @click="getEditData(scope.row)" style="margin-left:0">保存 |</el-button>
+          <el-button type="text" v-show="scope.row.show" @click="cancelEdit(scope.row)" style="margin-left:0">取消</el-button>
+          <el-button type="text"  v-show="!scope.row.show" @click="removeItem(scope.$index)" style="margin-left:0">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+  </div>
+</template>
+<script type="text/javascript">
+import objMixin from './objMixin'
+import CrmRelative from '@/components/CreateCom/CrmRelative'
+import Lockr from 'lockr'
+export default {
+  name: 'XhProduct', // 关联产品
+  components: {
+    CrmRelative
+  },
+  mixins: [objMixin],
+  props: {
+    value: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    crmType: {
+      type: String,
+      default: ''
+    },
+    isLC: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    return {
+      showPopover: false, // 展示产品框
+      showSelectView: false, // 内容
+      showSecondPopover: false,
+      productList: [],
+      totalPrice: 0,
+      discountRate: 0,
+      selectedData: { product: [] },
+      options: [{
+        value: 'ACAD',
+        label: 'ACAD'
+      }, {
+        value: 'AEC',
+        label: 'AEC'
+      }, {
+        value: 'AEC2',
+        label: 'AEC2'
+      }, {
+        value: 'AMA',
+        label: 'AMA'
+      }, {
+        value: 'AMA2',
+        label: 'AMA2'
+      }, {
+        value: 'CAM',
+        label: 'CAM'
+      }, {
+        value: 'CAM2',
+        label: 'CAM2'
+      }],
+      proValue: '',
+      isTableShow: false,
+      isLcTbl: false
+    }
+  },
+  computed: {
+    fieldList () {
+      if (this.isLcTbl) {
+        return [
+          { name: '产品线', field: 'ProductLine', formType: 'text' }
+        ]
+      } else {
+        return [
+          { name: '产品类型', field: 'ProductType', formType: 'text' },
+          { name: 'SKU值', field: 'SKU', formType: 'text' }
+        ]
+      }
+    }
+  },
+  watch: {
+    productList: {
+      handler (newVal, oldVal) {
+        this.selectedData = { product: this.productList || [] }
+        return newVal
+      },
+      deep: true,
+      immediate: true
+    },
+    isLC: {
+      handler (newVal, oldVal) {
+        this.isLcTbl = newVal
+        return newVal
+      },
+      deep: true,
+      immediate: true
+    },
+    value () {
+      // this.productList = this.value
+      console.log(this.productList, this.value)
+      // this.selectInfos(this.value)
+    }
+
+  },
+  mounted () {
+    this.productList = Lockr.get('productList')
+  },
+  beforeDestroy () {
+    Lockr.set('productList', [])
+  },
+  methods: {
+    cancelEdit (row) {
+      row.show = false
+    },
+    getEditData (row) {
+      row.show = false
+      let list = JSON.parse(JSON.stringify(this.productList))
+      for (let i in list) {
+        list[i].Amount = JSON.parse(this.productList[i].Amount)
+        delete list[i].show
+      }
+      this.$emit('value-change', {
+        data: this.productList
+          ? list
+          : [],
+        type: 'product'
+      })
+    },
+    getItem (data) {
+      this.proValue = data
+    },
+    showProduct () {
+      this.showPopover = true
+      this.showSelectView = true
+    },
+    hidenPopoverView () {
+      document.querySelector('#app').click()
+      this.showSecondPopover = false
+      this.proValue = ''
+    },
+    fieldFormatter (row, column) {
+      return row[column.property] || '--'
+    },
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      return { textAlign: 'left' }
+    },
+    /** 选中 */
+    selectInfos (data, flag) {
+      if (flag !== undefined) {
+        this.isLcTbl = flag
+      }
+      if (data && data.length > 0) {
+        this.isTableShow = true
+        let newSelects = []
+        data.forEach(element => {
+          newSelects.push(this.getShowItem(element))
+        })
+        this.productList = newSelects
+        Lockr.set('productList', newSelects)
+        // 数据回填
+        let list = JSON.parse(JSON.stringify(this.productList))
+        for (let i in list) {
+          delete list[i].show
+        }
+        this.$emit('value-change', {
+          data: this.productList
+            ? list
+            : [],
+          type: 'product'
+        })
+      } else {
+        this.isTableShow = false
+      }
+    },
+    getShowItem (data) {
+      const item = {}
+      if (!this.isLcTbl) {
+        item.ProductType = data.ProductType
+        item.SKU = data.SKU
+        item.Amount = data.Amount ? data.Amount : 1
+        item.show = false
+      } else {
+        item.Amount = data.Amount ? data.Amount : 1
+        item.ProductLine = data.ProductLine
+        item.Comment = data.Comment
+        item.Department = data.Department
+        item.show = false
+      }
+      return item
+    },
+    // 删除操作
+    removeItem (index) {
+      this.productList.splice(index, 1)
+      let list = JSON.parse(JSON.stringify(this.productList))
+      for (let i in list) {
+        delete list[i].show
+      }
+      this.$emit('value-change', {
+        data: this.productList
+          ? list
+          : [],
+        type: 'product'
+      })
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+@import '../../views/clients/styles/table.scss';
+.productWrap{
+  display: flex;
+  flex-direction: column;
+}
+.handel-header {
+  button {
+    width: 117px;
+    height: 36px;
+    border-radius: 4px;
+    border: 1px solid #4D88FF;
+    margin-bottom: 40px;
+    margin-left: 30px;
+    color: #4D88FF;
+    font-size: 14px;
+  }
+}
+// .handel-header /deep/ .el-button--default{
+//   padding: 0 20px;
+//   height: 36px;
+//   border-radius: 4px;
+//   border: 1px solid #4D88FF;
+//   font-size: 14px;
+//   font-weight: 400;
+//   color: #4D88FF;
+// }
+.el-table /deep/ thead th, thead td {
+  padding:3px 0px;
+}
+
+.handle-footer {
+  position: relative;
+  font-size: 12px;
+  padding: 5px;
+  .discount-title {
+    color: #666;
+  }
+  .total-info {
+    position: absolute;
+    right: 20px;
+    top: 5px;
+    .info-yellow {
+      color: #fd715a;
+    }
+  }
+}
+.el-scrollbar__wrap{
+  overflow-x:hidden;
+  }
+.popover-foot{
+  position: relative;
+  width: 100%;
+  border-top: 1px solid #f1f1f1;
+  padding-top: 10px;
+  button{
+    height: 20px;
+    line-height: 1px;
+    text-align: center;
+    font-size: 12px;
+    margin-left: 22px;
+  }
+}
+.productTitle /deep/ .el-dialog__headerbtn .el-dialog__close{
+  font-size: 24px;
+}
+</style>
diff --git a/src/components/CreateCom/XhProuctCate.vue b/src/components/CreateCom/XhProuctCate.vue
new file mode 100644
index 0000000..f60668c
--- /dev/null
+++ b/src/components/CreateCom/XhProuctCate.vue
@@ -0,0 +1,61 @@
+<template>
+  <el-cascader
+    ref="elCascader"
+    :options="options"
+    :show-all-levels="false"
+    :props="defaultProps"
+    v-model="dataValue"
+    :disabled="disabled"
+    style="width: 100%;"
+    change-on-select
+    @change="valueChange"/>
+</template>
+<script type="text/javascript">
+import arrayMixin from './arrayMixin'
+// import { productCategoryIndex } from '@/api/systemManagement/SystemCustomer'
+
+export default {
+  name: 'XhProducCate', // 新建 产品分类
+  components: {},
+  mixins: [arrayMixin],
+  props: {},
+  data () {
+    return {
+      options: [],
+      defaultProps: {
+        children: 'children',
+        label: 'label',
+        value: 'categoryId'
+      }
+    }
+  },
+  computed: {},
+  watch: {},
+  mounted () {
+    this.getProductCategoryIndex()
+  },
+  methods: {
+    /** 获取产品分类数据 */
+    getProductCategoryIndex () {
+      // productCategoryIndex({
+      //   type: 'tree'
+      // })
+      //   .then(res => {
+      //     this.options = res.data
+      //   })
+      //   .catch(() => {})
+    },
+
+    valueChange (val) {
+      this.$emit('value-change', {
+        index: this.index,
+        item: this.item,
+        value: val,
+        valueContent: this.$refs.elCascader.currentLabels.join(',')
+      })
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+</style>
diff --git a/src/components/CreateCom/XhReceivablesPlan.vue b/src/components/CreateCom/XhReceivablesPlan.vue
new file mode 100644
index 0000000..70ba5d1
--- /dev/null
+++ b/src/components/CreateCom/XhReceivablesPlan.vue
@@ -0,0 +1,70 @@
+<template>
+  <el-select
+    v-model="dataValue"
+    :disabled="disabled"
+    style="width: 100%;"
+    placeholder="请选择"
+    @change="valueChange(dataValue, option)">
+    <el-option
+      v-for="(item, index) in option"
+      :key="index"
+      :label="item.num"
+      :value="item.planId"/>
+  </el-select>
+</template>
+<script type="text/javascript">
+import stringMixin from './stringMixin'
+// import {
+//   crmQueryReceivablesPlansByContractId
+// } from '@/api/clients/contract'
+
+export default {
+  name: 'XhReceivablesPlan', // 回款 下的 回款计划
+  components: {},
+  mixins: [stringMixin],
+  props: {
+    relation: {
+      // 相关ID
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  data () {
+    return {
+      option: []
+    }
+  },
+  computed: {},
+  watch: {
+    relation: function (val) {
+      if (val.moduleType) {
+        this.getPlanList()
+      } else {
+        this.option = []
+      }
+    }
+  },
+  mounted () {
+    if (this.relation.moduleType) {
+      this.getPlanList()
+    }
+  },
+  methods: {
+    getPlanList () {
+      this.loading = true
+      // crmQueryReceivablesPlansByContractId({ contractId: this.relation.contractId })
+      //   .then(res => {
+      //     this.loading = false
+      //     this.option = res.data
+      //   })
+      //   .catch(() => {
+      //     this.loading = false
+      //   })
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+</style>
diff --git a/src/components/CreateCom/XhRelativeInput.vue b/src/components/CreateCom/XhRelativeInput.vue
new file mode 100644
index 0000000..83a9963
--- /dev/null
+++ b/src/components/CreateCom/XhRelativeInput.vue
@@ -0,0 +1,226 @@
+<template>
+  <el-popover
+    class='pop'
+    :disabled="item.disabled"
+    :offset="250"
+    placement="right"
+    popper-class="no-padding-popover"
+    width="500"
+    trigger="click">
+    <div class="container">
+      <flexbox class="header">
+        <div class="name">客户</div>
+        <!--<div class="detail"></div>-->
+        <img
+          class="close"
+          src="@/assets/img/task_close.png"
+          @click="hidenView" >
+      </flexbox>
+      <flexbox class="content">
+        <div class="cropper-box">
+          <span class='searchTitle'>查找内容:</span>
+          <el-input class='searchInput' v-model='popSearch' placeholder='请输入客户名称'></el-input>
+          <el-button  type="primary" class='searchBtn' @click='getCustomerTable'>立即查找</el-button>
+        </div>
+      </flexbox>
+      <el-table
+        v-loading="loading"
+        :data="popData"
+        :cell-style="popCellStyle"
+        :header-cell-style="headerCellStyle"
+        height="250"
+        style="margin-right:3px;"
+        highlight-current-row
+        @row-click="handlePopRowClick">
+        <el-table-column
+          v-for="(item, index) in popFieldList"
+          :key="index"
+          :prop="item.field"
+          :label="item.value"
+          align="center"
+          header-align="center"
+          show-overflow-tooltip/>
+      </el-table>
+      <div class="p-contianer">
+        <el-pagination
+          :current-page="currentPopPage"
+          :page-sizes="pagePopSizes"
+          :page-size.sync="pagePopSize"
+          :total="totalPop"
+          class="p-bar"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handlePopSizeChange"
+          @current-change="handlePopCurrentChange"/>
+      </div>
+    </div>
+    <el-input slot="reference" :disabled='true' v-model='customerChosed' placeholder='请点击选择客户'></el-input>
+  </el-popover>
+</template>
+<script type="text/javascript">
+import { GetPersonalCustomerPageList } from '@/api/customermanagement/customerManage'
+export default {
+  name: 'XhRelativeInput', // 新建 XhRelativeInput
+  components: {},
+  props: {
+    item: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    customerId: {
+      type: String,
+      default: () => {
+        return ''
+      }
+    }
+  },
+  data () {
+    return {
+      loading: false,
+      popData: [],
+      currentPopPage: 1,
+      pagePopSize: 15,
+      pagePopSizes: [15, 30, 60, 100],
+      customerChosed: '',
+      popSearch: '',
+      totalPop: 0
+    }
+  },
+  computed: {
+    popFieldList () {
+      if (this.item && this.item.field === 'CustomerId') {
+        return [
+          { field: 'CustomerNumber', value: '客户编号', width: '20' },
+          { field: 'CustomerName', value: '客户名称', width: '20' },
+          { field: 'Contacter', value: '联系人', width: '20' },
+          { field: 'ContactMobile', value: '联系人方式', width: '30' },
+          { field: 'CustomerStatus', value: '客户业务状态', width: '10' },
+          { field: 'CustomerSource', value: '客户来源', width: '10' },
+          { field: 'CustomerType', value: '客户大类型', width: '10' },
+          { field: 'CostomerCategory', value: '客户类别', width: '10' },
+          { field: 'Industry', value: '所属行业', width: '12' },
+          { field: 'ProvinceCode', value: '省编码', width: '10' },
+          { field: 'CityCode', value: '市编码', width: '10' },
+          { field: 'SaleOwerId', value: '销售员', width: '10' },
+          { field: 'SaleName', value: '销售员姓名', width: '10' },
+          { field: 'CreateTime', value: '创建时间', width: '10' },
+          { field: 'NextFollowTime', value: '最新跟进时间', width: '10' }
+        ]
+      } else {
+        return []
+      }
+    }
+  },
+  watch: {
+  },
+  mounted () {
+    console.log(1111111, this.item)
+    if (this.item && this.item.field === 'CustomerId') {
+      this.customerChosed = this.item.chosedCusName ? this.item.chosedCusName : ''
+      this.getCustomerTable()
+    }
+  },
+  methods: {
+    /** 通过回调控制style */
+    popCellStyle ({ row, column, rowIndex, columnIndex }) {
+      return { fontSize: '12px', textAlign: 'center', cursor: 'pointer' }
+    },
+    headerCellStyle ({ row, column, rowIndex, columnIndex }) {
+      return { fontSize: '12px', textAlign: 'center' }
+    },
+    handlePopSizeChange (newSize) {
+      this.pagePopSizes = newSize
+      this.getCustomerTable()
+    },
+    handlePopCurrentChange (newPage) {
+      this.currentPopPage = newPage
+      this.getCustomerTable()
+    },
+    getCustomerTable () {
+      let params = {
+        Name: this.popSearch,
+        PageIndex: this.currentPopPage,
+        PageSize: this.pagePopSize
+      }
+      if (this.item && this.item.field === 'CustomerId') {
+        GetPersonalCustomerPageList(params).then(res => {
+          if (res.data.ErrorCode === 200 && res.data.Result !== 0) {
+            this.popData = res.data.Result.List || []
+            this.totalPop = res.data.Result.Count
+          } else {
+            this.$message.error(res.data.Message)
+            this.loading = false
+          }
+        })
+      }
+    },
+    hidenView () {
+      document.querySelector('#app').click()
+      this.$emit('close', this.$el, this.data)
+    },
+    // 当某一行被点击时会触发该事件
+    handlePopRowClick (row, column, event) {
+      this.$emit('value-change', {index: this.item.field,
+        value: row.Id,
+        name: row.CustomerName})
+      this.customerChosed = row.CustomerName
+      console.log(this.customerChosed)
+      this.hidenView()
+    }
+
+  }
+}
+</script>
+<style lang="scss" scoped>
+.container {
+  position: relative;
+}
+
+.header {
+  height: 40px;
+  padding: 0 10px;
+  flex-shrink: 0;
+  .name {
+    font-size: 13px;
+    padding: 0 10px;
+    color: #333;
+  }
+  .detail {
+    font-size: 12px;
+    padding: 0 10px;
+    color: #aaaaaa;
+    border-left: 1px solid #aaaaaa;
+  }
+  .close {
+    position: absolute;
+    width: 40px;
+    height: 40px;
+    top: 0;
+    right: 10px;
+    padding: 10px;
+  }
+}
+.content{
+  .cropper-box{
+    display:flex;
+    flex-direction: row;
+    align-items: center;
+    padding: 0 20px;
+    .searchTitle{
+      font-size: 14px;
+      width: 124px;
+      color: #333;
+    }
+    .searchInput{
+      margin-right: 20px;
+    }
+  }
+}
+.p-contianer .p-bar{
+  margin: 5px 0 0 14px;
+}
+.pop /deep/ .el-input.is-disabled .el-input__inner{
+  cursor: pointer;
+}
+</style>
diff --git a/src/components/CreateCom/XhRelativeInputS.vue b/src/components/CreateCom/XhRelativeInputS.vue
new file mode 100644
index 0000000..f5bc496
--- /dev/null
+++ b/src/components/CreateCom/XhRelativeInputS.vue
@@ -0,0 +1,214 @@
+<template>
+  <el-popover
+    class='pop'
+    :disabled="item.disabled"
+    :offset="250"
+    placement="right"
+    popper-class="no-padding-popover"
+    width="500"
+    trigger="click">
+    <div class="container">
+      <flexbox class="header">
+        <div class="name">联系人</div>
+        <!--<div class="detail"></div>-->
+        <img
+          class="close"
+          src="@/assets/img/task_close.png"
+          @click="hidenView" >
+      </flexbox>
+      <flexbox class="content">
+        <div class="cropper-box">
+          <span class='searchTitle'>查找内容:</span>
+          <el-input class='searchInput' v-model='popSearch' placeholder='请输入联系人名称'></el-input>
+          <el-button  type="primary" class='searchBtn' @click='getCustomerTable'>立即查找</el-button>
+        </div>
+      </flexbox>
+      <el-table
+        v-loading="loading"
+        :data="popData"
+        :cell-style="popCellStyle"
+        :header-cell-style="headerCellStyle"
+        height="250"
+        style="margin-right:3px;"
+        highlight-current-row
+        @row-click="handlePopRowClick">
+        <el-table-column
+          v-for="(item, index) in popFieldList"
+          :key="index"
+          :prop="item.field"
+          :label="item.value"
+          align="center"
+          header-align="center"
+          show-overflow-tooltip/>
+      </el-table>
+      <div class="p-contianer">
+        <el-pagination
+          :current-page="currentPopPage"
+          :page-sizes="pagePopSizes"
+          :page-size.sync="pagePopSize"
+          :total="totalPop"
+          class="p-bar"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handlePopSizeChange"
+          @current-change="handlePopCurrentChange"/>
+      </div>
+    </div>
+    <el-input slot="reference" :disabled='true' v-model='contacterChosed' placeholder='请点击选择联系人'></el-input>
+  </el-popover>
+</template>
+<script type="text/javascript">
+import { GetPersonalContacterList } from '@/api/customermanagement/contacts'
+export default {
+  name: 'XhRelativeInputS', // 新建 XhRelativeInput
+  components: {},
+  props: {
+    item: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    customerId: {
+      type: String,
+      default: () => {
+        return ''
+      }
+    }
+  },
+  data () {
+    return {
+      loading: false,
+      popData: [],
+      currentPopPage: 1,
+      pagePopSize: 15,
+      pagePopSizes: [15, 30, 60, 100],
+      contacterChosed: '',
+      popSearch: '',
+      totalPop: 0
+    }
+  },
+  computed: {
+    popFieldList () {
+      if (this.item && this.item.field === 'ContacterId') {
+        return [
+          { field: 'ContacterNumber', value: '联系人编号', width: '20' },
+          { field: 'CustomerName', value: '联系人名称', width: '20' },
+          { field: 'RealName', value: '联系人真实姓名', width: '10' },
+          { field: 'Sex', value: '性别', width: '10' },
+          { field: 'MobilePhone', value: '联系人方式', width: '30' },
+          { field: 'JobPosition', value: '联系人职位', width: '10' },
+          { field: 'OwerUserName', value: '负责人', width: '10' }
+        ]
+      }
+    }
+  },
+  watch: {
+  },
+  mounted () {
+    if (this.item && this.item.field === 'ContacterId') {
+      this.contacterChosed = this.item.chosedCusName ? this.item.chosedCusName : ''
+      this.getCustomerTable()
+    }
+  },
+  methods: {
+    /** 通过回调控制style */
+    popCellStyle ({ row, column, rowIndex, columnIndex }) {
+      return { fontSize: '12px', textAlign: 'center', cursor: 'pointer' }
+    },
+    headerCellStyle ({ row, column, rowIndex, columnIndex }) {
+      return { fontSize: '12px', textAlign: 'center' }
+    },
+    handlePopSizeChange (newSize) {
+      this.pagePopSizes = newSize
+      this.getCustomerTable()
+    },
+    handlePopCurrentChange (newPage) {
+      this.currentPopPage = newPage
+      this.getCustomerTable()
+    },
+    getCustomerTable () {
+      let params = {
+        Name: this.popSearch,
+        PageIndex: this.currentPopPage,
+        PageSize: this.pagePopSize,
+        CustomerId: this.customerId
+      }
+      if (this.item && this.item.field === 'ContacterId') {
+        GetPersonalContacterList(params).then(res => {
+          if (res.data.ErrorCode === 200 && res.data.Result !== 0) {
+            this.popData = res.data.Result.List || []
+            this.totalPop = res.data.Result.Count
+          } else {
+            this.$message.error(res.data.Message)
+            this.loading = false
+          }
+        })
+      }
+    },
+    hidenView () {
+      document.querySelector('#app').click()
+      this.$emit('close', this.$el, this.data)
+    },
+    // 当某一行被点击时会触发该事件
+    handlePopRowClick (row, column, event) {
+      this.$emit('value-change', {index: this.item.field,
+        value: row.Id})
+      this.contacterChosed = row.RealName
+      this.hidenView()
+    }
+
+  }
+}
+</script>
+<style lang="scss" scoped>
+.container {
+  position: relative;
+}
+
+.header {
+  height: 40px;
+  padding: 0 10px;
+  flex-shrink: 0;
+  .name {
+    font-size: 13px;
+    padding: 0 10px;
+    color: #333;
+  }
+  .detail {
+    font-size: 12px;
+    padding: 0 10px;
+    color: #aaaaaa;
+    border-left: 1px solid #aaaaaa;
+  }
+  .close {
+    position: absolute;
+    width: 40px;
+    height: 40px;
+    top: 0;
+    right: 10px;
+    padding: 10px;
+  }
+}
+.content{
+  .cropper-box{
+    display:flex;
+    flex-direction: row;
+    align-items: center;
+    padding: 0 20px;
+    .searchTitle{
+      font-size: 14px;
+      width: 124px;
+      color: #333;
+    }
+    .searchInput{
+      margin-right: 20px;
+    }
+  }
+}
+.p-contianer .p-bar{
+  margin: 5px 0 0 14px;
+}
+.pop /deep/ .el-input.is-disabled .el-input__inner{
+  cursor: pointer;
+}
+</style>
diff --git a/src/components/CreateCom/XhSelect.vue b/src/components/CreateCom/XhSelect.vue
new file mode 100644
index 0000000..6b7f4af
--- /dev/null
+++ b/src/components/CreateCom/XhSelect.vue
@@ -0,0 +1,67 @@
+<template>
+  <el-select
+    v-model="dataValue"
+    :disabled="disabled"
+    style="width: 100%;"
+    placeholder="请选择"
+    @change="valueChange">
+    <el-option
+      v-for="(item, index) in option"
+      :key="index + 1"
+      :label="item.name"
+      :value="index + 1"/>
+  </el-select>
+</template>
+<script type="text/javascript">
+import stringMixin from './stringMixin'
+
+export default {
+  name: 'XhSelect', // 新建 select
+  components: {},
+  mixins: [stringMixin],
+  props: {},
+  data () {
+    return {
+      option: []
+    }
+  },
+  computed: {},
+  watch: {
+    item: {
+      handler (val) {
+        if (val && val.data.setting) {
+          var settingList = val.data.setting
+          if (settingList.length > 0 && typeof settingList[0] === 'string') {
+            var array = []
+            for (let index = 0; index < settingList.length; index++) {
+              const element = settingList[index]
+              array.push({ name: element, value: element })
+            }
+            this.option = array
+          } else if (
+            settingList.length > 0 &&
+            settingList[0].statusId &&
+            !settingList[0].value
+          ) {
+            // 商机阶段
+            this.option = settingList.map((item, index, array) => {
+              item.value = item.statusId
+              return item
+            })
+          } else {
+            this.option = settingList
+          }
+        } else {
+          this.option = []
+        }
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+  mounted () {},
+  methods: {}
+}
+</script>
+<style lang="less" scoped>
+</style>
diff --git a/src/components/CreateCom/XhStrucUserCell.vue b/src/components/CreateCom/XhStrucUserCell.vue
new file mode 100644
index 0000000..4022799
--- /dev/null
+++ b/src/components/CreateCom/XhStrucUserCell.vue
@@ -0,0 +1,134 @@
+<template>
+  <members-dep
+    :popover-display="'block'"
+    :dep-checked-data="dataStrucs"
+    :user-checked-data="dataUsers"
+    @popoverSubmit="popoverSubmit">
+    <div slot="membersDep">
+      <flexbox
+        wrap="wrap"
+        class="structure-container">
+        <div
+          v-for="(item, index) in dataUsers"
+          :key="'user'+index"
+          class="user-item">{{ item.name ? item.name : item.realname }}
+        </div>
+        <div
+          v-for="(item, index) in dataStrucs"
+          :key="'struc'+index"
+          class="user-item">{{ item.name }}
+        </div>
+        <div class="add-item">+添加</div>
+      </flexbox>
+    </div>
+  </members-dep>
+
+</template>
+<script type="text/javascript">
+import membersDep from '@/components/selectEmployee/membersDep'
+
+export default {
+  name: 'XhStrucUserCell', // 新建 struc-user-cell
+  components: {
+    membersDep
+  },
+  props: {
+    // 员工和 部门
+    users: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    strucs: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    value: {
+      type: Object,
+      default: () => {
+        return {
+          users: [],
+          strucs: []
+        }
+      }
+    },
+    /** 索引值 用于更新数据 */
+    index: Number,
+    /** 包含数据源 */
+    item: Object
+  },
+  data () {
+    return {
+      dataUsers: [], // 关联的时候展示name 编辑的时候展示realname
+      dataStrucs: []
+    }
+  },
+  computed: {},
+  watch: {
+    value: function (val) {
+      this.dataUsers = val.users
+      this.dataStrucs = val.strucs
+    },
+    users: function (val) {
+      this.dataUsers = val
+    },
+    strucs: function (val) {
+      this.dataStrucs = val
+    }
+  },
+  created () {
+    if (this.value) {
+      this.dataUsers = this.value.users
+      this.dataStrucs = this.value.strucs
+    }
+  },
+  methods: {
+    popoverSubmit (users, strucs) {
+      this.dataUsers = users
+      this.dataStrucs = strucs
+
+      this.$emit('value-change', {
+        index: this.index,
+        value: { users: users, strucs: strucs }
+      })
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+.structure-container {
+  min-height: 34px;
+  margin: 3px 0;
+  position: relative;
+  border-radius: 3px;
+  font-size: 12px;
+  border: 1px solid #ddd;
+  color: #333333;
+  padding: 0.5px;
+  line-height: 15px;
+  max-height: 105px;
+  overflow-y: auto;
+  .user-item {
+    padding: 5px;
+    background-color: #e2ebf9;
+    border-radius: 3px;
+    margin: 3px;
+    cursor: pointer;
+  }
+  .add-item {
+    padding: 5px;
+    color: #4D88FF;
+    cursor: pointer;
+  }
+  .delete-icon {
+    color: #999;
+    cursor: pointer;
+  }
+  &:hover {
+    border-color: #c0c4cc;
+  }
+}
+</style>
diff --git a/src/components/CreateCom/XhStructure.vue b/src/components/CreateCom/XhStructure.vue
new file mode 100644
index 0000000..3e90fb9
--- /dev/null
+++ b/src/components/CreateCom/XhStructure.vue
@@ -0,0 +1,246 @@
+<template>
+  <div>
+    <el-input
+      v-model="searchInput"
+      placeholder="搜索部门名称"
+      size="small"
+      suffix-icon="el-icon-search"
+      @input="inputchange"/>
+    <div
+      v-loading="loading"
+      class="search-list">
+      <el-breadcrumb
+        style="padding: 5px 0;"
+        separator-class="el-icon-arrow-right">
+        <el-breadcrumb-item
+          v-for="(item, index) in breadcrumbList"
+          :key="index">
+          <a
+            href="javascript:;"
+            @click="breadcrumbBtn(item, index)">{{ item.label }}</a>
+        </el-breadcrumb-item>
+      </el-breadcrumb>
+      <flexbox
+        v-for="(item, index) in showlist"
+        v-if="item.show"
+        :key="index"
+        class="stru-list">
+        <el-checkbox
+          v-model="item.isCheck"
+          :disabled="item.disabled"
+          class="stru-check"
+          @change="checkChange(item, index)"/>
+        <div
+          class="stru-name"
+          @click="enterChildren(item)">{{ item.name }}</div>
+        <div
+          v-if="item.children"
+          class="el-icon-arrow-right stru-enter"/>
+      </flexbox>
+    </div>
+  </div>
+</template>
+<script type="text/javascript">
+// import { depList } from '@/api/common'
+
+export default {
+  name: 'XhStructure', // 新建 structure
+  components: {},
+  props: {
+    value: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    /** 多选框 只能选一个 */
+    radio: {
+      type: Boolean,
+      default: false
+    },
+    /** 已选信息 */
+    selectedData: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    }
+  },
+  data () {
+    return {
+      breadcrumbList: [], // 面包屑数据
+      selectItems: [], // 选择项
+      showlist: [], // 展示数据
+      loading: false, // 加载动画
+      searchInput: ''
+    }
+  },
+  computed: {},
+  watch: {},
+  mounted () {
+    this.selectItems = this.selectedData
+    // 部门列表数据
+    this.getStructureList()
+  },
+  methods: {
+    // 部门列表数据
+    getStructureList () {
+      this.loading = true
+      // depList({
+      //   type: 'tree'
+      // })
+      //   .then(res => {
+      //     this.showlist = this.addIsCheckProp(res.data)
+      //     this.breadcrumbList.push({ label: '全部', data: this.showlist })
+
+      //     this.loading = false
+      //   })
+      //   .catch(() => {
+      //     this.loading = false
+      //   })
+    },
+    // 面包屑点击事件
+    breadcrumbBtn (item, index) {
+      if (this.radio && this.selectItems.length === 1) return
+      if (index + 1 <= this.breadcrumbList.length - 1) {
+        this.breadcrumbList.splice(index + 1, this.breadcrumbList.length - 1)
+      }
+      this.showlist = []
+      this.showlist = this.handelCheck(item.data)
+    },
+    // 点击checkbox选中
+    checkChange (item, aindex) {
+      this.$set(this.showlist, aindex, item)
+      var removeIndex = -1
+      for (let index = 0; index < this.selectItems.length; index++) {
+        const element = this.selectItems[index]
+        if (item.id === element.id) {
+          removeIndex = index
+        }
+      }
+      if (removeIndex === -1 && item.isCheck) {
+        this.selectItems.push(item)
+      } else if (removeIndex !== -1) {
+        this.selectItems.splice(removeIndex, 1)
+      }
+
+      /** 单选逻辑 */
+      if (this.radio) {
+        if (item.isCheck) {
+          this.showlist = this.showlist.map(function (element, index, array) {
+            if (element.id === item.id) {
+              element.disabled = false
+            } else {
+              element.disabled = true
+            }
+            return element
+          })
+        } else {
+          this.showlist = this.showlist.map(function (item, index, array) {
+            item.disabled = false
+            return item
+          })
+        }
+      }
+
+      this.$emit('changeCheckout', { data: this.selectItems })
+    },
+    /** 数据重新刷新时 循环标记展示数组 */
+    handelCheck (list) {
+      var self = this
+      list = list.map(function (item, index, array) {
+        item.isCheck = self.selectItemsHasItem(item)
+        return item
+      })
+      this.inputchange()
+      return list
+    },
+    selectItemsHasItem (item) {
+      if (this.selectItems.length === 0) {
+        return false
+      }
+      var hasItem = false
+      for (let index = 0; index < this.selectItems.length; index++) {
+        const element = this.selectItems[index]
+        if (item.id === element.id) {
+          hasItem = true
+          break
+        }
+      }
+      return hasItem
+    },
+    /**  */
+    /** 点击进入子数组 */
+    enterChildren (item) {
+      // 保证单选环境下 没有选中 才可进入children
+      if (item.children && !(this.radio && this.selectItems.length === 1)) {
+        this.showlist = []
+        this.showlist = this.handelCheck(this.addIsCheckProp(item.children))
+        this.breadcrumbList.push({ label: item.label, data: this.showlist })
+      }
+    },
+    /** 给默认数据加isCheck属性 */
+    addIsCheckProp (list) {
+      if (list.length > 0) {
+        var item = list[0]
+        if (item.hasOwnProperty('isCheck')) {
+          return list
+        } else {
+          return list.map(function (item, index, array) {
+            item.disabled = false
+            item.isCheck = false
+            item.show = true
+            return item
+          })
+        }
+      }
+      return list
+    },
+    // 父组件 选中
+    parentRemoveCheck (data) {
+      this.selectItems = data.data
+      var temps = this.showlist
+      this.showlist = []
+      this.showlist = this.handelCheck(temps)
+      /** 单选逻辑 */
+      if (this.radio) {
+        this.showlist = this.showlist.map(function (item, index, array) {
+          item.disabled = false
+          return item
+        })
+      }
+    },
+    /** 搜索 */
+    inputchange (val) {
+      this.showlist = this.showlist.map(function (item, index, array) {
+        if (item.name.indexOf(val) !== -1) {
+          item.show = true
+        } else {
+          item.show = false
+        }
+        return item
+      })
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+.search-list {
+  padding: 5px;
+  height: 248px;
+  overflow: auto;
+}
+.stru-list {
+  padding: 5px;
+  font-size: 13px;
+  .stru-check {
+    margin-right: 8px;
+  }
+  .stru-name {
+    flex: 1;
+  }
+  .stru-enter {
+    margin-right: 8px;
+  }
+}
+</style>
diff --git a/src/components/CreateCom/XhStructureCell.vue b/src/components/CreateCom/XhStructureCell.vue
new file mode 100644
index 0000000..f471cb0
--- /dev/null
+++ b/src/components/CreateCom/XhStructureCell.vue
@@ -0,0 +1,142 @@
+<template>
+  <el-popover
+    :disabled="disabled"
+    placement="bottom"
+    width="300"
+    trigger="click">
+    <xh-structure
+      v-if="!disabled && showSelectView"
+      ref="structure"
+      :radio="radio"
+      :selected-data="dataValue"
+      @changeCheckout="checkStructure"/>
+    <div slot="reference">
+      <flexbox
+        :class="[disabled ? 'is_disabled' : 'is_valid']"
+        wrap="wrap"
+        class="structure-container"
+        @click.native="focusClick">
+        <div
+          v-for="(item, index) in dataValue"
+          :key="index"
+          class="user-item"
+          @click.stop="deletestru(item,index)">{{ item.name }}
+          <i class="delete-icon el-icon-close"/>
+        </div>
+        <div class="add-item">+添加部门</div>
+      </flexbox>
+    </div>
+  </el-popover>
+</template>
+<script type="text/javascript">
+import XhStructure from './XhStructure'
+import arrayMixin from './arrayMixin'
+
+export default {
+  name: 'XhStructureCell', // 新建 structure-cell
+  components: {
+    XhStructure
+  },
+  mixins: [arrayMixin],
+  props: {
+    radio: {
+      // 是否单选
+      type: Boolean,
+      default: true
+    }
+  },
+  data () {
+    return {
+      showPopover: false, // 展示popover
+      showSelectView: false // 展示选择内容列表
+    }
+  },
+  computed: {},
+  watch: {},
+  mounted () {},
+  methods: {
+    /** 选中 */
+    checkStructure (data) {
+      this.dataValue = data.data
+      this.$emit('value-change', {
+        index: this.index,
+        value: data.data
+      })
+    },
+    /** 删除 */
+    deletestru (item, index) {
+      this.dataValue.splice(index, 1)
+      this.$refs.structure.parentRemoveCheck({
+        data: this.dataValue,
+        index: index
+      })
+      this.$emit('value-change', {
+        index: this.index,
+        value: this.dataValue
+      })
+    },
+    /** 聚焦动作 */
+    focusClick () {
+      this.showSelectView = true
+      this.$emit('focus')
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+.structure-container {
+  min-height: 34px;
+  margin: 3px 0;
+  position: relative;
+  border-radius: 3px;
+  font-size: 12px;
+  border: 1px solid #ddd;
+  color: #333333;
+  padding: 0.5px;
+  line-height: 15px;
+  max-height: 105px;
+  overflow-y: auto;
+  .user-item {
+    padding: 5px;
+    background-color: #e2ebf9;
+    border-radius: 3px;
+    margin: 3px;
+    cursor: pointer;
+  }
+  .add-item {
+    padding: 5px;
+    color: #4D88FF;
+    cursor: pointer;
+  }
+  .delete-icon {
+    color: #999;
+    cursor: pointer;
+  }
+  &:hover {
+    border-color: #c0c4cc;
+  }
+}
+
+.structure-container.is_disabled {
+  background-color: #f5f7fa;
+  border-color: #e4e7ed;
+  cursor: not-allowed;
+  .user-item {
+    background-color: #f0f4f8ea;
+    color: #c0c4cc;
+    cursor: not-allowed;
+  }
+  .delete-icon {
+    color: #c0c4cc;
+    cursor: not-allowed;
+  }
+  .add-item {
+    color: #c0c4cc;
+    cursor: not-allowed;
+  }
+}
+
+.structure-container.is_valid:hover {
+  border-color: #c0c4cc;
+}
+</style>
diff --git a/src/components/CreateCom/XhTextarea.vue b/src/components/CreateCom/XhTextarea.vue
new file mode 100644
index 0000000..3a89d40
--- /dev/null
+++ b/src/components/CreateCom/XhTextarea.vue
@@ -0,0 +1,41 @@
+<template>
+  <el-input
+    v-model="dataValue"
+    :rows="3"
+    :maxlength="200"
+    :disabled="disabled"
+    type="textarea"
+    resize="none"
+    show-word-limit
+    @input="valueChange"/>
+</template>
+<script type="text/javascript">
+import stringMixin from './stringMixin'
+
+export default {
+  name: 'XhTextarea', // 新建 textarea
+  components: {},
+  mixins: [stringMixin],
+  props: {},
+  data () {
+    return {}
+  },
+  computed: {},
+  watch: {},
+  mounted () {},
+  methods: {}
+}
+</script>
+<style lang="less" scoped>
+/** 调整textarea输入 */
+.el-textarea /deep/ .el-textarea__inner {
+  padding: 5px 8px;
+  border-radius: 3px;
+  border: 1px solid #ddd;
+  color: #333333;
+}
+.el-textarea /deep/ .el-textarea__inner:focus {
+  outline: 0;
+  border-color: #ddd;
+}
+</style>
diff --git a/src/components/CreateCom/XhUser.vue b/src/components/CreateCom/XhUser.vue
new file mode 100644
index 0000000..a8821b4
--- /dev/null
+++ b/src/components/CreateCom/XhUser.vue
@@ -0,0 +1,240 @@
+<template>
+  <div>
+    <el-input
+      v-model="searchInput"
+      placeholder="搜索成员"
+      size="small"
+      suffix-icon="el-icon-search"
+      @input="inputchange"/>
+    <div
+      v-loading="loading"
+      class="search-list">
+      <el-checkbox-group
+        v-model="selectItems"
+        @change="changeCheckout">
+        <el-checkbox
+          v-for="(item, i) in list"
+          v-if="item.show"
+          :key="i"
+          :label="item"
+          :disabled="item.disabled"
+          class="colleagues-list">
+          <div
+            v-photo="item"
+            v-lazy:background-image="$options.filters.filterUserLazyImg(item.img)"
+            class="div-photo search-img"/>
+          <span>{{ item.realname }}</span>
+        </el-checkbox>
+      </el-checkbox-group>
+    </div>
+  </div>
+</template>
+<script type="text/javascript">
+// import { usersList } from '@/api/common'
+
+export default {
+  name: 'XhUser', // 新建 user
+  components: {},
+  props: {
+    value: {
+      type: String,
+      default: ''
+    },
+    /** 多选框 只能选一个 */
+    radio: {
+      type: Boolean,
+      default: false
+    },
+    /** 已选信息 */
+    selectedData: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    /** 获取不同的员工展示列表 */
+    infoType: {
+      type: String,
+      default: 'default' // 返回全部  crm_contract crm_receivables oa_examine 合同审核人自选列表
+    },
+    infoRequest: Function,
+    /** 请求辅助参数 */
+    infoParams: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  data () {
+    return {
+      list: [],
+      selectItems: [], // 选择项
+      loading: false, // 加载动画
+      searchInput: ''
+    }
+  },
+  computed: {},
+  watch: {
+    selectedData: function (value) {
+      this.checkItems(value)
+    }
+  },
+  mounted () {
+    this.getUserList()
+  },
+  methods: {
+    // 获取员工列表
+    getUserList () {
+      this.loading = true
+      this.getRequest()(this.getParams())
+        .then(res => {
+          var self = this
+          this.list = res.data.map(function (item, index, array) {
+            item.disabled = false // 要求单选
+            item.show = true
+            if (self.selectedData.length > 0) {
+              let disabled = true
+              for (let index = 0; index < self.selectedData.length; index++) {
+                const element = self.selectedData[index]
+                if (element.userId === item.userId) {
+                  disabled = false
+                  self.selectItems.push(item)
+                }
+              }
+              if (self.radio) {
+                item.disabled = disabled
+              }
+            }
+            return item
+          })
+          this.loading = false
+        })
+        .catch(() => {
+          this.loading = false
+        })
+    },
+    getRequest () {
+      if (this.infoRequest) {
+        return this.infoRequest
+      } else if (this.infoType === 'default') {
+        // return usersList
+      } else if (
+        this.infoType === 'crm_contract' ||
+        this.infoType === 'crm_receivables' ||
+        this.infoType === 'oa_examine'
+      ) {
+        // return usersList
+      }
+    },
+    getParams () {
+      const params =
+        this.infoParams && Object.keys(this.infoParams.length !== 0)
+          ? this.infoParams
+          : {}
+      if (this.infoType === 'default') {
+        params.pageType = 0
+        return params
+      } else if (
+        this.infoType === 'crm_contract' ||
+        this.infoType === 'crm_receivables' ||
+        this.infoType === 'oa_examine'
+      ) {
+        params.pageType = 0
+        return params
+      }
+    },
+    changeCheckout (items) {
+      if (this.radio) {
+        if (items.length) {
+          var element = items[0]
+          this.list = this.list.map(function (item, index, array) {
+            if (element.userId === item.userId) {
+              item.disabled = false
+            } else {
+              item.disabled = true
+            }
+            return item
+          })
+        } else {
+          this.list = this.list.map(function (item, index, array) {
+            item.disabled = false
+            return item
+          })
+        }
+      }
+
+      this.$emit('changeCheckout', { data: this.selectItems })
+    },
+    /** 取消勾选 */
+    cancelCheckItem (item) {
+      var removeIndex = -1
+      for (let index = 0; index < this.selectItems.length; index++) {
+        const element = this.selectItems[index]
+        if (element.userId === item.userId) {
+          removeIndex = index
+        }
+      }
+      this.selectItems.splice(removeIndex, 1)
+      if (this.radio && this.selectItems.length === 0) {
+        this.list = this.list.map(function (item, index, array) {
+          item.disabled = false
+          return item
+        })
+      }
+    },
+    /** 标记勾选 */
+    checkItems (items) {
+      this.selectItems = []
+      if (items.length > 0) {
+        for (let bigIndex = 0; bigIndex < this.list.length; bigIndex++) {
+          const item = this.list[bigIndex]
+
+          let disabled = true
+          for (let index = 0; index < items.length; index++) {
+            const element = items[index]
+            if (element.userId === item.userId) {
+              disabled = false
+              this.selectItems.push(item)
+            }
+          }
+          if (this.radio) {
+            item.disabled = disabled
+          }
+        }
+      }
+    },
+    // 搜索
+    inputchange (val) {
+      this.list = this.list.map(function (item, index, array) {
+        if (item.realname.indexOf(val) !== -1) {
+          item.show = true
+        } else {
+          item.show = false
+        }
+        return item
+      })
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+/* 选择员工 */
+.search-img {
+  width: 24px;
+  height: 24px;
+  border-radius: 12px;
+  vertical-align: middle;
+  margin-right: 8px;
+}
+.search-list {
+  padding: 5px;
+  height: 248px;
+  overflow: auto;
+}
+.colleagues-list {
+  padding: 5px;
+  display: block;
+  margin-left: 0;
+}
+</style>
diff --git a/src/components/CreateCom/XhUserCell.vue b/src/components/CreateCom/XhUserCell.vue
new file mode 100644
index 0000000..1ca24dc
--- /dev/null
+++ b/src/components/CreateCom/XhUserCell.vue
@@ -0,0 +1,162 @@
+<template>
+  <el-popover
+    :disabled="disabled"
+    placement="bottom"
+    width="300"
+    trigger="click">
+    <xh-user
+      v-if="!disabled&&showSelectView"
+      ref="xhuser"
+      :info-type="infoType"
+      :info-params="infoParams"
+      :radio="radio"
+      :selected-data="dataValue"
+      @changeCheckout="checkUsers"/>
+    <div slot="reference">
+      <flexbox
+        :class="[disabled ? 'is_disabled' : 'is_valid']"
+        wrap="wrap"
+        class="user-container"
+        @click.native="focusClick">
+        <div
+          v-for="(item, index) in dataValue"
+          :key="index"
+          class="user-item"
+          @click.stop="deleteuser(index)">{{ item.realname }}
+          <i class="delete-icon el-icon-close"/>
+        </div>
+        <div class="add-item">+{{ placeholder }}</div>
+      </flexbox>
+    </div>
+  </el-popover>
+
+</template>
+<script type="text/javascript">
+import XhUser from './XhUser'
+import arrayMixin from './arrayMixin'
+
+export default {
+  name: 'XhUserCell', // 新建 user-cell
+  components: {
+    XhUser
+  },
+  mixins: [arrayMixin],
+  props: {
+    radio: {
+      // 是否单选
+      type: Boolean,
+      default: true
+    },
+    placeholder: {
+      type: String,
+      default: '添加员工'
+    },
+    /** 获取不同的员工展示列表 */
+    infoType: {
+      type: String,
+      default: 'default' // 返回全部  crm_contract crm_receivables oa_examine 合同审核人自选列表
+    },
+    /** 请求辅助参数 */
+    infoParams: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  data () {
+    return {
+      showPopover: false, // 展示popover
+      showSelectView: false // 展示选择内容列表
+    }
+  },
+  computed: {},
+  watch: {},
+  mounted () {},
+  methods: {
+    /** 选中 */
+    checkUsers (data) {
+      this.dataValue = data.data
+      this.$emit('value-change', {
+        item: this.item,
+        index: this.index,
+        value: data.data
+      })
+    },
+    /** 删除 */
+    deleteuser (index) {
+      if (this.$refs.xhuser) {
+        this.$refs.xhuser.cancelCheckItem(this.dataValue[index])
+      }
+      this.dataValue.splice(index, 1)
+      this.$emit('value-change', {
+        item: this.item,
+        index: this.index,
+        value: this.dataValue
+      })
+    },
+    /** 聚焦动作 */
+    focusClick () {
+      this.showSelectView = true
+      this.$emit('focus')
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+.user-container {
+  min-height: 34px;
+  margin: 3px 0;
+  position: relative;
+  border-radius: 3px;
+  font-size: 12px;
+  border: 1px solid #ddd;
+  color: #333333;
+  padding: 0.5px;
+  line-height: 15px;
+  max-height: 105px;
+  overflow-y: auto;
+  .user-item {
+    padding: 5px;
+    background-color: #e2ebf9;
+    border-radius: 3px;
+    margin: 3px;
+    cursor: pointer;
+  }
+  .add-item {
+    padding: 5px;
+    color: #4D88FF;
+    cursor: pointer;
+  }
+  .delete-icon {
+    color: #999;
+    cursor: pointer;
+  }
+  &:hover {
+    border-color: #c0c4cc;
+  }
+}
+
+.user-container.is_disabled {
+  background-color: #f5f7fa;
+  border-color: #e4e7ed;
+  cursor: not-allowed;
+  .user-item {
+    background-color: #f0f4f8ea;
+    color: #c0c4cc;
+    cursor: not-allowed;
+  }
+  .delete-icon {
+    color: #c0c4cc;
+    cursor: not-allowed;
+  }
+  .add-item {
+    color: #c0c4cc;
+    cursor: not-allowed;
+  }
+}
+
+.user-container.is_valid:hover {
+  border-color: #c0c4cc;
+}
+</style>
diff --git a/src/components/CreateCom/arrayMixin.js b/src/components/CreateCom/arrayMixin.js
new file mode 100644
index 0000000..7c1d111
--- /dev/null
+++ b/src/components/CreateCom/arrayMixin.js
@@ -0,0 +1,44 @@
+/** 自定义组件 共同逻辑 */
+export default {
+  data () {
+    return {
+      dataValue: []
+    }
+  },
+  watch: {
+    value: function (val) {
+      this.dataValue = val
+    }
+  },
+  props: {
+    value: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    /** 索引值 用于更新数据 */
+    index: Number,
+    /** 包含数据源 */
+    item: Object,
+    disabled: {
+      type: Boolean,
+      default: false
+    }
+  },
+
+  mounted () {
+    this.dataValue = this.value
+  },
+
+  methods: {
+    // 输入的值
+    valueChange (val) {
+      this.$emit('value-change', {
+        index: this.index,
+        value: val
+      })
+    }
+  }
+
+}
diff --git a/src/components/CreateCom/index.js b/src/components/CreateCom/index.js
new file mode 100644
index 0000000..ef3ce08
--- /dev/null
+++ b/src/components/CreateCom/index.js
@@ -0,0 +1,21 @@
+export { default as XhInput } from './XhInput'
+export { default as XhTextarea } from './XhTextarea'
+export { default as XhSelect } from './XhSelect'
+export { default as XhMultipleSelect } from './XhMultipleSelect'
+export { default as XhDate } from './XhDate'
+export { default as XhDateTime } from './XhDateTime'
+export { default as XhUser } from './XhUser'
+export { default as XhUserCell } from './XhUserCell'
+export { default as XhStructureCell } from './XhStructureCell'
+export { default as XhFiles } from './XhFiles'
+export { default as CrmRelativeCell } from './CrmRelativeCell'
+export { default as XhProuctCate } from './XhProuctCate'
+export { default as XhProduct } from './XhProduct'
+export { default as XhBusinessStatus } from './XhBusinessStatus'
+export { default as XhCustomerAddress } from './XhCustomerAddress'
+
+export { default as XhStrucUserCell } from './XhStrucUserCell'
+export { default as XhReceivablesPlan } from './XhReceivablesPlan'
+export { default as XhRelativeInput } from './XhRelativeInput'
+export { default as XhRelativeInputS } from './XhRelativeInputS'
+export { default as XhInputSelect } from './XhInputSelect'
diff --git a/src/components/CreateCom/objMixin.js b/src/components/CreateCom/objMixin.js
new file mode 100644
index 0000000..606dea8
--- /dev/null
+++ b/src/components/CreateCom/objMixin.js
@@ -0,0 +1,42 @@
+/** 自定义组件 共同逻辑 */
+export default {
+  data () {
+    return {
+      dataValue: []
+    }
+  },
+  watch: {
+  },
+  props: {
+    // value: {
+    //   type: Object,
+    //   default: () => {
+    //     return {}
+    //   }
+    // },
+    /** 索引值 用于更新数据 */
+    index: Number,
+    /** 包含数据源 */
+    item: Object,
+    disabled: {
+      type: Boolean,
+      default: false
+    }
+  },
+
+  mounted () {
+    /** 如果有值以传入值为主 如果无值 已默认值为主 */
+    // this.dataValue = this.value
+  },
+
+  methods: {
+    // 输入的值
+    valueChange (val) {
+      this.$emit('value-change', {
+        index: this.index,
+        value: val
+      })
+    }
+  }
+
+}
diff --git a/src/components/CreateCom/stringMixin.js b/src/components/CreateCom/stringMixin.js
new file mode 100644
index 0000000..ddcf222
--- /dev/null
+++ b/src/components/CreateCom/stringMixin.js
@@ -0,0 +1,49 @@
+/** 自定义组件 共同逻辑 */
+export default {
+  data () {
+    return {
+      dataValue: ''
+    }
+  },
+  watch: {
+    value: function (val) {
+      this.dataValue = val
+    }
+  },
+  props: {
+    value: {
+      type: [String, Number],
+      default: ''
+    },
+    /** 索引值 用于更新数据 */
+    index: Number,
+    /** 包含数据源 */
+    item: Object,
+    disabled: {
+      type: Boolean,
+      default: false
+    }
+  },
+
+  mounted () {
+    /** 如果有值以传入值为主 如果无值 已默认值为主 */
+    this.dataValue = this.value
+  },
+
+  methods: {
+    // 输入的值
+    valueChange (val, planList = []) {
+      const data = {
+        index: this.index,
+        value: val
+      }
+      if (planList.length > 0) {
+        data.plan = planList.filter(item => {
+          return item.planId === this.dataValue
+        })[0]
+      }
+      this.$emit('value-change', data)
+    }
+  }
+
+}
diff --git a/src/components/CreateSections.vue b/src/components/CreateSections.vue
new file mode 100644
index 0000000..45af1d1
--- /dev/null
+++ b/src/components/CreateSections.vue
@@ -0,0 +1,72 @@
+<template>
+  <div class="section">
+    <div
+      v-if="title && title.length > 0"
+      class="section-header">
+      <div
+        :style="{ 'border-left-color': mColor }"
+        class="section-mark"/>
+      <div class="section-title">{{ title }}</div>
+      <slot name="header"/>
+    </div>
+    <div class="content">
+      <slot/>
+    </div>
+  </div>
+</template>
+<script type="text/javascript">
+export default {
+  name: 'CreateSections',
+  components: {},
+  props: {
+    title: {
+      type: String,
+      default: ''
+    },
+    mColor: {
+      type: String,
+      default: '#4D88FF'
+    }
+  },
+  data () {
+    return {}
+  },
+  computed: {},
+  mounted () {},
+  methods: {}
+}
+</script>
+<style lang="less" scoped>
+.section {
+  position: relative;
+  background-color: white;
+  margin-top: 8px;
+}
+.section:first-child {
+  margin-top: 0;
+}
+
+.section-mark {
+  border-left-width: 2px;
+  border-left-style: solid;
+  height: 16px;
+}
+
+.section-header {
+  display: flex;
+  align-items: center;
+  padding: 5px 15px;
+  margin-bottom: 30px;
+}
+.section-title {
+  font-size: 18px;
+  color: #333;
+  margin-left: 8px;
+  flex-shrink: 0;
+  font-weight: 550;
+}
+
+.content {
+  padding: 0 10px;
+}
+</style>
diff --git a/src/components/CreateView.vue b/src/components/CreateView.vue
new file mode 100644
index 0000000..2b790dd
--- /dev/null
+++ b/src/components/CreateView.vue
@@ -0,0 +1,83 @@
+<template>
+  <transition name="opacity-fade">
+    <div
+      :style="{ 'background-color': backgroundColor, 'padding': padding+' 0', 'z-index': zIndex }"
+      class="c-view">
+      <el-card
+        v-loading="loading"
+        :style="{ 'width': width}"
+        :body-style="bodyStyle"
+        class="crm-create-card-container">
+        <slot name="header"/>
+        <slot/>
+      </el-card>
+    </div>
+  </transition>
+</template>
+<script type="text/javascript">
+import { getMaxIndex } from '@/utils/index'
+
+export default {
+  name: 'CreateView', // 所有新建效果的view
+  components: {},
+  props: {
+    bodyStyle: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    loading: {
+      type: Boolean,
+      default: false
+    },
+    // 更改背景颜色颜色
+    backgroundColor: {
+      type: String,
+      default: '#F5F6F9' // rgba(0, 0, 0, 0.6) 黑色半透明
+    },
+    /** 展示内容的宽 */
+    width: {
+      type: String,
+      default: '1046px'
+    },
+    /** 展示内容的上下padding */
+    padding: {
+      type: String,
+      default: '40px'
+    }
+  },
+  data () {
+    return {
+      zIndex: getMaxIndex(),
+      loadingObj: null
+    }
+  },
+  computed: {},
+  watch: {},
+  mounted () {},
+  methods: {}
+}
+</script>
+<style lang="less" scoped>
+.opacity-fade-enter-active,
+.opacity-fade-leave-active {
+  transition: all 0.2s;
+}
+.opacity-fade-enter,
+.opacity-fade-leave-to {
+  opacity: 0;
+}
+/** 容器布局 */
+.c-view {
+  position: fixed;
+  left: 0;
+  top: 0;
+  bottom: 0;
+  right: 0;
+}
+.crm-create-card-container {
+  margin: 0 auto;
+  height: 100%;
+}
+</style>
diff --git a/src/components/DetailCell.vue b/src/components/DetailCell.vue
new file mode 100644
index 0000000..aee2be5
--- /dev/null
+++ b/src/components/DetailCell.vue
@@ -0,0 +1,84 @@
+<template>
+  <div class="cell">
+    <div class="div-flex">
+      <div style="flex:1;">
+        <div class="cell-title">{{ title }}</div>
+        <div class="cell-detail">{{ detail }}</div>
+      </div>
+      <div style="flex-shrink:0;">
+        <slot name="value"/>
+        <div class="cell-time">{{ time }}</div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script type="text/javascript">
+export default {
+  name: 'DetailsCell', // 标题  详情  时间 常用布局
+  components: {},
+  props: {
+    title: {
+      type: String,
+      default: ''
+    },
+    detail: {
+      type: String,
+      default: ''
+    },
+    time: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {}
+  },
+  computed: {},
+  mounted () {},
+  methods: {}
+}
+</script>
+<style lang="less" scoped>
+.cell {
+  padding: 10px 15px;
+  position: relative;
+  background-color: white;
+}
+.cell:before {
+  content: ' ';
+  position: absolute;
+  top: 0;
+  right: 0;
+  height: 1px;
+  border-top: 1px solid #e5e5e5;
+  color: #e5e5e5;
+  -webkit-transform-origin: 0 0;
+  transform-origin: 0 0;
+  -webkit-transform: scaleY(0.5);
+  transform: scaleY(0.5);
+  left: 15px;
+  z-index: 2;
+}
+.cell:first-child:before {
+  display: none;
+}
+.div-flex {
+  display: -webkit-box;
+  display: -webkit-flex;
+  display: flex;
+}
+.cell-title {
+  color: #333333;
+  font-size: 13px;
+}
+.cell-detail {
+  color: #999999;
+  font-size: 12px;
+  margin-top: 8px;
+}
+.cell-time {
+  color: #333333;
+  font-size: 13px;
+}
+</style>
diff --git a/src/components/EditImage.vue b/src/components/EditImage.vue
new file mode 100644
index 0000000..f294bc5
--- /dev/null
+++ b/src/components/EditImage.vue
@@ -0,0 +1,156 @@
+<template>
+  <el-dialog
+    v-loading="loading"
+    :title="title"
+    :width="width"
+    :append-to-body="true"
+    :visible.sync="showDialog"
+    @close="hiddenView">
+    <flexbox class="content">
+      <div class="cropper-box">
+        <vueCropper
+          ref="cropper"
+          :can-move="true"
+          :auto-crop="true"
+          :fixed="true"
+          :fixed-number="fixedNumber"
+          :img="cropperImg"
+          output-type="png"
+          @realTime="realTime"/>
+      </div>
+      <div class="preview">
+        <div class="preview-name">预览</div>
+        <img
+          :style="{'width': previewWidth, 'height': previewHeight, 'border-radius': previewRadius}"
+          :src="previewImg"
+          class="preview-img" >
+      </div>
+    </flexbox>
+    <div
+      slot="footer"
+      class="dialog-footer">
+      <el-button
+        type="primary"
+        @click="submiteImage()">{{ saveButtonTitle }}</el-button>
+    </div>
+  </el-dialog>
+</template>
+<script type="text/javascript">
+import { VueCropper } from 'vue-cropper'
+
+export default {
+  name: 'EditImage', // 处理头像
+  components: {
+    VueCropper
+  },
+  props: {
+    width: {
+      type: String,
+      default: '450px'
+    },
+    title: {
+      type: String,
+      default: '编辑头像'
+    },
+    saveButtonTitle: {
+      type: String,
+      default: '开始上传'
+    },
+    show: {
+      type: Boolean,
+      default: false
+    },
+    fixedNumber: {
+      type: Array,
+      default: () => {
+        return [1, 1]
+      }
+    },
+    previewWidth: {
+      type: String,
+      default: '70px'
+    },
+    previewHeight: {
+      type: String,
+      default: '70px'
+    },
+    previewRadius: {
+      type: String,
+      default: '35px'
+    },
+    file: [File],
+    image: String
+  },
+  data () {
+    return {
+      loading: false,
+      showDialog: false,
+      cropperImg: '',
+      previewImg: ''
+    }
+  },
+  computed: {},
+  watch: {
+    show: {
+      handler (val) {
+        this.showDialog = val
+      },
+      deep: true,
+      immediate: true
+    },
+    image: function (val) {
+      this.cropperImg = val
+    }
+  },
+  mounted () {
+    this.cropperImg = this.image
+  },
+  methods: {
+    realTime (data) {
+      this.$refs.cropper.getCropData(cropperData => {
+        this.previewImg = cropperData
+      })
+    },
+    submiteImage () {
+      // 获取截图的blob数据
+      this.$refs.cropper.getCropBlob(data => {
+        this.$emit('save', {
+          blob: data,
+          file: this.file,
+          image: this.previewImg
+        })
+        this.hiddenView()
+      })
+    },
+    hiddenView () {
+      this.$emit('close')
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+.cropper-box {
+  width: 300px;
+  height: 300px;
+  margin-right: 15px;
+}
+
+.preview {
+  position: absolute;
+  bottom: 0;
+  right: 0;
+  .preview-name {
+    margin-bottom: 8px;
+    font-size: 13px;
+    color: #666;
+  }
+  .preview-img {
+    display: block;
+  }
+}
+
+.content {
+  position: relative;
+  padding: 0 30px;
+}
+</style>
diff --git a/src/components/Examine/CheckFlow.vue b/src/components/Examine/CheckFlow.vue
new file mode 100644
index 0000000..159a9d4
--- /dev/null
+++ b/src/components/Examine/CheckFlow.vue
@@ -0,0 +1,237 @@
+<template>
+  <div
+    v-loading="loading"
+    v-empty="list"
+    xs-empty-icon="none"
+    xs-empty-text="暂无记录">
+    <flexbox class="flow-head">
+      <div class="flow-head-name">审批流程</div>
+      <img
+        class="flow-head-close"
+        src="@/assets/img/task_close.png"
+        @click="close" >
+    </flexbox>
+    <div class="flow-body">
+      <flexbox
+        v-for="(item, index) in list"
+        :key="index"
+        class="cf-flow-item"
+        align="stretch"
+        justify="flex-start">
+        <img
+          :src="item.examineStatus|statusIcon"
+          class="cf-flow-item-img" >
+        <div>
+          <flexbox class="cf-flow-item-head">
+            <div class="cf-flow-item-des">{{ item.orderId|stepName }}</div>
+            <div>{{ item.examineTime }}</div>
+          </flexbox>
+          <flexbox class="cf-flow-item-info">
+            <div class="cf-flow-item-name">{{ item.realname }}</div>
+            <div><span>{{ getStatusName(item.examineStatus) }}</span>了此申请</div>
+          </flexbox>
+          <div
+            v-if="item.remarks"
+            class="cf-flow-item-content">{{ item.remarks }}
+            <div class="cf-flow-item-content-arrow"/>
+          </div>
+        </div>
+        <div class="cf-flow-item-line"/>
+      </flexbox>
+    </div>
+  </div>
+</template>
+
+<script>
+// import { crmExamineFlowRecordList } from '@/api/clients/common' // 审批记录
+// import { oaExamineFlowRecordList } from '@/api/oamanagement/examine'
+
+import Nzhcn from 'nzh/cn'
+
+export default {
+  /** 客户管理 的 合同详情  查看审批流程 */
+  name: 'CheckFlow',
+  components: {},
+  filters: {
+    statusIcon: function (status) {
+      // 0失败,1通过,2撤回,3创建,4待审核
+      // JAVA 0 未审核 1 审核通过 2 审核拒绝 3 审核中 4 已撤回 5 创建 6 待提交
+      // if (status === 2) {
+      //   return require('@/assets/img/check_fail.png')
+      // } else if (status === 1) {
+      //   return require('@/assets/img/check_suc.png')
+      // } else if (status === 4) {
+      //   return require('@/assets/img/check_revoke.png')
+      // } else if (status === 3) {
+      //   return require('@/assets/img/check_create.png')
+      // } else if (status === 0 || status === 6) {
+      //   return require('@/assets/img/check_wait.png')
+      // } else if (status === 5) {
+      //   return require('@/assets/img/check_create.png')
+      // }
+      return ''
+    },
+    stepName: function (index) {
+      return '第' + Nzhcn.encodeS(index) + '级'
+    }
+  },
+  props: {
+    examineType: {
+      type: String,
+      default: ''
+    },
+    // 详情信息id
+    id: [String, Number]
+  },
+  data () {
+    return {
+      loading: false,
+      list: []
+    }
+  },
+  computed: {},
+  watch: {
+    id: function (val) {
+      if (val) {
+        this.list = []
+        this.getDetail()
+      }
+    }
+  },
+  mounted () {},
+  methods: {
+    getDetail () {
+      if (this.id) {
+        this.loading = true
+        const request = {
+          // crm_contract: crmExamineFlowRecordList,
+          // crm_receivables: crmExamineFlowRecordList,
+          // oa_examine: oaExamineFlowRecordList
+        }[this.examineType]
+
+        request({
+          recordId: this.id
+        })
+          .then(res => {
+            this.loading = false
+            this.list = res.data
+            // this.$emit('value-change', {
+            //   config: res.data.config, // 审批类型
+            //   value: [] // 审批信息
+            // })
+          })
+          .catch(() => {
+            this.loading = false
+          })
+      }
+    },
+    // 获取状态名称
+    getStatusName (status) {
+      // 0拒绝,1通过,2撤回,3创建,4待审核
+      if (status === 0) {
+        return '未审核 '
+      } else if (status === 1) {
+        return '通过'
+      } else if (status === 2) {
+        return '拒绝'
+      } else if (status === 3) {
+        return '审核中'
+      } else if (status === 4) {
+        return '撤回'
+      } else if (status === 5) {
+        return '创建'
+      } else if (status === 6) {
+        return '待提交'
+      }
+      return ''
+    },
+    close () {
+      this.$emit('close')
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+/** 头部的css */
+.flow-head {
+  padding: 8px 15px;
+  border-bottom: 1px solid #e6e6e6;
+  .flow-head-name {
+    font-size: 14px;
+    color: #333;
+    flex: 1;
+  }
+  .flow-head-name {
+    display: block;
+    width: 30px;
+    height: 30px;
+  }
+  .flow-head-close {
+    cursor: pointer;
+    width: 30px;
+    height: 30px;
+    padding: 8px;
+  }
+}
+.flow-body {
+  padding: 15px;
+}
+/** 每行的css */
+.cf-flow-item {
+  position: relative;
+  padding-bottom: 15px;
+  .cf-flow-item-img {
+    display: block;
+    background-color: white;
+    width: 16px;
+    height: 16px;
+    border-radius: 8px;
+    margin-right: 10px;
+  }
+  .cf-flow-item-head {
+    color: #bababa;
+    font-size: 12px;
+    .cf-flow-item-des {
+      margin-right: 10px;
+    }
+  }
+  .cf-flow-item-info {
+    margin-top: 8px;
+    font-size: 12px;
+    color: #979797;
+    .cf-flow-item-name {
+      color: #333;
+      margin-right: 10px;
+    }
+  }
+  .cf-flow-item-line {
+    position: absolute;
+    z-index: -1;
+    width: 1px;
+    top: 0px;
+    bottom: 0px;
+    left: 8px;
+    background-color: #e6e6e6;
+  }
+  .cf-flow-item-content {
+    position: relative;
+    margin-top: 15px;
+    border-radius: 4px;
+    background-color: #f7f8fa;
+    font-size: 12px;
+    color: #929293;
+    padding: 8px;
+    line-height: 18px;
+    .cf-flow-item-content-arrow {
+      width: 8px;
+      height: 8px;
+      background-color: #f7f8fa;
+      transform: rotate(45deg);
+      position: absolute;
+      top: -4px;
+      left: 25px;
+    }
+  }
+}
+</style>
diff --git a/src/components/Examine/CreateExamineInfo.vue b/src/components/Examine/CreateExamineInfo.vue
new file mode 100644
index 0000000..05c34a9
--- /dev/null
+++ b/src/components/Examine/CreateExamineInfo.vue
@@ -0,0 +1,244 @@
+<template>
+  <div>
+    <el-form
+      v-if="examineInfo.examineType === 2"
+      ref="form"
+      :model="form"
+      :rules="rules"
+      label-position="top"
+      class="crm-create-box">
+      <el-form-item
+        prop="name"
+        class="crm-create-item">
+        <div
+          slot="label"
+          style="display: inline-block;">
+          <div style="margin:5px 0;font-size:12px;word-wrap:break-word;word-break:break-all;">
+            审核人
+            <span style="color:#999;"/>
+          </div>
+        </div>
+        <xh-user-cell
+          :info-type="types"
+          :value="draftUser ? [draftUser] : []"
+          @value-change="fieldValueChange"/>
+      </el-form-item>
+    </el-form>
+    <flexbox
+      v-else-if="examineInfo.examineType === 1"
+      class="fixed-examine"
+      wrap="wrap">
+      <el-popover
+        v-for="(item, index) in examineInfo.examineSteps"
+        :key="index"
+        :disabled="item.userList.length==0"
+        :content="item.userList|contentFilters"
+        placement="bottom"
+        trigger="hover">
+        <div
+          slot="reference"
+          class="fixed-examine-item">
+          <img src="@/assets/img/examine_head.png" >
+          <div class="detail">{{ item|detail }}</div>
+          <div class="step">{{ (index+1)|step }}</div>
+        </div>
+      </el-popover>
+    </flexbox>
+
+  </div>
+</template>
+<script type="text/javascript">
+// import { crmCreateExamineFlow } from '@/api/clients/common'
+// import { oaCreateExamineFlow } from '@/api/oamanagement/examine'
+
+import { XhUserCell } from '@/components/CreateCom'
+// import Nzhcn from 'nzh/cn'
+
+export default {
+  name: 'CreateExamineInfo',
+  components: {
+    XhUserCell
+  },
+  filters: {
+    detail: function (data) {
+      if (data.stepType === 2) {
+        return data.userList.length + '人或签'
+      } else if (data.stepType === 3) {
+        return data.userList.length + '人会签'
+      } else if (data.stepType === 1) {
+        return '负责人主管'
+      } else if (data.stepType === 4) {
+        return '上一级审批人主管'
+      }
+    },
+    step: function (index) {
+      // return '第' + Nzhcn.encodeS(index) + '级'
+    },
+    contentFilters: function (array) {
+      return array
+        .map(item => {
+          return item.realname
+        })
+        .join('、')
+    }
+  },
+  props: {
+    // CRM类型
+    types: {
+      type: String,
+      default: ''
+    },
+    // 办公审批 传ID
+    typesId: {
+      type: [String, Number],
+      default: ''
+    }
+  },
+  data () {
+    return {
+      form: {
+        name: ''
+      },
+      rules: {
+        name: [{ required: true, message: '审批人不能为空', trigger: 'blur' }]
+      },
+      // 审核信息 examineType 1 固定审批 2 授权审批
+      examineInfo: {},
+      draftUser: null
+    }
+  },
+  computed: {},
+  mounted () {
+    this.getDetail()
+  },
+  methods: {
+    getDetail () {
+      // const reqeust = {
+      //   oa_examine: oaCreateExamineFlow,
+      //   crm_contract: crmCreateExamineFlow,
+      //   crm_receivables: crmCreateExamineFlow
+      // }[this.types]
+
+      const params = {}
+      if (this.types === 'oa_examine') {
+        params.categoryId = this.typesId
+      } else {
+        params.id = this.typesId
+        params.categoryType = this.types === 'crm_contract' ? 1 : 2 // 1 合同 2 回款
+      }
+      // reqeust(params)
+      //   .then(res => {
+      //     this.examineInfo = res.data
+      //     if (res.data.examineType === 2 && res.data.examineUser) {
+      //       this.draftUser = {
+      //         realname: res.data.examineUserName,
+      //         userId: res.data.examineUser
+      //       }
+      //       this.form.name = res.data.examineUserName
+      //       this.$emit('value-change', {
+      //         examineType: res.data.examineType, // 审批类型
+      //         value: [this.draftUser] // 审批信息
+      //       })
+      //     } else {
+      //       this.form.name = ''
+      //       this.draftUser = null
+      //       this.$emit('value-change', {
+      //         examineType: res.data.examineType, // 审批类型
+      //         value: [] // 审批信息
+      //       })
+      //     }
+      //   })
+      //   .catch(() => {})
+    },
+    validateField (result) {
+      if (this.examineInfo.examineType === 2) {
+        // 授权审批人 需要验证关联人
+        this.$refs.form.validate(valid => {
+          if (valid) {
+            result() // 成功回调
+          } else {
+            return false
+          }
+        })
+      } else {
+        result() // 成功回调
+      }
+    },
+    // 字段的值更新
+    fieldValueChange (data) {
+      if (data.value.length) {
+        this.draftUser = data.value[0]
+        this.form.name = this.draftUser.userId
+      } else {
+        this.draftUser = null
+        this.form.name = ''
+      }
+      this.$emit('value-change', {
+        examineType: this.examineInfo.examineType, // 审批类型
+        value: data.value // 审批信息
+      })
+      this.$refs.form.validateField('name')
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+/** 将其改变为flex布局 */
+.crm-create-box {
+  display: flex;
+  flex-wrap: wrap;
+  padding: 0 10px;
+}
+
+.crm-create-item {
+  flex: 0 0 45%;
+  flex-shrink: 0;
+  // overflow: hidden;
+  padding-bottom: 10px;
+}
+
+.el-form-item /deep/ .el-form-item__label {
+  line-height: normal;
+  font-size: 13px;
+  color: #333333;
+  position: relative;
+  padding-left: 8px;
+  padding-bottom: 0;
+}
+
+.el-form /deep/ .el-form-item {
+  margin-bottom: 0px;
+}
+
+.el-form /deep/ .el-form-item.is-required .el-form-item__label:before {
+  content: '*';
+  color: #f56c6c;
+  margin-right: 4px;
+  position: absolute;
+  left: 0;
+  top: 5px;
+}
+
+// 固定审批信息
+.fixed-examine {
+  padding: 0px 10px;
+  text-align: center;
+  .fixed-examine-item {
+    padding: 10px 20px;
+    img {
+      width: 40px;
+      height: 40px;
+    }
+    .detail {
+      color: #777777;
+      font-size: 12px;
+      padding: 2px 0;
+      transform: scale(0.8, 0.8);
+    }
+    .step {
+      color: #333333;
+      font-size: 12px;
+    }
+  }
+}
+</style>
diff --git a/src/components/Examine/ExamineHandle.vue b/src/components/Examine/ExamineHandle.vue
new file mode 100644
index 0000000..45139c5
--- /dev/null
+++ b/src/components/Examine/ExamineHandle.vue
@@ -0,0 +1,246 @@
+<template>
+  <el-dialog
+    v-loading="loading"
+    :title="title"
+    :append-to-body="true"
+    :visible.sync="showDialog"
+    width="400px"
+    @close="hiddenView">
+    <div
+      v-if="status === 1 && detail.examineType === 2"
+      class="handle-type">
+      <flexbox class="handle-item">
+        <el-radio
+          v-model="handleType"
+          :label="1"><span/></el-radio>
+        <div
+          style="font-size: 12px;"
+          @click.native="handleType=1">审核结束</div>
+      </flexbox>
+      <flexbox
+        id="selectUser"
+        class="handle-item">
+        <el-radio
+          v-model="handleType"
+          :label="2"><span/></el-radio>
+        <xh-user-cell
+          class="select-user"
+          placeholder="选择下一审批人"
+          @focus="selectUserFocus"
+          @value-change="selectExamineUser"/>
+      </flexbox>
+    </div>
+    <div
+      v-if="status === 1 && detail.examineType === 2"
+      class="title">意见</div>
+    <el-input
+      v-model="content"
+      :rows="5"
+      :maxlength="200"
+      :placeholder="placeholder"
+      type="textarea"
+      resize="none"
+      show-word-limit/>
+    <div
+      slot="footer"
+      class="dialog-footer">
+      <el-button @click="handleClick('cancel')">取 消</el-button>
+      <el-button
+        type="primary"
+        @click="handleClick('confirm')">确 定</el-button>
+    </div>
+  </el-dialog>
+</template>
+<script type="text/javascript">
+// import { crmExamineFlowAuditExamine } from '@/api/clients/common'
+// import { oaExamineFlowAuditExamine } from '@/api/oamanagement/examine'
+
+import { XhUserCell } from '@/components/CreateCom'
+
+export default {
+  name: 'ExamineHandle', // 合同审核操作
+  components: {
+    XhUserCell
+  },
+  props: {
+    show: {
+      type: Boolean,
+      default: false
+    }, // 审核状态 1 审核通过 2 审核拒绝 4 已撤回
+    /** 操作类型  1通过0拒绝2撤回 */ status: {
+      type: [String, Number],
+      default: 1
+    },
+    // 详情信息id
+    id: [String, Number],
+    recordId: [String, Number],
+    // 审核信息 config 1 固定 0 自选
+    detail: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    // crm_contract crm_receivables oa_examine
+    examineType: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      loading: false,
+      showDialog: false,
+      handleType: 1,
+      selectUsers: [],
+      content: '' // 输入内容
+    }
+  },
+  computed: {
+    title () {
+      if (this.status === 1) {
+        return '审批通过'
+      } else if (this.status === 2) {
+        return '审批拒绝'
+      } else if (this.status === 4) {
+        return '撤回审批'
+      }
+      return ''
+    },
+    placeholder () {
+      // 1 审核通过 2 审核拒绝 4 已撤回
+      if (this.status === 1) {
+        return '请输入审批意见(选填)'
+      } else if (this.status === 2) {
+        return '请输入审批意见(必填)'
+      } else if (this.status === 4) {
+        return '请输入撤回理由(必填)'
+      }
+      return ''
+    }
+  },
+  watch: {
+    show: {
+      handler (val) {
+        this.showDialog = val
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+  mounted () {},
+  methods: {
+    submitInfo () {
+      if ((this.status === 2 || this.status === 4) && !this.content) {
+        this.$message.error(this.placeholder)
+      } else {
+        if (this.status === 2 || this.status === 1) {
+          // 1通过0拒绝2撤回
+          this.handlePassAndReject()
+        } else if (this.status === 4) {
+          this.handleRevoke()
+        }
+      }
+    },
+    // 撤回操作
+    handleRevoke () {
+      this.loading = true
+      this.getRequest()({
+        id: this.id,
+        recordId: this.recordId,
+        status: this.status,
+        remarks: this.content
+      })
+        .then(res => {
+          this.loading = false
+          this.$message.success('操作成功')
+          this.$emit('save')
+          this.$bus.emit('examine-handle-bus')
+          this.$store.dispatch('GetMessageNum')
+          this.hiddenView()
+        })
+        .catch(() => {
+          this.loading = false
+        })
+    },
+    getRequest () {
+      return {
+        // crm_contract: crmExamineFlowAuditExamine,
+        // crm_receivables: crmExamineFlowAuditExamine,
+        // oa_examine: oaExamineFlowAuditExamine
+      }[this.examineType]
+    },
+    // 通过 拒绝操作
+    handlePassAndReject () {
+      this.loading = true
+      var params = {
+        id: this.id,
+        recordId: this.recordId,
+        status: this.status,
+        remarks: this.content
+      }
+      if (this.status === 1 && this.detail.examineType === 2) {
+        if (this.handleType !== 1) {
+          params['nextUserId'] = this.selectUsers[0].userId
+        }
+      }
+      this.getRequest()(params)
+        .then(res => {
+          this.loading = false
+          this.$message.success('操作成功')
+          this.$emit('save', { type: this.status })
+          this.hiddenView()
+          this.$bus.emit('examine-handle-bus')
+          this.$store.dispatch('GetMessageNum')
+        })
+        .catch(() => {
+          this.loading = false
+        })
+    },
+    handleClick (type) {
+      if (type === 'cancel') {
+        this.hiddenView()
+      } else if (type === 'confirm') {
+        this.submitInfo()
+      }
+    },
+    /** 选择了下一审批人 */
+    selectUserFocus () {
+      this.handleType = 2
+    },
+    selectExamineUser (data) {
+      this.selectUsers = data.value
+    },
+    hiddenView () {
+      this.$emit('close')
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+.handle-type {
+  padding-bottom: 8px;
+  .handle-item {
+    padding: 8px 0;
+    cursor: pointer;
+  }
+}
+
+.el-dialog__wrapper /deep/ .el-dialog__body {
+  padding: 10px 25px 20px;
+}
+
+.el-radio-group /deep/ .el-radio + .el-radio {
+  margin-left: 0px;
+}
+
+.select-user {
+  flex: 1;
+}
+
+.title {
+  font-size: 12px;
+  padding-bottom: 8px;
+  color: #666;
+}
+</style>
diff --git a/src/components/Examine/ExamineInfo.vue b/src/components/Examine/ExamineInfo.vue
new file mode 100644
index 0000000..ff20ac8
--- /dev/null
+++ b/src/components/Examine/ExamineInfo.vue
@@ -0,0 +1,443 @@
+<template>
+  <div
+    v-loading="loading"
+    class="contract-flow-box">
+    <flexbox
+      direction="row-reverse"
+      style="position:relative;">
+      <el-popover
+        v-model="showFlowPopover"
+        placement="bottom"
+        width="300"
+        trigger="click">
+        <check-flow
+          ref="checkFlow"
+          :id="recordId"
+          :examine-type="examineType"
+          @close="showFlowPopover=false"/>
+        <el-button
+          slot="reference"
+          class="check-flow-button"
+          type="text">查看审批历史</el-button>
+      </el-popover>
+      <div style="min-height: 40px;">
+        <el-button
+          v-if="examineInfo.isRecheck==1"
+          class="flow-button white"
+          @click="examineHandle(4)">撤回审核</el-button>
+        <el-button
+          v-if="examineInfo.isCheck==1"
+          class="flow-button red"
+          @click="examineHandle(2)">拒绝</el-button>
+        <el-button
+          v-if="examineInfo.isCheck==1"
+          class="flow-button blue"
+          @click="examineHandle(1)">通过</el-button>
+      </div>
+    </flexbox>
+    <flexbox
+      v-if="examineInfo.examineType === 2"
+      class="check-items">
+      <flexbox
+        v-for="(item, index) in examineInfo.steps"
+        :key="index"
+        class="check-item">
+        <div>
+          <flexbox
+            class="check-item-user"
+            style="width:auto;">
+            <div
+              v-photo="item.examinUser"
+              v-lazy:background-image="$options.filters.filterUserLazyImg(item.examinUser.img)"
+              class="div-photo check-item-img"/>
+            <div class="check-item-name">{{ item.examinUser.realname }}</div>
+          </flexbox>
+          <flexbox class="check-item-info">
+            <img
+              :src="item.examineStatus|statusIcon"
+              class="check-item-img">
+            <div class="check-item-name">{{ getStatusName(item.examineStatus) }}</div>
+          </flexbox>
+        </div>
+        <i
+          v-if="examineInfo.steps.length -1 !== index"
+          class="el-icon-arrow-right check-item-arrow"/>
+      </flexbox>
+    </flexbox>
+    <flexbox
+      v-else-if="examineInfo.examineType === 1"
+      class="check-items"
+      wrap="wrap">
+      <el-popover
+        v-for="(item, index) in examineInfo.steps"
+        :key="index"
+        :disabled="!item.userList || item.userList.length==0"
+        placement="bottom"
+        trigger="hover">
+        <div class="popover-detail">
+          <flexbox
+            v-for="(subItem, subIndex) in item.userList"
+            :key="subIndex"
+            align="stretch"
+            class="popover-detail-item">
+            <img
+              :src="subItem.examineStatus|statusIcon"
+              class="popover-detail-item-img">
+            <div>
+              <div class="popover-detail-item-time">{{ subItem.examineTime }}</div>
+              <flexbox class="popover-detail-item-examine">
+                <div class="examine-name">{{ subItem.realname }}</div>
+                <div class="examine-info">{{ getStatusName(subItem.examineStatus) }}此申请</div>
+              </flexbox>
+            </div>
+          </flexbox>
+        </div>
+        <flexbox
+          slot="reference"
+          class="fixed-examine-item">
+          <div class="fixed-examine-info">
+            <img src="@/assets/img/examine_head.png" >
+            <div class="detail">{{ item|detailName }}</div>
+            <flexbox class="check-item-info">
+              <img
+                :src="item.examineStatus|statusIcon"
+                class="check-item-img">
+              <div class="check-item-name">{{ getStatusName(item.examineStatus) }}</div>
+            </flexbox>
+          </div>
+          <i
+            v-if="examineInfo.steps.length -1 !== index"
+            class="el-icon-arrow-right check-item-arrow"/>
+        </flexbox>
+      </el-popover>
+    </flexbox>
+    <examine-handle
+      :show="showExamineHandle"
+      :id="id"
+      :record-id="recordId"
+      :examine-type="examineType"
+      :detail="examineInfo"
+      :status="examineHandleInfo.status"
+      @close="showExamineHandle = false"
+      @save="examineHandleClick"/>
+  </div>
+</template>
+<script type="text/javascript">
+// import { crmExamineFlowStepList } from '@/api/clients/common' // 审批步骤
+// import { oaExamineFlowStepList } from '@/api/oamanagement/examine'
+
+import Nzhcn from 'nzh/cn'
+import ExamineHandle from './ExamineHandle' // 审批操作理由
+import CheckFlow from './CheckFlow' // 审批流程
+
+// 审核信息 config 1 固定 0 自选
+export default {
+  name: 'ExamineInfo', // 合同审核操作
+  components: {
+    ExamineHandle,
+    CheckFlow
+  },
+  filters: {
+    statusIcon: function (status) {
+      // 0失败,1通过,2撤回,3创建,4待审核
+      // JAVA 0 未审核 1 审核通过 2 审核拒绝 3 审核中 4 已撤回 5 创建 6 待提交
+      if (status === 2) {
+        return require('@/assets/img/check_fail.png')
+      } else if (status === 1) {
+        return require('@/assets/img/check_suc.png')
+      } else if (status === 4) {
+        return require('@/assets/img/check_revoke.png')
+      } else if (status === 3) {
+        return require('@/assets/img/check_create.png')
+      } else if (status === 0 || status === 6) {
+        return require('@/assets/img/check_wait.png')
+      } else if (status === 5) {
+        return require('@/assets/img/check_create.png')
+      }
+      return ''
+    },
+    detailName: function (data) {
+      if (data.stepType === 2) {
+        return data.userList.length + '人或签'
+      } else if (data.stepType === 3) {
+        return data.userList.length + '人会签'
+      } else if (data.stepType === 1) {
+        return '负责人主管'
+      } else if (data.stepType === 4) {
+        return '上一级审批人主管'
+      } else if (data.stepType === 5) {
+        return '创建人'
+      }
+    },
+    stepName: function (index) {
+      return '第' + Nzhcn.encodeS(index) + '级'
+    }
+  },
+  props: {
+    examineType: {
+      type: String,
+      default: ''
+    },
+    // 详情信息id
+    id: [String, Number],
+    // 审批流id
+    recordId: [String, Number],
+    ownerUserId: [String, Number]
+  },
+  data () {
+    return {
+      loading: false,
+      examineInfo: {}, // 审核信息
+      showFlowPopover: false,
+      examineHandleInfo: { status: 1 }, // 1 审核通过 2 审核拒绝 4 已撤回
+      showExamineHandle: false // 审核操作
+    }
+  },
+  computed: {},
+  watch: {
+    recordId: {
+      handler (val) {
+        if (val) {
+          this.examineInfo = {}
+          this.getFlowStepList()
+          if (this.$refs.checkFlow) {
+            this.$refs.checkFlow.getDetail()
+          }
+        }
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+  mounted () {},
+  methods: {
+    getFlowStepList () {
+      if (!this.recordId || !this.id) {
+        return
+      }
+      this.loading = true
+      // const request = {
+      //   crm_contract: crmExamineFlowStepList,
+      //   crm_receivables: crmExamineFlowStepList,
+      //   oa_examine: oaExamineFlowStepList
+      // }[this.examineType]
+
+      // request({
+      //   recordId: this.recordId,
+      //   ownerUserId: this.ownerUserId
+      // })
+      //   .then(res => {
+      //     this.loading = false
+      //     this.examineInfo = res.data
+      //     this.$emit('value-change', {
+      //       config: res.data.examineType, // 审批类型
+      //       value: [] // 审批信息
+      //     })
+      //   })
+      //   .catch(() => {
+      //     this.loading = false
+      //   })
+    },
+    // 撤回审核 通过 拒绝
+    examineHandle (status) {
+      this.examineHandleInfo.status = status
+      this.showExamineHandle = true
+    },
+    // 获取状态名称
+    getStatusName (status) {
+      if (status === 0) {
+        return '未审核'
+      } else if (status === 1) {
+        return '通过'
+      } else if (status === 2) {
+        return '拒绝'
+      } else if (status === 3) {
+        return '审核中'
+      } else if (status === 4) {
+        return '撤回'
+      } else if (status === 5) {
+        return '创建'
+      } else if (status === 6) {
+        return '待提交'
+      }
+      return ''
+    },
+    getContentFilters (array) {
+      var content = ''
+      for (let index = 0; index < array.length; index++) {
+        const item = array[index]
+        if (index === array.length - 1) {
+          content =
+            content + item.realname + ':' + this.getStatusName(item.checkType)
+        } else {
+          content =
+            content +
+            item.realname +
+            ':' +
+            this.getStatusName(item.checkType) +
+            '、'
+        }
+      }
+      return content
+    },
+    // 审批操作点击
+    examineHandleClick (data) {
+      this.getFlowStepList()
+      if (this.$refs.checkFlow) {
+        this.$refs.checkFlow.getDetail()
+      }
+      this.$emit('on-handle', data)
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+.contract-flow-box {
+  position: relative;
+  min-height: 100px;
+}
+.flow-button {
+  width: 75px;
+  height: 30px;
+  border-radius: 2px;
+  margin: 5px;
+  font-size: 13px;
+}
+.blue {
+  background-color: #4D88FF;
+  color: white;
+  border: none;
+}
+.red {
+  background-color: #ff6767;
+  color: white;
+  border: none;
+}
+.white {
+  background-color: white;
+  color: #777;
+}
+.check-flow-button {
+  font-size: 13px;
+  position: absolute;
+  left: 0;
+  top: 5px;
+}
+
+/** 审核流程 */
+.check-items {
+  overflow-x: auto;
+  padding: 10px 0;
+}
+
+.check-item {
+  width: auto;
+  flex-shrink: 0;
+  .check-item-user {
+    width: auto;
+    .check-item-img {
+      display: block;
+      width: 40px;
+      height: 40px;
+      border-radius: 20px;
+      margin-right: 8px;
+    }
+    .check-item-name {
+      color: #333;
+      font-size: 15px;
+      font-weight: 500;
+    }
+  }
+  .check-item-info {
+    width: auto;
+    margin-top: 5px;
+    .check-item-img {
+      display: block;
+      width: 16px;
+      height: 16px;
+      border-radius: 8px;
+      margin-right: 8px;
+    }
+    .check-item-name {
+      color: #aaa;
+      font-size: 12px;
+    }
+  }
+  .check-item-arrow {
+    color: #ccc;
+    margin: 0 16px;
+    font-size: 20px;
+    font-weight: 600;
+  }
+}
+
+// 固定审批信息
+.fixed-examine-item {
+  width: auto;
+  flex-shrink: 0;
+
+  .fixed-examine-info {
+    padding: 10px 20px;
+    text-align: center;
+    img {
+      width: 40px;
+      height: 40px;
+    }
+    .detail {
+      color: #777777;
+      font-size: 12px;
+      padding: 2px 0;
+      transform: scale(0.9, 0.9);
+    }
+    .check-item-info {
+      width: auto;
+      margin-top: 5px;
+      .check-item-img {
+        display: block;
+        width: 16px;
+        height: 16px;
+        border-radius: 8px;
+        margin-right: 8px;
+      }
+      .check-item-name {
+        color: #aaa;
+        font-size: 12px;
+      }
+    }
+  }
+
+  .check-item-arrow {
+    color: #ccc;
+    margin: 0 16px;
+    font-size: 20px;
+    font-weight: 600;
+  }
+}
+
+.popover-detail {
+  padding: 0 5px;
+}
+.popover-detail-item {
+  padding: 5px 0;
+  &-img {
+    display: block;
+    width: 16px;
+    height: 16px;
+    border-radius: 8px;
+    margin-right: 10px;
+  }
+  &-time {
+    color: #bababa;
+    font-size: 12px;
+  }
+  &-examine {
+    .examine-name {
+      color: #333;
+      margin-right: 10px;
+    }
+    .examine-info {
+      color: #666;
+    }
+  }
+}
+</style>
diff --git a/src/components/HelloWorld.vue b/src/components/HelloWorld.vue
new file mode 100644
index 0000000..1c19f2a
--- /dev/null
+++ b/src/components/HelloWorld.vue
@@ -0,0 +1,113 @@
+<template>
+  <div class="hello">
+    <h1>{{ msg }}</h1>
+    <h2>Essential Links</h2>
+    <ul>
+      <li>
+        <a
+          href="https://vuejs.org"
+          target="_blank"
+        >
+          Core Docs
+        </a>
+      </li>
+      <li>
+        <a
+          href="https://forum.vuejs.org"
+          target="_blank"
+        >
+          Forum
+        </a>
+      </li>
+      <li>
+        <a
+          href="https://chat.vuejs.org"
+          target="_blank"
+        >
+          Community Chat
+        </a>
+      </li>
+      <li>
+        <a
+          href="https://twitter.com/vuejs"
+          target="_blank"
+        >
+          Twitter
+        </a>
+      </li>
+      <br>
+      <li>
+        <a
+          href="http://vuejs-templates.github.io/webpack/"
+          target="_blank"
+        >
+          Docs for This Template
+        </a>
+      </li>
+    </ul>
+    <h2>Ecosystem</h2>
+    <ul>
+      <li>
+        <a
+          href="http://router.vuejs.org/"
+          target="_blank"
+        >
+          vue-router
+        </a>
+      </li>
+      <li>
+        <a
+          href="http://vuex.vuejs.org/"
+          target="_blank"
+        >
+          vuex
+        </a>
+      </li>
+      <li>
+        <a
+          href="http://vue-loader.vuejs.org/"
+          target="_blank"
+        >
+          vue-loader
+        </a>
+      </li>
+      <li>
+        <a
+          href="https://github.com/vuejs/awesome-vue"
+          target="_blank"
+        >
+          awesome-vue
+        </a>
+      </li>
+    </ul>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'HelloWorld',
+  data () {
+    return {
+      msg: 'Welcome to Your Vue.js App'
+    }
+  }
+}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+h1, h2 {
+  font-weight: normal;
+}
+ul {
+  list-style-type: none;
+  padding: 0;
+}
+li {
+  display: inline-block;
+  margin: 0 10px;
+}
+a {
+  color: #42b983;
+}
+</style>
diff --git a/src/components/MapView.vue b/src/components/MapView.vue
new file mode 100644
index 0000000..7b0a91e
--- /dev/null
+++ b/src/components/MapView.vue
@@ -0,0 +1,93 @@
+<template>
+  <div class="map-view">
+    <div id="choicemap"/>
+    <i
+      class="el-icon-close map-close"
+      @click="hiddenView"/>
+  </div>
+</template>
+
+<script type="text/javascript">
+import { getMaxIndex } from '@/utils/index'
+export default {
+  name: 'MapView', // 地图详情
+  components: {},
+  props: {
+    /**
+     * title 内容
+     * lat lng 经纬度
+     */
+    title: {
+      type: String,
+      default: ''
+    },
+    lat: {
+      type: Number,
+      default: 0
+    },
+    lng: {
+      type: Number,
+      default: 0
+    }
+  },
+  data () {
+    return {}
+  },
+  computed: {},
+  mounted () {
+    this.$el.style.zIndex = getMaxIndex()
+    document.body.appendChild(this.$el)
+
+    let map = new BMap.Map('choicemap', { enableMapClick: false })
+    let point = new BMap.Point(this.lng, this.lat)
+    map.centerAndZoom(point, 18)
+    map.enableScrollWheelZoom()
+
+    let marker = new BMap.Marker(point) // 创建标注
+    map.addOverlay(marker) // 将标注添加到地图中
+    let infoWindow = new BMap.InfoWindow(this.title) // 创建信息窗口对象
+    marker.addEventListener('click', function () {
+      map.openInfoWindow(infoWindow, point) // 开启信息窗口
+    })
+  },
+  destroyed () {
+    // remove DOM node after destroy
+    if (this.$el && this.$el.parentNode) {
+      this.$el.parentNode.removeChild(this.$el)
+    }
+  },
+  methods: {
+    hiddenView () {
+      this.$emit('hidden')
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+.map-view {
+  position: fixed;
+  width: 100%;
+  height: 100%;
+  top: 0;
+  left: 0;
+  background-color: #000;
+}
+
+.map-close {
+  position: absolute;
+  right: 10px;
+  top: 10px;
+  font-size: 28px;
+  color: #fff;
+  cursor: pointer;
+}
+
+#choicemap {
+  position: absolute;
+  left: 100px;
+  top: 100px;
+  bottom: 100px;
+  right: 100px;
+  overflow: hidden;
+}
+</style>
diff --git a/src/components/SlideView.vue b/src/components/SlideView.vue
new file mode 100644
index 0000000..c850f25
--- /dev/null
+++ b/src/components/SlideView.vue
@@ -0,0 +1,129 @@
+<template>
+  <transition
+    name="slide-fade"
+    @after-enter="afterEnter">
+      <el-card
+        id="slide"
+        ref="slide"
+        :style="{ 'z-index': zIndex }"
+        :body-style="bodyStyle"
+        class="slide-detail-card-container">
+        <slot/>
+      </el-card>
+  </transition>
+</template>
+<script type="text/javascript">
+import { getMaxIndex } from '@/utils/index'
+
+export default {
+  name: 'SlideView', // 客户管理详情 滑动view
+  components: {},
+  props: {
+    bodyStyle: {
+      type: Object,
+      default: () => {
+        return { padding: 0 }
+      }
+    },
+    /** 监听点击事件 隐藏视图 */
+    listenerIDs: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    /** 阻挡点击事件 隐藏视图 */
+    noListenerIDs: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    noListenerClass: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    appendToBody: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    return {
+      zIndex: getMaxIndex()
+    }
+  },
+  computed: {},
+  watch: {},
+  mounted () {
+    if (this.appendToBody) {
+      document.body.appendChild(this.$el)
+    }
+    this.listenerIDs.forEach(element => {
+      if (document.getElementById(element)) {
+        document
+          .getElementById(element)
+          .addEventListener('click', this.handleDocumentClick, false)
+      }
+    })
+  },
+
+  beforeDestroy () {
+    if (this.appendToBody && this.$el && this.$el.parentNode) {
+      this.$el.parentNode.removeChild(this.$el)
+    }
+  },
+  methods: {
+    handleDocumentClick (e) {
+      var hidden = true
+      this.noListenerIDs.forEach(element => {
+        if (
+          document.getElementById(element) &&
+          document.getElementById(element).contains(e.target)
+        ) {
+          hidden = false
+        }
+      })
+
+      this.noListenerClass.forEach(element => {
+        var items = document.getElementsByClassName(element)
+        if (items && hidden) {
+          for (let index = 0; index < items.length; index++) {
+            const element = items[index]
+            if (element.contains(e.target)) {
+              hidden = false
+              break
+            }
+          }
+        }
+      })
+
+      if (
+        document.getElementById('slide') &&
+        document.getElementById('slide').contains(e.target)
+      ) {
+        hidden = false
+      }
+      if (hidden) {
+        this.$emit('side-close')
+      }
+    },
+    afterEnter () {
+      this.$emit('afterEnter')
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+// .slide-fade-enter-active,
+// .slide-fade-leave-active {
+//   will-change: transform;
+//   transition: all 0.35s ease;
+// }
+// .slide-fade-enter,
+// .slide-fade-leave-to {
+//   transform: translateX(100%);
+// }
+</style>
diff --git a/src/components/common/SIdentify.vue b/src/components/common/SIdentify.vue
new file mode 100644
index 0000000..4020cdc
--- /dev/null
+++ b/src/components/common/SIdentify.vue
@@ -0,0 +1,164 @@
+<template>
+  <div class="s-canvas">
+    <canvas
+      id="s-canvas"
+      :width="contentWidth"
+      :height="contentHeight"
+    />
+  </div>
+</template>
+<script>
+export default {
+  name: 'SIdentify',
+  props: {
+    identifyCode: {
+      type: String,
+      default: '1234'
+    },
+    fontSizeMin: {
+      type: Number,
+      default: 25
+    },
+    fontSizeMax: {
+      type: Number,
+      default: 30
+    },
+    backgroundColorMin: {
+      type: Number,
+      default: 255
+    },
+    backgroundColorMax: {
+      type: Number,
+      default: 255
+    },
+    colorMin: {
+      type: Number,
+      default: 0
+    },
+    colorMax: {
+      type: Number,
+      default: 160
+    },
+    lineColorMin: {
+      type: Number,
+      default: 100
+    },
+    lineColorMax: {
+      type: Number,
+      default: 255
+    },
+    dotColorMin: {
+      type: Number,
+      default: 0
+    },
+    dotColorMax: {
+      type: Number,
+      default: 255
+    },
+    contentWidth: {
+      type: Number,
+      default: 112
+    },
+    contentHeight: {
+      type: Number,
+      default: 31
+    }
+  },
+  watch: {
+    identifyCode () {
+      this.drawPic()
+    }
+  },
+  mounted () {
+    this.drawPic()
+  },
+  methods: {
+    // 生成一个随机数
+    randomNum (min, max) {
+      return Math.floor(Math.random() * (max - min) + min)
+    },
+    // 生成一个随机的颜色
+    randomColor (min, max) {
+      const r = this.randomNum(min, max)
+      const g = this.randomNum(min, max)
+      const b = this.randomNum(min, max)
+      return 'rgb(' + r + ',' + g + ',' + b + ')'
+    },
+    drawPic () {
+      const canvas = document.getElementById('s-canvas')
+      const ctx = canvas.getContext('2d')
+      ctx.textBaseline = 'bottom'
+      // 绘制背景
+      ctx.fillStyle = this.randomColor(
+        this.backgroundColorMin,
+        this.backgroundColorMax
+      )
+      ctx.fillRect(0, 0, this.contentWidth, this.contentHeight)
+      // 绘制文字
+      for (let i = 0; i < this.identifyCode.length; i++) {
+        this.drawText(ctx, this.identifyCode[i], i)
+      }
+      this.drawLine(ctx)
+      this.drawDot(ctx)
+    },
+    drawText (ctx, txt, i) {
+      ctx.fillStyle = this.randomColor(this.colorMin, this.colorMax)
+      ctx.font =
+        this.randomNum(this.fontSizeMin, this.fontSizeMax) + 'px SimHei'
+      const x = (i + 1) * (this.contentWidth / (this.identifyCode.length + 1))
+      const y = this.randomNum(this.fontSizeMax, this.contentHeight - 5)
+      var deg = this.randomNum(-45, 45)
+      // 修改坐标原点和旋转角度
+      ctx.translate(x, y)
+      ctx.rotate((deg * Math.PI) / 180)
+      ctx.fillText(txt, 0, 0)
+      // 恢复坐标原点和旋转角度
+      ctx.rotate((-deg * Math.PI) / 180)
+      ctx.translate(-x, -y)
+    },
+    drawLine (ctx) {
+      // 绘制干扰线
+      for (let i = 0; i < 5; i++) {
+        ctx.strokeStyle = this.randomColor(
+          this.lineColorMin,
+          this.lineColorMax
+        )
+        ctx.beginPath()
+        ctx.moveTo(
+          this.randomNum(0, this.contentWidth),
+          this.randomNum(0, this.contentHeight)
+        )
+        ctx.lineTo(
+          this.randomNum(0, this.contentWidth),
+          this.randomNum(0, this.contentHeight)
+        )
+        ctx.stroke()
+      }
+    },
+    drawDot (ctx) {
+      // 绘制干扰点
+      for (let i = 0; i < 80; i++) {
+        ctx.fillStyle = this.randomColor(0, 255)
+        ctx.beginPath()
+        ctx.arc(
+          this.randomNum(0, this.contentWidth),
+          this.randomNum(0, this.contentHeight),
+          1,
+          0,
+          2 * Math.PI
+        )
+        ctx.fill()
+      }
+    }
+  }
+}
+</script>
+<style scoped>
+.s-canvas {
+  height: 38px;
+}
+.s-canvas canvas {
+  margin-top: 1px;
+  margin-left: 8px;
+}
+</style>
diff --git a/src/components/emoji.vue b/src/components/emoji.vue
new file mode 100644
index 0000000..ecd146e
--- /dev/null
+++ b/src/components/emoji.vue
@@ -0,0 +1,130 @@
+<template>
+  <div class="emoji">
+    <ul class="emoji-controller">
+      <li
+        v-for="(pannel,index) in pannels"
+        :key="index"
+        :class="{'active': index === activeIndex}"
+        @click="changeActive(index)">
+        {{ pannel }}
+      </li>
+    </ul>
+    <ul class="emoji-container">
+      <li
+        v-for="(emojiGroup, index) in emojis"
+        v-if="index === activeIndex"
+        :key="index"
+        style="padding: 0">
+        {{ emojiGroup }}--{{ index }}
+        <a
+          v-for="(emoji, index) in emojiGroup"
+          :key="index"
+          href="javascript:;"
+          @click="selectItem(emoji)">
+          <span
+            :title="emoji"
+            :class="'sprite-' + getPureName(emoji)"
+            class="emoji-item"/>
+        </a>
+      </li>
+    </ul>
+  </div>
+</template>
+<script>
+import data from '@/utils/emoji-data.js'
+export default {
+  name: 'Emoji',
+  data () {
+    return {
+      emojiData: data,
+      pannels: ['表情', '自然', '物品', '地点', '符号'],
+      activeIndex: 0
+    }
+  },
+  computed: {
+    emojis () {
+      return this.pannels.map(item => {
+        return Object.keys(this.emojiData[item])
+      })
+    }
+  },
+  created () {
+  },
+  methods: {
+    changeActive (index) {
+      this.activeIndex = index
+    },
+    getPureName (name) {
+      return name.replace(/:/g, '')
+    },
+    selectItem (emoji) {
+      this.$emit('select', emoji)
+    }
+  }
+}
+</script>
+
+<style lang='scss' scoped>
+@import '@/styles/emoji-sprite.scss';
+.emoji {
+  //   width: 420px;
+  //       box-shadow: 0 0 24px rgba(0,0,0,.18);
+  // //   height: 186px;
+  //   bottom: 30px;
+  //   background: #fff;
+  //   z-index: 10;
+  //   padding: 10px;
+  //   margin-right: 10px;
+  .emoji-controller {
+    height: 36px;
+    overflow: hidden;
+    margin-bottom: 0;
+    li {
+      float: left;
+      width: 76px;
+      font-size: 12px;
+      line-height: 36px;
+      cursor: pointer;
+      text-align: center;
+      position: relative;
+      &.active::after {
+        content: '';
+        width: 100%;
+        height: 1px;
+        background: #0689dd;
+        left: 0;
+        bottom: 4px;
+        position: absolute;
+      }
+    }
+  }
+  .emoji-container {
+    height: 175px;
+    overflow-y: auto;
+    overflow-x: hidden;
+    position: relative;
+    li {
+      font-size: 0;
+      padding: 5px;
+      a {
+        float: left;
+        overflow: hidden;
+        height: 35px;
+        transition: all ease-out 0.2s;
+        border-radius: 4px;
+        &:hover {
+          background-color: #d8d8d8;
+          border-color: #d8d8d8;
+        }
+        span {
+          width: 25px;
+          height: 25px;
+          display: inline-block;
+          border: 1px solid transparent;
+          cursor: pointer;
+        }
+      }
+    }
+  }
+}
+</style>
diff --git a/src/components/flexbox/flexbox-item.vue b/src/components/flexbox/flexbox-item.vue
new file mode 100644
index 0000000..bbf0d6a
--- /dev/null
+++ b/src/components/flexbox/flexbox-item.vue
@@ -0,0 +1,62 @@
+<template>
+  <div
+    :style="style"
+    class="vux-flexbox-item">
+    <slot/>
+  </div>
+</template>
+
+<script>
+const prefixList = ['-moz-box-', '-webkit-box-', '']
+
+export default {
+  name: 'FlexboxItem',
+  props: {
+    span: [Number, String],
+    order: [Number, String]
+  },
+  data () {
+    return {
+      bodyWidth: 0
+    }
+  },
+  computed: {
+    style () {
+      const styles = {}
+      const marginName =
+        this.$parent.orient === 'horizontal' ? 'marginLeft' : 'marginTop'
+
+      if (this.$parent.gutter * 1 !== 0) {
+        styles[marginName] = `${this.$parent.gutter}px`
+      }
+
+      if (this.span) {
+        for (let i = 0; i < prefixList.length; i++) {
+          styles[`${prefixList[i]}flex`] = `0 0 ${this.buildWidth(this.span) *
+            100}%`
+        }
+      }
+      if (typeof this.order !== 'undefined') {
+        styles.order = this.order
+      }
+      return styles
+    }
+  },
+  beforeMount () {
+    this.bodyWidth = document.documentElement.offsetWidth
+  },
+  methods: {
+    buildWidth (width) {
+      if (typeof width === 'number') {
+        if (width < 1) {
+          return width
+        } else {
+          return width / 12
+        }
+      } else if (typeof width === 'string') {
+        return width.replace('px', '') / this.bodyWidth
+      }
+    }
+  }
+}
+</script>
diff --git a/src/components/flexbox/flexbox.vue b/src/components/flexbox/flexbox.vue
new file mode 100644
index 0000000..f003b73
--- /dev/null
+++ b/src/components/flexbox/flexbox.vue
@@ -0,0 +1,81 @@
+<template>
+  <div
+    :class="{
+      'vux-flex-col': orient === 'vertical',
+      'vux-flex-row': orient === 'horizontal'
+    }"
+    :style="styles"
+    class="vux-flexbox">
+    <slot/>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'Flexbox',
+  props: {
+    gutter: {
+      type: Number,
+      default: 8
+    },
+    orient: {
+      type: String,
+      default: 'horizontal'
+    },
+    justify: String,
+    align: String,
+    wrap: String,
+    direction: String
+  },
+  computed: {
+    styles () {
+      const styles = {
+        'justify-content': this.justify,
+        '-webkit-justify-content': this.justify,
+        'align-items': this.align,
+        '-webkit-align-items': this.align,
+        'flex-wrap': this.wrap,
+        '-webkit-flex-wrap': this.wrap,
+        'flex-direction': this.direction,
+        '-webkit-flex-direction': this.direction
+      }
+      return styles
+    }
+  }
+}
+</script>
+
+<style lang="less">
+.vux-flexbox {
+  width: 100%;
+  text-align: left;
+  display: flex;
+  display: -webkit-flex;
+  box-align: center;
+  align-items: center;
+  .vux-flexbox-item {
+    flex: 1;
+    -webkit-flex: 1;
+    min-width: 20px;
+    width: 0%;
+    &:first-child {
+      margin-left: 0 !important;
+      margin-top: 0 !important;
+    }
+  }
+}
+
+.vux-flex-row {
+  box-direction: row;
+  box-orient: horizontal;
+  flex-direction: row;
+}
+
+.vux-flex-col {
+  box-orient: vertical;
+  flex-direction: column;
+  > .vux-flexbox-item {
+    width: 100%;
+  }
+}
+</style>
diff --git a/src/components/flexbox/index.js b/src/components/flexbox/index.js
new file mode 100644
index 0000000..69944ba
--- /dev/null
+++ b/src/components/flexbox/index.js
@@ -0,0 +1,7 @@
+import Flexbox from './flexbox'
+import FlexboxItem from './flexbox-item'
+
+export {
+  Flexbox,
+  FlexboxItem
+}
diff --git a/src/components/relatedBusiness.vue b/src/components/relatedBusiness.vue
new file mode 100644
index 0000000..3e15da2
--- /dev/null
+++ b/src/components/relatedBusiness.vue
@@ -0,0 +1,240 @@
+<template>
+  <div
+    :style="{'margin-left': marginLeft}"
+    class="related-business">
+    <!-- 新建- 关联业务 -->
+    <el-popover
+      v-if="!isTask && alterable"
+      v-model="showPopover"
+      placement="bottom"
+      width="800"
+      popper-class="no-padding-popover"
+      trigger="click">
+      <crm-relative
+        v-if="showRelative"
+        ref="crmrelative"
+        :show="showPopover"
+        :radio="false"
+        :selected-data="relatedListData"
+        :show-types="showTypes"
+        @close="crmrelativeClose"
+        @changeCheckout="checkInfos"/>
+      <p
+        v-if="showCRMPermission"
+        slot="reference"
+        class="add-file"
+        @click="showRelative = true">
+        <img
+          src="@/assets/img/relevance_business.png"
+          alt="">
+        关联业务
+      </p>
+    </el-popover>
+    <p
+      v-if="!alterable"
+      :style="{color: alterableColor}"
+      class="alterable-p">关联业务</p>
+    <div
+      v-for="(items, key) in relatedListData"
+      :key="key">
+      <related-business-cell
+        v-for="(item, itemIndex) in items"
+        :data="item"
+        :cell-index="itemIndex"
+        :type="key"
+        :key="itemIndex"
+        :show-foot="isTask"
+        @unbind="delRelevance"
+        @detail="checkRelatedDetail(key, item)"/>
+    </div>
+    <!-- 任务页面显示格式 -->
+    <el-popover
+      v-if="isTask"
+      v-model="showPopover"
+      placement="bottom"
+      width="800"
+      popper-class="no-padding-popover"
+      trigger="click">
+      <crm-relative
+        v-if="showTaskRelative"
+        ref="crmrelative"
+        :radio="false"
+        :show="showPopover"
+        :selected-data="relatedListData"
+        :show-types="showTypes"
+        @close="crmrelativeClose"
+        @changeCheckout="checkInfos"/>
+      <p
+        v-if="showCRMPermission"
+        slot="reference"
+        class="add-file"
+        @click="showTaskRelative = true">
+        <img
+          src="@/assets/img/relevance_business.png"
+          alt="">
+        关联业务
+      </p>
+    </el-popover>
+  </div>
+</template>
+
+<script>
+// 关联业务 - 弹出框
+// import { editTaskRelation } from '@/api/oamanagement/task'
+import CrmRelative from '@/components/CreateCom/CrmRelative'
+import RelatedBusinessCell from '@/views/OAManagement/components/relatedBusinessCell'
+import { objDeepCopy } from '@/utils'
+import { mapGetters } from 'vuex'
+
+export default {
+  components: {
+    CrmRelative,
+    RelatedBusinessCell
+  },
+  props: {
+    marginLeft: {
+      type: String,
+      default: '20px'
+    },
+    // 编辑时传递所有关联数据   关联联系人-contacts 关联客户-customer 商机-business 合同-contract
+    allData: {
+      type: Object,
+      default: () => {
+        return {
+          contacts: [],
+          customer: [],
+          business: [],
+          contract: []
+        }
+      }
+    },
+    // 是否是任务页面
+    isTask: {
+      type: Boolean,
+      default: false
+    },
+    taskID: Number,
+    alterable: {
+      type: Boolean,
+      default: true
+    },
+    alterableColor: {
+      type: String,
+      default: '#999'
+    }
+  },
+  data () {
+    return {
+      showTypes: ['customer', 'contacts', 'business', 'contract'],
+      showPopover: false,
+      relevanceAll: {
+        customerIds: [],
+        contractIds: [],
+        contactsIds: [],
+        businessIds: []
+      },
+      // 关联业务信息
+      relatedListData: {},
+      showRelative: false,
+      // 展示任务相关
+      showTaskRelative: false
+    }
+  },
+  computed: {
+    ...mapGetters(['crm']),
+    showCRMPermission () {
+      return this.crm
+    }
+  },
+  watch: {
+    allData: function () {
+      this.relatedListData = this.allData
+    }
+  },
+  mounted () {
+    // 编辑时勾选
+    this.relatedListData = this.allData
+  },
+  methods: {
+    crmrelativeClose () {
+      this.showPopover = false
+    },
+    checkInfos (val) {
+      this.showPopover = false
+      this.relatedListData = val.data
+      for (const key in val.data) {
+        const list = val.data[key]
+        this.relevanceAll[key + 'Ids'] = list.map(function (
+          item,
+          index,
+          array
+        ) {
+          return item[key + 'Id']
+        })
+      }
+      this.$emit('checkInfos', this.relevanceAll)
+    },
+    // 任务页面取消关联
+    delRelevance (field, index, item) {
+      this.$confirm('确认取消关联?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+        customClass: 'is-particulars'
+      })
+        .then(() => {
+          const params = { taskId: this.taskID }
+          const tempRelatedListData = objDeepCopy(this.relatedListData)
+          tempRelatedListData[field].splice(index, 1)
+          for (let index = 0; index < this.showTypes.length; index++) {
+            const typeItem = this.showTypes[index]
+            const typeArray = tempRelatedListData[typeItem] || []
+            params[typeItem + 'Ids'] = typeArray
+              .map(aItem => {
+                return aItem[typeItem + 'Id']
+              })
+              .join(',')
+          }
+          // editTaskRelation(params)
+          //   .then(res => {
+          //     this.relatedListData[field].splice(index, 1)
+          //     this.relatedListData = objDeepCopy(this.relatedListData)
+          //     this.$message.success('关联取消成功')
+          //   })
+          //   .catch(() => {})
+        })
+        .catch(() => {
+          this.$message.info('已取消操作')
+        })
+    },
+    checkRelatedDetail (field, val) {
+      val.key = val[field + 'Id']
+      this.$emit('checkRelatedDetail', field, val)
+    }
+  }
+}
+</script>
+
+<style scoped lang="less">
+.related-business {
+  color: #777;
+  font-size: 12px;
+  margin: 10px 0;
+  .alterable-p {
+    padding-bottom: 10px;
+    font-size: 13px;
+  }
+  .add-file {
+    margin: 10px 0;
+    font-size: 13px;
+    color: #4D88FF;
+    cursor: pointer;
+    display: inline-block;
+    img {
+      vertical-align: middle;
+      width: 15px;
+      margin-right: 5px;
+    }
+  }
+}
+</style>
diff --git a/src/components/reminder.vue b/src/components/reminder.vue
new file mode 100644
index 0000000..4b38868
--- /dev/null
+++ b/src/components/reminder.vue
@@ -0,0 +1,60 @@
+<template>
+  <flexbox class="reminder-wrapper">
+    <flexbox
+      align="stretch"
+      class="reminder-body">
+      <i class="wukong wukong-reminder reminder-icon"/>
+      <div
+        :style="{'font-size': fontSize + 'px'}"
+        class="reminder-content">
+        {{ content }}
+      </div>
+    </flexbox>
+  </flexbox>
+</template>
+
+<script type="text/javascript">
+// 警示信息
+
+export default {
+  name: 'Reminder',
+  components: {},
+  props: {
+    content: {
+      type: String,
+      default: '内容'
+    },
+    fontSize: {
+      type: String,
+      default: '13'
+    }
+  },
+  data () {
+    return {}
+  },
+  computed: {},
+  mounted () {},
+  destroyed () {},
+  methods: {}
+}
+</script>
+<style lang="less" scoped>
+.reminder-wrapper {
+  .reminder-body {
+    width: auto;
+    padding: 8px 15px;
+    border-radius: 4px;
+    background-color: #fff4e7;
+    .reminder-icon {
+      color: #ff7922;
+      flex-shrink: 0;
+      margin-right: 8px;
+    }
+
+    .reminder-content {
+      color: #9c9c9b;
+      line-height: 17px;
+    }
+  }
+}
+</style>
diff --git a/src/components/selectEmployee/membersDep.vue b/src/components/selectEmployee/membersDep.vue
new file mode 100644
index 0000000..4d17a52
--- /dev/null
+++ b/src/components/selectEmployee/membersDep.vue
@@ -0,0 +1,622 @@
+<template>
+  <el-popover
+    ref="popover"
+    :placement="placement"
+    :width="popoverWidth"
+    v-model="popoverVisible"
+    popper-class="project-com-popover"
+    trigger="click">
+    <div v-if="popoverContentShow">
+      <div class="title-icon">
+        <span>{{ title }}</span>
+        <span
+          class="el-icon-close rt"
+          @click="popoverVisible = false"/>
+      </div>
+      <div class="popover-content-box">
+        <div class="select-input">
+          <!-- 搜索员工列表 -->
+          <el-tabs
+            v-model="activeTabName"
+            :stretch="true"
+            @tab-click="tabClick">
+            <el-tab-pane
+              v-loading="userLoading"
+              v-if="!closeUser"
+              label="员工"
+              name="user">
+              <el-input
+                v-model="searchUserInput"
+                placeholder="搜索员工"
+                size="mini"
+                prefix-icon="el-icon-search"
+                @input="userSearchChange"/>
+              <div class="search-list">
+                <div
+                  v-for="(user, index) in userList"
+                  v-if="!user.hidden"
+                  :key="index"
+                  class="colleagues-list">
+                  <el-checkbox
+                    v-model="user.isCheck"
+                    @change="userCheckboxChange(user, index)">
+                    <div
+                      v-photo="user"
+                      v-lazy:background-image="$options.filters.filterUserLazyImg(user.img)"
+                      class="div-photo search-img header-circle"/>
+                    <span>{{ user.realname }}</span>
+                  </el-checkbox>
+                </div>
+              </div>
+            </el-tab-pane>
+            <el-tab-pane
+              v-loading="depLoading"
+              v-if="!closeDep"
+              label="部门"
+              name="dep">
+              <el-input
+                v-model="searchDepInput"
+                placeholder="搜索部门"
+                size="mini"
+                style="margin-bottom:10px;"
+                prefix-icon="el-icon-search"
+                @input="depSearchChange"/>
+              <div class="search-list">
+                <el-breadcrumb separator-class="el-icon-arrow-right">
+                  <el-breadcrumb-item
+                    v-for="(item, index) in breadcrumbList"
+                    :key="index">
+                    <a
+                      href="javascript:;"
+                      @click="breadcrumbBtn(item, index)">{{ item.label }}</a>
+                  </el-breadcrumb-item>
+                </el-breadcrumb>
+                <div
+                  v-for="(depItem, index) in depShowList"
+                  v-if="!depItem.hidden"
+                  :key="index"
+                  class="checkout-box">
+                  <el-checkbox
+                    v-model="depItem.isCheck"
+                    @change="depCheckboxChange(depItem, index)"/>
+                  <div @click="enterDepChildren(depItem)">
+                    <span>{{ depItem.name }}</span>
+                    <span
+                      v-if="depItem.children"
+                      class="el-icon-arrow-right"/>
+                  </div>
+                </div>
+              </div>
+            </el-tab-pane>
+          </el-tabs>
+        </div>
+        <div class="checked-content">
+          <div class="checked-top">
+            <span class="title">已选择</span>
+            <span
+              v-if="!closeUser"
+              class="title">员工 ({{ userSelectCount }})</span>
+            <span
+              v-if="!closeDep"
+              class="title">部门 ({{ depSelectCount }})</span>
+            <el-button
+              type="text"
+              class="rt"
+              @click="emptyClick">清空</el-button>
+          </div>
+          <div class="border-content">
+            <div
+              v-for="(item, index) in checkedUserDepList"
+              :key="index"
+              class="checked-list">
+              <div
+                v-photo="item"
+                v-lazy:background-image="$options.filters.filterUserLazyImg(item.img)"
+                v-if="item.type === 'user'"
+                class="div-photo"/>
+              <span v-if="item.type === 'user'"> {{ item.realname }} </span>
+              <span v-else> {{ item.name }} </span>
+              <span
+                class="rt el-icon-close"
+                @click="selectDelect(item, index)"/>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="popover-footer">
+        <el-button
+          type="primary"
+          @click="popoverSubmit">确 定</el-button>
+        <el-button @click="popoverVisible = false">取 消</el-button>
+      </div>
+    </div>
+    <div
+      slot="reference"
+      :style="{'display':contentBlock ? 'block' : 'inline-block'}"
+      @click="showContentClick">
+      <slot name="membersDep"/>
+    </div>
+  </el-popover>
+
+</template>
+<script>
+// import { usersList, depList } from '@/api/common'
+export default {
+  props: {
+    // 弹出框宽度
+    popoverWidth: {
+      type: String,
+      default: '600'
+    },
+    // 标题
+    title: {
+      type: String,
+      default: '选择成员'
+    },
+    // 显示位置
+    placement: {
+      type: String,
+      default: 'bottom-start'
+    },
+    // 内容框类型
+    contentBlock: {
+      type: Boolean,
+      default: true
+    },
+    // 编辑时 -- 用户默认勾选的数据
+    userCheckedData: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    // 编辑时 -- 部门默认勾选的数据
+    depCheckedData: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    // 是否关闭某个类的选择
+    closeUser: {
+      type: Boolean,
+      default: false
+    },
+    closeDep: {
+      type: Boolean,
+      default: false
+    },
+    userRequest: Function,
+    userParams: Object
+  },
+  data () {
+    return {
+      activeTabName: 'user',
+      // 筛选
+      searchUserInput: '',
+      searchDepInput: '',
+      popoverVisible: false,
+      // 内容展示
+      popoverContentShow: false,
+      // 加载动画
+      userLoading: false,
+      depLoading: false,
+      // 所有用户
+      userList: [],
+      // 展示客户
+      depShowList: [],
+      // 面包屑数据
+      breadcrumbList: [],
+      // 选中的数据 -- 员工和部门一个数组用于页面展示
+      checkedUserDepList: []
+    }
+  },
+  computed: {
+    userSelectCount () {
+      return this.checkedUserDepList.filter(item => {
+        return item.type === 'user'
+      }).length
+    },
+    depSelectCount () {
+      return this.checkedUserDepList.filter(item => {
+        return item.type === 'dep'
+      }).length
+    }
+  },
+  watch: {
+    userCheckedData: function () {
+      this.updateCheckInfoByWatch()
+    },
+    depCheckedData: function () {
+      this.updateCheckInfoByWatch()
+    },
+    popoverVisible: function (val) {
+      if (val) {
+        this.updateCheckInfoByWatch()
+      }
+    }
+  },
+  methods: {
+    initInfo () {
+      // 用户列表
+      this.checkedUserDepList = this.userCheckedData
+        .map(item => {
+          item.type = 'user'
+          return item
+        })
+        .concat(
+          this.depCheckedData.map(item => {
+            item.type = 'dep'
+            return item
+          })
+        )
+
+      if (!this.closeUser) {
+        this.getUserList()
+      } else if (!this.closeDep) {
+        this.activeTabName = 'dep'
+        this.getDepList()
+      }
+    },
+    tabClick () {
+      if (this.activeTabName === 'dep') {
+        if (this.depShowList.length === 0) {
+          this.getDepList()
+        }
+      }
+    },
+    userSearchChange (val) {
+      this.userList = this.userList.map(item => {
+        if (item.realname.indexOf(val) !== -1) {
+          item.hidden = false
+        } else {
+          item.hidden = true
+        }
+        return item
+      })
+    },
+    depSearchChange (val) {
+      this.depShowList = this.depShowList.map(item => {
+        if (item.name.indexOf(val) !== -1) {
+          item.hidden = false
+        } else {
+          item.hidden = true
+        }
+        return item
+      })
+    },
+    /**
+     * 部门信息
+     */
+    // 部门列表数据
+    getDepList () {
+      this.depLoading = true
+      // depList({ type: 'tree' })
+      //   .then(res => {
+      //     this.depShowList = res.data.map((item, index, array) => {
+      //       item.type = 'dep'
+      //       item.isCheck = this.getItemCheckInfo(item, 'dep')
+      //       return item
+      //     })
+      //     this.breadcrumbList.push({ label: '全部', data: this.depShowList })
+      //     this.depLoading = false
+      //   })
+      //   .catch(() => {
+      //     this.depLoading = false
+      //   })
+    },
+    // 部门下一级
+    enterDepChildren (depItem) {
+      if (depItem.children) {
+        this.depShowList = []
+        this.depShowList = depItem.children.map((item, index, array) => {
+          item.type = 'dep'
+          if (item.name.indexOf(this.searchDepInput) !== -1) {
+            item.hidden = false
+          } else {
+            item.hidden = true
+          }
+          item.isCheck = this.getItemCheckInfo(item, 'dep')
+          return item
+        })
+        this.breadcrumbList.push({
+          label: depItem.label,
+          data: this.depShowList
+        })
+      }
+    },
+    // 面包屑点击事件
+    breadcrumbBtn (item, index) {
+      if (index + 1 <= this.breadcrumbList.length - 1) {
+        this.breadcrumbList.splice(index + 1, this.breadcrumbList.length - 1)
+      }
+      this.depShowList = []
+      this.depShowList = item.data.map((item, index, array) => {
+        if (item.name.indexOf(this.searchDepInput) !== -1) {
+          item.hidden = false
+        } else {
+          item.hidden = true
+        }
+        item.isCheck = this.getItemCheckInfo(item, 'dep')
+        return item
+      })
+    },
+    // 部门勾选
+    depCheckboxChange (item, aindex) {
+      this.$set(this.depShowList, aindex, item)
+      this.updateCheckedUserDepListByCheck(item, 'dep')
+    },
+    /**
+     * 员工操作
+     */
+    getUserList () {
+      this.userLoading = true
+      // let request = usersList
+      // let params = {}
+      if (this.userRequest) {
+        // request = this.userRequest
+        // params = this.userParams || {}
+      } else {
+        // params = { pageType: 0 }
+      }
+      // request(params)
+      //   .then(res => {
+      //     this.userList = res.data.map(item => {
+      //       item.type = 'user'
+      //       item.isCheck = this.getItemCheckInfo(item, 'user')
+      //       return item
+      //     })
+      //     this.userLoading = false
+      //   })
+      //   .catch(() => {
+      //     this.userLoading = false
+      //   })
+    },
+    // 员工勾选
+    userCheckboxChange (item, aindex) {
+      this.$set(this.userList, aindex, item)
+      this.updateCheckedUserDepListByCheck(item, 'user')
+    },
+    // check 操作后的 存储数据刷新
+    updateCheckedUserDepListByCheck (item, type) {
+      var removeIndex = -1
+      for (let index = 0; index < this.checkedUserDepList.length; index++) {
+        const element = this.checkedUserDepList[index]
+        if (element.type === 'user' && item.userId === element.userId) {
+          removeIndex = index
+        } else if (element.type === 'dep' && item.id === element.id) {
+          removeIndex = index
+        }
+      }
+      if (removeIndex === -1) {
+        this.checkedUserDepList.push(item)
+      } else if (removeIndex !== -1) {
+        this.checkedUserDepList.splice(removeIndex, 1)
+      }
+    },
+    // 获取事项标记信息
+    getItemCheckInfo (item, type) {
+      if (this.checkedUserDepList.length === 0) {
+        return false
+      }
+      var hasItem = false
+      for (let index = 0; index < this.checkedUserDepList.length; index++) {
+        const element = this.checkedUserDepList[index]
+        if (element.type === 'user' && item.userId === element.userId) {
+          hasItem = true
+          break
+        } else if (element.type === 'dep' && item.id === element.id) {
+          hasItem = true
+          break
+        }
+      }
+      return hasItem
+    },
+    /**
+     * 删除 清空 等操作
+     */
+    // 删除一个选择员工或部门
+    selectDelect (selectItem, index) {
+      this.checkedUserDepList.splice(index, 1)
+      if (selectItem.type === 'dep') {
+        this.depShowList = this.depShowList.map((item, index, array) => {
+          item.isCheck = this.getItemCheckInfo(item, 'dep')
+          return item
+        })
+      } else {
+        this.userList = this.userList.map((item, index, array) => {
+          item.isCheck = this.getItemCheckInfo(item, 'user')
+          return item
+        })
+      }
+    },
+    // 提交按钮
+    popoverSubmit () {
+      this.popoverVisible = false
+      this.$emit(
+        'popoverSubmit',
+        this.checkedUserDepList.filter(item => {
+          return item.type === 'user'
+        }),
+        this.checkedUserDepList.filter(item => {
+          return item.type === 'dep'
+        })
+      )
+    },
+    // 清空按钮
+    emptyClick () {
+      this.checkedUserDepList = []
+      for (let index = 0; index < this.userList.length; index++) {
+        this.userList[index].isCheck = false
+      }
+
+      for (let index = 0; index < this.depShowList.length; index++) {
+        this.depShowList[index].isCheck = false
+      }
+    },
+    // 内容可见
+    showContentClick () {
+      if (!this.popoverContentShow) {
+        this.popoverContentShow = true
+        this.initInfo()
+      }
+    },
+    // 监听父类改变更新check
+    updateCheckInfoByWatch () {
+      this.checkedUserDepList = this.userCheckedData
+        .map(item => {
+          item.type = 'user'
+          return item
+        })
+        .concat(
+          this.depCheckedData.map(item => {
+            item.type = 'dep'
+            return item
+          })
+        )
+      this.userList = this.userList.map(item => {
+        item.isCheck = this.getItemCheckInfo(item, 'user')
+        return item
+      })
+      this.depShowList = this.depShowList.map((item, index, array) => {
+        item.isCheck = this.getItemCheckInfo(item, 'dep')
+        return item
+      })
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+@import '@/styles/mixin.scss';
+.popover-content-box {
+  display: flex;
+  .select-input {
+    flex: 1;
+    margin-right: 30px;
+    .select-input > .el-input {
+      margin: 10px 0;
+    }
+  }
+  .select-input /deep/ .el-tabs {
+    .el-tabs__active-bar {
+      display: none;
+    }
+    .el-tabs__nav-wrap::after {
+      height: 0;
+    }
+    .el-tabs__content {
+      border: 1px solid #e6e6e6;
+      height: 300px;
+      .el-checkbox {
+        margin-left: 0;
+        margin-right: 10px;
+      }
+    }
+    .el-breadcrumb {
+      margin-bottom: 15px;
+    }
+    .checkout-box {
+      display: flex;
+      margin-bottom: 10px;
+    }
+    .checkout-box > div {
+      flex: 1;
+      .el-icon-arrow-right {
+        float: right;
+      }
+      span {
+        cursor: pointer;
+      }
+    }
+    .el-tab-pane {
+      padding: 10px;
+      height: 100%;
+    }
+    .el-tab-pane > .el-input {
+      width: 90%;
+      margin: auto 5%;
+      .el-input__inner {
+        border-radius: 15px;
+      }
+    }
+  }
+  .checked-content {
+    flex: 1;
+    .checked-top {
+      height: 40px;
+      line-height: 40px;
+      margin-bottom: 15px;
+      .title {
+        color: #999999;
+      }
+    }
+    .border-content {
+      border: 1px solid #e6e6e6;
+      height: 300px;
+      overflow: auto;
+      padding: 20px 0;
+      @include scrollBar;
+      .checked-list {
+        height: 30px;
+        line-height: 30px;
+        padding: 0 20px;
+        cursor: pointer;
+        .el-icon-close {
+          opacity: 0;
+          margin-top: 8px;
+          margin-right: 0;
+        }
+        .div-photo {
+          width: 24px;
+          height: 24px;
+          border-radius: 12px;
+          vertical-align: middle;
+          margin-right: 8px;
+        }
+      }
+      .checked-list:hover {
+        -webkit-box-shadow: 0 0 8px 2px #eee;
+        box-shadow: 0 0 8px 2px #eee;
+        .el-icon-close {
+          opacity: 1;
+        }
+      }
+    }
+  }
+}
+.title-icon {
+  padding: 10px 20px 15px;
+  border-bottom: 1px solid #e6e6e6;
+  margin-bottom: 10px;
+  font-size: 16px;
+  .el-icon-close {
+    font-size: 20px;
+    color: #ccc;
+    margin-right: 0;
+  }
+}
+.popover-footer {
+  float: right;
+  margin: 20px 0 0;
+}
+/* 选择员工 */
+.search-img {
+  width: 24px;
+  height: 24px;
+  border-radius: 12px;
+  vertical-align: middle;
+  margin-right: 8px;
+}
+.search-list {
+  margin: 5px;
+  height: 248px;
+  overflow: auto;
+  margin-right: -10px;
+  padding-right: 10px;
+  @include scrollBar;
+}
+.colleagues-list {
+  padding: 5px;
+}
+</style>
diff --git a/src/components/timeTypeSelect/index.vue b/src/components/timeTypeSelect/index.vue
new file mode 100644
index 0000000..487424c
--- /dev/null
+++ b/src/components/timeTypeSelect/index.vue
@@ -0,0 +1,184 @@
+<template>
+  <el-popover
+    v-model="showTypePopover"
+    placement="bottom"
+    width="200"
+    popper-class="no-padding-popover"
+    trigger="click">
+    <div class="type-popper">
+      <div class="type-content">
+        <div
+          v-for="(item, index) in typeOptions"
+          :key="index"
+          :class="{ 'selected' : selectType.value === item.value && !showCustomContent}"
+          class="type-content-item"
+          @click="typeSelectClick(item)">
+          <div class="mark"/>{{ item.label }}
+        </div>
+        <div
+          :class="{ 'selected' : showCustomContent}"
+          class="type-content-item"
+          @click="showCustomContent = true">
+          <div class="mark"/>自定义
+        </div>
+      </div>
+      <div
+        v-if="showCustomContent"
+        class="type-content-custom">
+        <el-date-picker
+          v-model="startTime"
+          type="date"
+          value-format="yyyy-MM-dd"
+          placeholder="选择日期"/>
+        <el-date-picker
+          v-model="endTime"
+          type="date"
+          value-format="yyyy-MM-dd"
+          placeholder="选择日期"/>
+        <el-button @click="customSureClick">确定</el-button>
+      </div>
+    </div>
+    <el-input
+      slot="reference"
+      v-model="typeShowValue"
+      :readonly="true"
+      placeholder="请选择选择"
+      class="type-select">
+      <i
+        slot="suffix"
+        :class="['el-input__icon', 'el-icon-' + iconClass]"/>
+    </el-input>
+  </el-popover>
+</template>
+
+<script type="text/javascript">
+export default {
+  name: 'TimeTypeSelect',
+  props: {
+    defaultType: Object
+  },
+  data() {
+    return {
+      selectType: { label: '本年', value: 'year' },
+      showTypePopover: false,
+      showCustomContent: false, // 展示自定义时间内容
+      sureCustomContent: false, // 确定
+
+      startTime: '',
+      endTime: '',
+      typeOptions: [
+        { label: '今天', value: 'today' },
+        { label: '昨天', value: 'yesterday' },
+        { label: '本周', value: 'week' },
+        { label: '上周', value: 'lastWeek' },
+        { label: '本月', value: 'month' },
+        { label: '上月', value: 'lastMonth' },
+        { label: '本季度', value: 'quarter' },
+        { label: '上季度', value: 'lastQuarter' },
+        { label: '本年', value: 'year' },
+        { label: '去年', value: 'lastYear' }
+      ]
+    }
+  }, // 时间类型选择
+  computed: {
+    iconClass() {
+      return this.showTypePopover ? 'arrow-up' : 'arrow-down'
+    },
+    typeShowValue() {
+      if (this.sureCustomContent) {
+        if (this.startTime || this.endTime) {
+          return (this.startTime || '') + '-' + (this.endTime || '')
+        }
+        return ''
+      } else {
+        return this.selectType.label
+      }
+    }
+  },
+  mounted() {
+    if (this.defaultType) {
+      this.selectType = this.defaultType
+    } else {
+      this.$emit('change', { type: 'default', value: this.selectType.value })
+    }
+  },
+  methods: {
+    // 类型选择
+    typeSelectClick(item) {
+      this.showTypePopover = false
+      this.sureCustomContent = false
+      this.showCustomContent = false
+      this.selectType = item
+      this.$emit('change', { type: 'default', value: this.selectType.value })
+    },
+    // 选择自定义时间 确定
+    customSureClick() {
+      if (this.startTime && this.endTime) {
+        this.sureCustomContent = true
+        this.showTypePopover = false
+
+        this.$emit('change', {
+          type: 'custom',
+          startTime: this.startTime,
+          endTime: this.endTime
+        })
+      }
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+.type-select {
+  width: 200px;
+  margin-right: 15px;
+}
+
+// 时间选择
+.type-popper {
+  .type-content {
+    height: 250px;
+    overflow-y: auto;
+    .type-content-item {
+      height: 34px;
+      line-height: 34px;
+      padding: 0 20px;
+      color: #606266;
+      position: relative;
+      cursor: pointer;
+      .mark {
+        display: inline-block;
+        width: 8px;
+        height: 8px;
+        border-radius: 4px;
+        margin-right: 5px;
+        background-color: transparent;
+      }
+    }
+
+    .selected {
+      color: #409eff;
+      font-weight: 700;
+      .mark {
+        background-color: #409eff;
+      }
+    }
+    .type-content-item:hover {
+      background-color: #f5f7fa;
+    }
+  }
+
+  .type-content-custom {
+    padding: 5px 20px 10px;
+    position: relative;
+    overflow: hidden;
+    .el-date-editor {
+      width: 100%;
+      margin-bottom: 8px;
+    }
+
+    button {
+      float: right;
+    }
+  }
+}
+</style>
diff --git a/src/components/vuePictureViewer/img/pre_close.png b/src/components/vuePictureViewer/img/pre_close.png
new file mode 100644
index 0000000..7f31bb7
--- /dev/null
+++ b/src/components/vuePictureViewer/img/pre_close.png
Binary files differ
diff --git a/src/components/vuePictureViewer/img/pre_down.png b/src/components/vuePictureViewer/img/pre_down.png
new file mode 100644
index 0000000..127c227
--- /dev/null
+++ b/src/components/vuePictureViewer/img/pre_down.png
Binary files differ
diff --git a/src/components/vuePictureViewer/img/pre_left.png b/src/components/vuePictureViewer/img/pre_left.png
new file mode 100644
index 0000000..20a5ce2
--- /dev/null
+++ b/src/components/vuePictureViewer/img/pre_left.png
Binary files differ
diff --git a/src/components/vuePictureViewer/img/pre_max.png b/src/components/vuePictureViewer/img/pre_max.png
new file mode 100644
index 0000000..ba22f28
--- /dev/null
+++ b/src/components/vuePictureViewer/img/pre_max.png
Binary files differ
diff --git a/src/components/vuePictureViewer/img/pre_min.png b/src/components/vuePictureViewer/img/pre_min.png
new file mode 100644
index 0000000..7df42cd
--- /dev/null
+++ b/src/components/vuePictureViewer/img/pre_min.png
Binary files differ
diff --git a/src/components/vuePictureViewer/img/pre_right.png b/src/components/vuePictureViewer/img/pre_right.png
new file mode 100644
index 0000000..bc680d0
--- /dev/null
+++ b/src/components/vuePictureViewer/img/pre_right.png
Binary files differ
diff --git a/src/components/vuePictureViewer/img/pre_rotate.png b/src/components/vuePictureViewer/img/pre_rotate.png
new file mode 100644
index 0000000..ddbffee
--- /dev/null
+++ b/src/components/vuePictureViewer/img/pre_rotate.png
Binary files differ
diff --git a/src/components/vuePictureViewer/index.vue b/src/components/vuePictureViewer/index.vue
new file mode 100644
index 0000000..5f80faf
--- /dev/null
+++ b/src/components/vuePictureViewer/index.vue
@@ -0,0 +1,753 @@
+<template>
+  <div
+    id="vue-picture-viewer"
+    :style="maskContainer">
+    <!-- 头部 -->
+    <flexbox class="perview-header">
+      <div class="left">{{ imgIndex + 1 }} / {{ imgLength }}</div>
+      <div class="center">{{ bigImgName.slice(0,bigImgName.indexOf('.')) }}</div>
+      <img
+        class="close"
+        src="./img/pre_close.png"
+        @click="closeViewer" >
+    </flexbox>
+    <!-- 图片容器 -->
+    <div
+      ref="imgContainer"
+      :style="imgContainer"
+      class="imgContainer">
+      <img
+        v-if="bigShowType.isImage"
+        ref="bigImg"
+        :src="bigImgUrl"
+        :style="bigImgStyle"
+        alt="">
+      <flexbox
+        v-if="!bigShowType.isImage"
+        class="file-show">
+        <div class="file-icon">
+          <img :src="bigShowType.icon" >
+        </div>
+        <div class="file-handle">
+          <!-- <el-button type="primary"
+                     @click.native="fileHandle('online')">在线预览</el-button> -->
+          <el-button
+            type="primary"
+            plain
+            @click.native="fileHandle('download')">下载</el-button>
+        </div>
+      </flexbox>
+      <!-- tips -->
+      <transition name="fade">
+        <div
+          v-show="showTips"
+          class="tips">{{ tipsText }}</div>
+      </transition>
+    </div>
+    <div class="fixedHandle">
+      <!-- 操作按钮 -->
+      <flexbox
+        v-if="bigShowType.isImage"
+        class="handleContainer">
+        <img
+          src="./img/pre_max.png"
+          @click="enlarge" >
+        <img
+          src="./img/pre_min.png"
+          @click="reduce" >
+        <img
+          style="padding: 4.5px;"
+          src="./img/pre_rotate.png"
+          @click="rotate" >
+        <img
+          src="./img/pre_down.png"
+          @click="downloadImg(bigImgUrl, bigImgName)" >
+      </flexbox>
+      <!-- 缩略图容器 -->
+      <div
+        v-if="imgLength > 1"
+        class="thumbnailContainer">
+        <ul>
+          <li
+            v-for="(item, index) in imgData"
+            ref="thumbnailItem"
+            :key="index"
+            @click="switchImgUrl(index, $event)">
+            <img
+              v-if="isShowImage(item.url)"
+              :src="item.url"
+              alt="">
+            <img
+              v-if="!isShowImage(item.url)"
+              :src="getFileTypeIconWithSuffix(item.url)"
+              alt="">
+          </li>
+        </ul>
+      </div>
+    </div>
+    <!-- 左边箭头 -->
+    <div
+      class="leftArrowCon"
+      @click="handlePrev"
+      @mouseenter="enterLeft"
+      @mouseout="outLeft">
+      <img
+        v-show="leftArrowShow"
+        class="leftArrow"
+        src="./img/pre_left.png"
+        @click="enlarge" >
+    </div>
+    <!-- 右边箭头 -->
+    <div
+      class="rightArrowCon"
+      @click="handleNext"
+      @mouseenter="enterRight"
+      @mouseout="outRight">
+      <img
+        v-show="rightArrowShow"
+        class="rightArrow"
+        src="./img/pre_right.png" >
+    </div>
+  </div>
+</template>
+
+<script>
+import { getMaxIndex, downloadImage } from '@/utils'
+
+export default {
+  name: 'VuePictureViewer',
+  props: {
+    imgData: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    background: {
+      type: String,
+      default: 'rgba(0,0,0,0.4)'
+    },
+    // 选择的索引
+    selectIndex: {
+      type: Number,
+      default: -1
+    }
+  },
+  data() {
+    return {
+      // 默认不显示左右切换箭头
+      leftArrowShow: false,
+      rightArrowShow: false,
+      // 图片容器数据
+      rotateDeg: 0,
+      bigImgUrl: '',
+      bigShowType: { isImage: true, icon: '' }, // 不是图片的时候 展示 icon
+      bigImgName: '',
+      imgLength: 0,
+      imgIndex: 0,
+      showTips: false,
+      tipsText: '',
+      bigImgConWidth: '',
+      bigImgConHeight: '',
+      maskContainer: {
+        width: '100%',
+        height: '100%',
+        background: this.background,
+        position: 'fixed',
+        top: 0,
+        left: 0,
+        right: 0,
+        bottom: 0
+      },
+      imgContainer: {
+        width: 'auto',
+        height: 'auto',
+        position: 'absolute',
+        top: '50%',
+        left: '50%',
+        'z-index': 100,
+        transform: 'translate(-50%, -50%)'
+      },
+      bigImgStyle: {
+        display: 'block',
+        width: '80px',
+        height: '80px',
+        position: 'absolute',
+        top: 50 + '%',
+        left: 50 + '%',
+        marginLeft: '',
+        marginTop: '',
+        userSelect: 'none'
+      }
+    }
+  },
+  mounted() {
+    document
+      .getElementById('vue-picture-viewer')
+      .addEventListener('click', e => {
+        e.stopPropagation()
+      })
+
+    this.imgLength = this.imgData.length
+    this.imgIndex = this.selectIndex
+    this.$nextTick(() => {
+      this.bigImgUrl = this.imgData[this.imgIndex].url
+      this.getShowTypeInfo(this.bigImgUrl)
+      this.bigImgName = this.imgData[this.imgIndex].name
+      if (this.imgLength > 1) {
+        // 大于1的时候才会展示缩略图
+        var item = this.$refs.thumbnailItem
+        item[this.imgIndex].className = 'borderActive'
+      }
+    })
+    var self = this
+    this.$refs.bigImg.onload = () => {
+      self.init()
+    }
+
+    this.maskContainer['z-index'] = getMaxIndex()
+  },
+  beforeDestroy() {
+    if (document.getElementById('vue-picture-viewer')) {
+      document
+        .getElementById('vue-picture-viewer')
+        .removeEventListener('click', e => {
+          e.stopPropagation()
+        })
+    }
+  },
+  methods: {
+    // init
+    init() {
+      const screenW =
+        document.documentElement.offsetWidth || document.body.offsetWidth
+      const screenH =
+        document.documentElement.scrollHeight || document.body.scrollHeight
+      this.$nextTick(function() {
+        const ratio = [0.1, 0.2, 0.3, 0.4, 0.5, 0.7, 0.8, 0.9]
+        for (const item of ratio) {
+          if (
+            this.$refs.bigImg.naturalWidth * item < screenW &&
+            this.$refs.bigImg.naturalHeight * item < screenH - 200
+          ) {
+            this.bigImgConWidth = this.$refs.bigImg.naturalWidth * item
+            this.bigImgConHeight = this.$refs.bigImg.naturalHeight * item
+            this.imgContainer.width = this.bigImgConWidth + 'px'
+            this.imgContainer.height = this.bigImgConHeight + 'px'
+            this.bigImgStyle.width = this.bigImgConWidth + 'px'
+            this.bigImgStyle.height = this.bigImgConHeight + 'px'
+            this.bigImgStyle.marginLeft = -(this.bigImgConWidth / 2) + 'px'
+            this.bigImgStyle.marginTop = -(this.bigImgConHeight / 2) + 'px'
+          }
+        }
+      })
+    },
+    // rotate init
+    rotateInit() {
+      const screenH =
+        document.documentElement.scrollHeight || document.body.scrollHeight
+      const ratio = [0.1, 0.2, 0.3, 0.4, 0.5, 0.7, 0.8, 0.9]
+      for (const item of ratio) {
+        if (this.$refs.bigImg.naturalWidth * item < screenH - 160) {
+          this.bigImgConWidth = this.$refs.bigImg.naturalWidth * item
+          this.bigImgConHeight = this.$refs.bigImg.naturalHeight * item
+          this.imgContainer.width = this.bigImgConWidth + 'px'
+          this.imgContainer.height = this.bigImgConHeight + 'px'
+          this.bigImgStyle.width = this.bigImgConWidth + 'px'
+          this.bigImgStyle.height = this.bigImgConHeight + 'px'
+          this.bigImgStyle.marginLeft = -(this.bigImgConWidth / 2) + 'px'
+          this.bigImgStyle.marginTop = -(this.bigImgConHeight / 2) + 'px'
+        }
+      }
+    },
+    // 放大
+    enlarge() {
+      this.$nextTick(function() {
+        const screenW =
+          document.documentElement.offsetWidth || document.body.offsetWidth
+        const screenH =
+          document.documentElement.scrollHeight || document.body.scrollHeight
+        if (
+          (this.$refs.bigImg.offsetWidth >= this.$refs.bigImg.offsetHeight &&
+            this.$refs.bigImg.offsetHeight * 2 < screenH * 2) ||
+          (this.$refs.bigImg.offsetHeight >= this.$refs.bigImg.offsetWidth &&
+            this.$refs.bigImg.offsetWidth * 2 < screenW * 2)
+        ) {
+          this.$refs.bigImg.style.width =
+            this.$refs.bigImg.offsetWidth * 1.3 + 'px'
+          this.$refs.bigImg.style.height =
+            this.$refs.bigImg.offsetHeight * 1.3 + 'px'
+          this.$refs.bigImg.style.left = '50%'
+          this.$refs.bigImg.style.top = '50%'
+          this.bigImgStyle.marginLeft =
+            -this.$refs.bigImg.offsetWidth / 2 + 'px'
+          this.bigImgStyle.marginTop =
+            -this.$refs.bigImg.offsetHeight / 2 + 'px'
+        }
+      })
+    },
+    // 缩小
+    reduce() {
+      if (this.$refs.bigImg.offsetWidth > 80) {
+        /**
+           * clientWidth = width + padding
+             offsetWidth = width + padding + border  */
+        this.$refs.bigImg.style.width =
+          this.$refs.bigImg.offsetWidth * 0.7 + 'px'
+        this.$refs.bigImg.style.height =
+          this.$refs.bigImg.offsetHeight * 0.7 + 'px'
+        this.$refs.bigImg.style.left = '50%'
+        this.$refs.bigImg.style.top = '50%'
+        this.bigImgStyle.marginLeft = -this.$refs.bigImg.offsetWidth / 2 + 'px'
+        this.bigImgStyle.marginTop = -this.$refs.bigImg.offsetHeight / 2 + 'px'
+      }
+    },
+    // 旋转
+    rotate() {
+      if (this.rotateDeg === 0) {
+        this.$refs.bigImg.style.transform = 'rotate(90deg)'
+        this.rotateInit()
+        this.rotateDeg++
+      } else if (this.rotateDeg === 1) {
+        this.$refs.bigImg.style.transform = 'rotate(180deg)'
+        this.init()
+        this.rotateDeg++
+      } else if (this.rotateDeg === 2) {
+        this.$refs.bigImg.style.transform = 'rotate(270deg)'
+        this.rotateInit()
+        this.rotateDeg++
+      } else if (this.rotateDeg === 3) {
+        this.$refs.bigImg.style.transform = 'rotate(360deg)'
+        this.init()
+        this.rotateDeg = 0
+      }
+    },
+    // 点击缩略图切换图片
+    switchImgUrl(num, e) {
+      var item = this.$refs.thumbnailItem
+      item.forEach(function(i) {
+        i.className = ''
+      })
+      this.imgIndex = num
+      this.bigImgUrl = this.imgData[num].url
+      this.getShowTypeInfo(this.bigImgUrl)
+      this.bigImgName = this.imgData[num].name
+      e.currentTarget.className = 'borderActive'
+      if (this.bigShowType.isImage) {
+        this.init()
+      }
+    },
+    // 切换到上一张
+    handlePrev() {
+      if (this.imgIndex <= 0) {
+        this.tips('已经是第一张了!')
+        this.imgIndex = 0
+      } else {
+        if (this.$refs.bigImg) {
+          this.$refs.bigImg.style.transform = 'rotate(0deg)'
+          this.rotateDeg = 0
+        }
+
+        this.imgIndex--
+        this.bigImgUrl = this.imgData[this.imgIndex].url
+        this.getShowTypeInfo(this.bigImgUrl)
+        this.bigImgName = this.imgData[this.imgIndex].name
+        var item = this.$refs.thumbnailItem
+        item.forEach(function(i) {
+          i.className = ''
+        })
+        item[this.imgIndex].className = 'borderActive'
+        if (this.bigShowType.isImage) {
+          this.init()
+        }
+      }
+    },
+    // 切换到下一张
+    handleNext() {
+      if (this.imgIndex + 1 >= this.imgData.length) {
+        this.tips('已经是最后一张了!')
+      } else {
+        if (this.$refs.bigImg) {
+          this.$refs.bigImg.style.transform = 'rotate(0deg)'
+          this.rotateDeg = 0
+        }
+
+        this.imgIndex++
+        this.bigImgUrl = this.imgData[this.imgIndex].url
+        this.getShowTypeInfo(this.bigImgUrl)
+        this.bigImgName = this.imgData[this.imgIndex].name
+
+        var item = this.$refs.thumbnailItem
+        item.forEach(function(i) {
+          i.className = ''
+        })
+        item[this.imgIndex].className = 'borderActive'
+        if (this.bigShowType.isImage) {
+          this.init()
+        }
+      }
+    },
+    // 提示框
+    tips(msg) {
+      this.showTips = true
+      this.tipsText = msg
+      const _this = this
+      setTimeout(function() {
+        _this.showTips = false
+      }, 10000)
+    },
+    // 下载图片
+    downloadImg(data, filename) {
+      downloadImage(data, filename)
+    },
+    // 鼠标左移
+    enterLeft() {
+      this.leftArrowShow = true
+    },
+    outLeft() {
+      this.leftArrowShow = false
+    },
+    // 鼠标右移
+    enterRight() {
+      this.rightArrowShow = true
+    },
+    outRight() {
+      this.rightArrowShow = false
+    },
+    // 关闭查看器
+    closeViewer() {
+      this.$emit('close-viewer')
+    },
+    /** 附件逻辑 */
+    fileHandle(type) {
+      var a = document.createElement('a')
+      a.href = this.bigImgUrl
+      a.download = this.bigImgName ? this.bigImgName : '文件'
+      a.target = '_black'
+      document.body.appendChild(a)
+      a.click()
+      document.body.removeChild(a)
+    },
+    getShowTypeInfo(url) {
+      const temps = url ? url.split('.') : []
+      var ext = ''
+      if (temps.length > 0) {
+        ext = temps[temps.length - 1]
+      } else {
+        ext = ''
+      }
+      var icon = ''
+      var isImage = true
+      if (this.arrayContain(['jpg', 'png', 'gif', 'jpeg'], ext)) {
+        isImage = true
+        icon = require('@/assets/img/file_img.png')
+      } else if (this.arrayContain(['mp4', 'mp3', 'avi'], ext)) {
+        isImage = false
+        icon = require('@/assets/img/file_excle.png')
+      } else if (this.arrayContain(['xlsx', 'xls', 'XLSX', 'XLS'], ext)) {
+        isImage = false
+        icon = require('@/assets/img/file_excle.png')
+      } else if (this.arrayContain(['doc', 'docx', 'DOC', 'DOCX'], ext)) {
+        isImage = false
+        icon = require('@/assets/img/file_word.png')
+      } else if (this.arrayContain(['rar', 'zip'], ext)) {
+        isImage = false
+        icon = require('@/assets/img/file_zip.png')
+      } else if (ext === 'pdf') {
+        isImage = false
+        icon = require('@/assets/img/file_pdf.png')
+      } else if (ext === 'ppt' || ext === 'pptx') {
+        isImage = false
+        icon = require('@/assets/img/file_ppt.png')
+      } else if (this.arrayContain(['txt', 'text'], ext)) {
+        isImage = false
+        icon = require('@/assets/img/file_txt.png')
+      } else {
+        isImage = false
+        icon = require('@/assets/img/file_unknown.png')
+      }
+      this.bigShowType = { isImage: isImage, icon: icon }
+    },
+    getFileTypeIconWithSuffix(url) {
+      const temps = url ? url.split('.') : []
+      var ext = ''
+      if (temps.length > 0) {
+        ext = temps[temps.length - 1]
+      } else {
+        ext = ''
+      }
+      if (this.arrayContain(['jpg', 'png', 'gif', 'jpeg'], ext)) {
+        return require('@/assets/img/file_img.png')
+      } else if (this.arrayContain(['mp4', 'mp3', 'avi'], ext)) {
+        return require('@/assets/img/file_excle.png')
+      } else if (this.arrayContain(['xlsx', 'xls', 'XLSX', 'XLS'], ext)) {
+        return require('@/assets/img/file_excle.png')
+      } else if (this.arrayContain(['doc', 'docx', 'DOC', 'DOCX'], ext)) {
+        return require('@/assets/img/file_word.png')
+      } else if (this.arrayContain(['rar', 'zip'], ext)) {
+        return require('@/assets/img/file_zip.png')
+      } else if (ext === 'pdf') {
+        return require('@/assets/img/file_pdf.png')
+      } else if (ext === 'ppt' || ext === 'pptx') {
+        return require('@/assets/img/file_ppt.png')
+      } else if (this.arrayContain(['txt', 'text'], ext)) {
+        return require('@/assets/img/file_txt.png')
+      }
+      return require('@/assets/img/file_unknown.png')
+    },
+    isShowImage(url) {
+      const temps = url ? url.split('.') : []
+      var ext = ''
+      if (temps.length > 0) {
+        ext = temps[temps.length - 1]
+      } else {
+        ext = ''
+      }
+      if (this.arrayContain(['jpg', 'png', 'gif', 'jpeg'], ext)) {
+        return true
+      }
+      return false
+    },
+    arrayContain(array, string) {
+      return array.some(item => {
+        return item === string
+      })
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.perview-header {
+  width: 100%;
+  height: 40px;
+  background: rgba(0, 0, 0, 0.6);
+  color: rgba(255, 255, 255, 0.8);
+  line-height: 40px;
+  position: fixed;
+  top: 0;
+  left: 0;
+  z-index: 101;
+  padding: 10px;
+  .left {
+    flex-shrink: 0;
+    font-size: 14px;
+  }
+  .center {
+    text-align: center;
+    flex: 1;
+    padding: 0 20px;
+  }
+  .close {
+    display: block;
+    padding: 8px;
+    width: 40px;
+    height: 40px;
+    cursor: pointer;
+  }
+}
+
+.leftArrowCon {
+  width: 30%;
+  height: calc(100% - 40px);
+  background: transparent;
+  position: absolute;
+  top: 40px;
+  left: 0;
+  z-index: 98;
+  cursor: pointer;
+}
+.rightArrowCon {
+  width: 30%;
+  height: calc(100% - 40px);
+  background: transparent;
+  position: absolute;
+  top: 40px;
+  right: 0;
+  z-index: 99;
+  cursor: pointer;
+}
+.leftArrow {
+  position: absolute;
+  top: 50%;
+  left: 30px;
+  margin-top: -60px;
+  transition: all 0.5s;
+  width: 50px;
+  height: 50px;
+  pointer-events: none;
+}
+.rightArrow {
+  position: absolute;
+  top: 50%;
+  right: 30px;
+  margin-top: -60px;
+  width: 50px;
+  height: 50px;
+  transition: all 0.5s;
+  pointer-events: none;
+}
+.imgContainer .tips {
+  background: rgba(0, 0, 0, 0.7);
+  color: #fff;
+  text-align: center;
+  line-height: 40px;
+  position: absolute;
+  left: 50%;
+  top: 50%;
+  min-width: 150px;
+  margin-left: -60px;
+  margin-top: -20px;
+  border-radius: 6px;
+  padding: 4px 4px;
+  font-size: 14px;
+}
+.fixedHandle {
+  width: 800px;
+  height: 140px;
+  position: fixed;
+  left: 50%;
+  bottom: 0;
+  margin-left: -400px;
+  overflow: hidden;
+  z-index: 100;
+}
+.handleContainer {
+  width: 210px;
+  height: 40px;
+  background: rgba(0, 0, 0, 0.6);
+  line-height: 40px;
+  border-radius: 20px;
+  position: absolute;
+  left: 50%;
+  bottom: 100px;
+  padding: 0 14px;
+  margin-left: -100px;
+
+  img {
+    display: block;
+    width: 40px;
+    height: 40px;
+    padding: 8px;
+    margin: 0 2px;
+    cursor: pointer;
+  }
+}
+.handleItem {
+  width: 28px;
+  height: 28px;
+  color: white;
+}
+ul {
+  padding: 0;
+  margin: 0;
+}
+ul li {
+  list-style: none;
+  display: inline-block;
+  width: 30px;
+  height: 30px;
+  margin-left: 20px;
+  cursor: pointer;
+}
+
+.thumbnailContainer {
+  max-width: 800px;
+  background: rgba(255, 255, 255, 0.7);
+  position: absolute;
+  left: 50%;
+  bottom: 0;
+  border-top-left-radius: 5px;
+  border-top-right-radius: 5px;
+  transform: translate(-50%, 0%);
+  overflow-x: auto;
+  overflow-y: hidden;
+}
+
+.thumbnailContainer ul {
+  padding-top: 10px;
+  padding-bottom: 10px;
+  text-align: center;
+  white-space: nowrap;
+}
+.thumbnailContainer ul li {
+  display: inline-block;
+  width: 38px;
+  height: 38px;
+  box-sizing: content-box;
+  margin-left: 10px;
+  user-select: none;
+}
+.thumbnailContainer ul li:last-child {
+  margin-right: 10px;
+}
+.thumbnailContainer ul li img {
+  display: inline-block;
+  width: 38px;
+  height: 38px;
+  border-radius: 3px;
+  box-sizing: content-box;
+}
+.fade-enter-active,
+.fade-leave-active {
+  transition: opacity 1s;
+}
+.fade-enter,
+.fade-leave-to {
+  opacity: 0;
+}
+
+/* 添加border */
+.borderActive {
+  box-shadow: 0px 4px 7px 0px rgb(241, 140, 112);
+}
+/* 修改原生的滚动条 */
+::-webkit-scrollbar {
+  /* 血槽宽度 */
+  width: 8px;
+  height: 8px;
+}
+::-webkit-scrollbar-thumb {
+  /* 拖动条 */
+  background: rgba(0, 0, 0, 0.3);
+  border-radius: 6px;
+}
+::-webkit-scrollbar-track {
+  /* 背景槽 */
+  background: #ddd;
+  border-radius: 6px;
+}
+/** 文件展示*/
+.file-show {
+  position: absolute;
+  top: 60%;
+  left: 50%;
+  width: 450px;
+  height: 260px;
+  margin-top: -150px;
+  margin-left: -225px;
+  background-color: white;
+  border-radius: 3px;
+  padding: 0 80px;
+  .file-icon {
+    flex: 1;
+    img {
+      display: block;
+      width: 100px;
+    }
+  }
+
+  .file-handle {
+    button {
+      display: block;
+      width: 120px;
+      margin-left: 0;
+      margin-right: 0;
+      height: 34px;
+    }
+    button:first-child {
+      margin-bottom: 20px;
+    }
+  }
+}
+</style>
diff --git a/src/directives/empty/empty.scss b/src/directives/empty/empty.scss
new file mode 100644
index 0000000..53fbf87
--- /dev/null
+++ b/src/directives/empty/empty.scss
@@ -0,0 +1,7 @@
+.xs-empty-parent--relative {
+  position: relative !important
+}
+
+.xs-empty-parent--hidden {
+  overflow: hidden !important
+}
diff --git a/src/directives/empty/empty.vue b/src/directives/empty/empty.vue
new file mode 100644
index 0000000..ee6bbcf
--- /dev/null
+++ b/src/directives/empty/empty.vue
@@ -0,0 +1,97 @@
+<template>
+  <div
+    v-show="visible"
+    :style="{ backgroundColor: background || '' }"
+    :class="[customClass]"
+    class="empty-mask">
+    <div class="empty-content">
+      <img
+        v-if="iconUrl"
+        :src="iconUrl"
+        class="empty-icon" >
+      <p
+        v-if="showText"
+        class="empty-text">{{ showText }}</p>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  data () {
+    return {
+      text: null,
+      background: null,
+      visible: false,
+      icon: null,
+      customClass: ''
+    }
+  },
+  computed: {
+    iconUrl: function () {
+      /** 内置几个类型  当时none的时候  不展示 */
+      if (this.icon) {
+        if (this.icon === 'none') {
+          return ''
+        } else if (this.icon === 'nopermission') {
+          return require('@/assets/img/nopermission.png')
+        } else {
+          return require('@/assets/img/empty.png')
+        }
+      } else {
+        return require('@/assets/img/empty.png')
+      }
+    },
+    showText: function () {
+      /** 内置几个类型  当时none的时候  不展示 */
+      if (this.text) {
+        return this.text
+      } else {
+        return '没有找到数据'
+      }
+    }
+  },
+  methods: {
+    setText (text) {
+      if (text) {
+        this.text = text
+      }
+    },
+    setIcon (icon) {
+      this.icon = icon
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.empty-mask {
+  position: absolute;
+  z-index: 2000;
+  background-color: rgba(255, 255, 255, 0.98);
+  margin: 0;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+}
+
+.empty-content {
+  top: 50%;
+  width: 100%;
+  text-align: center;
+  position: absolute;
+}
+
+.empty-text {
+  margin: 3px 0;
+  color: #aaa;
+  font-size: 13px;
+}
+
+.empty-icon {
+  display: block;
+  width: 150px;
+  margin: 0 auto 20px auto;
+}
+</style>
diff --git a/src/directives/empty/index.js b/src/directives/empty/index.js
new file mode 100644
index 0000000..fdecac8
--- /dev/null
+++ b/src/directives/empty/index.js
@@ -0,0 +1,102 @@
+/* eslint-disable no-mixed-operators */
+import Vue from 'vue'
+import Empty from './empty.vue'
+import {
+  addClass,
+  removeClass,
+  getStyle
+} from 'element-ui/src/utils/dom'
+const Mask = Vue.extend(Empty)
+/**
+ * xs-empty-text
+ * 在绑定了v-empty指令的元素上添加xs-empty-text属性,其值会被渲染为加载文案,并显示在加载图标的下方
+ * xs-empty-icon
+ * 定义了几个类型  none 就是不展示icon 其他或者无值 就是一种效果
+ * xs-empty-background
+ * 背景色
+ * xs-empty-custom-class
+ * 类选择器样式 多个以空格分开
+ */
+const loadingDirective = {}
+loadingDirective.install = Vue => {
+  if (Vue.prototype.$isServer) return
+  const toggleEmpty = (el, binding) => {
+    /** 如果是数组 判断数组长度  否则 判断是否存在 当做Boolean */
+    if ((Object.prototype.toString.call(binding.value) === '[object Array]' && binding.value.length === 0) ||
+      (Object.prototype.toString.call(binding.value) !== '[object Array]' && binding.value)) {
+      Vue.nextTick(() => {
+        el.originalPosition = getStyle(el, 'position')
+        insertDom(el, el, binding)
+      })
+    } else { // 移除效果
+      el.domVisible = false
+      removeClass(el, 'xs-empty-parent--relative')
+      removeClass(el, 'xs-empty-parent--hidden')
+      el.instance.visible = false
+    }
+  }
+  const insertDom = (parent, el, binding) => {
+    if (!el.domVisible && getStyle(el, 'display') !== 'none' && getStyle(el, 'visibility') !== 'hidden') {
+      Object.keys(el.maskStyle).forEach(property => {
+        el.mask.style[property] = el.maskStyle[property]
+      })
+
+      if (el.originalPosition !== 'absolute' && el.originalPosition !== 'fixed') {
+        addClass(parent, 'xs-empty-parent--relative')
+      }
+      el.domVisible = true
+
+      parent.appendChild(el.mask)
+      Vue.nextTick(() => {
+        el.instance.visible = true
+      })
+      el.domInserted = true
+    }
+  }
+
+  Vue.directive('empty', {
+    bind: function (el, binding, vnode) {
+      const textExr = el.getAttribute('xs-empty-text')
+      const iconExr = el.getAttribute('xs-empty-icon')
+      const backgroundExr = el.getAttribute('xs-empty-background')
+      const customClassExr = el.getAttribute('xs-empty-custom-class')
+      const vm = vnode.context
+      const mask = new Mask({
+        el: document.createElement('div'),
+        data: {
+          text: vm && vm[textExr] || textExr,
+          icon: vm && vm[iconExr] || iconExr,
+          background: vm && vm[backgroundExr] || backgroundExr,
+          customClass: vm && vm[customClassExr] || customClassExr
+        }
+      })
+      el.instance = mask
+      el.mask = mask.$el
+      el.maskStyle = {}
+
+      binding.value && toggleEmpty(el, binding)
+    },
+
+    update: function (el, binding) {
+      el.instance.setText(el.getAttribute('xs-empty-text'))
+      el.instance.setIcon(el.getAttribute('xs-empty-icon'))
+      if (binding.oldValue !== binding.value) {
+        toggleEmpty(el, binding)
+      }
+    },
+
+    unbind: function (el, binding) {
+      if (el.domInserted) {
+        el.mask &&
+          el.mask.parentNode &&
+          el.mask.parentNode.removeChild(el.mask)
+        toggleEmpty(el, {
+          value: false,
+          modifiers: binding.modifiers
+        })
+      }
+    }
+  })
+}
+
+export default loadingDirective
diff --git a/src/directives/focus.js b/src/directives/focus.js
new file mode 100644
index 0000000..b920ba3
--- /dev/null
+++ b/src/directives/focus.js
@@ -0,0 +1,7 @@
+const focus = {
+  update (el) {
+    el.querySelector('input').focus()
+  }
+}
+
+export default focus
diff --git a/src/directives/index.js b/src/directives/index.js
new file mode 100644
index 0000000..745b67b
--- /dev/null
+++ b/src/directives/index.js
@@ -0,0 +1,24 @@
+const clickoutside = {
+  bind (el, binding, vnode) {
+    function documentHandler (e) {
+      // 这里判断点击的元素是否是本身,是本身,则返回
+      if (el.contains(e.target)) {
+        return false
+      }
+      // 判断指令中是否绑定了函数
+      if (binding.expression) {
+        binding.value(e)
+      }
+    }
+    // 给当前元素绑定个私有变量,方便在unbind中可以解除事件监听
+    el.__vueClickOutside__ = documentHandler
+    document.addEventListener('click', documentHandler)
+  },
+  unbind (el, binding) {
+    // 解除事件监听
+    document.removeEventListener('click', el.__vueClickOutside__)
+    delete el.__vueClickOutside__
+  }
+}
+
+export default clickoutside
diff --git a/src/directives/photo/index.js b/src/directives/photo/index.js
new file mode 100644
index 0000000..8c97b3c
--- /dev/null
+++ b/src/directives/photo/index.js
@@ -0,0 +1,91 @@
+/* eslint-disable no-mixed-operators */
+import Vue from 'vue'
+import Photo from './photo.vue'
+import {
+  addClass,
+  removeClass,
+  getStyle
+} from 'element-ui/src/utils/dom'
+const Mask = Vue.extend(Photo)
+
+const loadingDirective = {}
+loadingDirective.install = Vue => {
+  if (Vue.prototype.$isServer) return
+  const togglePhoto = (el, binding) => {
+    /** 如果是数组 判断数组长度  否则 判断是否存在 当做Boolean */
+    if (binding.value && !binding.value.img) {
+      Vue.nextTick(() => {
+        el.originalPosition = getStyle(el, 'position')
+        insertDom(el, el, binding)
+      })
+    } else { // 移除效果
+      el.domVisible = false
+      removeClass(el, 'xs-photo-parent--relative')
+      removeClass(el, 'xs-photo-parent--hidden')
+      el.instance.visible = false
+    }
+  }
+  const insertDom = (parent, el, binding) => {
+    if (!el.domVisible && getStyle(el, 'display') !== 'none' && getStyle(el, 'visibility') !== 'hidden') {
+      Object.keys(el.maskStyle).forEach(property => {
+        el.mask.style[property] = el.maskStyle[property]
+      })
+
+      if (el.originalPosition !== 'absolute' && el.originalPosition !== 'fixed') {
+        addClass(parent, 'xs-photo-parent--relative')
+      }
+      el.domVisible = true
+
+      parent.appendChild(el.mask)
+      Vue.nextTick(() => {
+        el.instance.visible = true
+      })
+      el.domInserted = true
+    }
+  }
+
+  Vue.directive('photo', {
+    bind: function (el, binding, vnode) {
+      const vm = vnode.context
+      let text = ''
+      if (binding.value && !binding.value.img) {
+        text = binding.value.realname && binding.value.realname.length > 2 ? binding.value.realname.substring(binding.value.realname.length - 2, binding.value.realname.length) : binding.value.realname
+      }
+      const mask = new Mask({
+        el: document.createElement('div'),
+        data: {
+          text: vm && vm[text] || text
+        }
+      })
+      el.instance = mask
+      el.mask = mask.$el
+      el.maskStyle = {}
+      text && togglePhoto(el, binding)
+    },
+
+    update: function (el, binding) {
+      let text = ''
+      if (binding.value && !binding.value.img) {
+        text = binding.value.realname && binding.value.realname.length > 2 ? binding.value.realname.substring(binding.value.realname.length - 2, binding.value.realname.length) : binding.value.realname
+      }
+      el.instance.setText(text)
+      if (binding.oldValue !== binding.value) {
+        togglePhoto(el, binding)
+      }
+    },
+
+    unbind: function (el, binding) {
+      if (el.domInserted) {
+        el.mask &&
+          el.mask.parentNode &&
+          el.mask.parentNode.removeChild(el.mask)
+        togglePhoto(el, {
+          value: false,
+          modifiers: binding.modifiers
+        })
+      }
+    }
+  })
+}
+
+export default loadingDirective
diff --git a/src/directives/photo/photo.scss b/src/directives/photo/photo.scss
new file mode 100644
index 0000000..d7ce2e3
--- /dev/null
+++ b/src/directives/photo/photo.scss
@@ -0,0 +1,7 @@
+.xs-photo-parent--relative {
+  position: relative !important
+}
+
+.xs-photo-parent--hidden {
+  overflow: hidden !important
+}
diff --git a/src/directives/photo/photo.vue b/src/directives/photo/photo.vue
new file mode 100644
index 0000000..ae6c40d
--- /dev/null
+++ b/src/directives/photo/photo.vue
@@ -0,0 +1,79 @@
+<template>
+  <div
+    v-show="visible"
+    class="photo-wrap">
+    <flexbox
+      :style="{'font-size' : fontSize+'px'}"
+      class="photo-content"
+      justify="center"
+      align="center">
+      <div v-if="text">{{ text }}</div>
+    </flexbox>
+  </div>
+</template>
+
+<script>
+export default {
+  data () {
+    return {
+      text: null,
+      visible: false,
+      fontSize: 12
+    }
+  },
+  computed: {},
+  watch: {
+    visible: function (params) {
+      this.$nextTick(() => {
+        if (this.$el.getBoundingClientRect().height > 0) {
+          let fontSize = this.$el.getBoundingClientRect().height * 0.38
+          if (fontSize > 40) {
+            fontSize = 40
+          }
+          this.fontSize = fontSize
+        } else {
+          this.fontSize = 12
+        }
+      })
+    }
+  },
+  mounted () {},
+  methods: {
+    setText (text) {
+      if (text) {
+        this.text = text
+      }
+    },
+    setIcon (icon) {
+      this.icon = icon
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.photo-wrap {
+  position: absolute;
+  z-index: 1;
+  // background-color: white;
+  margin: 0;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  .photo-content {
+    width: 100%;
+    height: 100%;
+    border-radius: 50%;
+    background-color: #2486e4;
+    color: white;
+    div {
+      width: 100%;
+      text-align: center;
+      transform: scale(0.9, 0.9);
+      max-height: 50px;
+      overflow: hidden;
+    }
+  }
+}
+</style>
diff --git a/src/directives/scrollx/index.js b/src/directives/scrollx/index.js
new file mode 100644
index 0000000..278cd1d
--- /dev/null
+++ b/src/directives/scrollx/index.js
@@ -0,0 +1,135 @@
+
+// 盒子滚动条拖拽
+import { on, off } from '@/utils/dom'
+import Vue from 'vue'
+import { debounce } from 'throttle-debounce'
+
+let targetDrag = { // 托拽
+  isDown: false,
+  coord: {
+    x: 0,
+    y: 0
+  }
+}
+
+let dom = null
+let ignoreClass = [] // 忽略的类名
+
+const scrollMousedown = event => {
+  dom.style.cursor = 'pointer'
+  targetDrag.isDown = true
+  targetDrag.coord.x = event.pageX
+  targetDrag.coord.y = event.pageY
+}
+
+const scrollMouseup = event => {
+  dom.style.cursor = 'default'
+  targetDrag.isDown = false
+  targetDrag.coord.x = 0
+  targetDrag.coord.y = 0
+}
+
+const scrollMousemove = event => {
+  const movX = targetDrag.coord.x - event.pageX
+  targetDrag.coord.x = event.pageX
+  if (checkDomIsIgnore(event)) {
+    dom.style.cursor = 'default'
+    targetDrag.isDown = false
+  } else if (targetDrag.isDown) {
+    dom.scrollLeft = dom.scrollLeft + movX
+  }
+}
+
+const scrollMouseout = event => {
+  dom.style.cursor = 'default'
+  targetDrag.isDown = false
+}
+
+const scrollMousewheel = event => {
+  if (checkIsIgnore(event)) {
+    dom.style.cursor = 'default'
+    targetDrag.isDown = false
+  } else {
+    dom.scrollLeft += event.deltaY
+  }
+}
+
+/**
+ * 检查dom是否忽略
+ * @param {*} e
+ */
+const checkDomIsIgnore = debounce(300, (e) => {
+  let ignore = false
+  ignoreClass.forEach(element => {
+    var items = document.getElementsByClassName(element)
+    if (items && !ignore) {
+      for (let index = 0; index < items.length; index++) {
+        const element = items[index]
+        if (element.contains(e.target)) {
+          ignore = true
+          break
+        }
+      }
+    }
+  })
+  return ignore
+})
+
+/**
+ * 忽略滚轮
+ * @param {*} e
+ */
+const checkIsIgnore = (e) => {
+  let ignore = false
+  ignoreClass.forEach(element => {
+    var items = document.getElementsByClassName(element)
+    if (items && !ignore) {
+      for (let index = 0; index < items.length; index++) {
+        const element = items[index]
+        const rect = element.getBoundingClientRect()
+        if ((e.clientY > rect.top && (e.clientY < (rect.top + rect.height))) && (e.clientX > rect.left && (e.clientX < (rect.left + rect.width)))) {
+          ignore = true
+          break
+        }
+      }
+    }
+  })
+  return ignore
+}
+
+export default Vue.directive('scrollx', {
+  bind: function (el, binding, vnode) {
+    const valueData = binding.value
+    ignoreClass = valueData.ignoreClass
+  },
+
+  inserted: function (el) {
+    dom = el
+
+    // 鼠标按下
+    on(el, 'mousedown', scrollMousedown)
+    on(el, 'mouseout', scrollMouseout)
+    on(el, 'wheel', scrollMousewheel)
+    // 鼠标释放
+    on(el, 'mouseup', scrollMouseup)
+    // 鼠标托拽
+    on(el, 'mousemove', scrollMousemove)
+  },
+
+  unbind: function (el) {
+    off(el, 'mousedown', scrollMousedown)
+    off(el, 'mouseup', scrollMouseup)
+    off(el, 'mouseout', scrollMouseout)
+    off(el, 'wheel', scrollMousewheel)
+    off(el, 'mousemove', scrollMousemove)
+
+    // 清空
+    targetDrag = { // 托拽
+      isDown: false,
+      coord: {
+        x: 0,
+        y: 0
+      }
+    }
+  }
+})
diff --git a/src/directives/style.scss b/src/directives/style.scss
new file mode 100644
index 0000000..095e057
--- /dev/null
+++ b/src/directives/style.scss
@@ -0,0 +1,2 @@
+@import './empty/empty.scss';
+@import './photo/photo.scss';
\ No newline at end of file
diff --git a/src/filters/index.js b/src/filters/index.js
new file mode 100644
index 0000000..a9584a1
--- /dev/null
+++ b/src/filters/index.js
@@ -0,0 +1,35 @@
+// set function formatTime to filter
+import {
+  timestampToFormatTime,
+  formatTimeToTimestamp
+} from '@/utils'
+
+/**
+ * 时间戳到格式化时间
+ * {{item.createTime|filterTimestampToFormatTime('MM-DD dddd')}}
+ * @param {*} time
+ * @param {*} cFormat
+ */
+export function filterTimestampToFormatTime (time, cFormat) {
+  if (!cFormat) {
+    cFormat = 'YYYY-MM-DD HH:mm'
+  }
+  if (!time || time === 0) {
+    return ''
+  }
+  return timestampToFormatTime(time, cFormat)
+}
+
+/** 格式化时间到时间戳 */
+export function filterFormatTimeToTimestamp (format) {
+  return formatTimeToTimestamp(format)
+}
+
+/** 用户头像的占位图标 */
+export function filterUserLazyImg (value) {
+  return {
+    src: value,
+    error: require('@/assets/img/head.png'),
+    loading: require('@/assets/img/loading.gif')
+  }
+}
diff --git a/src/main.js b/src/main.js
new file mode 100644
index 0000000..16f1d7a
--- /dev/null
+++ b/src/main.js
@@ -0,0 +1,88 @@
+// The Vue build version to load with the `import` command
+// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
+import Vue from 'vue'
+import App from './App'
+import router from './router'
+
+// 组件ElementUI
+import ElementUI from 'element-ui'
+import 'element-ui/lib/theme-chalk/index.css'
+
+// vuex状态管理
+import store from './store'
+// 样式
+import less from 'less'
+import '@/styles/index.scss' // global css
+import '@/styles/animate.css'
+
+// 自定义全局点击空白处组件
+import clickoutside from './directives' // global filters
+import focus from './directives/focus'
+import empty from './directives/empty'
+import photo from './directives/photo'
+import Lockr from 'lockr'
+/** 常用flex组件 */
+import {
+  Flexbox,
+  FlexboxItem
+} from '@/components/flexbox'
+/** 事件传递 */
+import VueBus from 'vue-bus'
+/** 懒加载图片 */
+import VueLazyload from 'vue-lazyload'
+import * as filters from './filters'
+import moment from 'moment'
+// 表情
+import {
+  emoji
+} from './utils/emoji' // global filters
+import fullCalendar from 'vue-fullcalendar'
+// import cache from '@/utils/cache'
+import 'lib-flexible'
+
+// cache.loadingCache()
+
+Vue.component('full-calendar', fullCalendar)
+
+// 注册全局过滤器
+Object.keys(filters).forEach(key => {
+  Vue.filter(key, filters[key])
+})
+
+// 处理时间的过滤器
+Vue.use(require('vue-moment'))
+moment.locale('zh_cn')
+
+Vue.use(VueLazyload, {
+  preLoad: 1.3,
+  error: require('@/assets/img/send_img.png'),
+  loading: require('@/assets/img/loading.gif'),
+  attempt: 1
+})
+
+Vue.prototype.emoji = emoji
+
+Vue.use(VueBus)
+Vue.component('flexbox', Flexbox)
+Vue.component('flexbox-item', FlexboxItem)
+Vue.use(empty)
+Vue.use(photo) // 本地存储插件
+console.log(process.env.NODE_ENV)
+
+window.Lockr = Lockr // 使用本地存储插件
+Vue.directive('clickoutside', clickoutside)
+Vue.directive('focus', focus)
+Vue.use(ElementUI, {zIndex: 3000})
+
+Vue.use(less)
+
+Vue.config.productionTip = false
+
+/* eslint-disable no-new */
+new Vue({
+  el: '#app',
+  router,
+  store,
+  components: { App },
+  template: '<App/>'
+})
diff --git a/src/router/index.js b/src/router/index.js
new file mode 100644
index 0000000..7b3bf2b
--- /dev/null
+++ b/src/router/index.js
@@ -0,0 +1,190 @@
+import Vue from 'vue'
+import VueRouter from 'vue-router'
+
+const Login = () =>
+    import('@/views/login/index')
+const Logining = () =>
+    import('@/views/login/logining')
+const Home = () =>
+    import('@/views/home/Home')
+const Welcome = () =>
+    import('@/views/welcome/Welcome')
+    // 销售模块
+const ClientsManage = () =>
+    import('@/views/clients/customer/clientsManage')
+const ClueIndex = () =>
+    import('@/views/clients/clue/ClueIndex')
+const ContactsIndex = () =>
+    import('@/views/clients/contacts/ContactsIndex')
+const BusinessIndex = () =>
+    import('@/views/clients/business/BusinessIndex')
+const ContractIndex = () =>
+    import('@/views/clients/contract/ContractIndex')
+const OfferIndex = () =>
+    import('@/views/clients/offers/OfferIndex')
+const ProductIndex = () =>
+    import('@/views/clients/product/ProductIndex')
+const EmployeeManage = () =>
+    import('@/views/company/employeeManage/EmployeeManage')
+const OffcialAuthority = () =>
+    import('@/views/company/offcialAuthority')
+const StaffLog = () =>
+    import('@/views/company/staffLog')
+const ApartmentManage = () =>
+    import('@/views/company/ApartmentManage')
+const SystemSetting = () =>
+    import('@/views/company/systemSetting')
+const ModuleManage = () =>
+    import('@/views/module/ModuleManage')
+    // 人事模块
+const SealContractIndex = () =>
+    import('@/views/clients/sealContract/SealContractIndex')
+const SealOfferIndex = () =>
+    import('@/views/clients/sealOffers/SealOfferIndex')
+    // 商务模块
+const BusinessCustomerManage = () =>
+    import('@/views/clients/businessCustomer/BusinessCustomerManage')
+const BusinessChancesIndex = () =>
+    import('@/views/clients/businessChances/BusinessChancesIndex')
+const BusinessContractsIndex = () =>
+    import('@/views/clients/businessContracts/BusinessContractsIndex')
+    // PWS API
+const EwsAnalyze = () =>
+    import('@/views/PWS/EwsAnalyze')
+const Subscriptions = () =>
+    import('@/views/PWS/Subscriptions')
+
+Vue.use(VueRouter)
+
+const routes = [{
+  path: '',
+  redirect: '/login'
+},
+{
+  path: '/login',
+  component: Login
+},
+{
+  path: '/logining',
+  component: Logining
+},
+{
+  path: '/home',
+  component: Home,
+  redirect: '/welcome',
+  children: [{
+    path: '/welcome',
+    component: Welcome
+  },
+  {
+    path: '/ModuleManage',
+    component: ModuleManage
+  },
+  {
+    path: '/clientsManage',
+    component: ClientsManage
+  },
+  {
+    path: '/ClueIndex',
+    component: ClueIndex
+  },
+  {
+    path: '/ContactsIndex',
+    component: ContactsIndex
+  },
+  {
+    path: '/BusinessIndex',
+    component: BusinessIndex
+  },
+  {
+    path: '/ContractIndex',
+    component: ContractIndex
+  },
+  {
+    path: '/OfferIndex',
+    component: OfferIndex
+  },
+  {
+    path: '/SealContractIndex',
+    component: SealContractIndex
+  },
+  {
+    path: '/SealOfferIndex',
+    component: SealOfferIndex
+  },
+  {
+    path: '/BusinessCustomerManage',
+    component: BusinessCustomerManage
+  },
+  {
+    path: '/BusinessChancesIndex',
+    component: BusinessChancesIndex
+  },
+  {
+    path: '/BusinessContractsIndex',
+    component: BusinessContractsIndex
+  },
+  {
+    path: '/ProductIndex',
+    component: ProductIndex
+  },
+  {
+    path: '/ApartmentManage',
+    component: ApartmentManage
+  },
+  {
+    path: '/offcialAuthority',
+    component: OffcialAuthority
+  },
+  {
+    path: '/staffLog',
+    component: StaffLog
+  },
+  {
+    path: '/EmployeeManage',
+    component: EmployeeManage
+  },
+  {
+    path: '/systemSetting',
+    component: SystemSetting
+  },
+  {
+    path: '/ewsAnalyze',
+    component: EwsAnalyze
+  },
+  {
+    path: '/Subscriptions',
+    component: Subscriptions
+  }
+  ]
+}
+]
+
+const router = new VueRouter({
+  routes,
+  mode: 'hash'
+})
+
+// 路由导航守卫,在跳转前判断
+router.beforeEach((to, from, next) => {
+  if (window.location.href.indexOf('code') >= 0) { // 如果code存在
+    // 如果url中包含code   split?分割成数组,取第二个
+    let code = window.location.href.split('?')[1]
+    console.log(window.location.href)
+    code = code.substring(5, code.indexOf('&')) // 截取字符串第6位开始截取直到&出现截取成功
+    console.log(code)
+    sessionStorage.setItem('code', code)
+    next()
+  } else {
+    if (to.path === '/login') { // 如果是登录页
+      localStorage.removeItem('token')
+    }
+    if (!localStorage.getItem('token') && to.path !== '/login') { // 如果token不存在 并且 不是mylogin页面
+      next({ path: '/login' })
+    } else {
+      next()
+    }
+  }
+})
+
+export default router
diff --git a/src/store/getters.js b/src/store/getters.js
new file mode 100644
index 0000000..57737fe
--- /dev/null
+++ b/src/store/getters.js
@@ -0,0 +1,48 @@
+const getters = {
+  moduleBlock: state => state.user.moduleBlock
+  // userInfo: state => state.user.userInfo,
+  // lang: state => state.app.lang,
+  // logo: state => {
+  //   if (state.app.logo) {
+  //     return state.app.logo
+  //   }
+  //   return require('@/assets/img/logo.jpg')
+  // },
+  // name: state => {
+  //   if (state.app.name) {
+  //     return state.app.name
+  //   }
+  //   return '东晨工元CRM系统'
+  // },
+  // activeIndex: state => state.app.sidebar.activeIndex,
+  // navActiveIndex: state => state.app.navbar.activeIndex,
+  // // 权限
+  // allAuth: state => state.user.allAuth,
+  // crm: state => state.user.crm,
+  // bi: state => state.user.bi,
+  // manage: state => state.user.manage,
+  // oa: state => state.user.oa,
+  // project: state => state.user.project,
+  // // 路由
+  // addRouters: state => state.permission.addRouters,
+  // oaRouters: state => state.permission.oaRouters,
+  // crmRouters: state => state.permission.crmRouters,
+  // biRouters: state => state.permission.biRouters,
+  // manageRouters: state => state.permission.manageRouters,
+  // // 客户管理信息
+  // messageNum: state => state.customer.messageNum,
+  // messageOANum: state => state.oa.messageOANum,
+  // // 配置信息
+  // CRMConfig: state => state.app.CRMConfig
+}
+/**
+ * 使用说明
+ * import { mapGetters } from 'vuex'
+ * computed: {
+    ...mapGetters([
+      'userInfo'
+    ])
+  }
+ */
+
+export default getters
diff --git a/src/store/index.js b/src/store/index.js
new file mode 100644
index 0000000..76da196
--- /dev/null
+++ b/src/store/index.js
@@ -0,0 +1,24 @@
+
+import Vue from 'vue'
+import Vuex from 'vuex'
+import user from './modules/user'
+// import permission from './modules/permission'
+// import app from './modules/app'
+// import oa from './modules/oa'
+// import customer from './modules/customer'
+import getters from './getters'
+
+Vue.use(Vuex)
+
+const store = new Vuex.Store({
+  modules: {
+    // app,
+    // permission,
+    // oa,
+    user
+    // customer
+  },
+  getters
+})
+
+export default store
diff --git a/src/store/modules/app.js b/src/store/modules/app.js
new file mode 100644
index 0000000..8415e4f
--- /dev/null
+++ b/src/store/modules/app.js
@@ -0,0 +1,85 @@
+// import {
+//   adminSystemIndex
+// } from '@/api/systemManagement/SystemConfig'
+// import {
+//   crmSettingConfigData
+// } from '@/api/systemManagement/SystemCustomer'
+// import Lockr from 'lockr'
+
+/** 记录 侧边索引 */
+const app = {
+  state: {
+    logo: '',
+    name: '',
+    lang: localStorage.lang || 'cn',
+    sidebar: {
+      activeIndex: '' // 目前激活的 行
+    },
+    navbar: {
+      activeIndex: '' // 导航目前是第几个 个人中心需要
+    },
+    /** CRM配置信息 */
+    CRMConfig: {}
+  },
+
+  mutations: {
+    SET_ACTIVEINDEX: (state, path) => {
+      state.sidebar.activeIndex = path
+    },
+    SET_NAVACTIVEINDEX: (state, path) => {
+      state.navbar.activeIndex = path
+    },
+    SET_APPLOGO: (state, logo) => {
+      state.logo = logo
+    },
+    SET_APPNAME: (state, name) => {
+      state.name = name
+    },
+    SET_LANG: (state, lang) => {
+      state.lang = lang
+      window.app.$i18n.locale = lang
+      localStorage.setItem('lang', lang)
+      window.location.reload()
+    },
+    SET_CRMCONFIG: (state, config) => {
+      state.CRMConfig = config
+    }
+  },
+
+  actions: {
+    // 登录
+    SystemLogoAndName ({
+      commit
+    }) {
+      return new Promise((resolve, reject) => {
+        // adminSystemIndex().then(response => {
+        //   commit('SET_APPNAME', response.data.name)
+        //   commit('SET_APPLOGO', response.data.logo)
+        //   Lockr.set('systemLogo', response.data.logo)
+        //   Lockr.set('systemName', response.data.name)
+        //   resolve(response)
+        // }).catch(error => {
+        //   reject(error)
+        // })
+      })
+    },
+
+    /**
+     * 获取客户管理配置
+     */
+    CRMSettingConfig ({
+      commit
+    }) {
+      return new Promise((resolve, reject) => {
+        // crmSettingConfigData().then(response => {
+        //   commit('SET_CRMCONFIG', response.data)
+        //   resolve(response)
+        // }).catch(error => {
+        //   reject(error)
+        // })
+      })
+    }
+  }
+}
+
+export default app
diff --git a/src/store/modules/customer.js b/src/store/modules/customer.js
new file mode 100644
index 0000000..3fda8dd
--- /dev/null
+++ b/src/store/modules/customer.js
@@ -0,0 +1,61 @@
+// import {
+//   crmMessagNumAPI
+// } from '@/api/clients/message'
+
+/**
+ * 消息记录
+ */
+const app = {
+  state: {
+    // 待办事项消息
+    messageNum: {
+      todayCustomer: 0,
+      followLeads: 0,
+      followCustomer: 0,
+      checkContract: 0,
+      checkReceivables: 0,
+      remindReceivablesPlan: 0,
+      endContract: 0,
+      totalNum: 0
+    }
+  },
+
+  mutations: {
+    /**
+     * 更改待办事项
+     */
+    SET_MESSAGENUM: (state, messageNum) => {
+      let totalNum = 0
+      for (const key in messageNum) {
+        if (key !== 'totalNum') {
+          totalNum += (messageNum[key] || 0)
+        }
+      }
+      messageNum.totalNum = totalNum
+      state.messageNum = messageNum
+    }
+  },
+
+  actions: {
+    // 登录
+    // GetMessageNum({
+    //   state,
+    //   commit
+    // }) {
+    //   return new Promise((resolve, reject) => {
+    //     crmMessagNumAPI()
+    //       .then(response => {
+    //         commit('SET_MESSAGENUM', response.data)
+    //         commit('SET_CRMROUTERSNUM', state.messageNum.totalNum)
+    //         resolve(response)
+    //       })
+    //       .catch(error => {
+    //         reject(error)
+    //       })
+    //   })
+    // }
+
+  }
+}
+
+export default app
diff --git a/src/store/modules/oa.js b/src/store/modules/oa.js
new file mode 100644
index 0000000..778da1d
--- /dev/null
+++ b/src/store/modules/oa.js
@@ -0,0 +1,70 @@
+import {
+  oaMessageNumAPI
+} from '@/api/oamanagement/workbench'
+import {
+  objDeepCopy
+} from '@/utils'
+
+/**
+ * 消息记录
+ */
+const oa = {
+  state: {
+    // 待办事项消息
+    messageOANum: {
+      eventNum: 0,
+      taskNum: 0,
+      announcementNum: 0,
+      logNum: 0,
+      examineNum: 0
+    }
+  },
+
+  mutations: {
+    /**
+     * 更改待办事项
+     */
+    SET_MESSAGEOANUM: (state, messageOANum) => {
+      state.messageOANum = messageOANum
+    }
+  },
+
+  actions: {
+    /**
+     * 获取待办消息数
+     * @param {*} param
+     */
+    GetOAMessageNum({
+      state,
+      commit
+    }, type) {
+      return new Promise((resolve, reject) => {
+        const params = {}
+        if (type) {
+          params.type = type
+        }
+        oaMessageNumAPI(params)
+          .then(response => {
+            if (type) {
+              const copyNum = objDeepCopy(state.messageOANum)
+              copyNum[type + 'Num'] = response.data[type + 'Num'] || 0
+              commit('SET_MESSAGEOANUM', copyNum)
+            } else {
+              commit('SET_MESSAGEOANUM', response.data)
+            }
+            if (resolve) {
+              resolve(response)
+            }
+          })
+          .catch(error => {
+            if (reject) {
+              reject(error)
+            }
+          })
+      })
+    }
+
+  }
+}
+
+export default oa
diff --git a/src/store/modules/permission.js b/src/store/modules/permission.js
new file mode 100644
index 0000000..772165a
--- /dev/null
+++ b/src/store/modules/permission.js
@@ -0,0 +1,141 @@
+import {
+  asyncRouterMap
+} from '@/router'
+import Vue from 'vue'
+
+/**
+ *
+ * @param {*} router
+ * @param {*} authInfo
+ */
+function checkAuth(router, authInfo) {
+  // 判断当前路由在权限数组中是否存在
+  if (router.meta) {
+    const metaInfo = router.meta
+    if (!metaInfo.requiresAuth) {
+      return true
+    } else {
+      if (metaInfo.index === 0) {
+        return !!authInfo[metaInfo.type]
+      } else if (metaInfo.index === 1) {
+        if (authInfo[metaInfo.type]) {
+          return !!authInfo[metaInfo.type][metaInfo.subType]
+        }
+        return false
+      } else {
+        var typeAuth = authInfo[metaInfo.type]
+        for (let index = 0; index < metaInfo.subType.length; index++) {
+          const field = metaInfo.subType[index]
+          typeAuth = typeAuth[field]
+          if (typeAuth && metaInfo.subType.length - 1 === index) {
+            return true
+          } else if (!typeAuth) {
+            return false
+          }
+        }
+      }
+    }
+  }
+  return true
+}
+
+/**
+ *
+ * @param {*} routers
+ * @param {*} authInfo
+ */
+const filterAsyncRouter = function(routers, authInfo) {
+  const res = []
+  routers.forEach(router => {
+    const tmp = {
+      ...router
+    }
+    if (checkAuth(tmp, authInfo)) {
+      if (tmp.children) {
+        tmp.children = filterAsyncRouter(tmp.children, authInfo)
+      }
+      res.push(tmp)
+    }
+  })
+  return res
+}
+
+const permission = {
+  state: {
+    addRouters: [],
+    crmRouters: {
+      name: 'crm',
+      children: []
+    },
+    biRouters: {
+      name: 'bi',
+      children: []
+    },
+    manageRouters: {
+      name: 'manager',
+      children: []
+    },
+    oaRouters: {
+      name: 'oa',
+      children: []
+    }
+  },
+  mutations: {
+    SET_ROUTERS: (state, routers) => {
+      state.addRouters = routers
+      for (let index = 0; index < routers.length; index++) {
+        const element = routers[index]
+        if (element.name === 'oa') {
+          state.oaRouters = element
+        } else if (element.name === 'crm') {
+          state.crmRouters = element
+        } else if (element.name === 'bi') {
+          state.biRouters = element
+        } else if (element.name === 'manager') {
+          state.manageRouters = element
+        }
+      }
+    },
+
+    /**
+     * 客户管理待办消息数
+     */
+    SET_CRMROUTERSNUM: (state, num) => {
+      const messageItem = state.crmRouters.children[1]
+      messageItem.meta.num = num
+      Vue.set(state.crmRouters.children, 1, messageItem)
+    }
+  },
+  actions: {
+    GenerateRoutes({
+      commit
+    }, data) {
+      return new Promise(resolve => {
+        const accessedRouters = filterAsyncRouter(asyncRouterMap, data)
+        let redirect = ''
+        for (let index = 0; index < accessedRouters.length; index++) {
+          const element = accessedRouters[index]
+          if (element.children && element.children.length > 0) {
+            element.redirect = element.path + '/' + element.children[0].path
+          }
+
+          // 获取跳转
+          if (element.redirect && !redirect) {
+            redirect = element.redirect
+          }
+        }
+        if (redirect) {
+          accessedRouters.push({
+            path: '/',
+            redirect: redirect,
+            hidden: true
+          })
+        }
+        commit('SET_ROUTERS', accessedRouters)
+        resolve()
+      })
+    }
+  }
+}
+
+export default permission
diff --git a/src/store/modules/user.js b/src/store/modules/user.js
new file mode 100644
index 0000000..fad2856
--- /dev/null
+++ b/src/store/modules/user.js
@@ -0,0 +1,134 @@
+// import {
+//   login
+// } from '@/api/login'
+// import {
+//   adminIndexAuthList
+// } from '@/api/common'
+
+// import {
+//   adminUsersRead
+// } from '@/api/personCenter/personCenter'
+// import {
+// addAuth,
+// removeAuth
+// } from '@/utils/auth'
+import Lockr from 'lockr'
+import { GetCurrentUserModules } from '@/api/moduleManage/moduleManage'
+
+const user = {
+  state: {
+    userInfo: null, // 用户信息
+    // 权限信息
+    allAuth: null, // 总权限信息 默认空 调整动态路由
+    crm: {}, // 客户管理
+    bi: {}, // 商业智能
+    manage: {}, // 管理后台
+    oa: {}, // 办公
+    project: {}, // 项目管理
+    moduleBlock: {} // 模块管理
+  },
+
+  mutations: {
+    SET_USERINFO: (state, userInfo) => {
+      state.userInfo = userInfo
+    },
+    SET_ALLAUTH: (state, allAuth) => {
+      state.allAuth = allAuth
+    },
+    SET_CRM: (state, crm) => {
+      state.crm = crm
+    },
+    SET_BI: (state, bi) => {
+      state.bi = bi
+    },
+    SET_MANAGE: (state, manage) => {
+      state.manage = manage
+    },
+    SET_OA: (state, oa) => {
+      state.oa = oa
+    },
+    SET_PROJECT: (state, project) => {
+      state.project = project
+    },
+    SET_MODULE: (state, moduleBlock) => {
+      state.moduleBlock = moduleBlock
+    }
+  },
+
+  actions: {
+    // 登录
+    Login ({
+      commit
+    }, userInfo) {
+      return new Promise((resolve, reject) => {
+        // login(userInfo).then(data => {
+        // Lockr.set('Admin-Token', data['Admin-Token'])
+        // Lockr.set('loginUserInfo', data.user)
+
+        // Lockr.set('authList', data.auth)
+
+        // addAuth(data['Admin-Token'])
+        // commit('SET_USERINFO', data.user)
+        // // 权限
+        // commit('SET_ALLAUTH', data.auth)
+        // commit('SET_CRM', data.auth.crm)
+        // commit('SET_BI', data.auth.bi)
+        // commit('SET_MANAGE', data.auth.manage)
+        // commit('SET_OA', data.auth.oa)
+        // commit('SET_PROJECT', data.auth.project)
+        //   resolve(data)
+        // }).catch(error => {
+        //   reject(error)
+        // })
+      })
+    },
+
+    // 获取权限
+    getAuth ({
+      commit
+    }) {
+      return new Promise((resolve, reject) => {
+        GetCurrentUserModules().then((response) => {
+          const data = response.data.Result
+          Lockr.set('authList', data)
+          commit('SET_MODULE', data)
+          resolve(data)
+        }).catch(error => {
+          reject(error)
+        })
+      })
+    },
+
+    // 获取用户信息
+    GetUserInfo ({
+      commit,
+      state
+    }) {
+      return new Promise((resolve, reject) => {
+        // adminUsersRead().then(response => {
+        //   commit('SET_USERINFO', response.data)
+        //   resolve(response)
+        // }).catch(error => {
+        //   reject(error)
+        // })
+      })
+    },
+
+    // 登出
+    LogOut ({
+      commit
+    }) {
+      return new Promise((resolve, reject) => {
+        // logout().then(() => {
+        //   /** flush 清空localStorage .rm('authKey') 按照key清除 */
+        //   removeAuth()
+        //   resolve()
+        // }).catch(error => {
+        //   reject(error)
+        // })
+      })
+    }
+  }
+}
+
+export default user
diff --git a/src/styles/animate.css b/src/styles/animate.css
new file mode 100644
index 0000000..943f845
--- /dev/null
+++ b/src/styles/animate.css
@@ -0,0 +1,3623 @@
+@charset "UTF-8";
+
+/*!
+ * animate.css -http://daneden.me/animate
+ * Version - 3.7.0
+ * Licensed under the MIT license - http://opensource.org/licenses/MIT
+ *
+ * Copyright (c) 2018 Daniel Eden
+ */
+
+@-webkit-keyframes bounce {
+  from,
+  20%,
+  53%,
+  80%,
+  to {
+    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+
+  40%,
+  43% {
+    -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
+    animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
+    -webkit-transform: translate3d(0, -30px, 0);
+    transform: translate3d(0, -30px, 0);
+  }
+
+  70% {
+    -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
+    animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
+    -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 {
+  from,
+  20%,
+  53%,
+  80%,
+  to {
+    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+
+  40%,
+  43% {
+    -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
+    animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
+    -webkit-transform: translate3d(0, -30px, 0);
+    transform: translate3d(0, -30px, 0);
+  }
+
+  70% {
+    -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
+    animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
+    -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 {
+  from,
+  50%,
+  to {
+    opacity: 1;
+  }
+
+  25%,
+  75% {
+    opacity: 0;
+  }
+}
+
+@keyframes flash {
+  from,
+  50%,
+  to {
+    opacity: 1;
+  }
+
+  25%,
+  75% {
+    opacity: 0;
+  }
+}
+
+.flash {
+  -webkit-animation-name: flash;
+  animation-name: flash;
+}
+
+/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */
+
+@-webkit-keyframes pulse {
+  from {
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+
+  50% {
+    -webkit-transform: scale3d(1.05, 1.05, 1.05);
+    transform: scale3d(1.05, 1.05, 1.05);
+  }
+
+  to {
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+}
+
+@keyframes pulse {
+  from {
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+
+  50% {
+    -webkit-transform: scale3d(1.05, 1.05, 1.05);
+    transform: scale3d(1.05, 1.05, 1.05);
+  }
+
+  to {
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+}
+
+.pulse {
+  -webkit-animation-name: pulse;
+  animation-name: pulse;
+}
+
+@-webkit-keyframes rubberBand {
+  from {
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+
+  30% {
+    -webkit-transform: scale3d(1.25, 0.75, 1);
+    transform: scale3d(1.25, 0.75, 1);
+  }
+
+  40% {
+    -webkit-transform: scale3d(0.75, 1.25, 1);
+    transform: scale3d(0.75, 1.25, 1);
+  }
+
+  50% {
+    -webkit-transform: scale3d(1.15, 0.85, 1);
+    transform: scale3d(1.15, 0.85, 1);
+  }
+
+  65% {
+    -webkit-transform: scale3d(0.95, 1.05, 1);
+    transform: scale3d(0.95, 1.05, 1);
+  }
+
+  75% {
+    -webkit-transform: scale3d(1.05, 0.95, 1);
+    transform: scale3d(1.05, 0.95, 1);
+  }
+
+  to {
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+}
+
+@keyframes rubberBand {
+  from {
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+
+  30% {
+    -webkit-transform: scale3d(1.25, 0.75, 1);
+    transform: scale3d(1.25, 0.75, 1);
+  }
+
+  40% {
+    -webkit-transform: scale3d(0.75, 1.25, 1);
+    transform: scale3d(0.75, 1.25, 1);
+  }
+
+  50% {
+    -webkit-transform: scale3d(1.15, 0.85, 1);
+    transform: scale3d(1.15, 0.85, 1);
+  }
+
+  65% {
+    -webkit-transform: scale3d(0.95, 1.05, 1);
+    transform: scale3d(0.95, 1.05, 1);
+  }
+
+  75% {
+    -webkit-transform: scale3d(1.05, 0.95, 1);
+    transform: scale3d(1.05, 0.95, 1);
+  }
+
+  to {
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+}
+
+.rubberBand {
+  -webkit-animation-name: rubberBand;
+  animation-name: rubberBand;
+}
+
+@-webkit-keyframes shake {
+  from,
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 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 {
+  from,
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 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: rotate3d(0, 0, 1, 15deg);
+    transform: rotate3d(0, 0, 1, 15deg);
+  }
+
+  40% {
+    -webkit-transform: rotate3d(0, 0, 1, -10deg);
+    transform: rotate3d(0, 0, 1, -10deg);
+  }
+
+  60% {
+    -webkit-transform: rotate3d(0, 0, 1, 5deg);
+    transform: rotate3d(0, 0, 1, 5deg);
+  }
+
+  80% {
+    -webkit-transform: rotate3d(0, 0, 1, -5deg);
+    transform: rotate3d(0, 0, 1, -5deg);
+  }
+
+  to {
+    -webkit-transform: rotate3d(0, 0, 1, 0deg);
+    transform: rotate3d(0, 0, 1, 0deg);
+  }
+}
+
+@keyframes swing {
+  20% {
+    -webkit-transform: rotate3d(0, 0, 1, 15deg);
+    transform: rotate3d(0, 0, 1, 15deg);
+  }
+
+  40% {
+    -webkit-transform: rotate3d(0, 0, 1, -10deg);
+    transform: rotate3d(0, 0, 1, -10deg);
+  }
+
+  60% {
+    -webkit-transform: rotate3d(0, 0, 1, 5deg);
+    transform: rotate3d(0, 0, 1, 5deg);
+  }
+
+  80% {
+    -webkit-transform: rotate3d(0, 0, 1, -5deg);
+    transform: rotate3d(0, 0, 1, -5deg);
+  }
+
+  to {
+    -webkit-transform: rotate3d(0, 0, 1, 0deg);
+    transform: rotate3d(0, 0, 1, 0deg);
+  }
+}
+
+.swing {
+  -webkit-transform-origin: top center;
+  transform-origin: top center;
+  -webkit-animation-name: swing;
+  animation-name: swing;
+}
+
+@-webkit-keyframes tada {
+  from {
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+
+  10%,
+  20% {
+    -webkit-transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg);
+    transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg);
+  }
+
+  30%,
+  50%,
+  70%,
+  90% {
+    -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
+    transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
+  }
+
+  40%,
+  60%,
+  80% {
+    -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
+    transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
+  }
+
+  to {
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+}
+
+@keyframes tada {
+  from {
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+
+  10%,
+  20% {
+    -webkit-transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg);
+    transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg);
+  }
+
+  30%,
+  50%,
+  70%,
+  90% {
+    -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
+    transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
+  }
+
+  40%,
+  60%,
+  80% {
+    -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
+    transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
+  }
+
+  to {
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+}
+
+.tada {
+  -webkit-animation-name: tada;
+  animation-name: tada;
+}
+
+/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */
+
+@-webkit-keyframes wobble {
+  from {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+
+  15% {
+    -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
+    transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
+  }
+
+  30% {
+    -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
+    transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
+  }
+
+  45% {
+    -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
+    transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
+  }
+
+  60% {
+    -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
+    transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
+  }
+
+  75% {
+    -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
+    transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
+  }
+
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+@keyframes wobble {
+  from {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+
+  15% {
+    -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
+    transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
+  }
+
+  30% {
+    -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
+    transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
+  }
+
+  45% {
+    -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
+    transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
+  }
+
+  60% {
+    -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
+    transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
+  }
+
+  75% {
+    -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
+    transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
+  }
+
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+.wobble {
+  -webkit-animation-name: wobble;
+  animation-name: wobble;
+}
+
+@-webkit-keyframes jello {
+  from,
+  11.1%,
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+
+  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(-0.78125deg) skewY(-0.78125deg);
+    transform: skewX(-0.78125deg) skewY(-0.78125deg);
+  }
+
+  77.7% {
+    -webkit-transform: skewX(0.390625deg) skewY(0.390625deg);
+    transform: skewX(0.390625deg) skewY(0.390625deg);
+  }
+
+  88.8% {
+    -webkit-transform: skewX(-0.1953125deg) skewY(-0.1953125deg);
+    transform: skewX(-0.1953125deg) skewY(-0.1953125deg);
+  }
+}
+
+@keyframes jello {
+  from,
+  11.1%,
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+
+  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(-0.78125deg) skewY(-0.78125deg);
+    transform: skewX(-0.78125deg) skewY(-0.78125deg);
+  }
+
+  77.7% {
+    -webkit-transform: skewX(0.390625deg) skewY(0.390625deg);
+    transform: skewX(0.390625deg) skewY(0.390625deg);
+  }
+
+  88.8% {
+    -webkit-transform: skewX(-0.1953125deg) skewY(-0.1953125deg);
+    transform: skewX(-0.1953125deg) skewY(-0.1953125deg);
+  }
+}
+
+.jello {
+  -webkit-animation-name: jello;
+  animation-name: jello;
+  -webkit-transform-origin: center;
+  transform-origin: center;
+}
+
+@-webkit-keyframes heartBeat {
+  0% {
+    -webkit-transform: scale(1);
+    transform: scale(1);
+  }
+
+  14% {
+    -webkit-transform: scale(1.3);
+    transform: scale(1.3);
+  }
+
+  28% {
+    -webkit-transform: scale(1);
+    transform: scale(1);
+  }
+
+  42% {
+    -webkit-transform: scale(1.3);
+    transform: scale(1.3);
+  }
+
+  70% {
+    -webkit-transform: scale(1);
+    transform: scale(1);
+  }
+}
+
+@keyframes heartBeat {
+  0% {
+    -webkit-transform: scale(1);
+    transform: scale(1);
+  }
+
+  14% {
+    -webkit-transform: scale(1.3);
+    transform: scale(1.3);
+  }
+
+  28% {
+    -webkit-transform: scale(1);
+    transform: scale(1);
+  }
+
+  42% {
+    -webkit-transform: scale(1.3);
+    transform: scale(1.3);
+  }
+
+  70% {
+    -webkit-transform: scale(1);
+    transform: scale(1);
+  }
+}
+
+.heartBeat {
+  -webkit-animation-name: heartBeat;
+  animation-name: heartBeat;
+  -webkit-animation-duration: 1.3s;
+  animation-duration: 1.3s;
+  -webkit-animation-timing-function: ease-in-out;
+  animation-timing-function: ease-in-out;
+}
+
+@-webkit-keyframes bounceIn {
+  from,
+  20%,
+  40%,
+  60%,
+  80%,
+  to {
+    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+  }
+
+  0% {
+    opacity: 0;
+    -webkit-transform: scale3d(0.3, 0.3, 0.3);
+    transform: scale3d(0.3, 0.3, 0.3);
+  }
+
+  20% {
+    -webkit-transform: scale3d(1.1, 1.1, 1.1);
+    transform: scale3d(1.1, 1.1, 1.1);
+  }
+
+  40% {
+    -webkit-transform: scale3d(0.9, 0.9, 0.9);
+    transform: scale3d(0.9, 0.9, 0.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(0.97, 0.97, 0.97);
+    transform: scale3d(0.97, 0.97, 0.97);
+  }
+
+  to {
+    opacity: 1;
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+}
+
+@keyframes bounceIn {
+  from,
+  20%,
+  40%,
+  60%,
+  80%,
+  to {
+    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+  }
+
+  0% {
+    opacity: 0;
+    -webkit-transform: scale3d(0.3, 0.3, 0.3);
+    transform: scale3d(0.3, 0.3, 0.3);
+  }
+
+  20% {
+    -webkit-transform: scale3d(1.1, 1.1, 1.1);
+    transform: scale3d(1.1, 1.1, 1.1);
+  }
+
+  40% {
+    -webkit-transform: scale3d(0.9, 0.9, 0.9);
+    transform: scale3d(0.9, 0.9, 0.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(0.97, 0.97, 0.97);
+    transform: scale3d(0.97, 0.97, 0.97);
+  }
+
+  to {
+    opacity: 1;
+    -webkit-transform: scale3d(1, 1, 1);
+    transform: scale3d(1, 1, 1);
+  }
+}
+
+.bounceIn {
+  -webkit-animation-duration: 0.75s;
+  animation-duration: 0.75s;
+  -webkit-animation-name: bounceIn;
+  animation-name: bounceIn;
+}
+
+@-webkit-keyframes bounceInDown {
+  from,
+  60%,
+  75%,
+  90%,
+  to {
+    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    animation-timing-function: cubic-bezier(0.215, 0.61, 0.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: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+@keyframes bounceInDown {
+  from,
+  60%,
+  75%,
+  90%,
+  to {
+    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    animation-timing-function: cubic-bezier(0.215, 0.61, 0.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: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+.bounceInDown {
+  -webkit-animation-name: bounceInDown;
+  animation-name: bounceInDown;
+}
+
+@-webkit-keyframes bounceInLeft {
+  from,
+  60%,
+  75%,
+  90%,
+  to {
+    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    animation-timing-function: cubic-bezier(0.215, 0.61, 0.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: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+@keyframes bounceInLeft {
+  from,
+  60%,
+  75%,
+  90%,
+  to {
+    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    animation-timing-function: cubic-bezier(0.215, 0.61, 0.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: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+.bounceInLeft {
+  -webkit-animation-name: bounceInLeft;
+  animation-name: bounceInLeft;
+}
+
+@-webkit-keyframes bounceInRight {
+  from,
+  60%,
+  75%,
+  90%,
+  to {
+    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+  }
+
+  from {
+    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: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+@keyframes bounceInRight {
+  from,
+  60%,
+  75%,
+  90%,
+  to {
+    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+  }
+
+  from {
+    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: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+.bounceInRight {
+  -webkit-animation-name: bounceInRight;
+  animation-name: bounceInRight;
+}
+
+@-webkit-keyframes bounceInUp {
+  from,
+  60%,
+  75%,
+  90%,
+  to {
+    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+  }
+
+  from {
+    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: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+@keyframes bounceInUp {
+  from,
+  60%,
+  75%,
+  90%,
+  to {
+    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+  }
+
+  from {
+    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: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+.bounceInUp {
+  -webkit-animation-name: bounceInUp;
+  animation-name: bounceInUp;
+}
+
+@-webkit-keyframes bounceOut {
+  20% {
+    -webkit-transform: scale3d(0.9, 0.9, 0.9);
+    transform: scale3d(0.9, 0.9, 0.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(0.3, 0.3, 0.3);
+    transform: scale3d(0.3, 0.3, 0.3);
+  }
+}
+
+@keyframes bounceOut {
+  20% {
+    -webkit-transform: scale3d(0.9, 0.9, 0.9);
+    transform: scale3d(0.9, 0.9, 0.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(0.3, 0.3, 0.3);
+    transform: scale3d(0.3, 0.3, 0.3);
+  }
+}
+
+.bounceOut {
+  -webkit-animation-duration: 0.75s;
+  animation-duration: 0.75s;
+  -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 {
+  from {
+    opacity: 0;
+  }
+
+  to {
+    opacity: 1;
+  }
+}
+
+@keyframes fadeIn {
+  from {
+    opacity: 0;
+  }
+
+  to {
+    opacity: 1;
+  }
+}
+
+.fadeIn {
+  -webkit-animation-name: fadeIn;
+  animation-name: fadeIn;
+}
+
+@-webkit-keyframes fadeInDown {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(0, -100%, 0);
+    transform: translate3d(0, -100%, 0);
+  }
+
+  to {
+    opacity: 1;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+@keyframes fadeInDown {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(0, -100%, 0);
+    transform: translate3d(0, -100%, 0);
+  }
+
+  to {
+    opacity: 1;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+.fadeInDown {
+  -webkit-animation-name: fadeInDown;
+  animation-name: fadeInDown;
+}
+
+@-webkit-keyframes fadeInDownBig {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(0, -2000px, 0);
+    transform: translate3d(0, -2000px, 0);
+  }
+
+  to {
+    opacity: 1;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+@keyframes fadeInDownBig {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(0, -2000px, 0);
+    transform: translate3d(0, -2000px, 0);
+  }
+
+  to {
+    opacity: 1;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+.fadeInDownBig {
+  -webkit-animation-name: fadeInDownBig;
+  animation-name: fadeInDownBig;
+}
+
+@-webkit-keyframes fadeInLeft {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(-100%, 0, 0);
+    transform: translate3d(-100%, 0, 0);
+  }
+
+  to {
+    opacity: 1;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+@keyframes fadeInLeft {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(-100%, 0, 0);
+    transform: translate3d(-100%, 0, 0);
+  }
+
+  to {
+    opacity: 1;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+.fadeInLeft {
+  -webkit-animation-name: fadeInLeft;
+  animation-name: fadeInLeft;
+}
+
+@-webkit-keyframes fadeInLeftBig {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(-2000px, 0, 0);
+    transform: translate3d(-2000px, 0, 0);
+  }
+
+  to {
+    opacity: 1;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+@keyframes fadeInLeftBig {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(-2000px, 0, 0);
+    transform: translate3d(-2000px, 0, 0);
+  }
+
+  to {
+    opacity: 1;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+.fadeInLeftBig {
+  -webkit-animation-name: fadeInLeftBig;
+  animation-name: fadeInLeftBig;
+}
+
+@-webkit-keyframes fadeInRight {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(100%, 0, 0);
+    transform: translate3d(100%, 0, 0);
+  }
+
+  to {
+    opacity: 1;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+@keyframes fadeInRight {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(100%, 0, 0);
+    transform: translate3d(100%, 0, 0);
+  }
+
+  to {
+    opacity: 1;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+.fadeInRight {
+  -webkit-animation-name: fadeInRight;
+  animation-name: fadeInRight;
+}
+
+@-webkit-keyframes fadeInRightBig {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(2000px, 0, 0);
+    transform: translate3d(2000px, 0, 0);
+  }
+
+  to {
+    opacity: 1;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+@keyframes fadeInRightBig {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(2000px, 0, 0);
+    transform: translate3d(2000px, 0, 0);
+  }
+
+  to {
+    opacity: 1;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+.fadeInRightBig {
+  -webkit-animation-name: fadeInRightBig;
+  animation-name: fadeInRightBig;
+}
+
+@-webkit-keyframes fadeInUp {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(0, 100%, 0);
+    transform: translate3d(0, 100%, 0);
+  }
+
+  to {
+    opacity: 1;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+@keyframes fadeInUp {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(0, 100%, 0);
+    transform: translate3d(0, 100%, 0);
+  }
+
+  to {
+    opacity: 1;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+.fadeInUp {
+  -webkit-animation-name: fadeInUp;
+  animation-name: fadeInUp;
+}
+
+@-webkit-keyframes fadeInUpBig {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(0, 2000px, 0);
+    transform: translate3d(0, 2000px, 0);
+  }
+
+  to {
+    opacity: 1;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+@keyframes fadeInUpBig {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(0, 2000px, 0);
+    transform: translate3d(0, 2000px, 0);
+  }
+
+  to {
+    opacity: 1;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+.fadeInUpBig {
+  -webkit-animation-name: fadeInUpBig;
+  animation-name: fadeInUpBig;
+}
+
+@-webkit-keyframes fadeOut {
+  from {
+    opacity: 1;
+  }
+
+  to {
+    opacity: 0;
+  }
+}
+
+@keyframes fadeOut {
+  from {
+    opacity: 1;
+  }
+
+  to {
+    opacity: 0;
+  }
+}
+
+.fadeOut {
+  -webkit-animation-name: fadeOut;
+  animation-name: fadeOut;
+}
+
+@-webkit-keyframes fadeOutDown {
+  from {
+    opacity: 1;
+  }
+
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(0, 100%, 0);
+    transform: translate3d(0, 100%, 0);
+  }
+}
+
+@keyframes fadeOutDown {
+  from {
+    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 {
+  from {
+    opacity: 1;
+  }
+
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(0, 2000px, 0);
+    transform: translate3d(0, 2000px, 0);
+  }
+}
+
+@keyframes fadeOutDownBig {
+  from {
+    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 {
+  from {
+    opacity: 1;
+  }
+
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(-100%, 0, 0);
+    transform: translate3d(-100%, 0, 0);
+  }
+}
+
+@keyframes fadeOutLeft {
+  from {
+    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 {
+  from {
+    opacity: 1;
+  }
+
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(-2000px, 0, 0);
+    transform: translate3d(-2000px, 0, 0);
+  }
+}
+
+@keyframes fadeOutLeftBig {
+  from {
+    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 {
+  from {
+    opacity: 1;
+  }
+
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(100%, 0, 0);
+    transform: translate3d(100%, 0, 0);
+  }
+}
+
+@keyframes fadeOutRight {
+  from {
+    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 {
+  from {
+    opacity: 1;
+  }
+
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(2000px, 0, 0);
+    transform: translate3d(2000px, 0, 0);
+  }
+}
+
+@keyframes fadeOutRightBig {
+  from {
+    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 {
+  from {
+    opacity: 1;
+  }
+
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(0, -100%, 0);
+    transform: translate3d(0, -100%, 0);
+  }
+}
+
+@keyframes fadeOutUp {
+  from {
+    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 {
+  from {
+    opacity: 1;
+  }
+
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(0, -2000px, 0);
+    transform: translate3d(0, -2000px, 0);
+  }
+}
+
+@keyframes fadeOutUpBig {
+  from {
+    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 {
+  from {
+    -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0)
+      rotate3d(0, 1, 0, -360deg);
+    transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, -360deg);
+    -webkit-animation-timing-function: ease-out;
+    animation-timing-function: ease-out;
+  }
+
+  40% {
+    -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px)
+      rotate3d(0, 1, 0, -190deg);
+    transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px)
+      rotate3d(0, 1, 0, -190deg);
+    -webkit-animation-timing-function: ease-out;
+    animation-timing-function: ease-out;
+  }
+
+  50% {
+    -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px)
+      rotate3d(0, 1, 0, -170deg);
+    transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px)
+      rotate3d(0, 1, 0, -170deg);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+  }
+
+  80% {
+    -webkit-transform: perspective(400px) scale3d(0.95, 0.95, 0.95) translate3d(0, 0, 0)
+      rotate3d(0, 1, 0, 0deg);
+    transform: perspective(400px) scale3d(0.95, 0.95, 0.95) translate3d(0, 0, 0)
+      rotate3d(0, 1, 0, 0deg);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+  }
+
+  to {
+    -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0)
+      rotate3d(0, 1, 0, 0deg);
+    transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, 0deg);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+  }
+}
+
+@keyframes flip {
+  from {
+    -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0)
+      rotate3d(0, 1, 0, -360deg);
+    transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, -360deg);
+    -webkit-animation-timing-function: ease-out;
+    animation-timing-function: ease-out;
+  }
+
+  40% {
+    -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px)
+      rotate3d(0, 1, 0, -190deg);
+    transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px)
+      rotate3d(0, 1, 0, -190deg);
+    -webkit-animation-timing-function: ease-out;
+    animation-timing-function: ease-out;
+  }
+
+  50% {
+    -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px)
+      rotate3d(0, 1, 0, -170deg);
+    transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px)
+      rotate3d(0, 1, 0, -170deg);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+  }
+
+  80% {
+    -webkit-transform: perspective(400px) scale3d(0.95, 0.95, 0.95) translate3d(0, 0, 0)
+      rotate3d(0, 1, 0, 0deg);
+    transform: perspective(400px) scale3d(0.95, 0.95, 0.95) translate3d(0, 0, 0)
+      rotate3d(0, 1, 0, 0deg);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+  }
+
+  to {
+    -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0)
+      rotate3d(0, 1, 0, 0deg);
+    transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, 0deg);
+    -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 {
+  from {
+    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+    transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+    opacity: 0;
+  }
+
+  40% {
+    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+    transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+  }
+
+  60% {
+    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
+    transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
+    opacity: 1;
+  }
+
+  80% {
+    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
+    transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
+  }
+
+  to {
+    -webkit-transform: perspective(400px);
+    transform: perspective(400px);
+  }
+}
+
+@keyframes flipInX {
+  from {
+    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+    transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+    opacity: 0;
+  }
+
+  40% {
+    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+    transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+  }
+
+  60% {
+    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
+    transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
+    opacity: 1;
+  }
+
+  80% {
+    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
+    transform: perspective(400px) rotate3d(1, 0, 0, -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 {
+  from {
+    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+    transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+    opacity: 0;
+  }
+
+  40% {
+    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
+    transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+  }
+
+  60% {
+    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
+    transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
+    opacity: 1;
+  }
+
+  80% {
+    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
+    transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
+  }
+
+  to {
+    -webkit-transform: perspective(400px);
+    transform: perspective(400px);
+  }
+}
+
+@keyframes flipInY {
+  from {
+    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+    transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+    opacity: 0;
+  }
+
+  40% {
+    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
+    transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
+    -webkit-animation-timing-function: ease-in;
+    animation-timing-function: ease-in;
+  }
+
+  60% {
+    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
+    transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
+    opacity: 1;
+  }
+
+  80% {
+    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
+    transform: perspective(400px) rotate3d(0, 1, 0, -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 {
+  from {
+    -webkit-transform: perspective(400px);
+    transform: perspective(400px);
+  }
+
+  30% {
+    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+    transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+    opacity: 1;
+  }
+
+  to {
+    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+    transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+    opacity: 0;
+  }
+}
+
+@keyframes flipOutX {
+  from {
+    -webkit-transform: perspective(400px);
+    transform: perspective(400px);
+  }
+
+  30% {
+    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+    transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+    opacity: 1;
+  }
+
+  to {
+    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+    transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+    opacity: 0;
+  }
+}
+
+.flipOutX {
+  -webkit-animation-duration: 0.75s;
+  animation-duration: 0.75s;
+  -webkit-animation-name: flipOutX;
+  animation-name: flipOutX;
+  -webkit-backface-visibility: visible !important;
+  backface-visibility: visible !important;
+}
+
+@-webkit-keyframes flipOutY {
+  from {
+    -webkit-transform: perspective(400px);
+    transform: perspective(400px);
+  }
+
+  30% {
+    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg);
+    transform: perspective(400px) rotate3d(0, 1, 0, -15deg);
+    opacity: 1;
+  }
+
+  to {
+    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+    transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+    opacity: 0;
+  }
+}
+
+@keyframes flipOutY {
+  from {
+    -webkit-transform: perspective(400px);
+    transform: perspective(400px);
+  }
+
+  30% {
+    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg);
+    transform: perspective(400px) rotate3d(0, 1, 0, -15deg);
+    opacity: 1;
+  }
+
+  to {
+    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+    transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+    opacity: 0;
+  }
+}
+
+.flipOutY {
+  -webkit-animation-duration: 0.75s;
+  animation-duration: 0.75s;
+  -webkit-backface-visibility: visible !important;
+  backface-visibility: visible !important;
+  -webkit-animation-name: flipOutY;
+  animation-name: flipOutY;
+}
+
+@-webkit-keyframes lightSpeedIn {
+  from {
+    -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);
+    opacity: 1;
+  }
+
+  80% {
+    -webkit-transform: skewX(-5deg);
+    transform: skewX(-5deg);
+  }
+
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+@keyframes lightSpeedIn {
+  from {
+    -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);
+    opacity: 1;
+  }
+
+  80% {
+    -webkit-transform: skewX(-5deg);
+    transform: skewX(-5deg);
+  }
+
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+.lightSpeedIn {
+  -webkit-animation-name: lightSpeedIn;
+  animation-name: lightSpeedIn;
+  -webkit-animation-timing-function: ease-out;
+  animation-timing-function: ease-out;
+}
+
+@-webkit-keyframes lightSpeedOut {
+  from {
+    opacity: 1;
+  }
+
+  to {
+    -webkit-transform: translate3d(100%, 0, 0) skewX(30deg);
+    transform: translate3d(100%, 0, 0) skewX(30deg);
+    opacity: 0;
+  }
+}
+
+@keyframes lightSpeedOut {
+  from {
+    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 {
+  from {
+    -webkit-transform-origin: center;
+    transform-origin: center;
+    -webkit-transform: rotate3d(0, 0, 1, -200deg);
+    transform: rotate3d(0, 0, 1, -200deg);
+    opacity: 0;
+  }
+
+  to {
+    -webkit-transform-origin: center;
+    transform-origin: center;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+    opacity: 1;
+  }
+}
+
+@keyframes rotateIn {
+  from {
+    -webkit-transform-origin: center;
+    transform-origin: center;
+    -webkit-transform: rotate3d(0, 0, 1, -200deg);
+    transform: rotate3d(0, 0, 1, -200deg);
+    opacity: 0;
+  }
+
+  to {
+    -webkit-transform-origin: center;
+    transform-origin: center;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+    opacity: 1;
+  }
+}
+
+.rotateIn {
+  -webkit-animation-name: rotateIn;
+  animation-name: rotateIn;
+}
+
+@-webkit-keyframes rotateInDownLeft {
+  from {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    -webkit-transform: rotate3d(0, 0, 1, -45deg);
+    transform: rotate3d(0, 0, 1, -45deg);
+    opacity: 0;
+  }
+
+  to {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+    opacity: 1;
+  }
+}
+
+@keyframes rotateInDownLeft {
+  from {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    -webkit-transform: rotate3d(0, 0, 1, -45deg);
+    transform: rotate3d(0, 0, 1, -45deg);
+    opacity: 0;
+  }
+
+  to {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+    opacity: 1;
+  }
+}
+
+.rotateInDownLeft {
+  -webkit-animation-name: rotateInDownLeft;
+  animation-name: rotateInDownLeft;
+}
+
+@-webkit-keyframes rotateInDownRight {
+  from {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    -webkit-transform: rotate3d(0, 0, 1, 45deg);
+    transform: rotate3d(0, 0, 1, 45deg);
+    opacity: 0;
+  }
+
+  to {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+    opacity: 1;
+  }
+}
+
+@keyframes rotateInDownRight {
+  from {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    -webkit-transform: rotate3d(0, 0, 1, 45deg);
+    transform: rotate3d(0, 0, 1, 45deg);
+    opacity: 0;
+  }
+
+  to {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+    opacity: 1;
+  }
+}
+
+.rotateInDownRight {
+  -webkit-animation-name: rotateInDownRight;
+  animation-name: rotateInDownRight;
+}
+
+@-webkit-keyframes rotateInUpLeft {
+  from {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    -webkit-transform: rotate3d(0, 0, 1, 45deg);
+    transform: rotate3d(0, 0, 1, 45deg);
+    opacity: 0;
+  }
+
+  to {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+    opacity: 1;
+  }
+}
+
+@keyframes rotateInUpLeft {
+  from {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    -webkit-transform: rotate3d(0, 0, 1, 45deg);
+    transform: rotate3d(0, 0, 1, 45deg);
+    opacity: 0;
+  }
+
+  to {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+    opacity: 1;
+  }
+}
+
+.rotateInUpLeft {
+  -webkit-animation-name: rotateInUpLeft;
+  animation-name: rotateInUpLeft;
+}
+
+@-webkit-keyframes rotateInUpRight {
+  from {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    -webkit-transform: rotate3d(0, 0, 1, -90deg);
+    transform: rotate3d(0, 0, 1, -90deg);
+    opacity: 0;
+  }
+
+  to {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+    opacity: 1;
+  }
+}
+
+@keyframes rotateInUpRight {
+  from {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    -webkit-transform: rotate3d(0, 0, 1, -90deg);
+    transform: rotate3d(0, 0, 1, -90deg);
+    opacity: 0;
+  }
+
+  to {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+    opacity: 1;
+  }
+}
+
+.rotateInUpRight {
+  -webkit-animation-name: rotateInUpRight;
+  animation-name: rotateInUpRight;
+}
+
+@-webkit-keyframes rotateOut {
+  from {
+    -webkit-transform-origin: center;
+    transform-origin: center;
+    opacity: 1;
+  }
+
+  to {
+    -webkit-transform-origin: center;
+    transform-origin: center;
+    -webkit-transform: rotate3d(0, 0, 1, 200deg);
+    transform: rotate3d(0, 0, 1, 200deg);
+    opacity: 0;
+  }
+}
+
+@keyframes rotateOut {
+  from {
+    -webkit-transform-origin: center;
+    transform-origin: center;
+    opacity: 1;
+  }
+
+  to {
+    -webkit-transform-origin: center;
+    transform-origin: center;
+    -webkit-transform: rotate3d(0, 0, 1, 200deg);
+    transform: rotate3d(0, 0, 1, 200deg);
+    opacity: 0;
+  }
+}
+
+.rotateOut {
+  -webkit-animation-name: rotateOut;
+  animation-name: rotateOut;
+}
+
+@-webkit-keyframes rotateOutDownLeft {
+  from {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    opacity: 1;
+  }
+
+  to {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    -webkit-transform: rotate3d(0, 0, 1, 45deg);
+    transform: rotate3d(0, 0, 1, 45deg);
+    opacity: 0;
+  }
+}
+
+@keyframes rotateOutDownLeft {
+  from {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    opacity: 1;
+  }
+
+  to {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    -webkit-transform: rotate3d(0, 0, 1, 45deg);
+    transform: rotate3d(0, 0, 1, 45deg);
+    opacity: 0;
+  }
+}
+
+.rotateOutDownLeft {
+  -webkit-animation-name: rotateOutDownLeft;
+  animation-name: rotateOutDownLeft;
+}
+
+@-webkit-keyframes rotateOutDownRight {
+  from {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    opacity: 1;
+  }
+
+  to {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    -webkit-transform: rotate3d(0, 0, 1, -45deg);
+    transform: rotate3d(0, 0, 1, -45deg);
+    opacity: 0;
+  }
+}
+
+@keyframes rotateOutDownRight {
+  from {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    opacity: 1;
+  }
+
+  to {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    -webkit-transform: rotate3d(0, 0, 1, -45deg);
+    transform: rotate3d(0, 0, 1, -45deg);
+    opacity: 0;
+  }
+}
+
+.rotateOutDownRight {
+  -webkit-animation-name: rotateOutDownRight;
+  animation-name: rotateOutDownRight;
+}
+
+@-webkit-keyframes rotateOutUpLeft {
+  from {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    opacity: 1;
+  }
+
+  to {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    -webkit-transform: rotate3d(0, 0, 1, -45deg);
+    transform: rotate3d(0, 0, 1, -45deg);
+    opacity: 0;
+  }
+}
+
+@keyframes rotateOutUpLeft {
+  from {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    opacity: 1;
+  }
+
+  to {
+    -webkit-transform-origin: left bottom;
+    transform-origin: left bottom;
+    -webkit-transform: rotate3d(0, 0, 1, -45deg);
+    transform: rotate3d(0, 0, 1, -45deg);
+    opacity: 0;
+  }
+}
+
+.rotateOutUpLeft {
+  -webkit-animation-name: rotateOutUpLeft;
+  animation-name: rotateOutUpLeft;
+}
+
+@-webkit-keyframes rotateOutUpRight {
+  from {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    opacity: 1;
+  }
+
+  to {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    -webkit-transform: rotate3d(0, 0, 1, 90deg);
+    transform: rotate3d(0, 0, 1, 90deg);
+    opacity: 0;
+  }
+}
+
+@keyframes rotateOutUpRight {
+  from {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    opacity: 1;
+  }
+
+  to {
+    -webkit-transform-origin: right bottom;
+    transform-origin: right bottom;
+    -webkit-transform: rotate3d(0, 0, 1, 90deg);
+    transform: rotate3d(0, 0, 1, 90deg);
+    opacity: 0;
+  }
+}
+
+.rotateOutUpRight {
+  -webkit-animation-name: rotateOutUpRight;
+  animation-name: rotateOutUpRight;
+}
+
+@-webkit-keyframes hinge {
+  0% {
+    -webkit-transform-origin: top left;
+    transform-origin: top left;
+    -webkit-animation-timing-function: ease-in-out;
+    animation-timing-function: ease-in-out;
+  }
+
+  20%,
+  60% {
+    -webkit-transform: rotate3d(0, 0, 1, 80deg);
+    transform: rotate3d(0, 0, 1, 80deg);
+    -webkit-transform-origin: top left;
+    transform-origin: top left;
+    -webkit-animation-timing-function: ease-in-out;
+    animation-timing-function: ease-in-out;
+  }
+
+  40%,
+  80% {
+    -webkit-transform: rotate3d(0, 0, 1, 60deg);
+    transform: rotate3d(0, 0, 1, 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% {
+    -webkit-transform-origin: top left;
+    transform-origin: top left;
+    -webkit-animation-timing-function: ease-in-out;
+    animation-timing-function: ease-in-out;
+  }
+
+  20%,
+  60% {
+    -webkit-transform: rotate3d(0, 0, 1, 80deg);
+    transform: rotate3d(0, 0, 1, 80deg);
+    -webkit-transform-origin: top left;
+    transform-origin: top left;
+    -webkit-animation-timing-function: ease-in-out;
+    animation-timing-function: ease-in-out;
+  }
+
+  40%,
+  80% {
+    -webkit-transform: rotate3d(0, 0, 1, 60deg);
+    transform: rotate3d(0, 0, 1, 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-duration: 2s;
+  animation-duration: 2s;
+  -webkit-animation-name: hinge;
+  animation-name: hinge;
+}
+
+@-webkit-keyframes jackInTheBox {
+  from {
+    opacity: 0;
+    -webkit-transform: scale(0.1) rotate(30deg);
+    transform: scale(0.1) rotate(30deg);
+    -webkit-transform-origin: center bottom;
+    transform-origin: center bottom;
+  }
+
+  50% {
+    -webkit-transform: rotate(-10deg);
+    transform: rotate(-10deg);
+  }
+
+  70% {
+    -webkit-transform: rotate(3deg);
+    transform: rotate(3deg);
+  }
+
+  to {
+    opacity: 1;
+    -webkit-transform: scale(1);
+    transform: scale(1);
+  }
+}
+
+@keyframes jackInTheBox {
+  from {
+    opacity: 0;
+    -webkit-transform: scale(0.1) rotate(30deg);
+    transform: scale(0.1) rotate(30deg);
+    -webkit-transform-origin: center bottom;
+    transform-origin: center bottom;
+  }
+
+  50% {
+    -webkit-transform: rotate(-10deg);
+    transform: rotate(-10deg);
+  }
+
+  70% {
+    -webkit-transform: rotate(3deg);
+    transform: rotate(3deg);
+  }
+
+  to {
+    opacity: 1;
+    -webkit-transform: scale(1);
+    transform: scale(1);
+  }
+}
+
+.jackInTheBox {
+  -webkit-animation-name: jackInTheBox;
+  animation-name: jackInTheBox;
+}
+
+/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */
+
+@-webkit-keyframes rollIn {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);
+    transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);
+  }
+
+  to {
+    opacity: 1;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+@keyframes rollIn {
+  from {
+    opacity: 0;
+    -webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);
+    transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);
+  }
+
+  to {
+    opacity: 1;
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+.rollIn {
+  -webkit-animation-name: rollIn;
+  animation-name: rollIn;
+}
+
+/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */
+
+@-webkit-keyframes rollOut {
+  from {
+    opacity: 1;
+  }
+
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);
+    transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);
+  }
+}
+
+@keyframes rollOut {
+  from {
+    opacity: 1;
+  }
+
+  to {
+    opacity: 0;
+    -webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);
+    transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);
+  }
+}
+
+.rollOut {
+  -webkit-animation-name: rollOut;
+  animation-name: rollOut;
+}
+
+@-webkit-keyframes zoomIn {
+  from {
+    opacity: 0;
+    -webkit-transform: scale3d(0.3, 0.3, 0.3);
+    transform: scale3d(0.3, 0.3, 0.3);
+  }
+
+  50% {
+    opacity: 1;
+  }
+}
+
+@keyframes zoomIn {
+  from {
+    opacity: 0;
+    -webkit-transform: scale3d(0.3, 0.3, 0.3);
+    transform: scale3d(0.3, 0.3, 0.3);
+  }
+
+  50% {
+    opacity: 1;
+  }
+}
+
+.zoomIn {
+  -webkit-animation-name: zoomIn;
+  animation-name: zoomIn;
+}
+
+@-webkit-keyframes zoomInDown {
+  from {
+    opacity: 0;
+    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0);
+    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+  }
+
+  60% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+  }
+}
+
+@keyframes zoomInDown {
+  from {
+    opacity: 0;
+    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0);
+    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+  }
+
+  60% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+  }
+}
+
+.zoomInDown {
+  -webkit-animation-name: zoomInDown;
+  animation-name: zoomInDown;
+}
+
+@-webkit-keyframes zoomInLeft {
+  from {
+    opacity: 0;
+    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0);
+    transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+  }
+
+  60% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+  }
+}
+
+@keyframes zoomInLeft {
+  from {
+    opacity: 0;
+    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0);
+    transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+  }
+
+  60% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+  }
+}
+
+.zoomInLeft {
+  -webkit-animation-name: zoomInLeft;
+  animation-name: zoomInLeft;
+}
+
+@-webkit-keyframes zoomInRight {
+  from {
+    opacity: 0;
+    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0);
+    transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+  }
+
+  60% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+  }
+}
+
+@keyframes zoomInRight {
+  from {
+    opacity: 0;
+    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0);
+    transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+  }
+
+  60% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+  }
+}
+
+.zoomInRight {
+  -webkit-animation-name: zoomInRight;
+  animation-name: zoomInRight;
+}
+
+@-webkit-keyframes zoomInUp {
+  from {
+    opacity: 0;
+    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0);
+    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+  }
+
+  60% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+  }
+}
+
+@keyframes zoomInUp {
+  from {
+    opacity: 0;
+    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0);
+    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+  }
+
+  60% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+  }
+}
+
+.zoomInUp {
+  -webkit-animation-name: zoomInUp;
+  animation-name: zoomInUp;
+}
+
+@-webkit-keyframes zoomOut {
+  from {
+    opacity: 1;
+  }
+
+  50% {
+    opacity: 0;
+    -webkit-transform: scale3d(0.3, 0.3, 0.3);
+    transform: scale3d(0.3, 0.3, 0.3);
+  }
+
+  to {
+    opacity: 0;
+  }
+}
+
+@keyframes zoomOut {
+  from {
+    opacity: 1;
+  }
+
+  50% {
+    opacity: 0;
+    -webkit-transform: scale3d(0.3, 0.3, 0.3);
+    transform: scale3d(0.3, 0.3, 0.3);
+  }
+
+  to {
+    opacity: 0;
+  }
+}
+
+.zoomOut {
+  -webkit-animation-name: zoomOut;
+  animation-name: zoomOut;
+}
+
+@-webkit-keyframes zoomOutDown {
+  40% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+  }
+
+  to {
+    opacity: 0;
+    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0);
+    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0);
+    -webkit-transform-origin: center bottom;
+    transform-origin: center bottom;
+    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+  }
+}
+
+@keyframes zoomOutDown {
+  40% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+  }
+
+  to {
+    opacity: 0;
+    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0);
+    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0);
+    -webkit-transform-origin: center bottom;
+    transform-origin: center bottom;
+    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+  }
+}
+
+.zoomOutDown {
+  -webkit-animation-name: zoomOutDown;
+  animation-name: zoomOutDown;
+}
+
+@-webkit-keyframes zoomOutLeft {
+  40% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0);
+  }
+
+  to {
+    opacity: 0;
+    -webkit-transform: scale(0.1) translate3d(-2000px, 0, 0);
+    transform: scale(0.1) translate3d(-2000px, 0, 0);
+    -webkit-transform-origin: left center;
+    transform-origin: left center;
+  }
+}
+
+@keyframes zoomOutLeft {
+  40% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0);
+  }
+
+  to {
+    opacity: 0;
+    -webkit-transform: scale(0.1) translate3d(-2000px, 0, 0);
+    transform: scale(0.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(0.475, 0.475, 0.475) translate3d(-42px, 0, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0);
+  }
+
+  to {
+    opacity: 0;
+    -webkit-transform: scale(0.1) translate3d(2000px, 0, 0);
+    transform: scale(0.1) translate3d(2000px, 0, 0);
+    -webkit-transform-origin: right center;
+    transform-origin: right center;
+  }
+}
+
+@keyframes zoomOutRight {
+  40% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0);
+  }
+
+  to {
+    opacity: 0;
+    -webkit-transform: scale(0.1) translate3d(2000px, 0, 0);
+    transform: scale(0.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(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+  }
+
+  to {
+    opacity: 0;
+    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0);
+    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0);
+    -webkit-transform-origin: center bottom;
+    transform-origin: center bottom;
+    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+  }
+}
+
+@keyframes zoomOutUp {
+  40% {
+    opacity: 1;
+    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
+    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
+    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
+  }
+
+  to {
+    opacity: 0;
+    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0);
+    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0);
+    -webkit-transform-origin: center bottom;
+    transform-origin: center bottom;
+    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
+  }
+}
+
+.zoomOutUp {
+  -webkit-animation-name: zoomOutUp;
+  animation-name: zoomOutUp;
+}
+
+@-webkit-keyframes slideInDown {
+  from {
+    -webkit-transform: translate3d(0, -100%, 0);
+    transform: translate3d(0, -100%, 0);
+    visibility: visible;
+  }
+
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+@keyframes slideInDown {
+  from {
+    -webkit-transform: translate3d(0, -100%, 0);
+    transform: translate3d(0, -100%, 0);
+    visibility: visible;
+  }
+
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+.slideInDown {
+  -webkit-animation-name: slideInDown;
+  animation-name: slideInDown;
+}
+
+@-webkit-keyframes slideInLeft {
+  from {
+    -webkit-transform: translate3d(-100%, 0, 0);
+    transform: translate3d(-100%, 0, 0);
+    visibility: visible;
+  }
+
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+@keyframes slideInLeft {
+  from {
+    -webkit-transform: translate3d(-100%, 0, 0);
+    transform: translate3d(-100%, 0, 0);
+    visibility: visible;
+  }
+
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+.slideInLeft {
+  -webkit-animation-name: slideInLeft;
+  animation-name: slideInLeft;
+}
+
+@-webkit-keyframes slideInRight {
+  from {
+    -webkit-transform: translate3d(100%, 0, 0);
+    transform: translate3d(100%, 0, 0);
+    visibility: visible;
+  }
+
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+@keyframes slideInRight {
+  from {
+    -webkit-transform: translate3d(100%, 0, 0);
+    transform: translate3d(100%, 0, 0);
+    visibility: visible;
+  }
+
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+.slideInRight {
+  -webkit-animation-name: slideInRight;
+  animation-name: slideInRight;
+}
+
+@-webkit-keyframes slideInUp {
+  from {
+    -webkit-transform: translate3d(0, 100%, 0);
+    transform: translate3d(0, 100%, 0);
+    visibility: visible;
+  }
+
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+@keyframes slideInUp {
+  from {
+    -webkit-transform: translate3d(0, 100%, 0);
+    transform: translate3d(0, 100%, 0);
+    visibility: visible;
+  }
+
+  to {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+.slideInUp {
+  -webkit-animation-name: slideInUp;
+  animation-name: slideInUp;
+}
+
+@-webkit-keyframes slideOutDown {
+  from {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+
+  to {
+    visibility: hidden;
+    -webkit-transform: translate3d(0, 100%, 0);
+    transform: translate3d(0, 100%, 0);
+  }
+}
+
+@keyframes slideOutDown {
+  from {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 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 {
+  from {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+
+  to {
+    visibility: hidden;
+    -webkit-transform: translate3d(-100%, 0, 0);
+    transform: translate3d(-100%, 0, 0);
+  }
+}
+
+@keyframes slideOutLeft {
+  from {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 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 {
+  from {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+
+  to {
+    visibility: hidden;
+    -webkit-transform: translate3d(100%, 0, 0);
+    transform: translate3d(100%, 0, 0);
+  }
+}
+
+@keyframes slideOutRight {
+  from {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 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 {
+  from {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+
+  to {
+    visibility: hidden;
+    -webkit-transform: translate3d(0, -100%, 0);
+    transform: translate3d(0, -100%, 0);
+  }
+}
+
+@keyframes slideOutUp {
+  from {
+    -webkit-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0);
+  }
+
+  to {
+    visibility: hidden;
+    -webkit-transform: translate3d(0, -100%, 0);
+    transform: translate3d(0, -100%, 0);
+  }
+}
+
+.slideOutUp {
+  -webkit-animation-name: slideOutUp;
+  animation-name: slideOutUp;
+}
+
+.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.delay-1s {
+  -webkit-animation-delay: 1s;
+  animation-delay: 1s;
+}
+
+.animated.delay-2s {
+  -webkit-animation-delay: 2s;
+  animation-delay: 2s;
+}
+
+.animated.delay-3s {
+  -webkit-animation-delay: 3s;
+  animation-delay: 3s;
+}
+
+.animated.delay-4s {
+  -webkit-animation-delay: 4s;
+  animation-delay: 4s;
+}
+
+.animated.delay-5s {
+  -webkit-animation-delay: 5s;
+  animation-delay: 5s;
+}
+
+.animated.fast {
+  -webkit-animation-duration: 800ms;
+  animation-duration: 800ms;
+}
+
+.animated.faster {
+  -webkit-animation-duration: 500ms;
+  animation-duration: 500ms;
+}
+
+.animated.slow {
+  -webkit-animation-duration: 2s;
+  animation-duration: 2s;
+}
+
+.animated.slower {
+  -webkit-animation-duration: 3s;
+  animation-duration: 3s;
+}
+
+@media (prefers-reduced-motion) {
+  .animated {
+    -webkit-animation: unset !important;
+    animation: unset !important;
+    -webkit-transition: none !important;
+    transition: none !important;
+  }
+}
diff --git a/src/styles/calendars.scss b/src/styles/calendars.scss
new file mode 100644
index 0000000..5b02b7f
--- /dev/null
+++ b/src/styles/calendars.scss
@@ -0,0 +1,168 @@
+#calendar {
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  background: #fff;
+}
+
+#calendar /deep/ .fc-license-message {
+  display: none !important;
+}
+
+#calendar /deep/ .fc-toolbar {
+  padding-top: 1em;
+
+  .fc-left {
+    padding-left: 20px;
+
+    .fc-button-group {
+      .fc-button {
+        text-shadow: none;
+      }
+
+      .fc-state-default {
+        background: #f0f0f0;
+        padding: 0 1.2em;
+        border: 0;
+        margin-right: 3px;
+      }
+
+      .fc-state-down {
+        box-shadow: none;
+        text-shadow: none;
+      }
+
+      .fc-state-active {
+        background: #4D88FF;
+        color: #fff;
+      }
+    }
+
+    .fc-today-button {
+      background: #fff;
+      margin-right: 50px;
+    }
+  }
+
+  .fc-center {
+    margin-left: -277px;
+
+    h2 {
+      font-size: 20px;
+      font-weight: normal;
+      margin-top: 5px;
+    }
+
+    .fc-prevYear-button,
+    .fc-prev-button,
+    .fc-next-button,
+    .fc-nextYear-button {
+      background: none;
+      border: 0;
+      color: #aaa;
+      outline: none;
+      box-shadow: none;
+    }
+
+    .fc-button-group {
+
+      .fc-prev-button .fc-icon-left-single-arrow:after,
+      .fc-next-button .fc-icon-right-single-arrow:after {
+        font-size: 160%;
+        font-weight: none;
+      }
+    }
+  }
+}
+
+#calendar /deep/ .fc-view-container {
+  .fc-body {
+    .fc-row {
+      .fc-day {
+        border-color: #e9e9e9;
+      }
+
+      .fc-bg {
+
+        .fc-sat,
+        .fc-sun {
+          background: #fbfbfb;
+        }
+
+        .fc-today {
+          background: none;
+        }
+      }
+
+      .fc-content-skeleton {
+        .fc-today {
+          .fc-day-number {
+            background: #4D88FF;
+            border-radius: 50%;
+            padding: 3px;
+            color: #fff;
+            min-width: 16px;
+            text-align: center;
+          }
+        }
+
+        .fc-day-grid-event {
+          border: 0 !important;
+          border-radius: 23px;
+          margin-left: 5px;
+          margin-right: 5px;
+
+          .fc-content {
+            color: #fff;
+
+            .fc-time {
+              display: none;
+            }
+
+            .fc-title {
+              float: left;
+              width: 100%;
+              overflow: hidden;
+              white-space: nowrap;
+              text-overflow: ellipsis;
+            }
+          }
+        }
+      }
+
+      .fc-day-number {
+        margin: 5px;
+      }
+
+      .fc-day-grid-event {
+        border-left: 2px solid #ff9668 !important;
+        border-radius: 0;
+        margin-left: 0;
+        margin-right: 0;
+        padding: 2px 15px;
+      }
+    }
+  }
+
+  .fc-body>tr>.fc-widget-content {
+    border: 0;
+  }
+
+  .fc-head {
+    .fc-head-container {
+      border: 0;
+      border-bottom: 1px solid #ddd;
+    }
+  }
+}
+
+#calendar /deep/ .fc-day-header {
+  background: #f5f5f5;
+  border-width: 0;
+  font-weight: normal;
+
+  span {
+    height: 50px;
+    line-height: 50px;
+  }
+}
diff --git a/src/styles/element-ui.scss b/src/styles/element-ui.scss
new file mode 100644
index 0000000..cca0bbc
--- /dev/null
+++ b/src/styles/element-ui.scss
@@ -0,0 +1,122 @@
+ //to reset element-ui default css
+// .el-upload {
+//   input[type="file"] {
+//     display: none !important;
+//   }
+// }
+
+// .el-upload__input {
+//   display: none;
+// }
+
+// //暂时性解决diolag 问题 https://github.com/ElemeFE/element/issues/2461
+// .el-dialog {
+//   transform: none;
+//   left: 0;
+//   position: relative;
+//   margin: 0 auto;
+// }
+
+// //element ui upload
+// .upload-container {
+//   .el-upload {
+//     width: 100%;
+//     .el-upload-dragger {
+//       width: 100%;
+//       height: 200px;
+//     }
+//   }
+// }
+
+// /** checkbox 更改 */
+// .el-checkbox__label {
+//   font-size: 13px;
+//   color: #333333;
+// }
+
+// .el-checkbox__input.is-checked+.el-checkbox__label {
+//   color: #333333;
+// }
+.el-dialog{
+  border-radius: 8px !important;
+}
+.el-dialog__header{
+  border-bottom: 1px solid #F1F1F1;
+}
+.el-dialog .el-dialog__title{
+  color: #333;
+  font-weight: 550;
+}
+.el-dialog .el-dialog__footer{
+  text-align: center;
+}
+// .el-dialog .el-form--inline.el-form--label-top .el-form-item__content{
+//   display: inline-block;
+//   width: 70%;
+// }
+// .el-dialog .el-form--inline .el-form-item__label{
+//   width: 21%;
+//   text-align: right;
+// }
+.el-input .el-input__inner {
+  padding: 0 8px;
+  height: 36px ; 
+  line-height: 36px; 
+}
+.el-input .el-input__inner:hover{
+  border-color: #4D88FF !important;
+}
+.el-cascader:not(.is-disabled):hover .el-input__inner{
+  border-color: #4D88FF !important;
+}
+.el-cascader-node:not(.is-disabled):hover, .el-cascader-node:not(.is-disabled):focus{
+  
+  background: #F7FAFF !important;
+}
+.el-select-dropdown__item.hover, .el-select-dropdown__item:hover{
+  background: #F7FAFF !important;
+}
+.el-tooltip__popper.is-light{
+  color: #fff;
+  background: #4D88FF !important;
+  border: 1px solid #4D88FF !important;
+}
+.el-tooltip__popper[x-placement^="right"] .popper__arrow{
+  border-right-color: #4D88FF !important;
+}
+.el-tooltip__popper[x-placement^="right"] .popper__arrow::after{
+  border-right-color: #4D88FF !important;
+}
+.el-form-item.is-error .el-input__inner, .el-form-item.is-error .el-input__inner:focus, .el-form-item.is-error .el-textarea__inner, .el-form-item.is-error .el-textarea__inner:focus{
+  border-color: #FF4D4D !important;
+  background: rgba(255, 77, 77, 0.05) !important;
+}
+.el-form-item__error{
+  color: #FF4D4D !important;
+}
+.el-popper[x-placement^="bottom"] .popper__arrow{
+  display: none;
+}
+.el-textarea .el-textarea__inner {
+  padding: 5px 8px;
+}
+
+.el-radio .el-radio__label {
+  padding-left: 8px;
+}
+
+.el-checkbox .el-checkbox__label {
+  padding-left: 8px;
+}
+
+body .el-table th.gutter{
+  display: table-cell !important;
+}
+
+body .el-table colgroup.gutter{
+  display: table-cell !important;
+}
+.el-button--primary{
+  background-color: #4D88FF !important;
+  border-color: #4D88FF !important;
+}
\ No newline at end of file
diff --git a/src/styles/element-variables.scss b/src/styles/element-variables.scss
new file mode 100644
index 0000000..63bf18d
--- /dev/null
+++ b/src/styles/element-variables.scss
@@ -0,0 +1,38 @@
+/* 改变主题色变量 */
+$--color-primary: #4D88FF;
+
+/** border */
+$--border-color-base: #ddd;
+$--border-radius-base: 2px;
+$--font-size-base: 13px;
+
+// $--color-text-primary: #303133;
+$--color-text-regular: #333;
+// $--color-text-secondary: #909399; #aaa 说明文字
+// $--color-text-placeholder: #c0c4cc;
+
+/** input */
+// $--input-border-radius: 3px;
+$--input-height: 34px;
+$--input-border-radius:3px;
+
+/** button */
+$--button-padding-vertical: 8px;
+$--button-padding-horizontal: 12px;
+$--button-font-size: 13px;
+
+/* Radio
+-------------------------- */
+$--radio-font-size: 13px;
+$--radio-checked-text-color: $--color-text-regular;
+$--select-font-size: 12px;
+
+/* Checkbox
+-------------------------- */
+$--checkbox-font-size: 13px;
+$--checkbox-checked-text-color: $--color-text-regular;
+
+/* 改变 icon 字体路径变量,必需 */
+$--font-path: '~element-ui/lib/theme-chalk/fonts';
+
+@import "~element-ui/packages/theme-chalk/src/index";
\ No newline at end of file
diff --git a/src/styles/emoji-sprite.scss b/src/styles/emoji-sprite.scss
new file mode 100644
index 0000000..8ffdb9d
--- /dev/null
+++ b/src/styles/emoji-sprite.scss
@@ -0,0 +1,3558 @@
+[class*="sprite-"] {
+  width:25px;
+  height: 25px;
+  background: url('../assets/img/sprite/vue-emoji.png');
+  background-repeat: no-repeat;
+  vertical-align: top;
+  display: inline-block;
+  margin: 5px;
+  background-size: 882.8125px 867.1875px;
+}
+
+.sprite-a {
+  background-position: -1.953125px -1.953125px;
+}
+
+.sprite-a-100 {
+  background-position: -30.859375px -1.953125px;
+}
+
+.sprite-a-1234 {
+  background-position: -59.765625px -1.953125px;
+}
+
+.sprite-a-8ball {
+  background-position: -88.671875px -1.953125px;
+}
+
+.sprite-ab {
+  background-position: -117.578125px -1.953125px;
+}
+
+.sprite-abc {
+  background-position: -146.484375px -1.953125px;
+}
+
+.sprite-abcd {
+  background-position: -175.390625px -1.953125px;
+}
+
+.sprite-accept {
+  background-position: -204.296875px -1.953125px;
+}
+
+.sprite-aerial_tramway {
+  background-position: -233.203125px -1.953125px;
+}
+
+.sprite-agree {
+  background-position: -262.109375px -1.953125px;
+}
+
+.sprite-airplane {
+  background-position: -291.015625px -1.953125px;
+}
+
+.sprite-alarm_clock {
+  background-position: -319.921875px -1.953125px;
+}
+
+.sprite-alien {
+  background-position: -348.828125px -1.953125px;
+}
+
+.sprite-ambulance {
+  background-position: -377.734375px -1.953125px;
+}
+
+.sprite-anchor {
+  background-position: -406.640625px -1.953125px;
+}
+
+.sprite-angel {
+  background-position: -435.546875px -1.953125px;
+}
+
+.sprite-anger {
+  background-position: -464.453125px -1.953125px;
+}
+
+.sprite-angry {
+  background-position: -493.359375px -1.953125px;
+}
+
+.sprite-anguished {
+  background-position: -522.265625px -1.953125px;
+}
+
+.sprite-ant {
+  background-position: -551.171875px -1.953125px;
+}
+
+.sprite-apple {
+  background-position: -580.078125px -1.953125px;
+}
+
+.sprite-aquarius {
+  background-position: -608.984375px -1.953125px;
+}
+
+.sprite-aries {
+  background-position: -637.890625px -1.953125px;
+}
+
+.sprite-arrow_backward {
+  background-position: -666.796875px -1.953125px;
+}
+
+.sprite-arrow_double_down {
+  background-position: -695.703125px -1.953125px;
+}
+
+.sprite-arrow_double_up {
+  background-position: -724.609375px -1.953125px;
+}
+
+.sprite-arrow_down {
+  background-position: -753.515625px -1.953125px;
+}
+
+.sprite-arrow_down_small {
+  background-position: -782.421875px -1.953125px;
+}
+
+.sprite-arrow_forward {
+  background-position: -811.328125px -1.953125px;
+}
+
+.sprite-arrow_heading_down {
+  background-position: -1.953125px -30.859375px;
+}
+
+.sprite-arrow_heading_up {
+  background-position: -30.859375px -30.859375px;
+}
+
+.sprite-arrow_left {
+  background-position: -59.765625px -30.859375px;
+}
+
+.sprite-arrow_lower_left {
+  background-position: -88.671875px -30.859375px;
+}
+
+.sprite-arrow_lower_right {
+  background-position: -117.578125px -30.859375px;
+}
+
+.sprite-arrow_right {
+  background-position: -146.484375px -30.859375px;
+}
+
+.sprite-arrow_right_hook {
+  background-position: -175.390625px -30.859375px;
+}
+
+.sprite-arrow_up {
+  background-position: -204.296875px -30.859375px;
+}
+
+.sprite-arrow_up_down {
+  background-position: -233.203125px -30.859375px;
+}
+
+.sprite-arrow_up_small {
+  background-position: -262.109375px -30.859375px;
+}
+
+.sprite-arrow_upper_left {
+  background-position: -291.015625px -30.859375px;
+}
+
+.sprite-arrow_upper_right {
+  background-position: -319.921875px -30.859375px;
+}
+
+.sprite-arrows_clockwise {
+  background-position: -348.828125px -30.859375px;
+}
+
+.sprite-arrows_counterclockwise {
+  background-position: -377.734375px -30.859375px;
+}
+
+.sprite-art {
+  background-position: -406.640625px -30.859375px;
+}
+
+.sprite-articulated_lorry {
+  background-position: -435.546875px -30.859375px;
+}
+
+.sprite-astonished {
+  background-position: -464.453125px -30.859375px;
+}
+
+.sprite-atm {
+  background-position: -493.359375px -30.859375px;
+}
+
+.sprite-b {
+  background-position: -522.265625px -30.859375px;
+}
+
+.sprite-baby {
+  background-position: -551.171875px -30.859375px;
+}
+
+.sprite-baby_bottle {
+  background-position: -580.078125px -30.859375px;
+}
+
+.sprite-baby_chick {
+  background-position: -608.984375px -30.859375px;
+}
+
+.sprite-baby_symbol {
+  background-position: -637.890625px -30.859375px;
+}
+
+.sprite-back {
+  background-position: -666.796875px -30.859375px;
+}
+
+.sprite-baggage_claim {
+  background-position: -695.703125px -30.859375px;
+}
+
+.sprite-balloon {
+  background-position: -724.609375px -30.859375px;
+}
+
+.sprite-ballot_box_with_check {
+  background-position: -753.515625px -30.859375px;
+}
+
+.sprite-bamboo {
+  background-position: -782.421875px -30.859375px;
+}
+
+.sprite-banana {
+  background-position: -811.328125px -30.859375px;
+}
+
+.sprite-bangbang {
+  background-position: -1.953125px -59.765625px;
+}
+
+.sprite-bank {
+  background-position: -30.859375px -59.765625px;
+}
+
+.sprite-bar_chart {
+  background-position: -59.765625px -59.765625px;
+}
+
+.sprite-barber {
+  background-position: -88.671875px -59.765625px;
+}
+
+.sprite-baseball {
+  background-position: -117.578125px -59.765625px;
+}
+
+.sprite-basketball {
+  background-position: -146.484375px -59.765625px;
+}
+
+.sprite-bath {
+  background-position: -175.390625px -59.765625px;
+}
+
+.sprite-bathtub {
+  background-position: -204.296875px -59.765625px;
+}
+
+.sprite-battery {
+  background-position: -233.203125px -59.765625px;
+}
+
+.sprite-bear {
+  background-position: -262.109375px -59.765625px;
+}
+
+.sprite-bee {
+  background-position: -291.015625px -59.765625px;
+}
+
+.sprite-beer {
+  background-position: -319.921875px -59.765625px;
+}
+
+.sprite-beers {
+  background-position: -348.828125px -59.765625px;
+}
+
+.sprite-beetle {
+  background-position: -377.734375px -59.765625px;
+}
+
+.sprite-beginner {
+  background-position: -406.640625px -59.765625px;
+}
+
+.sprite-bell {
+  background-position: -435.546875px -59.765625px;
+}
+
+.sprite-bento {
+  background-position: -464.453125px -59.765625px;
+}
+
+.sprite-bicyclist {
+  background-position: -493.359375px -59.765625px;
+}
+
+.sprite-bike {
+  background-position: -522.265625px -59.765625px;
+}
+
+.sprite-bikini {
+  background-position: -551.171875px -59.765625px;
+}
+
+.sprite-bird {
+  background-position: -580.078125px -59.765625px;
+}
+
+.sprite-birthday {
+  background-position: -608.984375px -59.765625px;
+}
+
+.sprite-black_circle {
+  background-position: -637.890625px -59.765625px;
+}
+
+.sprite-black_joker {
+  background-position: -666.796875px -59.765625px;
+}
+
+.sprite-black_medium_small_square {
+  background-position: -695.703125px -59.765625px;
+}
+
+.sprite-black_medium_square {
+  background-position: -724.609375px -59.765625px;
+}
+
+.sprite-black_nib {
+  background-position: -753.515625px -59.765625px;
+}
+
+.sprite-black_small_square {
+  background-position: -782.421875px -59.765625px;
+}
+
+.sprite-black_square {
+  background-position: -811.328125px -59.765625px;
+}
+
+.sprite-black_square_button {
+  background-position: -1.953125px -88.671875px;
+}
+
+.sprite-blossom {
+  background-position: -30.859375px -88.671875px;
+}
+
+.sprite-blowfish {
+  background-position: -59.765625px -88.671875px;
+}
+
+.sprite-blue_book {
+  background-position: -88.671875px -88.671875px;
+}
+
+.sprite-blue_car {
+  background-position: -117.578125px -88.671875px;
+}
+
+.sprite-blue_heart {
+  background-position: -146.484375px -88.671875px;
+}
+
+.sprite-blush {
+  background-position: -175.390625px -88.671875px;
+}
+
+.sprite-boar {
+  background-position: -204.296875px -88.671875px;
+}
+
+.sprite-boat {
+  background-position: -233.203125px -88.671875px;
+}
+
+.sprite-bomb {
+  background-position: -262.109375px -88.671875px;
+}
+
+.sprite-book {
+  background-position: -291.015625px -88.671875px;
+}
+
+.sprite-bookmark {
+  background-position: -319.921875px -88.671875px;
+}
+
+.sprite-bookmark_tabs {
+  background-position: -348.828125px -88.671875px;
+}
+
+.sprite-books {
+  background-position: -377.734375px -88.671875px;
+}
+
+.sprite-boom {
+  background-position: -406.640625px -88.671875px;
+}
+
+.sprite-boot {
+  background-position: -435.546875px -88.671875px;
+}
+
+.sprite-bouquet {
+  background-position: -464.453125px -88.671875px;
+}
+
+.sprite-bow {
+  background-position: -493.359375px -88.671875px;
+}
+
+.sprite-bowling {
+  background-position: -522.265625px -88.671875px;
+}
+
+.sprite-bowtie {
+  background-position: -551.171875px -88.671875px;
+}
+
+.sprite-boy {
+  background-position: -580.078125px -88.671875px;
+}
+
+.sprite-bread {
+  background-position: -608.984375px -88.671875px;
+}
+
+.sprite-bride_with_veil {
+  background-position: -637.890625px -88.671875px;
+}
+
+.sprite-bridge_at_night {
+  background-position: -666.796875px -88.671875px;
+}
+
+.sprite-briefcase {
+  background-position: -695.703125px -88.671875px;
+}
+
+.sprite-broken_heart {
+  background-position: -724.609375px -88.671875px;
+}
+
+.sprite-bug {
+  background-position: -753.515625px -88.671875px;
+}
+
+.sprite-bulb {
+  background-position: -782.421875px -88.671875px;
+}
+
+.sprite-bullettrain_front {
+  background-position: -811.328125px -88.671875px;
+}
+
+.sprite-bullettrain_side {
+  background-position: -1.953125px -117.578125px;
+}
+
+.sprite-bus {
+  background-position: -30.859375px -117.578125px;
+}
+
+.sprite-busstop {
+  background-position: -59.765625px -117.578125px;
+}
+
+.sprite-bust_in_silhouette {
+  background-position: -88.671875px -117.578125px;
+}
+
+.sprite-busts_in_silhouette {
+  background-position: -117.578125px -117.578125px;
+}
+
+.sprite-cactus {
+  background-position: -146.484375px -117.578125px;
+}
+
+.sprite-cake {
+  background-position: -175.390625px -117.578125px;
+}
+
+.sprite-calendar {
+  background-position: -204.296875px -117.578125px;
+}
+
+.sprite-calling {
+  background-position: -233.203125px -117.578125px;
+}
+
+.sprite-camel {
+  background-position: -262.109375px -117.578125px;
+}
+
+.sprite-camera {
+  background-position: -291.015625px -117.578125px;
+}
+
+.sprite-cancer {
+  background-position: -319.921875px -117.578125px;
+}
+
+.sprite-candy {
+  background-position: -348.828125px -117.578125px;
+}
+
+.sprite-capital_abcd {
+  background-position: -377.734375px -117.578125px;
+}
+
+.sprite-capricorn {
+  background-position: -406.640625px -117.578125px;
+}
+
+.sprite-car {
+  background-position: -435.546875px -117.578125px;
+}
+
+.sprite-card_index {
+  background-position: -464.453125px -117.578125px;
+}
+
+.sprite-carousel_horse {
+  background-position: -493.359375px -117.578125px;
+}
+
+.sprite-cat {
+  background-position: -522.265625px -117.578125px;
+}
+
+.sprite-cat2 {
+  background-position: -551.171875px -117.578125px;
+}
+
+.sprite-cd {
+  background-position: -580.078125px -117.578125px;
+}
+
+.sprite-chart {
+  background-position: -608.984375px -117.578125px;
+}
+
+.sprite-chart_with_downwards_trend {
+  background-position: -637.890625px -117.578125px;
+}
+
+.sprite-chart_with_upwards_trend {
+  background-position: -666.796875px -117.578125px;
+}
+
+.sprite-checkered_flag {
+  background-position: -695.703125px -117.578125px;
+}
+
+.sprite-cherries {
+  background-position: -724.609375px -117.578125px;
+}
+
+.sprite-cherry_blossom {
+  background-position: -753.515625px -117.578125px;
+}
+
+.sprite-chestnut {
+  background-position: -782.421875px -117.578125px;
+}
+
+.sprite-chicken {
+  background-position: -811.328125px -117.578125px;
+}
+
+.sprite-children_crossing {
+  background-position: -1.953125px -146.484375px;
+}
+
+.sprite-chocolate_bar {
+  background-position: -30.859375px -146.484375px;
+}
+
+.sprite-christmas_tree {
+  background-position: -59.765625px -146.484375px;
+}
+
+.sprite-church {
+  background-position: -88.671875px -146.484375px;
+}
+
+.sprite-cinema {
+  background-position: -117.578125px -146.484375px;
+}
+
+.sprite-circus_tent {
+  background-position: -146.484375px -146.484375px;
+}
+
+.sprite-city_sunrise {
+  background-position: -175.390625px -146.484375px;
+}
+
+.sprite-city_sunset {
+  background-position: -204.296875px -146.484375px;
+}
+
+.sprite-cl {
+  background-position: -233.203125px -146.484375px;
+}
+
+.sprite-clap {
+  background-position: -262.109375px -146.484375px;
+}
+
+.sprite-clapper {
+  background-position: -291.015625px -146.484375px;
+}
+
+.sprite-clipboard {
+  background-position: -319.921875px -146.484375px;
+}
+
+.sprite-clock1 {
+  background-position: -348.828125px -146.484375px;
+}
+
+.sprite-clock10 {
+  background-position: -377.734375px -146.484375px;
+}
+
+.sprite-clock1030 {
+  background-position: -406.640625px -146.484375px;
+}
+
+.sprite-clock11 {
+  background-position: -435.546875px -146.484375px;
+}
+
+.sprite-clock1130 {
+  background-position: -464.453125px -146.484375px;
+}
+
+.sprite-clock12 {
+  background-position: -493.359375px -146.484375px;
+}
+
+.sprite-clock1230 {
+  background-position: -522.265625px -146.484375px;
+}
+
+.sprite-clock130 {
+  background-position: -551.171875px -146.484375px;
+}
+
+.sprite-clock2 {
+  background-position: -580.078125px -146.484375px;
+}
+
+.sprite-clock230 {
+  background-position: -608.984375px -146.484375px;
+}
+
+.sprite-clock3 {
+  background-position: -637.890625px -146.484375px;
+}
+
+.sprite-clock330 {
+  background-position: -666.796875px -146.484375px;
+}
+
+.sprite-clock4 {
+  background-position: -695.703125px -146.484375px;
+}
+
+.sprite-clock430 {
+  background-position: -724.609375px -146.484375px;
+}
+
+.sprite-clock5 {
+  background-position: -753.515625px -146.484375px;
+}
+
+.sprite-clock530 {
+  background-position: -782.421875px -146.484375px;
+}
+
+.sprite-clock6 {
+  background-position: -811.328125px -146.484375px;
+}
+
+.sprite-clock630 {
+  background-position: -1.953125px -175.390625px;
+}
+
+.sprite-clock7 {
+  background-position: -30.859375px -175.390625px;
+}
+
+.sprite-clock730 {
+  background-position: -59.765625px -175.390625px;
+}
+
+.sprite-clock8 {
+  background-position: -88.671875px -175.390625px;
+}
+
+.sprite-clock830 {
+  background-position: -117.578125px -175.390625px;
+}
+
+.sprite-clock9 {
+  background-position: -146.484375px -175.390625px;
+}
+
+.sprite-clock930 {
+  background-position: -175.390625px -175.390625px;
+}
+
+.sprite-closed_book {
+  background-position: -204.296875px -175.390625px;
+}
+
+.sprite-closed_lock_with_key {
+  background-position: -233.203125px -175.390625px;
+}
+
+.sprite-closed_umbrella {
+  background-position: -262.109375px -175.390625px;
+}
+
+.sprite-cloud {
+  background-position: -291.015625px -175.390625px;
+}
+
+.sprite-clubs {
+  background-position: -319.921875px -175.390625px;
+}
+
+.sprite-cn {
+  background-position: -348.828125px -175.390625px;
+}
+
+.sprite-cocktail {
+  background-position: -377.734375px -175.390625px;
+}
+
+.sprite-coffee {
+  background-position: -406.640625px -175.390625px;
+}
+
+.sprite-cold_sweat {
+  background-position: -435.546875px -175.390625px;
+}
+
+.sprite-collision {
+  background-position: -464.453125px -175.390625px;
+}
+
+.sprite-computer {
+  background-position: -493.359375px -175.390625px;
+}
+
+.sprite-confetti_ball {
+  background-position: -522.265625px -175.390625px;
+}
+
+.sprite-confounded {
+  background-position: -551.171875px -175.390625px;
+}
+
+.sprite-confused {
+  background-position: -580.078125px -175.390625px;
+}
+
+.sprite-congratulations {
+  background-position: -608.984375px -175.390625px;
+}
+
+.sprite-construction {
+  background-position: -637.890625px -175.390625px;
+}
+
+.sprite-construction_worker {
+  background-position: -666.796875px -175.390625px;
+}
+
+.sprite-convenience_store {
+  background-position: -695.703125px -175.390625px;
+}
+
+.sprite-cookie {
+  background-position: -724.609375px -175.390625px;
+}
+
+.sprite-cool {
+  background-position: -753.515625px -175.390625px;
+}
+
+.sprite-cop {
+  background-position: -782.421875px -175.390625px;
+}
+
+.sprite-copyright {
+  background-position: -811.328125px -175.390625px;
+}
+
+.sprite-corn {
+  background-position: -1.953125px -204.296875px;
+}
+
+.sprite-couple {
+  background-position: -30.859375px -204.296875px;
+}
+
+.sprite-couple_with_heart {
+  background-position: -59.765625px -204.296875px;
+}
+
+.sprite-couplekiss {
+  background-position: -88.671875px -204.296875px;
+}
+
+.sprite-cow {
+  background-position: -117.578125px -204.296875px;
+}
+
+.sprite-cow2 {
+  background-position: -146.484375px -204.296875px;
+}
+
+.sprite-credit_card {
+  background-position: -175.390625px -204.296875px;
+}
+
+.sprite-crescent_moon {
+  background-position: -204.296875px -204.296875px;
+}
+
+.sprite-crocodile {
+  background-position: -233.203125px -204.296875px;
+}
+
+.sprite-crossed_flags {
+  background-position: -262.109375px -204.296875px;
+}
+
+.sprite-crown {
+  background-position: -291.015625px -204.296875px;
+}
+
+.sprite-cry {
+  background-position: -319.921875px -204.296875px;
+}
+
+.sprite-crying_cat_face {
+  background-position: -348.828125px -204.296875px;
+}
+
+.sprite-crystal_ball {
+  background-position: -377.734375px -204.296875px;
+}
+
+.sprite-cupid {
+  background-position: -406.640625px -204.296875px;
+}
+
+.sprite-curly_loop {
+  background-position: -435.546875px -204.296875px;
+}
+
+.sprite-currency_exchange {
+  background-position: -464.453125px -204.296875px;
+}
+
+.sprite-curry {
+  background-position: -493.359375px -204.296875px;
+}
+
+.sprite-custard {
+  background-position: -522.265625px -204.296875px;
+}
+
+.sprite-customs {
+  background-position: -551.171875px -204.296875px;
+}
+
+.sprite-cyclone {
+  background-position: -580.078125px -204.296875px;
+}
+
+.sprite-dancer {
+  background-position: -608.984375px -204.296875px;
+}
+
+.sprite-dancers {
+  background-position: -637.890625px -204.296875px;
+}
+
+.sprite-dango {
+  background-position: -666.796875px -204.296875px;
+}
+
+.sprite-dart {
+  background-position: -695.703125px -204.296875px;
+}
+
+.sprite-dash {
+  background-position: -724.609375px -204.296875px;
+}
+
+.sprite-date {
+  background-position: -753.515625px -204.296875px;
+}
+
+.sprite-de {
+  background-position: -782.421875px -204.296875px;
+}
+
+.sprite-deciduous_tree {
+  background-position: -811.328125px -204.296875px;
+}
+
+.sprite-department_store {
+  background-position: -1.953125px -233.203125px;
+}
+
+.sprite-diamond_shape_with_a_dot_inside {
+  background-position: -30.859375px -233.203125px;
+}
+
+.sprite-diamonds {
+  background-position: -59.765625px -233.203125px;
+}
+
+.sprite-disappointed {
+  background-position: -88.671875px -233.203125px;
+}
+
+.sprite-disappointed_relieved {
+  background-position: -117.578125px -233.203125px;
+}
+
+.sprite-dizzy {
+  background-position: -146.484375px -233.203125px;
+}
+
+.sprite-dizzy_face {
+  background-position: -175.390625px -233.203125px;
+}
+
+.sprite-do_not_litter {
+  background-position: -204.296875px -233.203125px;
+}
+
+.sprite-dog {
+  background-position: -233.203125px -233.203125px;
+}
+
+.sprite-dog2 {
+  background-position: -262.109375px -233.203125px;
+}
+
+.sprite-dollar {
+  background-position: -291.015625px -233.203125px;
+}
+
+.sprite-dolls {
+  background-position: -319.921875px -233.203125px;
+}
+
+.sprite-dolphin {
+  background-position: -348.828125px -233.203125px;
+}
+
+.sprite-donut {
+  background-position: -377.734375px -233.203125px;
+}
+
+.sprite-door {
+  background-position: -406.640625px -233.203125px;
+}
+
+.sprite-doughnut {
+  background-position: -435.546875px -233.203125px;
+}
+
+.sprite-dragon {
+  background-position: -464.453125px -233.203125px;
+}
+
+.sprite-dragon_face {
+  background-position: -493.359375px -233.203125px;
+}
+
+.sprite-dress {
+  background-position: -522.265625px -233.203125px;
+}
+
+.sprite-dromedary_camel {
+  background-position: -551.171875px -233.203125px;
+}
+
+.sprite-droplet {
+  background-position: -580.078125px -233.203125px;
+}
+
+.sprite-dvd {
+  background-position: -608.984375px -233.203125px;
+}
+
+.sprite-e-mail {
+  background-position: -637.890625px -233.203125px;
+}
+
+.sprite-ear {
+  background-position: -666.796875px -233.203125px;
+}
+
+.sprite-ear_of_rice {
+  background-position: -695.703125px -233.203125px;
+}
+
+.sprite-earth_africa {
+  background-position: -724.609375px -233.203125px;
+}
+
+.sprite-earth_americas {
+  background-position: -753.515625px -233.203125px;
+}
+
+.sprite-earth_asia {
+  background-position: -782.421875px -233.203125px;
+}
+
+.sprite-egg {
+  background-position: -811.328125px -233.203125px;
+}
+
+.sprite-eggplant {
+  background-position: -1.953125px -262.109375px;
+}
+
+.sprite-eight {
+  background-position: -30.859375px -262.109375px;
+}
+
+.sprite-eight_pointed_black_star {
+  background-position: -59.765625px -262.109375px;
+}
+
+.sprite-eight_spoked_asterisk {
+  background-position: -88.671875px -262.109375px;
+}
+
+.sprite-electric_plug {
+  background-position: -117.578125px -262.109375px;
+}
+
+.sprite-elephant {
+  background-position: -146.484375px -262.109375px;
+}
+
+.sprite-email {
+  background-position: -175.390625px -262.109375px;
+}
+
+.sprite-end {
+  background-position: -204.296875px -262.109375px;
+}
+
+.sprite-envelope {
+  background-position: -233.203125px -262.109375px;
+}
+
+.sprite-es {
+  background-position: -262.109375px -262.109375px;
+}
+
+.sprite-euro {
+  background-position: -291.015625px -262.109375px;
+}
+
+.sprite-european_castle {
+  background-position: -319.921875px -262.109375px;
+}
+
+.sprite-european_post_office {
+  background-position: -348.828125px -262.109375px;
+}
+
+.sprite-evergreen_tree {
+  background-position: -377.734375px -262.109375px;
+}
+
+.sprite-exclamation {
+  background-position: -406.640625px -262.109375px;
+}
+
+.sprite-expressionless {
+  background-position: -435.546875px -262.109375px;
+}
+
+.sprite-eyeglasses {
+  background-position: -464.453125px -262.109375px;
+}
+
+.sprite-eyes {
+  background-position: -493.359375px -262.109375px;
+}
+
+.sprite-facepunch {
+  background-position: -522.265625px -262.109375px;
+}
+
+.sprite-factory {
+  background-position: -551.171875px -262.109375px;
+}
+
+.sprite-fallen_leaf {
+  background-position: -580.078125px -262.109375px;
+}
+
+.sprite-family {
+  background-position: -608.984375px -262.109375px;
+}
+
+.sprite-fast_forward {
+  background-position: -637.890625px -262.109375px;
+}
+
+.sprite-fax {
+  background-position: -666.796875px -262.109375px;
+}
+
+.sprite-fearful {
+  background-position: -695.703125px -262.109375px;
+}
+
+.sprite-feelsgood {
+  background-position: -724.609375px -262.109375px;
+}
+
+.sprite-feet {
+  background-position: -753.515625px -262.109375px;
+}
+
+.sprite-ferris_wheel {
+  background-position: -782.421875px -262.109375px;
+}
+
+.sprite-file_folder {
+  background-position: -811.328125px -262.109375px;
+}
+
+.sprite-finnadie {
+  background-position: -1.953125px -291.015625px;
+}
+
+.sprite-fire {
+  background-position: -30.859375px -291.015625px;
+}
+
+.sprite-fire_engine {
+  background-position: -59.765625px -291.015625px;
+}
+
+.sprite-fireworks {
+  background-position: -88.671875px -291.015625px;
+}
+
+.sprite-first_quarter_moon {
+  background-position: -117.578125px -291.015625px;
+}
+
+.sprite-first_quarter_moon_with_face {
+  background-position: -146.484375px -291.015625px;
+}
+
+.sprite-fish {
+  background-position: -175.390625px -291.015625px;
+}
+
+.sprite-fish_cake {
+  background-position: -204.296875px -291.015625px;
+}
+
+.sprite-fishing_pole_and_fish {
+  background-position: -233.203125px -291.015625px;
+}
+
+.sprite-fist {
+  background-position: -262.109375px -291.015625px;
+}
+
+.sprite-five {
+  background-position: -291.015625px -291.015625px;
+}
+
+.sprite-flags {
+  background-position: -319.921875px -291.015625px;
+}
+
+.sprite-flashlight {
+  background-position: -348.828125px -291.015625px;
+}
+
+.sprite-floppy_disk {
+  background-position: -377.734375px -291.015625px;
+}
+
+.sprite-flower_playing_cards {
+  background-position: -406.640625px -291.015625px;
+}
+
+.sprite-flushed {
+  background-position: -435.546875px -291.015625px;
+}
+
+.sprite-foggy {
+  background-position: -464.453125px -291.015625px;
+}
+
+.sprite-football {
+  background-position: -493.359375px -291.015625px;
+}
+
+.sprite-fork_and_knife {
+  background-position: -522.265625px -291.015625px;
+}
+
+.sprite-fountain {
+  background-position: -551.171875px -291.015625px;
+}
+
+.sprite-four {
+  background-position: -580.078125px -291.015625px;
+}
+
+.sprite-four_leaf_clover {
+  background-position: -608.984375px -291.015625px;
+}
+
+.sprite-fr {
+  background-position: -637.890625px -291.015625px;
+}
+
+.sprite-free {
+  background-position: -666.796875px -291.015625px;
+}
+
+.sprite-fried_shrimp {
+  background-position: -695.703125px -291.015625px;
+}
+
+.sprite-fries {
+  background-position: -724.609375px -291.015625px;
+}
+
+.sprite-frog {
+  background-position: -753.515625px -291.015625px;
+}
+
+.sprite-frowning {
+  background-position: -782.421875px -291.015625px;
+}
+
+.sprite-fu {
+  background-position: -811.328125px -291.015625px;
+}
+
+.sprite-fuelpump {
+  background-position: -1.953125px -319.921875px;
+}
+
+.sprite-full_moon {
+  background-position: -30.859375px -319.921875px;
+}
+
+.sprite-full_moon_with_face {
+  background-position: -59.765625px -319.921875px;
+}
+
+.sprite-game_die {
+  background-position: -88.671875px -319.921875px;
+}
+
+.sprite-gb {
+  background-position: -117.578125px -319.921875px;
+}
+
+.sprite-gem {
+  background-position: -146.484375px -319.921875px;
+}
+
+.sprite-gemini {
+  background-position: -175.390625px -319.921875px;
+}
+
+.sprite-ghost {
+  background-position: -204.296875px -319.921875px;
+}
+
+.sprite-gift {
+  background-position: -233.203125px -319.921875px;
+}
+
+.sprite-gift_heart {
+  background-position: -262.109375px -319.921875px;
+}
+
+.sprite-girl {
+  background-position: -291.015625px -319.921875px;
+}
+
+.sprite-github {
+  background-position: -840.234375px -1.953125px;
+}
+
+.sprite-globe_with_meridians {
+  background-position: -319.921875px -319.921875px;
+}
+
+.sprite-gmail {
+  background-position: -840.234375px -17.578125px;
+}
+
+.sprite-goat {
+  background-position: -348.828125px -319.921875px;
+}
+
+.sprite-goberserk {
+  background-position: -377.734375px -319.921875px;
+}
+
+.sprite-godmode {
+  background-position: -406.640625px -319.921875px;
+}
+
+.sprite-golf {
+  background-position: -435.546875px -319.921875px;
+}
+
+.sprite-grapes {
+  background-position: -464.453125px -319.921875px;
+}
+
+.sprite-green_apple {
+  background-position: -493.359375px -319.921875px;
+}
+
+.sprite-green_book {
+  background-position: -522.265625px -319.921875px;
+}
+
+.sprite-green_heart {
+  background-position: -551.171875px -319.921875px;
+}
+
+.sprite-grey_exclamation {
+  background-position: -580.078125px -319.921875px;
+}
+
+.sprite-grey_question {
+  background-position: -608.984375px -319.921875px;
+}
+
+.sprite-grimacing {
+  background-position: -637.890625px -319.921875px;
+}
+
+.sprite-grin {
+  background-position: -666.796875px -319.921875px;
+}
+
+.sprite-grinning {
+  background-position: -695.703125px -319.921875px;
+}
+
+.sprite-guardsman {
+  background-position: -724.609375px -319.921875px;
+}
+
+.sprite-guitar {
+  background-position: -753.515625px -319.921875px;
+}
+
+.sprite-gun {
+  background-position: -782.421875px -319.921875px;
+}
+
+.sprite-haircut {
+  background-position: -811.328125px -319.921875px;
+}
+
+.sprite-hamburger {
+  background-position: -1.953125px -348.828125px;
+}
+
+.sprite-hammer {
+  background-position: -30.859375px -348.828125px;
+}
+
+.sprite-hamster {
+  background-position: -59.765625px -348.828125px;
+}
+
+.sprite-hand {
+  background-position: -88.671875px -348.828125px;
+}
+
+.sprite-handbag {
+  background-position: -117.578125px -348.828125px;
+}
+
+.sprite-hankey {
+  background-position: -146.484375px -348.828125px;
+}
+
+.sprite-hash {
+  background-position: -175.390625px -348.828125px;
+}
+
+.sprite-hatched_chick {
+  background-position: -204.296875px -348.828125px;
+}
+
+.sprite-hatching_chick {
+  background-position: -233.203125px -348.828125px;
+}
+
+.sprite-headphones {
+  background-position: -262.109375px -348.828125px;
+}
+
+.sprite-hear_no_evil {
+  background-position: -291.015625px -348.828125px;
+}
+
+.sprite-heart {
+  background-position: -319.921875px -348.828125px;
+}
+
+.sprite-heart_decoration {
+  background-position: -348.828125px -348.828125px;
+}
+
+.sprite-heart_eyes {
+  background-position: -377.734375px -348.828125px;
+}
+
+.sprite-heart_eyes_cat {
+  background-position: -406.640625px -348.828125px;
+}
+
+.sprite-heartbeat {
+  background-position: -435.546875px -348.828125px;
+}
+
+.sprite-heartpulse {
+  background-position: -464.453125px -348.828125px;
+}
+
+.sprite-hearts {
+  background-position: -493.359375px -348.828125px;
+}
+
+.sprite-heavy_check_mark {
+  background-position: -522.265625px -348.828125px;
+}
+
+.sprite-heavy_division_sign {
+  background-position: -551.171875px -348.828125px;
+}
+
+.sprite-heavy_dollar_sign {
+  background-position: -580.078125px -348.828125px;
+}
+
+.sprite-heavy_exclamation_mark {
+  background-position: -608.984375px -348.828125px;
+}
+
+.sprite-heavy_minus_sign {
+  background-position: -637.890625px -348.828125px;
+}
+
+.sprite-heavy_multiplication_x {
+  background-position: -666.796875px -348.828125px;
+}
+
+.sprite-heavy_plus_sign {
+  background-position: -695.703125px -348.828125px;
+}
+
+.sprite-helicopter {
+  background-position: -724.609375px -348.828125px;
+}
+
+.sprite-herb {
+  background-position: -753.515625px -348.828125px;
+}
+
+.sprite-hibiscus {
+  background-position: -782.421875px -348.828125px;
+}
+
+.sprite-high_brightness {
+  background-position: -811.328125px -348.828125px;
+}
+
+.sprite-high_heel {
+  background-position: -1.953125px -377.734375px;
+}
+
+.sprite-hocho {
+  background-position: -30.859375px -377.734375px;
+}
+
+.sprite-honey_pot {
+  background-position: -59.765625px -377.734375px;
+}
+
+.sprite-honeybee {
+  background-position: -88.671875px -377.734375px;
+}
+
+.sprite-horse {
+  background-position: -117.578125px -377.734375px;
+}
+
+.sprite-horse_racing {
+  background-position: -146.484375px -377.734375px;
+}
+
+.sprite-hospital {
+  background-position: -175.390625px -377.734375px;
+}
+
+.sprite-hotel {
+  background-position: -204.296875px -377.734375px;
+}
+
+.sprite-hotsprings {
+  background-position: -233.203125px -377.734375px;
+}
+
+.sprite-hourglass {
+  background-position: -262.109375px -377.734375px;
+}
+
+.sprite-hourglass_flowing_sand {
+  background-position: -291.015625px -377.734375px;
+}
+
+.sprite-house {
+  background-position: -319.921875px -377.734375px;
+}
+
+.sprite-house_with_garden {
+  background-position: -348.828125px -377.734375px;
+}
+
+.sprite-hurtrealbad {
+  background-position: -377.734375px -377.734375px;
+}
+
+.sprite-hushed {
+  background-position: -406.640625px -377.734375px;
+}
+
+.sprite-ice_cream {
+  background-position: -435.546875px -377.734375px;
+}
+
+.sprite-icecream {
+  background-position: -464.453125px -377.734375px;
+}
+
+.sprite-id {
+  background-position: -493.359375px -377.734375px;
+}
+
+.sprite-ideograph_advantage {
+  background-position: -522.265625px -377.734375px;
+}
+
+.sprite-imp {
+  background-position: -551.171875px -377.734375px;
+}
+
+.sprite-inbox_tray {
+  background-position: -580.078125px -377.734375px;
+}
+
+.sprite-incoming_envelope {
+  background-position: -608.984375px -377.734375px;
+}
+
+.sprite-information_desk_person {
+  background-position: -637.890625px -377.734375px;
+}
+
+.sprite-information_source {
+  background-position: -666.796875px -377.734375px;
+}
+
+.sprite-innocent {
+  background-position: -695.703125px -377.734375px;
+}
+
+.sprite-interrobang {
+  background-position: -724.609375px -377.734375px;
+}
+
+.sprite-iphone {
+  background-position: -753.515625px -377.734375px;
+}
+
+.sprite-it {
+  background-position: -782.421875px -377.734375px;
+}
+
+.sprite-izakaya_lantern {
+  background-position: -811.328125px -377.734375px;
+}
+
+.sprite-jack_o_lantern {
+  background-position: -1.953125px -406.640625px;
+}
+
+.sprite-japan {
+  background-position: -30.859375px -406.640625px;
+}
+
+.sprite-japanese_castle {
+  background-position: -59.765625px -406.640625px;
+}
+
+.sprite-japanese_goblin {
+  background-position: -88.671875px -406.640625px;
+}
+
+.sprite-japanese_ogre {
+  background-position: -117.578125px -406.640625px;
+}
+
+.sprite-jeans {
+  background-position: -146.484375px -406.640625px;
+}
+
+.sprite-joy {
+  background-position: -175.390625px -406.640625px;
+}
+
+.sprite-joy_cat {
+  background-position: -204.296875px -406.640625px;
+}
+
+.sprite-jp {
+  background-position: -233.203125px -406.640625px;
+}
+
+.sprite-key {
+  background-position: -262.109375px -406.640625px;
+}
+
+.sprite-keycap_ten {
+  background-position: -291.015625px -406.640625px;
+}
+
+.sprite-kimono {
+  background-position: -319.921875px -406.640625px;
+}
+
+.sprite-kiss {
+  background-position: -348.828125px -406.640625px;
+}
+
+.sprite-kissing {
+  background-position: -377.734375px -406.640625px;
+}
+
+.sprite-kissing_cat {
+  background-position: -406.640625px -406.640625px;
+}
+
+.sprite-kissing_closed_eyes {
+  background-position: -435.546875px -406.640625px;
+}
+
+.sprite-kissing_face {
+  background-position: -464.453125px -406.640625px;
+}
+
+.sprite-kissing_heart {
+  background-position: -493.359375px -406.640625px;
+}
+
+.sprite-kissing_smiling_eyes {
+  background-position: -522.265625px -406.640625px;
+}
+
+.sprite-koala {
+  background-position: -551.171875px -406.640625px;
+}
+
+.sprite-koko {
+  background-position: -580.078125px -406.640625px;
+}
+
+.sprite-kr {
+  background-position: -608.984375px -406.640625px;
+}
+
+.sprite-large_blue_circle {
+  background-position: -637.890625px -406.640625px;
+}
+
+.sprite-large_blue_diamond {
+  background-position: -666.796875px -406.640625px;
+}
+
+.sprite-large_orange_diamond {
+  background-position: -695.703125px -406.640625px;
+}
+
+.sprite-last_quarter_moon {
+  background-position: -724.609375px -406.640625px;
+}
+
+.sprite-last_quarter_moon_with_face {
+  background-position: -753.515625px -406.640625px;
+}
+
+.sprite-laughing {
+  background-position: -782.421875px -406.640625px;
+}
+
+.sprite-leaves {
+  background-position: -811.328125px -406.640625px;
+}
+
+.sprite-ledger {
+  background-position: -1.953125px -435.546875px;
+}
+
+.sprite-left_luggage {
+  background-position: -30.859375px -435.546875px;
+}
+
+.sprite-left_right_arrow {
+  background-position: -59.765625px -435.546875px;
+}
+
+.sprite-leftwards_arrow_with_hook {
+  background-position: -88.671875px -435.546875px;
+}
+
+.sprite-lemon {
+  background-position: -117.578125px -435.546875px;
+}
+
+.sprite-leo {
+  background-position: -146.484375px -435.546875px;
+}
+
+.sprite-leopard {
+  background-position: -175.390625px -435.546875px;
+}
+
+.sprite-libra {
+  background-position: -204.296875px -435.546875px;
+}
+
+.sprite-light_rail {
+  background-position: -233.203125px -435.546875px;
+}
+
+.sprite-link {
+  background-position: -262.109375px -435.546875px;
+}
+
+.sprite-linkedin {
+  background-position: -840.234375px -33.203125px;
+}
+
+.sprite-lips {
+  background-position: -291.015625px -435.546875px;
+}
+
+.sprite-lipstick {
+  background-position: -319.921875px -435.546875px;
+}
+
+.sprite-lock {
+  background-position: -348.828125px -435.546875px;
+}
+
+.sprite-lock_with_ink_pen {
+  background-position: -377.734375px -435.546875px;
+}
+
+.sprite-lollipop {
+  background-position: -406.640625px -435.546875px;
+}
+
+.sprite-loop {
+  background-position: -435.546875px -435.546875px;
+}
+
+.sprite-loudspeaker {
+  background-position: -464.453125px -435.546875px;
+}
+
+.sprite-love_hotel {
+  background-position: -493.359375px -435.546875px;
+}
+
+.sprite-love_letter {
+  background-position: -522.265625px -435.546875px;
+}
+
+.sprite-low_brightness {
+  background-position: -551.171875px -435.546875px;
+}
+
+.sprite-m {
+  background-position: -580.078125px -435.546875px;
+}
+
+.sprite-mag {
+  background-position: -608.984375px -435.546875px;
+}
+
+.sprite-mag_right {
+  background-position: -637.890625px -435.546875px;
+}
+
+.sprite-mahjong {
+  background-position: -666.796875px -435.546875px;
+}
+
+.sprite-mailbox {
+  background-position: -695.703125px -435.546875px;
+}
+
+.sprite-mailbox_closed {
+  background-position: -724.609375px -435.546875px;
+}
+
+.sprite-mailbox_with_mail {
+  background-position: -753.515625px -435.546875px;
+}
+
+.sprite-mailbox_with_no_mail {
+  background-position: -782.421875px -435.546875px;
+}
+
+.sprite-man {
+  background-position: -811.328125px -435.546875px;
+}
+
+.sprite-man_with_gua_pi_mao {
+  background-position: -1.953125px -464.453125px;
+}
+
+.sprite-man_with_turban {
+  background-position: -30.859375px -464.453125px;
+}
+
+.sprite-mans_shoe {
+  background-position: -59.765625px -464.453125px;
+}
+
+.sprite-maple_leaf {
+  background-position: -88.671875px -464.453125px;
+}
+
+.sprite-mask {
+  background-position: -117.578125px -464.453125px;
+}
+
+.sprite-massage {
+  background-position: -146.484375px -464.453125px;
+}
+
+.sprite-meat_on_bone {
+  background-position: -175.390625px -464.453125px;
+}
+
+.sprite-mega {
+  background-position: -204.296875px -464.453125px;
+}
+
+.sprite-melon {
+  background-position: -233.203125px -464.453125px;
+}
+
+.sprite-memo {
+  background-position: -262.109375px -464.453125px;
+}
+
+.sprite-mens {
+  background-position: -291.015625px -464.453125px;
+}
+
+.sprite-metal {
+  background-position: -319.921875px -464.453125px;
+}
+
+.sprite-metro {
+  background-position: -348.828125px -464.453125px;
+}
+
+.sprite-microphone {
+  background-position: -377.734375px -464.453125px;
+}
+
+.sprite-microscope {
+  background-position: -406.640625px -464.453125px;
+}
+
+.sprite-milky_way {
+  background-position: -435.546875px -464.453125px;
+}
+
+.sprite-minibus {
+  background-position: -464.453125px -464.453125px;
+}
+
+.sprite-minidisc {
+  background-position: -493.359375px -464.453125px;
+}
+
+.sprite-mobile_phone_off {
+  background-position: -522.265625px -464.453125px;
+}
+
+.sprite-money_with_wings {
+  background-position: -551.171875px -464.453125px;
+}
+
+.sprite-moneybag {
+  background-position: -580.078125px -464.453125px;
+}
+
+.sprite-monkey {
+  background-position: -608.984375px -464.453125px;
+}
+
+.sprite-monkey_face {
+  background-position: -637.890625px -464.453125px;
+}
+
+.sprite-monorail {
+  background-position: -666.796875px -464.453125px;
+}
+
+.sprite-mortar_board {
+  background-position: -695.703125px -464.453125px;
+}
+
+.sprite-mount_fuji {
+  background-position: -724.609375px -464.453125px;
+}
+
+.sprite-mountain_bicyclist {
+  background-position: -753.515625px -464.453125px;
+}
+
+.sprite-mountain_cableway {
+  background-position: -782.421875px -464.453125px;
+}
+
+.sprite-mountain_railway {
+  background-position: -811.328125px -464.453125px;
+}
+
+.sprite-mouse {
+  background-position: -1.953125px -493.359375px;
+}
+
+.sprite-mouse2 {
+  background-position: -30.859375px -493.359375px;
+}
+
+.sprite-movie_camera {
+  background-position: -59.765625px -493.359375px;
+}
+
+.sprite-moyai {
+  background-position: -88.671875px -493.359375px;
+}
+
+.sprite-muscle {
+  background-position: -117.578125px -493.359375px;
+}
+
+.sprite-mushroom {
+  background-position: -146.484375px -493.359375px;
+}
+
+.sprite-musical_keyboard {
+  background-position: -175.390625px -493.359375px;
+}
+
+.sprite-musical_note {
+  background-position: -204.296875px -493.359375px;
+}
+
+.sprite-musical_score {
+  background-position: -233.203125px -493.359375px;
+}
+
+.sprite-mute {
+  background-position: -262.109375px -493.359375px;
+}
+
+.sprite-nail_care {
+  background-position: -291.015625px -493.359375px;
+}
+
+.sprite-name_badge {
+  background-position: -319.921875px -493.359375px;
+}
+
+.sprite-neckbeard {
+  background-position: -348.828125px -493.359375px;
+}
+
+.sprite-necktie {
+  background-position: -377.734375px -493.359375px;
+}
+
+.sprite-negative_squared_cross_mark {
+  background-position: -406.640625px -493.359375px;
+}
+
+.sprite-neutral_face {
+  background-position: -435.546875px -493.359375px;
+}
+
+.sprite-new {
+  background-position: -464.453125px -493.359375px;
+}
+
+.sprite-new_moon {
+  background-position: -493.359375px -493.359375px;
+}
+
+.sprite-new_moon_with_face {
+  background-position: -522.265625px -493.359375px;
+}
+
+.sprite-newspaper {
+  background-position: -551.171875px -493.359375px;
+}
+
+.sprite-ng {
+  background-position: -580.078125px -493.359375px;
+}
+
+.sprite-nine {
+  background-position: -608.984375px -493.359375px;
+}
+
+.sprite-no_bell {
+  background-position: -637.890625px -493.359375px;
+}
+
+.sprite-no_bicycles {
+  background-position: -666.796875px -493.359375px;
+}
+
+.sprite-no_entry {
+  background-position: -695.703125px -493.359375px;
+}
+
+.sprite-no_entry_sign {
+  background-position: -724.609375px -493.359375px;
+}
+
+.sprite-no_good {
+  background-position: -753.515625px -493.359375px;
+}
+
+.sprite-no_mobile_phones {
+  background-position: -782.421875px -493.359375px;
+}
+
+.sprite-no_mouth {
+  background-position: -811.328125px -493.359375px;
+}
+
+.sprite-no_pedestrians {
+  background-position: -1.953125px -522.265625px;
+}
+
+.sprite-no_smoking {
+  background-position: -30.859375px -522.265625px;
+}
+
+.sprite-non-potable_water {
+  background-position: -59.765625px -522.265625px;
+}
+
+.sprite-nose {
+  background-position: -88.671875px -522.265625px;
+}
+
+.sprite-notebook {
+  background-position: -117.578125px -522.265625px;
+}
+
+.sprite-notebook_with_decorative_cover {
+  background-position: -146.484375px -522.265625px;
+}
+
+.sprite-notes {
+  background-position: -175.390625px -522.265625px;
+}
+
+.sprite-nut_and_bolt {
+  background-position: -204.296875px -522.265625px;
+}
+
+.sprite-o {
+  background-position: -233.203125px -522.265625px;
+}
+
+.sprite-o2 {
+  background-position: -262.109375px -522.265625px;
+}
+
+.sprite-ocean {
+  background-position: -291.015625px -522.265625px;
+}
+
+.sprite-octocat {
+  background-position: -319.921875px -522.265625px;
+}
+
+.sprite-octopus {
+  background-position: -348.828125px -522.265625px;
+}
+
+.sprite-oden {
+  background-position: -377.734375px -522.265625px;
+}
+
+.sprite-office {
+  background-position: -406.640625px -522.265625px;
+}
+
+.sprite-ok {
+  background-position: -435.546875px -522.265625px;
+}
+
+.sprite-ok_hand {
+  background-position: -464.453125px -522.265625px;
+}
+
+.sprite-ok_woman {
+  background-position: -493.359375px -522.265625px;
+}
+
+.sprite-older_man {
+  background-position: -522.265625px -522.265625px;
+}
+
+.sprite-older_woman {
+  background-position: -551.171875px -522.265625px;
+}
+
+.sprite-on {
+  background-position: -580.078125px -522.265625px;
+}
+
+.sprite-oncoming_automobile {
+  background-position: -608.984375px -522.265625px;
+}
+
+.sprite-oncoming_bus {
+  background-position: -637.890625px -522.265625px;
+}
+
+.sprite-oncoming_police_car {
+  background-position: -666.796875px -522.265625px;
+}
+
+.sprite-oncoming_taxi {
+  background-position: -695.703125px -522.265625px;
+}
+
+.sprite-one {
+  background-position: -724.609375px -522.265625px;
+}
+
+.sprite-open_file_folder {
+  background-position: -753.515625px -522.265625px;
+}
+
+.sprite-open_hands {
+  background-position: -782.421875px -522.265625px;
+}
+
+.sprite-open_mouth {
+  background-position: -811.328125px -522.265625px;
+}
+
+.sprite-ophiuchus {
+  background-position: -1.953125px -551.171875px;
+}
+
+.sprite-orange_book {
+  background-position: -30.859375px -551.171875px;
+}
+
+.sprite-outbox_tray {
+  background-position: -59.765625px -551.171875px;
+}
+
+.sprite-ox {
+  background-position: -88.671875px -551.171875px;
+}
+
+.sprite-package {
+  background-position: -117.578125px -551.171875px;
+}
+
+.sprite-page_facing_up {
+  background-position: -146.484375px -551.171875px;
+}
+
+.sprite-page_with_curl {
+  background-position: -175.390625px -551.171875px;
+}
+
+.sprite-pager {
+  background-position: -204.296875px -551.171875px;
+}
+
+.sprite-palm_tree {
+  background-position: -233.203125px -551.171875px;
+}
+
+.sprite-panda_face {
+  background-position: -262.109375px -551.171875px;
+}
+
+.sprite-paperclip {
+  background-position: -291.015625px -551.171875px;
+}
+
+.sprite-parking {
+  background-position: -319.921875px -551.171875px;
+}
+
+.sprite-part_alternation_mark {
+  background-position: -348.828125px -551.171875px;
+}
+
+.sprite-partly_sunny {
+  background-position: -377.734375px -551.171875px;
+}
+
+.sprite-passport_control {
+  background-position: -406.640625px -551.171875px;
+}
+
+.sprite-paw_prints {
+  background-position: -435.546875px -551.171875px;
+}
+
+.sprite-peach {
+  background-position: -464.453125px -551.171875px;
+}
+
+.sprite-pear {
+  background-position: -493.359375px -551.171875px;
+}
+
+.sprite-pencil {
+  background-position: -522.265625px -551.171875px;
+}
+
+.sprite-pencil2 {
+  background-position: -551.171875px -551.171875px;
+}
+
+.sprite-penguin {
+  background-position: -580.078125px -551.171875px;
+}
+
+.sprite-pensive {
+  background-position: -608.984375px -551.171875px;
+}
+
+.sprite-performing_arts {
+  background-position: -637.890625px -551.171875px;
+}
+
+.sprite-persevere {
+  background-position: -666.796875px -551.171875px;
+}
+
+.sprite-person_frowning {
+  background-position: -695.703125px -551.171875px;
+}
+
+.sprite-person_with_blond_hair {
+  background-position: -724.609375px -551.171875px;
+}
+
+.sprite-person_with_pouting_face {
+  background-position: -753.515625px -551.171875px;
+}
+
+.sprite-phone {
+  background-position: -782.421875px -551.171875px;
+}
+
+.sprite-pig {
+  background-position: -811.328125px -551.171875px;
+}
+
+.sprite-pig2 {
+  background-position: -1.953125px -580.078125px;
+}
+
+.sprite-pig_nose {
+  background-position: -30.859375px -580.078125px;
+}
+
+.sprite-pill {
+  background-position: -59.765625px -580.078125px;
+}
+
+.sprite-pineapple {
+  background-position: -88.671875px -580.078125px;
+}
+
+.sprite-pisces {
+  background-position: -117.578125px -580.078125px;
+}
+
+.sprite-pizza {
+  background-position: -146.484375px -580.078125px;
+}
+
+.sprite-plus1 {
+  background-position: -175.390625px -580.078125px;
+}
+
+.sprite-point_down {
+  background-position: -204.296875px -580.078125px;
+}
+
+.sprite-point_left {
+  background-position: -233.203125px -580.078125px;
+}
+
+.sprite-point_right {
+  background-position: -262.109375px -580.078125px;
+}
+
+.sprite-point_up {
+  background-position: -291.015625px -580.078125px;
+}
+
+.sprite-point_up_2 {
+  background-position: -319.921875px -580.078125px;
+}
+
+.sprite-police_car {
+  background-position: -348.828125px -580.078125px;
+}
+
+.sprite-poodle {
+  background-position: -377.734375px -580.078125px;
+}
+
+.sprite-poop {
+  background-position: -406.640625px -580.078125px;
+}
+
+.sprite-post_office {
+  background-position: -435.546875px -580.078125px;
+}
+
+.sprite-postal_horn {
+  background-position: -464.453125px -580.078125px;
+}
+
+.sprite-postbox {
+  background-position: -493.359375px -580.078125px;
+}
+
+.sprite-potable_water {
+  background-position: -522.265625px -580.078125px;
+}
+
+.sprite-pouch {
+  background-position: -551.171875px -580.078125px;
+}
+
+.sprite-poultry_leg {
+  background-position: -580.078125px -580.078125px;
+}
+
+.sprite-pound {
+  background-position: -608.984375px -580.078125px;
+}
+
+.sprite-pouting_cat {
+  background-position: -637.890625px -580.078125px;
+}
+
+.sprite-pray {
+  background-position: -666.796875px -580.078125px;
+}
+
+.sprite-princess {
+  background-position: -695.703125px -580.078125px;
+}
+
+.sprite-punch {
+  background-position: -724.609375px -580.078125px;
+}
+
+.sprite-purple_heart {
+  background-position: -753.515625px -580.078125px;
+}
+
+.sprite-purse {
+  background-position: -782.421875px -580.078125px;
+}
+
+.sprite-pushpin {
+  background-position: -811.328125px -580.078125px;
+}
+
+.sprite-put_litter_in_its_place {
+  background-position: -1.953125px -608.984375px;
+}
+
+.sprite-question {
+  background-position: -30.859375px -608.984375px;
+}
+
+.sprite-rabbit {
+  background-position: -59.765625px -608.984375px;
+}
+
+.sprite-rabbit2 {
+  background-position: -88.671875px -608.984375px;
+}
+
+.sprite-racehorse {
+  background-position: -117.578125px -608.984375px;
+}
+
+.sprite-radio {
+  background-position: -146.484375px -608.984375px;
+}
+
+.sprite-radio_button {
+  background-position: -175.390625px -608.984375px;
+}
+
+.sprite-rage {
+  background-position: -204.296875px -608.984375px;
+}
+
+.sprite-rage1 {
+  background-position: -233.203125px -608.984375px;
+}
+
+.sprite-rage2 {
+  background-position: -262.109375px -608.984375px;
+}
+
+.sprite-rage3 {
+  background-position: -291.015625px -608.984375px;
+}
+
+.sprite-rage4 {
+  background-position: -319.921875px -608.984375px;
+}
+
+.sprite-railway_car {
+  background-position: -348.828125px -608.984375px;
+}
+
+.sprite-rainbow {
+  background-position: -377.734375px -608.984375px;
+}
+
+.sprite-raised_hand {
+  background-position: -406.640625px -608.984375px;
+}
+
+.sprite-raised_hands {
+  background-position: -435.546875px -608.984375px;
+}
+
+.sprite-raising_hand {
+  background-position: -464.453125px -608.984375px;
+}
+
+.sprite-ram {
+  background-position: -493.359375px -608.984375px;
+}
+
+.sprite-ramen {
+  background-position: -522.265625px -608.984375px;
+}
+
+.sprite-rat {
+  background-position: -551.171875px -608.984375px;
+}
+
+.sprite-recycle {
+  background-position: -580.078125px -608.984375px;
+}
+
+.sprite-red_car {
+  background-position: -608.984375px -608.984375px;
+}
+
+.sprite-red_circle {
+  background-position: -637.890625px -608.984375px;
+}
+
+.sprite-refuse {
+  background-position: -666.796875px -608.984375px;
+}
+
+.sprite-registered {
+  background-position: -695.703125px -608.984375px;
+}
+
+.sprite-relaxed {
+  background-position: -724.609375px -608.984375px;
+}
+
+.sprite-relieved {
+  background-position: -753.515625px -608.984375px;
+}
+
+.sprite-repeat {
+  background-position: -782.421875px -608.984375px;
+}
+
+.sprite-repeat_one {
+  background-position: -811.328125px -608.984375px;
+}
+
+.sprite-restroom {
+  background-position: -1.953125px -637.890625px;
+}
+
+.sprite-revolving_hearts {
+  background-position: -30.859375px -637.890625px;
+}
+
+.sprite-rewind {
+  background-position: -59.765625px -637.890625px;
+}
+
+.sprite-ribbon {
+  background-position: -88.671875px -637.890625px;
+}
+
+.sprite-rice {
+  background-position: -117.578125px -637.890625px;
+}
+
+.sprite-rice_ball {
+  background-position: -146.484375px -637.890625px;
+}
+
+.sprite-rice_cracker {
+  background-position: -175.390625px -637.890625px;
+}
+
+.sprite-rice_scene {
+  background-position: -204.296875px -637.890625px;
+}
+
+.sprite-ring {
+  background-position: -233.203125px -637.890625px;
+}
+
+.sprite-rocket {
+  background-position: -262.109375px -637.890625px;
+}
+
+.sprite-roller_coaster {
+  background-position: -291.015625px -637.890625px;
+}
+
+.sprite-rooster {
+  background-position: -319.921875px -637.890625px;
+}
+
+.sprite-rose {
+  background-position: -348.828125px -637.890625px;
+}
+
+.sprite-rotating_light {
+  background-position: -377.734375px -637.890625px;
+}
+
+.sprite-round_pushpin {
+  background-position: -406.640625px -637.890625px;
+}
+
+.sprite-rowboat {
+  background-position: -435.546875px -637.890625px;
+}
+
+.sprite-ru {
+  background-position: -464.453125px -637.890625px;
+}
+
+.sprite-rugby_football {
+  background-position: -493.359375px -637.890625px;
+}
+
+.sprite-runner {
+  background-position: -522.265625px -637.890625px;
+}
+
+.sprite-running {
+  background-position: -551.171875px -637.890625px;
+}
+
+.sprite-running_shirt_with_sash {
+  background-position: -580.078125px -637.890625px;
+}
+
+.sprite-sa {
+  background-position: -608.984375px -637.890625px;
+}
+
+.sprite-sagittarius {
+  background-position: -637.890625px -637.890625px;
+}
+
+.sprite-sailboat {
+  background-position: -666.796875px -637.890625px;
+}
+
+.sprite-sake {
+  background-position: -695.703125px -637.890625px;
+}
+
+.sprite-sandal {
+  background-position: -724.609375px -637.890625px;
+}
+
+.sprite-santa {
+  background-position: -753.515625px -637.890625px;
+}
+
+.sprite-satellite {
+  background-position: -782.421875px -637.890625px;
+}
+
+.sprite-satisfied {
+  background-position: -811.328125px -637.890625px;
+}
+
+.sprite-saxophone {
+  background-position: -1.953125px -666.796875px;
+}
+
+.sprite-school {
+  background-position: -30.859375px -666.796875px;
+}
+
+.sprite-school_satchel {
+  background-position: -59.765625px -666.796875px;
+}
+
+.sprite-scissors {
+  background-position: -88.671875px -666.796875px;
+}
+
+.sprite-scorpius {
+  background-position: -117.578125px -666.796875px;
+}
+
+.sprite-scream {
+  background-position: -146.484375px -666.796875px;
+}
+
+.sprite-scream_cat {
+  background-position: -175.390625px -666.796875px;
+}
+
+.sprite-scroll {
+  background-position: -204.296875px -666.796875px;
+}
+
+.sprite-seat {
+  background-position: -233.203125px -666.796875px;
+}
+
+.sprite-secret {
+  background-position: -262.109375px -666.796875px;
+}
+
+.sprite-see_no_evil {
+  background-position: -291.015625px -666.796875px;
+}
+
+.sprite-seedling {
+  background-position: -319.921875px -666.796875px;
+}
+
+.sprite-seven {
+  background-position: -348.828125px -666.796875px;
+}
+
+.sprite-shaved_ice {
+  background-position: -377.734375px -666.796875px;
+}
+
+.sprite-sheep {
+  background-position: -406.640625px -666.796875px;
+}
+
+.sprite-shell {
+  background-position: -435.546875px -666.796875px;
+}
+
+.sprite-ship {
+  background-position: -464.453125px -666.796875px;
+}
+
+.sprite-shipit {
+  background-position: -493.359375px -666.796875px;
+}
+
+.sprite-shirt {
+  background-position: -526.5625px -666.796875px;
+}
+
+.sprite-shit {
+  background-position: -555.46875px -666.796875px;
+}
+
+.sprite-shoe {
+  background-position: -584.375px -666.796875px;
+}
+
+.sprite-shower {
+  background-position: -613.28125px -666.796875px;
+}
+
+.sprite-signal_strength {
+  background-position: -642.1875px -666.796875px;
+}
+
+.sprite-six {
+  background-position: -671.09375px -666.796875px;
+}
+
+.sprite-six_pointed_star {
+  background-position: -700px -666.796875px;
+}
+
+.sprite-ski {
+  background-position: -728.90625px -666.796875px;
+}
+
+.sprite-skull {
+  background-position: -757.8125px -666.796875px;
+}
+
+.sprite-sleeping {
+  background-position: -786.71875px -666.796875px;
+}
+
+.sprite-sleepy {
+  background-position: -815.625px -666.796875px;
+}
+
+.sprite-slot_machine {
+  background-position: -1.953125px -695.703125px;
+}
+
+.sprite-small_blue_diamond {
+  background-position: -30.859375px -695.703125px;
+}
+
+.sprite-small_orange_diamond {
+  background-position: -59.765625px -695.703125px;
+}
+
+.sprite-small_red_triangle {
+  background-position: -88.671875px -695.703125px;
+}
+
+.sprite-small_red_triangle_down {
+  background-position: -117.578125px -695.703125px;
+}
+
+.sprite-smile {
+  background-position: -146.484375px -695.703125px;
+}
+
+.sprite-smile_cat {
+  background-position: -175.390625px -695.703125px;
+}
+
+.sprite-smiley {
+  background-position: -204.296875px -695.703125px;
+}
+
+.sprite-smiley_cat {
+  background-position: -233.203125px -695.703125px;
+}
+
+.sprite-smiling_imp {
+  background-position: -262.109375px -695.703125px;
+}
+
+.sprite-smirk {
+  background-position: -291.015625px -695.703125px;
+}
+
+.sprite-smirk_cat {
+  background-position: -319.921875px -695.703125px;
+}
+
+.sprite-smoking {
+  background-position: -348.828125px -695.703125px;
+}
+
+.sprite-snail {
+  background-position: -377.734375px -695.703125px;
+}
+
+.sprite-snake {
+  background-position: -406.640625px -695.703125px;
+}
+
+.sprite-snowboarder {
+  background-position: -435.546875px -695.703125px;
+}
+
+.sprite-snowflake {
+  background-position: -464.453125px -695.703125px;
+}
+
+.sprite-snowman {
+  background-position: -526.5625px -695.703125px;
+}
+
+.sprite-sob {
+  background-position: -555.46875px -695.703125px;
+}
+
+.sprite-soccer {
+  background-position: -584.375px -695.703125px;
+}
+
+.sprite-soon {
+  background-position: -613.28125px -695.703125px;
+}
+
+.sprite-sos {
+  background-position: -642.1875px -695.703125px;
+}
+
+.sprite-sound {
+  background-position: -671.09375px -695.703125px;
+}
+
+.sprite-space_invader {
+  background-position: -700px -695.703125px;
+}
+
+.sprite-spades {
+  background-position: -728.90625px -695.703125px;
+}
+
+.sprite-spaghetti {
+  background-position: -757.8125px -695.703125px;
+}
+
+.sprite-sparkle {
+  background-position: -786.71875px -695.703125px;
+}
+
+.sprite-sparkler {
+  background-position: -815.625px -695.703125px;
+}
+
+.sprite-sparkles {
+  background-position: -1.953125px -724.609375px;
+}
+
+.sprite-sparkling_heart {
+  background-position: -30.859375px -724.609375px;
+}
+
+.sprite-speak_no_evil {
+  background-position: -59.765625px -724.609375px;
+}
+
+.sprite-speaker {
+  background-position: -88.671875px -724.609375px;
+}
+
+.sprite-speech_balloon {
+  background-position: -117.578125px -724.609375px;
+}
+
+.sprite-speedboat {
+  background-position: -146.484375px -724.609375px;
+}
+
+.sprite-squirrel {
+  background-position: -175.390625px -724.609375px;
+}
+
+.sprite-stackoverflow {
+  background-position: -840.234375px -48.828125px;
+}
+
+.sprite-star {
+  background-position: -208.59375px -724.609375px;
+}
+
+.sprite-star2 {
+  background-position: -237.5px -724.609375px;
+}
+
+.sprite-stars {
+  background-position: -266.40625px -724.609375px;
+}
+
+.sprite-station {
+  background-position: -295.3125px -724.609375px;
+}
+
+.sprite-statue_of_liberty {
+  background-position: -324.21875px -724.609375px;
+}
+
+.sprite-steam_locomotive {
+  background-position: -353.125px -724.609375px;
+}
+
+.sprite-stew {
+  background-position: -382.03125px -724.609375px;
+}
+
+.sprite-straight_ruler {
+  background-position: -410.9375px -724.609375px;
+}
+
+.sprite-strawberry {
+  background-position: -439.84375px -724.609375px;
+}
+
+.sprite-stuck_out_tongue {
+  background-position: -468.75px -724.609375px;
+}
+
+.sprite-stuck_out_tongue_closed_eyes {
+  background-position: -497.65625px -724.609375px;
+}
+
+.sprite-stuck_out_tongue_winking_eye {
+  background-position: -526.5625px -724.609375px;
+}
+
+.sprite-sun_with_face {
+  background-position: -555.46875px -724.609375px;
+}
+
+.sprite-sunflower {
+  background-position: -584.375px -724.609375px;
+}
+
+.sprite-sunglasses {
+  background-position: -613.28125px -724.609375px;
+}
+
+.sprite-sunny {
+  background-position: -642.1875px -724.609375px;
+}
+
+.sprite-sunrise {
+  background-position: -671.09375px -724.609375px;
+}
+
+.sprite-sunrise_over_mountains {
+  background-position: -700px -724.609375px;
+}
+
+.sprite-surfer {
+  background-position: -728.90625px -724.609375px;
+}
+
+.sprite-sushi {
+  background-position: -757.8125px -724.609375px;
+}
+
+.sprite-suspect {
+  background-position: -786.71875px -724.609375px;
+}
+
+.sprite-suspension_railway {
+  background-position: -815.625px -724.609375px;
+}
+
+.sprite-sweat {
+  background-position: -1.953125px -753.515625px;
+}
+
+.sprite-sweat_drops {
+  background-position: -30.859375px -753.515625px;
+}
+
+.sprite-sweat_smile {
+  background-position: -59.765625px -753.515625px;
+}
+
+.sprite-sweet_potato {
+  background-position: -88.671875px -753.515625px;
+}
+
+.sprite-swimmer {
+  background-position: -117.578125px -753.515625px;
+}
+
+.sprite-symbols {
+  background-position: -146.484375px -753.515625px;
+}
+
+.sprite-syringe {
+  background-position: -208.59375px -753.515625px;
+}
+
+.sprite-tada {
+  background-position: -237.5px -753.515625px;
+}
+
+.sprite-tanabata_tree {
+  background-position: -266.40625px -753.515625px;
+}
+
+.sprite-tangerine {
+  background-position: -295.3125px -753.515625px;
+}
+
+.sprite-taurus {
+  background-position: -324.21875px -753.515625px;
+}
+
+.sprite-taxi {
+  background-position: -353.125px -753.515625px;
+}
+
+.sprite-tea {
+  background-position: -382.03125px -753.515625px;
+}
+
+.sprite-telephone {
+  background-position: -410.9375px -753.515625px;
+}
+
+.sprite-telephone_receiver {
+  background-position: -439.84375px -753.515625px;
+}
+
+.sprite-telescope {
+  background-position: -468.75px -753.515625px;
+}
+
+.sprite-tennis {
+  background-position: -497.65625px -753.515625px;
+}
+
+.sprite-tent {
+  background-position: -526.5625px -753.515625px;
+}
+
+.sprite-thought_balloon {
+  background-position: -555.46875px -753.515625px;
+}
+
+.sprite-three {
+  background-position: -584.375px -753.515625px;
+}
+
+.sprite-thumbsdown {
+  background-position: -613.28125px -753.515625px;
+}
+
+.sprite-thumbsup {
+  background-position: -642.1875px -753.515625px;
+}
+
+.sprite-ticket {
+  background-position: -671.09375px -753.515625px;
+}
+
+.sprite-tiger {
+  background-position: -700px -753.515625px;
+}
+
+.sprite-tiger2 {
+  background-position: -728.90625px -753.515625px;
+}
+
+.sprite-tired_face {
+  background-position: -757.8125px -753.515625px;
+}
+
+.sprite-tm {
+  background-position: -786.71875px -753.515625px;
+}
+
+.sprite-toilet {
+  background-position: -815.625px -753.515625px;
+}
+
+.sprite-tokyo_tower {
+  background-position: -1.953125px -782.421875px;
+}
+
+.sprite-tomato {
+  background-position: -30.859375px -782.421875px;
+}
+
+.sprite-tongue {
+  background-position: -59.765625px -782.421875px;
+}
+
+.sprite-top {
+  background-position: -88.671875px -782.421875px;
+}
+
+.sprite-tophat {
+  background-position: -117.578125px -782.421875px;
+}
+
+.sprite-tractor {
+  background-position: -146.484375px -782.421875px;
+}
+
+.sprite-traffic_light {
+  background-position: -175.390625px -782.421875px;
+}
+
+.sprite-train {
+  background-position: -204.296875px -782.421875px;
+}
+
+.sprite-train2 {
+  background-position: -233.203125px -782.421875px;
+}
+
+.sprite-tram {
+  background-position: -262.109375px -782.421875px;
+}
+
+.sprite-triangular_flag_on_post {
+  background-position: -291.015625px -782.421875px;
+}
+
+.sprite-triangular_ruler {
+  background-position: -319.921875px -782.421875px;
+}
+
+.sprite-trident {
+  background-position: -348.828125px -782.421875px;
+}
+
+.sprite-triumph {
+  background-position: -377.734375px -782.421875px;
+}
+
+.sprite-trolleybus {
+  background-position: -406.640625px -782.421875px;
+}
+
+.sprite-trollface {
+  background-position: -435.546875px -782.421875px;
+}
+
+.sprite-trophy {
+  background-position: -464.453125px -782.421875px;
+}
+
+.sprite-tropical_drink {
+  background-position: -493.359375px -782.421875px;
+}
+
+.sprite-tropical_fish {
+  background-position: -522.265625px -782.421875px;
+}
+
+.sprite-truck {
+  background-position: -551.171875px -782.421875px;
+}
+
+.sprite-trumpet {
+  background-position: -580.078125px -782.421875px;
+}
+
+.sprite-tshirt {
+  background-position: -608.984375px -782.421875px;
+}
+
+.sprite-tulip {
+  background-position: -637.890625px -782.421875px;
+}
+
+.sprite-tumblr {
+  background-position: -840.234375px -64.453125px;
+}
+
+.sprite-turtle {
+  background-position: -666.796875px -782.421875px;
+}
+
+.sprite-tv {
+  background-position: -695.703125px -782.421875px;
+}
+
+.sprite-twisted_rightwards_arrows {
+  background-position: -724.609375px -782.421875px;
+}
+
+.sprite-twitter {
+  background-position: -840.234375px -80.078125px;
+}
+
+.sprite-two {
+  background-position: -753.515625px -782.421875px;
+}
+
+.sprite-two_hearts {
+  background-position: -782.421875px -782.421875px;
+}
+
+.sprite-two_men_holding_hands {
+  background-position: -811.328125px -782.421875px;
+}
+
+.sprite-two_women_holding_hands {
+  background-position: -1.953125px -811.328125px;
+}
+
+.sprite-u5272 {
+  background-position: -30.859375px -811.328125px;
+}
+
+.sprite-u5408 {
+  background-position: -59.765625px -811.328125px;
+}
+
+.sprite-u55b6 {
+  background-position: -88.671875px -811.328125px;
+}
+
+.sprite-u6307 {
+  background-position: -117.578125px -811.328125px;
+}
+
+.sprite-u6708 {
+  background-position: -146.484375px -811.328125px;
+}
+
+.sprite-u6709 {
+  background-position: -175.390625px -811.328125px;
+}
+
+.sprite-u6e80 {
+  background-position: -204.296875px -811.328125px;
+}
+
+.sprite-u7121 {
+  background-position: -233.203125px -811.328125px;
+}
+
+.sprite-u7533 {
+  background-position: -262.109375px -811.328125px;
+}
+
+.sprite-u7981 {
+  background-position: -291.015625px -811.328125px;
+}
+
+.sprite-u7a7a {
+  background-position: -319.921875px -811.328125px;
+}
+
+.sprite-uk {
+  background-position: -348.828125px -811.328125px;
+}
+
+.sprite-umbrella {
+  background-position: -377.734375px -811.328125px;
+}
+
+.sprite-unamused {
+  background-position: -406.640625px -811.328125px;
+}
+
+.sprite-underage {
+  background-position: -435.546875px -811.328125px;
+}
+
+.sprite-unlock {
+  background-position: -464.453125px -811.328125px;
+}
+
+.sprite-up {
+  background-position: -493.359375px -811.328125px;
+}
+
+.sprite-us {
+  background-position: -522.265625px -811.328125px;
+}
+
+.sprite-v {
+  background-position: -551.171875px -811.328125px;
+}
+
+.sprite-vertical_traffic_light {
+  background-position: -580.078125px -811.328125px;
+}
+
+.sprite-vhs {
+  background-position: -608.984375px -811.328125px;
+}
+
+.sprite-vibration_mode {
+  background-position: -637.890625px -811.328125px;
+}
+
+.sprite-video_camera {
+  background-position: -666.796875px -811.328125px;
+}
+
+.sprite-video_game {
+  background-position: -695.703125px -811.328125px;
+}
+
+.sprite-violin {
+  background-position: -724.609375px -811.328125px;
+}
+
+.sprite-virgo {
+  background-position: -753.515625px -811.328125px;
+}
+
+.sprite-volcano {
+  background-position: -782.421875px -811.328125px;
+}
+
+.sprite-vs {
+  background-position: -811.328125px -811.328125px;
+}
+
+.sprite-walking {
+  background-position: -855.859375px -1.953125px;
+}
+
+.sprite-waning_crescent_moon {
+  background-position: -855.859375px -30.859375px;
+}
+
+.sprite-waning_gibbous_moon {
+  background-position: -855.859375px -59.765625px;
+}
+
+.sprite-warning {
+  background-position: -855.859375px -88.671875px;
+}
+
+.sprite-watch {
+  background-position: -840.234375px -117.578125px;
+}
+
+.sprite-water_buffalo {
+  background-position: -840.234375px -146.484375px;
+}
+
+.sprite-watermelon {
+  background-position: -840.234375px -175.390625px;
+}
+
+.sprite-wave {
+  background-position: -840.234375px -204.296875px;
+}
+
+.sprite-wavy_dash {
+  background-position: -840.234375px -233.203125px;
+}
+
+.sprite-waxing_crescent_moon {
+  background-position: -840.234375px -262.109375px;
+}
+
+.sprite-waxing_gibbous_moon {
+  background-position: -840.234375px -291.015625px;
+}
+
+.sprite-wc {
+  background-position: -840.234375px -319.921875px;
+}
+
+.sprite-weary {
+  background-position: -840.234375px -348.828125px;
+}
+
+.sprite-wedding {
+  background-position: -840.234375px -377.734375px;
+}
+
+.sprite-whale {
+  background-position: -840.234375px -406.640625px;
+}
+
+.sprite-whale2 {
+  background-position: -840.234375px -435.546875px;
+}
+
+.sprite-wheelchair {
+  background-position: -840.234375px -464.453125px;
+}
+
+.sprite-white_check_mark {
+  background-position: -840.234375px -493.359375px;
+}
+
+.sprite-white_circle {
+  background-position: -840.234375px -522.265625px;
+}
+
+.sprite-white_flower {
+  background-position: -840.234375px -551.171875px;
+}
+
+.sprite-white_large_square {
+  background-position: -840.234375px -580.078125px;
+}
+
+.sprite-white_medium_small_square {
+  background-position: -840.234375px -608.984375px;
+}
+
+.sprite-white_medium_square {
+  background-position: -840.234375px -637.890625px;
+}
+
+.sprite-white_small_square {
+  background-position: -844.53125px -666.796875px;
+}
+
+.sprite-white_square_button {
+  background-position: -844.53125px -695.703125px;
+}
+
+.sprite-wind_chime {
+  background-position: -844.53125px -724.609375px;
+}
+
+.sprite-wine_glass {
+  background-position: -844.53125px -753.515625px;
+}
+
+.sprite-wink {
+  background-position: -840.234375px -782.421875px;
+}
+
+.sprite-wolf {
+  background-position: -840.234375px -811.328125px;
+}
+
+.sprite-woman {
+  background-position: -1.953125px -840.234375px;
+}
+
+.sprite-womans_clothes {
+  background-position: -30.859375px -840.234375px;
+}
+
+.sprite-womans_hat {
+  background-position: -59.765625px -840.234375px;
+}
+
+.sprite-womens {
+  background-position: -88.671875px -840.234375px;
+}
+
+.sprite-worried {
+  background-position: -117.578125px -840.234375px;
+}
+
+.sprite-wrench {
+  background-position: -146.484375px -840.234375px;
+}
+
+.sprite-x {
+  background-position: -175.390625px -840.234375px;
+}
+
+.sprite-yellow_heart {
+  background-position: -204.296875px -840.234375px;
+}
+
+.sprite-yen {
+  background-position: -233.203125px -840.234375px;
+}
+
+.sprite-yum {
+  background-position: -262.109375px -840.234375px;
+}
+
+.sprite-zap {
+  background-position: -291.015625px -840.234375px;
+}
+
+.sprite-zero {
+  background-position: -319.921875px -840.234375px;
+}
+
+.sprite-zzz {
+  background-position: -348.828125px -840.234375px;
+}
diff --git a/src/styles/iconPath.scss b/src/styles/iconPath.scss
new file mode 100644
index 0000000..ca25dca
--- /dev/null
+++ b/src/styles/iconPath.scss
@@ -0,0 +1,171 @@
+
+.iconList{
+  span{
+    margin-left: 10px;
+  }
+}
+.iconList.hover{
+  span{
+    color: #4D88FF;
+  }
+}
+// financial
+.icon-financial{
+  background: url('../assets/aside/financial.png') no-repeat;
+  background-size: 20px 20px;
+  background-position: 0px 5px;
+}
+.el-select-dropdown__item.icon-financial.hover{
+  background: url('../assets/aside/financial_active.png') no-repeat !important;
+  background-size: 20px 20px !important;
+  background-position: 0px 5px !important;
+}
+.el-select-dropdown__item.icon-financial.selected{
+  background: url('../assets/aside/financial_active.png') no-repeat !important;
+  background-size: 20px 20px !important;
+  background-position: 0px 5px !important;
+}
+// company
+.icon-company{
+  background: url('../assets/aside/company.png') no-repeat;
+  background-size: 20px 20px;
+  background-position: 0px 5px;
+}
+.el-select-dropdown__item.icon-company.hover{
+  background: url('../assets/aside/company_active.png') no-repeat !important;
+  background-size: 20px 20px !important;
+  background-position: 0px 5px !important;
+}
+.el-select-dropdown__item.icon-company.selected{
+  background: url('../assets/aside/company_active.png') no-repeat !important;
+  background-size: 20px 20px !important;
+  background-position: 0px 5px !important;
+}
+// customer
+.icon-customer{
+  background: url('../assets/aside/customer.png') no-repeat;
+  background-size: 20px 20px;
+  background-position: 0px 5px;
+}
+.el-select-dropdown__item.icon-customer.hover{
+  background: url('../assets/aside/customer_active.png') no-repeat !important;
+  background-size: 20px 20px !important;
+  background-position: 0px 5px !important;
+}
+.el-select-dropdown__item.icon-customer.selected{
+  background: url('../assets/aside/customer_active.png') no-repeat !important;
+  background-size: 20px 20px !important;
+  background-position: 0px 5px !important;
+}
+// order
+.icon-order{
+  background: url('../assets/aside/order.png') no-repeat;
+  background-size: 20px 20px;
+  background-position: 0px 5px;
+}
+.el-select-dropdown__item.icon-order.hover{
+  background: url('../assets/aside/order_active.png') no-repeat !important;
+  background-size: 20px 20px !important;
+  background-position: 0px 5px !important;
+}
+.el-select-dropdown__item.icon-order.selected{
+  background: url('../assets/aside/order_active.png') no-repeat !important;
+  background-size: 20px 20px !important;
+  background-position: 0px 5px !important;
+}
+// product
+.icon-product{
+  background: url('../assets/aside/product.png') no-repeat;
+  background-size: 20px 20px;
+  background-position: 0px 5px;
+}
+.el-select-dropdown__item.icon-product.hover{
+  background: url('../assets/aside/product_active.png') no-repeat !important;
+  background-size: 20px 20px !important;
+  background-position: 0px 5px !important;
+}
+.el-select-dropdown__item.icon-product.selected{
+  background: url('../assets/aside/product_active.png') no-repeat !important;
+  background-size: 20px 20px !important;
+  background-position: 0px 5px !important;
+}
+// system
+.icon-system{
+  background: url('../assets/aside/system.png') no-repeat;
+  background-size: 20px 20px;
+  background-position: 0px 5px;
+}
+.el-select-dropdown__item.icon-system.hover{
+  background: url('../assets/aside/system_active.png') no-repeat !important;
+  background-size: 20px 20px !important;
+  background-position: 0px 5px !important;
+}
+.el-select-dropdown__item.icon-system.selected{
+  background: url('../assets/aside/system_active.png') no-repeat !important;
+  background-size: 20px 20px !important;
+  background-position: 0px 5px !important;
+}
+// total
+.icon-total{
+  background: url('../assets/aside/total.png') no-repeat;
+  background-size: 20px 20px;
+  background-position: 0px 5px;
+}
+.el-select-dropdown__item.icon-total.hover{
+  background: url('../assets/aside/total_active.png') no-repeat !important;
+  background-size: 20px 20px !important;
+  background-position: 0px 5px !important;
+}
+.el-select-dropdown__item.icon-total.selected{
+  background: url('../assets/aside/total_active.png') no-repeat !important;
+  background-size: 20px 20px !important;
+  background-position: 0px 5px !important;
+}
+// workbench
+.icon-workbench{
+  background: url('../assets/aside/workbench.png') no-repeat;
+  background-size: 20px 20px;
+  background-position: 0px 5px;
+}
+.el-select-dropdown__item.icon-workbench.hover{
+  background: url('../assets/aside/workbench_active.png') no-repeat !important;
+  background-size: 20px 20px !important;
+  background-position: 0px 5px !important;
+}
+.el-select-dropdown__item.icon-workbench.selected{
+  background: url('../assets/aside/workbench_active.png') no-repeat !important;
+  background-size: 20px 20px !important;
+  background-position: 0px 5px !important;
+}
+// business
+.icon-business{
+  background: url('../assets/aside/business.png') no-repeat;
+  background-size: 20px 20px;
+  background-position: 0px 5px;
+}
+.el-select-dropdown__item.icon-business.hover{
+  background: url('../assets/aside/business_active.png') no-repeat !important;
+  background-size: 20px 20px !important;
+  background-position: 0px 5px !important;
+}
+.el-select-dropdown__item.icon-business.selected{
+  background: url('../assets/aside/business_active.png') no-repeat !important;
+  background-size: 20px 20px !important;
+  background-position: 0px 5px !important;
+}
+// personnel
+.icon-personnel{
+  background: url('../assets/aside/personnel.png') no-repeat;
+  background-size: 20px 20px;
+  background-position: 0px 5px;
+}
+.el-select-dropdown__item.icon-personnel.hover{
+  background: url('../assets/aside/personnel_active.png') no-repeat !important;
+  background-size: 20px 20px !important;
+  background-position: 0px 5px !important;
+}
+.el-select-dropdown__item.icon-personnel.selected{
+  background: url('../assets/aside/personnel_active.png') no-repeat !important;
+  background-size: 20px 20px !important;
+  background-position: 0px 5px !important;
+}
\ No newline at end of file
diff --git a/src/styles/index.scss b/src/styles/index.scss
new file mode 100644
index 0000000..49a7585
--- /dev/null
+++ b/src/styles/index.scss
@@ -0,0 +1,223 @@
+@import './transition.scss';
+@import './element-ui.scss';
+@import './element-variables.scss';
+@import './iconPath.scss';
+// // 指令;
+@import '../directives/empty/empty.scss';
+@import '../assets/fonts/iconfont.css';
+@import '../directives/style.scss';
+
+
+
+// main-color #ff7d00
+body {
+  height: 100%;
+  -moz-osx-font-smoothing: grayscale;
+  -webkit-font-smoothing: antialiased;
+  text-rendering: optimizeLegibility;
+  font-family: 'MicrosoftYaHei', 'Avenir', Helvetica, Arial, sans-serif;
+  color: #333;
+  font-size: 14px;
+  background: #f5f6f9;
+}
+
+// 滚动条样式
+::-webkit-scrollbar-track-piece {
+  background: #EFEFEF;
+}
+
+::-webkit-scrollbar {
+  width: 7px;
+  height: 7px;
+}
+
+::-webkit-scrollbar-thumb {
+  background: #C7D1DA;
+  border-radius: 3.5px;
+}
+
+html {
+  height: 100%;
+  box-sizing: border-box;
+}
+
+#app {
+  height: 100%;
+}
+
+a,
+a:focus,
+a:hover {
+  cursor: pointer;
+  color: inherit;
+  outline: none;
+  text-decoration: none;
+}
+
+div:focus {
+  outline: none;
+}
+
+a:focus,
+a:active {
+  outline: none;
+}
+
+a,
+a:focus,
+a:hover {
+  cursor: pointer;
+  color: inherit;
+  text-decoration: none;
+}
+
+.clearfix {
+  &:after {
+    visibility: hidden;
+    display: block;
+    font-size: 0;
+    content: " ";
+    clear: both;
+    height: 0;
+  }
+}
+
+tr,
+th,
+td {
+  font-weight: normal;
+}
+
+li {
+  list-style: none;
+}
+
+* {
+  margin: 0;
+  padding: 0;
+  box-sizing: border-box;
+}
+
+// 文本
+.text-one-line {
+  overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+}
+
+
+/* 右浮动 */
+.rt {
+  float: right;
+  margin-right: 30px;
+}
+
+/* 左浮动 */
+.lt {
+  float: left;
+  margin-left: 30px;
+}
+
+// 控制svg颜色
+path {
+  fill: inherit !important
+}
+
+// 通过 popper-class 去除默认padding
+.no-padding-popover {
+  padding: 0;
+}
+
+// 去除百度地图 图标
+.BMap_cpyCtrl {
+  display: none;
+}
+
+.anchorBL {
+  display: none;
+}
+
+/** 懒加载样式*/
+img[lazy="loading"] {
+  display: inline-block;
+  padding: 8px;
+  // width: 20px !important;
+  // height: 20px !important;
+  margin: 0 auto;
+}
+
+div[lazy=loading] {
+  display: inline-block;
+  padding: 8px;
+  // width: 20px !important;
+  // height: 20px !important;
+  margin: 0 auto;
+}
+
+// div 头像图片样式
+.div-photo {
+  background-size: 100% 100%;
+  background-repeat: no-repeat;
+  display: inline-block;
+}
+
+/** 拖拽时候的样式 */
+.draggingStyle {
+  cursor: pointer;
+}
+
+// 修改头像为圆形
+.header-circle {
+  border-radius: 50%;
+}
+
+.router-view {
+  width: 100%;
+  position: relative;
+  height: 100%;
+  overflow: hidden;
+}
+
+.project-settings-list-top {
+  top: 110px !important;
+}
+
+.task-board-rechristen-popover {
+  padding: 0;
+  margin-top: -40px !important;
+}
+
+.tooltip-change-border {
+  border-color: #eee !important;
+  box-shadow: 0 0 12px 1px #eee;
+  padding: 5px 10px !important;
+}
+
+.tooltip-change-border .popper__arrow {
+  border-color: transparent !important;
+}
+
+.task-tooltip {
+  z-index: 1 !important;
+}
+
+.el-breadcrumb {
+  margin-bottom: 15px;
+  font-size: 12px;
+}
+// 关闭message 内容样式
+.el-close-message {
+  p {
+    line-height: 20px;
+    max-height: 60px;
+    overflow-y: scroll;
+    white-space: pre-wrap;
+    word-wrap: break-word;
+    margin-right: 13px;
+  }
+}
+
+// 去除焦点时的蓝色边框
+* :focus {
+  outline: none;
+}
diff --git a/src/styles/mixin.scss b/src/styles/mixin.scss
new file mode 100644
index 0000000..2e170db
--- /dev/null
+++ b/src/styles/mixin.scss
@@ -0,0 +1,44 @@
+@mixin clearfix {
+  &:after {
+    content: "";
+    display: table;
+    clear: both;
+  }
+}
+
+@mixin scrollBar {
+  &::-webkit-scrollbar-track-piece {
+    background: #EFEFEF;
+  }
+  &::-webkit-scrollbar {
+    width: 6px;
+  }
+  &::-webkit-scrollbar-thumb {
+    background: #C7D1DA;
+    border-radius: 3px;
+  }
+}
+
+@mixin relative {
+  position: relative;
+  width: 100%;
+  height: 100%;
+}
+
+@mixin left {
+  display: flex;
+  align-items: center;
+  justify-content: flex-start;
+}
+
+@mixin center {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+@mixin right {
+  display: flex;
+  align-items: center;
+  justify-content: flex-end;
+}
diff --git a/src/styles/transition.scss b/src/styles/transition.scss
new file mode 100644
index 0000000..8dd9b04
--- /dev/null
+++ b/src/styles/transition.scss
@@ -0,0 +1,46 @@
+//globl transition css
+
+/*fade*/
+.fade-enter-active,
+.fade-leave-active {
+  transition: opacity 0.28s;
+}
+
+.fade-enter,
+.fade-leave-active {
+  opacity: 0;
+}
+
+/*fade-transform*/
+.fade-transform-leave-active,
+.fade-transform-enter-active {
+  transition: all .5s;
+}
+.fade-transform-enter {
+  opacity: 0;
+  transform: translateX(-30px);
+}
+.fade-transform-leave-to {
+  opacity: 0;
+  transform: translateX(30px);
+}
+
+/*fade*/
+.breadcrumb-enter-active,
+.breadcrumb-leave-active {
+  transition: all .5s;
+}
+
+.breadcrumb-enter,
+.breadcrumb-leave-active {
+  opacity: 0;
+  transform: translateX(20px);
+}
+
+.breadcrumb-move {
+  transition: all .5s;
+}
+
+.breadcrumb-leave-active {
+  position: absolute;
+}
diff --git a/src/styles/xr-theme.css b/src/styles/xr-theme.css
new file mode 100644
index 0000000..ccd8b16
--- /dev/null
+++ b/src/styles/xr-theme.css
@@ -0,0 +1,9 @@
+/**  rel="stylesheet/less" lang="less"*/
+/** border */
+/** border */
+/** table */
+/** tree */
+/* Popover
+-------------------------- */
+/* Dialog
+-------------------------- */
diff --git a/src/styles/xr-theme.scss b/src/styles/xr-theme.scss
new file mode 100644
index 0000000..e6e9608
--- /dev/null
+++ b/src/styles/xr-theme.scss
@@ -0,0 +1,33 @@
+
+/**  rel="stylesheet/less" lang="less"*/
+$xr-color-primary: #ff6a00; // 主色调橘色 #4D88FF
+
+/** border */
+$xr-border-color-base: #ddd;
+$xr-border-radius-base: 2px;
+$xr-border-line-color: #e6e6e6;
+
+/** border */
+$xr-color-text-placeholder: #c0c4cc;
+
+/** table */
+$--table-border-color: #e6e6e6;
+$--table-header-background: #FAFDFF;
+
+/** tree */
+$--tree-node-hover-color: white;
+$--tree-expand-icon-color: white;
+
+$xr-font-size-base: 13px;
+$xr-font-size-small: 12px;
+$xr-font-size-large: 18px;
+
+/* Popover
+-------------------------- */
+
+/* Dialog
+-------------------------- */
+$--dialog-title-font-size: 16px;
+
+
+
diff --git a/src/utils/auth.js b/src/utils/auth.js
new file mode 100644
index 0000000..6215e05
--- /dev/null
+++ b/src/utils/auth.js
@@ -0,0 +1,35 @@
+import axios from 'axios'
+import cache from './cache'
+import Lockr from 'lockr'
+import store from '@/store'
+
+/** 移除授权信息 */
+export function removeAuth () {
+  return new Promise((resolve, reject) => {
+    cache.rmAxiosCache()
+    store.commit('SET_ALLAUTH', null)
+    delete axios.defaults.headers['token']
+    resolve(true)
+  })
+}
+
+/** 注入授权信息 */
+export function addAuth (adminToken) {
+  return new Promise((resolve, reject) => {
+    axios.defaults.headers['token'] = adminToken
+    resolve(true)
+  })
+}
+
+/** 获取授权信息 */
+export function getAuth () {
+  /** 全局路由触发这个方法  如果有缓存暂时在这里交与 */
+  if (Lockr.get('Admin-Token') && !axios.defaults.headers['token']) {
+    cache.updateAxiosCache()
+  }
+
+  if (axios.defaults.headers['token']) {
+    return true
+  }
+  return false
+}
diff --git a/src/utils/baseconfig.js b/src/utils/baseconfig.js
new file mode 100644
index 0000000..d18bb0c
--- /dev/null
+++ b/src/utils/baseconfig.js
@@ -0,0 +1,5 @@
+
+/* 上传图片文件端口 */
+// export const ApiBaseUrl = process.env.NODE_ENV === 'development' ? 'http://www.probim.cn:6683' : 'http://192.168.0.107:8080'
+console.log(process.env.NODE_ENV)
+export const ResouceUrl = process.env.NODE_ENV === 'development' ? 'http://192.168.0.107:8081' : 'http://crm.urlink.com.cn:6684'
diff --git a/src/utils/cache.js b/src/utils/cache.js
new file mode 100644
index 0000000..02db98c
--- /dev/null
+++ b/src/utils/cache.js
@@ -0,0 +1,46 @@
+// import store from '@/store'
+import Lockr from 'lockr'
+import axios from 'axios'
+// import {
+//   requestverify
+// } from '@/api/login'
+
+const cache = {
+  /**
+   * 载入全部登陆信息
+   */
+  loadingCache: function () {
+    // requestverify().then(res => {
+    //   Lockr.set('Login-Cache', res.data)
+    // }).catch((err) => {
+    //   console.log(err)
+    // })
+
+    // if (Lockr.get('Admin-Token') && !axios.defaults.headers['token']) {
+    //   /** 将用户信息放入缓存 */
+    //   const userInfo = Lockr.get('loginUserInfo')
+    //   if (userInfo) {
+    //     store.commit('SET_USERINFO', userInfo)
+    //   }
+    // }
+    // store.commit('SET_APPNAME', Lockr.get('systemName'))
+    // store.commit('SET_APPLOGO', Lockr.get('systemLogo'))
+    // store.dispatch('SystemLogoAndName')
+  },
+  /**
+   * 请求和更新登录缓存
+   */
+  updateAxiosCache: function () {
+    axios.defaults.headers['token'] = Lockr.get('Admin-Token')
+    // store.dispatch('GetUserInfo')
+  },
+  /**
+   * 移除登录信息
+   * @param {*}
+   */
+  rmAxiosCache: function () {
+    Lockr.rm('Admin-Token')
+  }
+}
+
+export default cache
diff --git a/src/utils/dist/request.dev.js b/src/utils/dist/request.dev.js
new file mode 100644
index 0000000..2fd2fb6
--- /dev/null
+++ b/src/utils/dist/request.dev.js
@@ -0,0 +1,119 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports["default"] = void 0;
+
+var _axios = _interopRequireDefault(require("axios"));
+
+var _elementUi = require("element-ui");
+
+var _auth = require("@/utils/auth");
+
+var _lockr = _interopRequireDefault(require("lockr"));
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
+
+var showLoginMessageBox = false;
+_axios["default"].defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8'; // 创建axios实例
+
+console.log(process.env);
+
+var service = _axios["default"].create({
+  baseURL: process.env.BASE_API,
+  // api 的 base_url
+  // baseURL: 'http://192.168.0.107:8080/api',
+  timeout: 15000 // 请求超时时间
+
+}); // request拦截器
+
+
+service.interceptors.request.use(function (config) {
+  var flag = config.headers['Content-Type'] && config.headers['Content-Type'].indexOf('application/json') !== -1;
+
+  if (!flag) {
+    var mult = config.headers['Content-Type'] && config.headers['Content-Type'].indexOf('multipart/form-data') !== -1;
+
+    if (mult) {
+      config.data = config.data;
+    } else {
+      // config.data = qs.stringify(config.data)
+      config.data = config.data;
+    }
+  }
+
+  config.headers['token'] = _lockr["default"].get('Admin-Token');
+  var url = config.url;
+  url += url.indexOf('?') >= 0 ? '&' : '?';
+  url += 'r=' + (Math.random() * 100000 + 1);
+  config.url = url;
+  return config;
+}, function (error) {
+  console.log(error); // Do something with request error
+
+  return Promise.reject(error);
+}); // response 拦截器
+
+service.interceptors.response.use(function (response) {
+  /**
+   * code为非200是抛错
+   */
+  var res = response.data;
+
+  if (response.status === 200 && response.config.responseType === 'blob') {
+    // 文件类型特殊处理
+    return response;
+  } else if (res && !res.ErrorCode) {
+    return response;
+  } else if (res.ErrorCode !== 0) {
+    // 302登录已失效
+    if (res.ErrorCode === 302 || res.ErrorCode === 401) {
+      if (!showLoginMessageBox) {
+        showLoginMessageBox = true;
+
+        _elementUi.MessageBox.confirm('你已被登出,请重新登录', '确定登出', {
+          showCancelButton: false,
+          showClose: false,
+          confirmButtonText: '重新登录',
+          type: 'warning',
+          callback: function callback(action) {
+            showLoginMessageBox = false;
+
+            if (action === 'confirm') {
+              (0, _auth.removeAuth)().then(function () {
+                var rout = window.location.href;
+                var a = rout.lastIndexOf('/');
+                rout = rout.substring(0, a);
+                window.location.href = rout + '/login'; // location.reload() // 为了重新实例化vue-router对象 避免bug
+              })["catch"](function () {
+                location.reload();
+              });
+            }
+          }
+        });
+      }
+    } else if (res.ErrorCode === 200) {
+      return response;
+    } else {
+      if (res.Message) {
+        (0, _elementUi.Message)({
+          message: res.Message,
+          type: 'error'
+        });
+      }
+    }
+
+    return Promise.reject(res);
+  } else {
+    return res;
+  }
+}, function (error) {
+  (0, _elementUi.Message)({
+    message: '网络请求失败,请稍候再试',
+    type: 'error'
+  });
+  return Promise.reject(error);
+});
+var _default = service;
+exports["default"] = _default;
\ No newline at end of file
diff --git a/src/utils/dom.js b/src/utils/dom.js
new file mode 100644
index 0000000..7887333
--- /dev/null
+++ b/src/utils/dom.js
@@ -0,0 +1,45 @@
+/**
+ * 功能:dom绑定事件
+ * 参数:element(dom节点)
+ *      event(事件名称)
+ *      handler(回调)
+ *返回:无
+ * */
+export const on = (function () {
+  if (document.addEventListener) {
+    return function (element, event, handler) {
+      if (element && event && handler) {
+        element.addEventListener(event, handler, false)
+      }
+    }
+  } else {
+    return function (element, event, handler) {
+      if (element && event && handler) {
+        element.attachEvent('on' + event, handler)
+      }
+    }
+  }
+})()
+
+/**
+ * 功能:移除dom绑定的事件
+ * 参数:element(dom节点)
+ *      event(事件名称)
+ *      handler(回调函数)
+ * 返回:无
+ * */
+export const off = (function () {
+  if (document.removeEventListener) {
+    return function (element, event, handler) {
+      if (element && event) {
+        element.removeEventListener(event, handler, false)
+      }
+    }
+  } else {
+    return function (element, event, handler) {
+      if (element && event) {
+        element.detachEvent('on' + event, handler)
+      }
+    }
+  }
+})()
diff --git a/src/utils/emoji-data.js b/src/utils/emoji-data.js
new file mode 100644
index 0000000..7d5352d
--- /dev/null
+++ b/src/utils/emoji-data.js
@@ -0,0 +1,3 @@
+const str = '{"表情":{":bowtie:":"bowtie.png",":smile:":"smile.png",":laughing:":"laughing.png",":blush:":"blush.png",":smiley:":"smiley.png",":relaxed:":"relaxed.png",":smirk:":"smirk.png",":heart_eyes:":"heart_eyes.png",":kissing_heart:":"kissing_heart.png",":kissing_closed_eyes:":"kissing_closed_eyes.png",":flushed:":"flushed.png",":relieved:":"relieved.png",":satisfied:":"satisfied.png",":grin:":"grin.png",":wink:":"wink.png",":stuck_out_tongue_winking_eye:":"stuck_out_tongue_winking_eye.png",":stuck_out_tongue_closed_eyes:":"stuck_out_tongue_closed_eyes.png",":grinning:":"grinning.png",":kissing:":"kissing.png",":kissing_smiling_eyes:":"kissing_smiling_eyes.png",":stuck_out_tongue:":"stuck_out_tongue.png",":sleeping:":"sleeping.png",":worried:":"worried.png",":frowning:":"frowning.png",":anguished:":"anguished.png",":open_mouth:":"open_mouth.png",":grimacing:":"grimacing.png",":confused:":"confused.png",":hushed:":"hushed.png",":expressionless:":"expressionless.png",":unamused:":"unamused.png",":sweat_smile:":"sweat_smile.png",":sweat:":"sweat.png",":disappointed_relieved:":"disappointed_relieved.png",":weary:":"weary.png",":pensive:":"pensive.png",":disappointed:":"disappointed.png",":confounded:":"confounded.png",":fearful:":"fearful.png",":cold_sweat:":"cold_sweat.png",":persevere:":"persevere.png",":cry:":"cry.png",":sob:":"sob.png",":joy:":"joy.png",":astonished:":"astonished.png",":scream:":"scream.png",":neckbeard:":"neckbeard.png",":tired_face:":"tired_face.png",":angry:":"angry.png",":rage:":"rage.png",":triumph:":"triumph.png",":sleepy:":"sleepy.png",":yum:":"yum.png",":mask:":"mask.png",":sunglasses:":"sunglasses.png",":dizzy_face:":"dizzy_face.png",":imp:":"imp.png",":smiling_imp:":"smiling_imp.png",":neutral_face:":"neutral_face.png",":no_mouth:":"no_mouth.png",":innocent:":"innocent.png",":alien:":"alien.png",":yellow_heart:":"yellow_heart.png",":blue_heart:":"blue_heart.png",":purple_heart:":"purple_heart.png",":heart:":"heart.png",":green_heart:":"green_heart.png",":broken_heart:":"broken_heart.png",":heartbeat:":"heartbeat.png",":heartpulse:":"heartpulse.png",":two_hearts:":"two_hearts.png",":revolving_hearts:":"revolving_hearts.png",":cupid:":"cupid.png",":sparkling_heart:":"sparkling_heart.png",":sparkles:":"sparkles.png",":star:":"star.png",":star2:":"star2.png",":dizzy:":"dizzy.png",":boom:":"boom.png",":collision:":"collision.png",":anger:":"anger.png",":exclamation:":"exclamation.png",":question:":"question.png",":grey_exclamation:":"grey_exclamation.png",":grey_question:":"grey_question.png",":zzz:":"zzz.png",":dash:":"dash.png",":sweat_drops:":"sweat_drops.png",":notes:":"notes.png",":musical_note:":"musical_note.png",":fire:":"fire.png",":shit:":"shit.png",":thumbsup:":"thumbsup.png",":thumbsdown:":"thumbsdown.png",":ok_hand:":"ok_hand.png",":punch:":"punch.png",":facepunch:":"facepunch.png",":fist:":"fist.png",":v:":"v.png",":wave:":"wave.png",":hand:":"hand.png",":raised_hand:":"raised_hand.png",":open_hands:":"open_hands.png",":point_up:":"point_up.png",":point_down:":"point_down.png",":point_left:":"point_left.png",":point_right:":"point_right.png",":raised_hands:":"raised_hands.png",":pray:":"pray.png",":point_up_2:":"point_up_2.png",":clap:":"clap.png",":muscle:":"muscle.png",":metal:":"metal.png",":fu:":"fu.png",":runner:":"runner.png",":running:":"running.png",":couple:":"couple.png",":family:":"family.png",":two_men_holding_hands:":"two_men_holding_hands.png",":two_women_holding_hands:":"two_women_holding_hands.png",":dancer:":"dancer.png",":dancers:":"dancers.png",":ok_woman:":"ok_woman.png",":no_good:":"no_good.png",":information_desk_person:":"information_desk_person.png",":raising_hand:":"raising_hand.png",":bride_with_veil:":"bride_with_veil.png",":person_with_pouting_face:":"person_with_pouting_face.png",":person_frowning:":"person_frowning.png",":bow:":"bow.png",":couplekiss:":"couplekiss.png",":couple_with_heart:":"couple_with_heart.png",":massage:":"massage.png",":haircut:":"haircut.png",":nail_care:":"nail_care.png",":boy:":"boy.png",":girl:":"girl.png",":woman:":"woman.png",":man:":"man.png",":baby:":"baby.png",":older_woman:":"older_woman.png",":older_man:":"older_man.png",":person_with_blond_hair:":"person_with_blond_hair.png",":man_with_gua_pi_mao:":"man_with_gua_pi_mao.png",":man_with_turban:":"man_with_turban.png",":construction_worker:":"construction_worker.png",":cop:":"cop.png",":angel:":"angel.png",":princess:":"princess.png",":smiley_cat:":"smiley_cat.png",":smile_cat:":"smile_cat.png",":heart_eyes_cat:":"heart_eyes_cat.png",":kissing_cat:":"kissing_cat.png",":smirk_cat:":"smirk_cat.png",":scream_cat:":"scream_cat.png",":crying_cat_face:":"crying_cat_face.png",":joy_cat:":"joy_cat.png",":pouting_cat:":"pouting_cat.png",":japanese_ogre:":"japanese_ogre.png",":japanese_goblin:":"japanese_goblin.png",":see_no_evil:":"see_no_evil.png",":hear_no_evil:":"hear_no_evil.png",":speak_no_evil:":"speak_no_evil.png",":guardsman:":"guardsman.png",":skull:":"skull.png",":feet:":"feet.png",":lips:":"lips.png",":kiss:":"kiss.png",":droplet:":"droplet.png",":ear:":"ear.png",":eyes:":"eyes.png",":nose:":"nose.png",":tongue:":"tongue.png",":love_letter:":"love_letter.png",":bust_in_silhouette:":"bust_in_silhouette.png",":busts_in_silhouette:":"busts_in_silhouette.png",":speech_balloon:":"speech_balloon.png",":thought_balloon:":"thought_balloon.png",":feelsgood:":"feelsgood.png",":finnadie:":"finnadie.png",":goberserk:":"goberserk.png",":godmode:":"godmode.png",":hurtrealbad:":"hurtrealbad.png",":rage1:":"rage1.png",":rage2:":"rage2.png",":rage3:":"rage3.png",":rage4:":"rage4.png",":suspect:":"suspect.png",":trollface:":"trollface.png"},"自然":{":sunny:":"sunny.png",":umbrella:":"umbrella.png",":cloud:":"cloud.png",":snowflake:":"snowflake.png",":snowman:":"snowman.png",":zap:":"zap.png",":cyclone:":"cyclone.png",":foggy:":"foggy.png",":ocean:":"ocean.png",":cat:":"cat.png",":dog:":"dog.png",":mouse:":"mouse.png",":hamster:":"hamster.png",":rabbit:":"rabbit.png",":wolf:":"wolf.png",":frog:":"frog.png",":tiger:":"tiger.png",":koala:":"koala.png",":bear:":"bear.png",":pig:":"pig.png",":pig_nose:":"pig_nose.png",":cow:":"cow.png",":boar:":"boar.png",":monkey_face:":"monkey_face.png",":monkey:":"monkey.png",":horse:":"horse.png",":racehorse:":"racehorse.png",":camel:":"camel.png",":sheep:":"sheep.png",":elephant:":"elephant.png",":panda_face:":"panda_face.png",":snake:":"snake.png",":bird:":"bird.png",":baby_chick:":"baby_chick.png",":hatched_chick:":"hatched_chick.png",":hatching_chick:":"hatching_chick.png",":chicken:":"chicken.png",":penguin:":"penguin.png",":turtle:":"turtle.png",":bug:":"bug.png",":honeybee:":"honeybee.png",":ant:":"ant.png",":beetle:":"beetle.png",":snail:":"snail.png",":octopus:":"octopus.png",":tropical_fish:":"tropical_fish.png",":fish:":"fish.png",":whale:":"whale.png",":whale2:":"whale2.png",":dolphin:":"dolphin.png",":cow2:":"cow2.png",":ram:":"ram.png",":rat:":"rat.png",":water_buffalo:":"water_buffalo.png",":tiger2:":"tiger2.png",":rabbit2:":"rabbit2.png",":dragon:":"dragon.png",":goat:":"goat.png",":rooster:":"rooster.png",":dog2:":"dog2.png",":pig2:":"pig2.png",":mouse2:":"mouse2.png",":ox:":"ox.png",":dragon_face:":"dragon_face.png",":blowfish:":"blowfish.png",":crocodile:":"crocodile.png",":dromedary_camel:":"dromedary_camel.png",":leopard:":"leopard.png",":cat2:":"cat2.png",":poodle:":"poodle.png",":paw_prints:":"paw_prints.png",":bouquet:":"bouquet.png",":cherry_blossom:":"cherry_blossom.png",":tulip:":"tulip.png",":four_leaf_clover:":"four_leaf_clover.png",":rose:":"rose.png",":sunflower:":"sunflower.png",":hibiscus:":"hibiscus.png",":maple_leaf:":"maple_leaf.png",":leaves:":"leaves.png",":fallen_leaf:":"fallen_leaf.png",":herb:":"herb.png",":mushroom:":"mushroom.png",":cactus:":"cactus.png",":palm_tree:":"palm_tree.png",":evergreen_tree:":"evergreen_tree.png",":deciduous_tree:":"deciduous_tree.png",":chestnut:":"chestnut.png",":seedling:":"seedling.png",":blossom:":"blossom.png",":ear_of_rice:":"ear_of_rice.png",":shell:":"shell.png",":globe_with_meridians:":"globe_with_meridians.png",":sun_with_face:":"sun_with_face.png",":full_moon_with_face:":"full_moon_with_face.png",":new_moon_with_face:":"new_moon_with_face.png",":new_moon:":"new_moon.png",":waxing_crescent_moon:":"waxing_crescent_moon.png",":first_quarter_moon:":"first_quarter_moon.png",":waxing_gibbous_moon:":"waxing_gibbous_moon.png",":full_moon:":"full_moon.png",":waning_gibbous_moon:":"waning_gibbous_moon.png",":last_quarter_moon:":"last_quarter_moon.png",":waning_crescent_moon:":"waning_crescent_moon.png",":last_quarter_moon_with_face:":"last_quarter_moon_with_face.png",":first_quarter_moon_with_face:":"first_quarter_moon_with_face.png",":crescent_moon:":"crescent_moon.png",":earth_africa:":"earth_africa.png",":earth_americas:":"earth_americas.png",":earth_asia:":"earth_asia.png",":volcano:":"volcano.png",":milky_way:":"milky_way.png",":partly_sunny:":"partly_sunny.png",":octocat:":"octocat.png",":squirrel:":"squirrel.png"},"物品":{":bamboo:":"bamboo.png",":gift_heart:":"gift_heart.png",":dolls:":"dolls.png",":school_satchel:":"school_satchel.png",":mortar_board:":"mortar_board.png",":flags:":"flags.png",":fireworks:":"fireworks.png",":sparkler:":"sparkler.png",":wind_chime:":"wind_chime.png",":rice_scene:":"rice_scene.png",":jack_o_lantern:":"jack_o_lantern.png",":ghost:":"ghost.png",":santa:":"santa.png",":christmas_tree:":"christmas_tree.png",":gift:":"gift.png",":bell:":"bell.png",":no_bell:":"no_bell.png",":tanabata_tree:":"tanabata_tree.png",":tada:":"tada.png",":confetti_ball:":"confetti_ball.png",":balloon:":"balloon.png",":crystal_ball:":"crystal_ball.png",":cd:":"cd.png",":dvd:":"dvd.png",":floppy_disk:":"floppy_disk.png",":camera:":"camera.png",":video_camera:":"video_camera.png",":movie_camera:":"movie_camera.png",":computer:":"computer.png",":tv:":"tv.png",":iphone:":"iphone.png",":phone:":"phone.png",":telephone:":"telephone.png",":telephone_receiver:":"telephone_receiver.png",":pager:":"pager.png",":fax:":"fax.png",":minidisc:":"minidisc.png",":vhs:":"vhs.png",":sound:":"sound.png",":speaker:":"speaker.png",":mute:":"mute.png",":loudspeaker:":"loudspeaker.png",":mega:":"mega.png",":hourglass:":"hourglass.png",":hourglass_flowing_sand:":"hourglass_flowing_sand.png",":alarm_clock:":"alarm_clock.png",":watch:":"watch.png",":radio:":"radio.png",":satellite:":"satellite.png",":loop:":"loop.png",":mag:":"mag.png",":mag_right:":"mag_right.png",":unlock:":"unlock.png",":lock:":"lock.png",":lock_with_ink_pen:":"lock_with_ink_pen.png",":closed_lock_with_key:":"closed_lock_with_key.png",":key:":"key.png",":bulb:":"bulb.png",":flashlight:":"flashlight.png",":high_brightness:":"high_brightness.png",":low_brightness:":"low_brightness.png",":electric_plug:":"electric_plug.png",":battery:":"battery.png",":calling:":"calling.png",":email:":"email.png",":mailbox:":"mailbox.png",":postbox:":"postbox.png",":bath:":"bath.png",":bathtub:":"bathtub.png",":shower:":"shower.png",":toilet:":"toilet.png",":wrench:":"wrench.png",":nut_and_bolt:":"nut_and_bolt.png",":hammer:":"hammer.png",":seat:":"seat.png",":moneybag:":"moneybag.png",":yen:":"yen.png",":dollar:":"dollar.png",":pound:":"pound.png",":euro:":"euro.png",":credit_card:":"credit_card.png",":money_with_wings:":"money_with_wings.png",":e-mail:":"e-mail.png",":inbox_tray:":"inbox_tray.png",":outbox_tray:":"outbox_tray.png",":envelope:":"envelope.png",":incoming_envelope:":"incoming_envelope.png",":postal_horn:":"postal_horn.png",":mailbox_closed:":"mailbox_closed.png",":mailbox_with_mail:":"mailbox_with_mail.png",":mailbox_with_no_mail:":"mailbox_with_no_mail.png",":package:":"package.png",":door:":"door.png",":smoking:":"smoking.png",":bomb:":"bomb.png",":gun:":"gun.png",":hocho:":"hocho.png",":pill:":"pill.png",":syringe:":"syringe.png",":page_facing_up:":"page_facing_up.png",":page_with_curl:":"page_with_curl.png",":bookmark_tabs:":"bookmark_tabs.png",":bar_chart:":"bar_chart.png",":chart_with_upwards_trend:":"chart_with_upwards_trend.png",":chart_with_downwards_trend:":"chart_with_downwards_trend.png",":scroll:":"scroll.png",":clipboard:":"clipboard.png",":calendar:":"calendar.png",":date:":"date.png",":card_index:":"card_index.png",":file_folder:":"file_folder.png",":open_file_folder:":"open_file_folder.png",":scissors:":"scissors.png",":pushpin:":"pushpin.png",":paperclip:":"paperclip.png",":black_nib:":"black_nib.png",":pencil2:":"pencil2.png",":straight_ruler:":"straight_ruler.png",":triangular_ruler:":"triangular_ruler.png",":closed_book:":"closed_book.png",":green_book:":"green_book.png",":blue_book:":"blue_book.png",":orange_book:":"orange_book.png",":notebook:":"notebook.png",":notebook_with_decorative_cover:":"notebook_with_decorative_cover.png",":ledger:":"ledger.png",":books:":"books.png",":bookmark:":"bookmark.png",":name_badge:":"name_badge.png",":microscope:":"microscope.png",":telescope:":"telescope.png",":newspaper:":"newspaper.png",":football:":"football.png",":basketball:":"basketball.png",":soccer:":"soccer.png",":baseball:":"baseball.png",":tennis:":"tennis.png",":8ball:":"8ball.png",":rugby_football:":"rugby_football.png",":bowling:":"bowling.png",":golf:":"golf.png",":mountain_bicyclist:":"mountain_bicyclist.png",":bicyclist:":"bicyclist.png",":horse_racing:":"horse_racing.png",":snowboarder:":"snowboarder.png",":swimmer:":"swimmer.png",":surfer:":"surfer.png",":ski:":"ski.png",":spades:":"spades.png",":hearts:":"hearts.png",":clubs:":"clubs.png",":diamonds:":"diamonds.png",":gem:":"gem.png",":ring:":"ring.png",":trophy:":"trophy.png",":musical_score:":"musical_score.png",":musical_keyboard:":"musical_keyboard.png",":violin:":"violin.png",":space_invader:":"space_invader.png",":video_game:":"video_game.png",":black_joker:":"black_joker.png",":flower_playing_cards:":"flower_playing_cards.png",":game_die:":"game_die.png",":dart:":"dart.png",":mahjong:":"mahjong.png",":clapper:":"clapper.png",":memo:":"memo.png",":pencil:":"pencil.png",":book:":"book.png",":art:":"art.png",":microphone:":"microphone.png",":headphones:":"headphones.png",":trumpet:":"trumpet.png",":saxophone:":"saxophone.png",":guitar:":"guitar.png",":shoe:":"shoe.png",":sandal:":"sandal.png",":high_heel:":"high_heel.png",":lipstick:":"lipstick.png",":boot:":"boot.png",":shirt:":"shirt.png",":tshirt:":"tshirt.png",":necktie:":"necktie.png",":womans_clothes:":"womans_clothes.png",":dress:":"dress.png",":running_shirt_with_sash:":"running_shirt_with_sash.png",":jeans:":"jeans.png",":kimono:":"kimono.png",":bikini:":"bikini.png",":ribbon:":"ribbon.png",":tophat:":"tophat.png",":crown:":"crown.png",":womans_hat:":"womans_hat.png",":mans_shoe:":"mans_shoe.png",":closed_umbrella:":"closed_umbrella.png",":briefcase:":"briefcase.png",":handbag:":"handbag.png",":pouch:":"pouch.png",":purse:":"purse.png",":eyeglasses:":"eyeglasses.png",":fishing_pole_and_fish:":"fishing_pole_and_fish.png",":coffee:":"coffee.png",":tea:":"tea.png",":sake:":"sake.png",":baby_bottle:":"baby_bottle.png",":beer:":"beer.png",":beers:":"beers.png",":cocktail:":"cocktail.png",":tropical_drink:":"tropical_drink.png",":wine_glass:":"wine_glass.png",":fork_and_knife:":"fork_and_knife.png",":pizza:":"pizza.png",":hamburger:":"hamburger.png",":fries:":"fries.png",":poultry_leg:":"poultry_leg.png",":meat_on_bone:":"meat_on_bone.png",":spaghetti:":"spaghetti.png",":curry:":"curry.png",":fried_shrimp:":"fried_shrimp.png",":bento:":"bento.png",":sushi:":"sushi.png",":fish_cake:":"fish_cake.png",":rice_ball:":"rice_ball.png",":rice_cracker:":"rice_cracker.png",":rice:":"rice.png",":ramen:":"ramen.png",":stew:":"stew.png",":oden:":"oden.png",":dango:":"dango.png",":egg:":"egg.png",":bread:":"bread.png",":doughnut:":"doughnut.png",":custard:":"custard.png",":icecream:":"icecream.png",":ice_cream:":"ice_cream.png",":shaved_ice:":"shaved_ice.png",":birthday:":"birthday.png",":cake:":"cake.png",":cookie:":"cookie.png",":chocolate_bar:":"chocolate_bar.png",":candy:":"candy.png",":lollipop:":"lollipop.png",":honey_pot:":"honey_pot.png",":apple:":"apple.png",":green_apple:":"green_apple.png",":tangerine:":"tangerine.png",":lemon:":"lemon.png",":cherries:":"cherries.png",":grapes:":"grapes.png",":watermelon:":"watermelon.png",":strawberry:":"strawberry.png",":peach:":"peach.png",":melon:":"melon.png",":banana:":"banana.png",":pear:":"pear.png",":pineapple:":"pineapple.png",":sweet_potato:":"sweet_potato.png",":eggplant:":"eggplant.png",":tomato:":"tomato.png",":corn:":"corn.png"},"地点":{":house:":"house.png",":house_with_garden:":"house_with_garden.png",":school:":"school.png",":office:":"office.png",":post_office:":"post_office.png",":hospital:":"hospital.png",":bank:":"bank.png",":convenience_store:":"convenience_store.png",":love_hotel:":"love_hotel.png",":hotel:":"hotel.png",":wedding:":"wedding.png",":church:":"church.png",":department_store:":"department_store.png",":european_post_office:":"european_post_office.png",":city_sunrise:":"city_sunrise.png",":city_sunset:":"city_sunset.png",":japanese_castle:":"japanese_castle.png",":european_castle:":"european_castle.png",":tent:":"tent.png",":factory:":"factory.png",":tokyo_tower:":"tokyo_tower.png",":japan:":"japan.png",":mount_fuji:":"mount_fuji.png",":sunrise_over_mountains:":"sunrise_over_mountains.png",":sunrise:":"sunrise.png",":stars:":"stars.png",":statue_of_liberty:":"statue_of_liberty.png",":bridge_at_night:":"bridge_at_night.png",":carousel_horse:":"carousel_horse.png",":rainbow:":"rainbow.png",":ferris_wheel:":"ferris_wheel.png",":fountain:":"fountain.png",":roller_coaster:":"roller_coaster.png",":ship:":"ship.png",":speedboat:":"speedboat.png",":boat:":"boat.png",":sailboat:":"sailboat.png",":rowboat:":"rowboat.png",":anchor:":"anchor.png",":rocket:":"rocket.png",":airplane:":"airplane.png",":helicopter:":"helicopter.png",":steam_locomotive:":"steam_locomotive.png",":tram:":"tram.png",":mountain_railway:":"mountain_railway.png",":bike:":"bike.png",":aerial_tramway:":"aerial_tramway.png",":suspension_railway:":"suspension_railway.png",":mountain_cableway:":"mountain_cableway.png",":tractor:":"tractor.png",":blue_car:":"blue_car.png",":oncoming_automobile:":"oncoming_automobile.png",":car:":"car.png",":red_car:":"red_car.png",":taxi:":"taxi.png",":oncoming_taxi:":"oncoming_taxi.png",":articulated_lorry:":"articulated_lorry.png",":bus:":"bus.png",":oncoming_bus:":"oncoming_bus.png",":rotating_light:":"rotating_light.png",":police_car:":"police_car.png",":oncoming_police_car:":"oncoming_police_car.png",":fire_engine:":"fire_engine.png",":ambulance:":"ambulance.png",":minibus:":"minibus.png",":truck:":"truck.png",":train:":"train.png",":station:":"station.png",":train2:":"train2.png",":bullettrain_front:":"bullettrain_front.png",":bullettrain_side:":"bullettrain_side.png",":light_rail:":"light_rail.png",":monorail:":"monorail.png",":railway_car:":"railway_car.png",":trolleybus:":"trolleybus.png",":ticket:":"ticket.png",":fuelpump:":"fuelpump.png",":vertical_traffic_light:":"vertical_traffic_light.png",":traffic_light:":"traffic_light.png",":warning:":"warning.png",":construction:":"construction.png",":beginner:":"beginner.png",":atm:":"atm.png",":slot_machine:":"slot_machine.png",":busstop:":"busstop.png",":barber:":"barber.png",":hotsprings:":"hotsprings.png",":checkered_flag:":"checkered_flag.png",":crossed_flags:":"crossed_flags.png",":izakaya_lantern:":"izakaya_lantern.png",":moyai:":"moyai.png",":circus_tent:":"circus_tent.png",":performing_arts:":"performing_arts.png",":round_pushpin:":"round_pushpin.png",":triangular_flag_on_post:":"triangular_flag_on_post.png",":jp:":"jp.png",":kr:":"kr.png",":cn:":"cn.png",":us:":"us.png",":fr:":"fr.png",":es:":"es.png",":it:":"it.png",":ru:":"ru.png",":gb:":"gb.png",":uk:":"uk.png",":de:":"de.png"},"符号":{":one:":"one.png",":two:":"two.png",":three:":"three.png",":four:":"four.png",":five:":"five.png",":six:":"six.png",":seven:":"seven.png",":eight:":"eight.png",":nine:":"nine.png",":keycap_ten:":"keycap_ten.png",":1234:":"1234.png",":zero:":"zero.png",":hash:":"hash.png",":symbols:":"symbols.png",":arrow_backward:":"arrow_backward.png",":arrow_down:":"arrow_down.png",":arrow_forward:":"arrow_forward.png",":arrow_left:":"arrow_left.png",":capital_abcd:":"capital_abcd.png",":abcd:":"abcd.png",":abc:":"abc.png",":arrow_lower_left:":"arrow_lower_left.png",":arrow_lower_right:":"arrow_lower_right.png",":arrow_right:":"arrow_right.png",":arrow_up:":"arrow_up.png",":arrow_upper_left:":"arrow_upper_left.png",":arrow_upper_right:":"arrow_upper_right.png",":arrow_double_down:":"arrow_double_down.png",":arrow_double_up:":"arrow_double_up.png",":arrow_down_small:":"arrow_down_small.png",":arrow_heading_down:":"arrow_heading_down.png",":arrow_heading_up:":"arrow_heading_up.png",":leftwards_arrow_with_hook:":"leftwards_arrow_with_hook.png",":arrow_right_hook:":"arrow_right_hook.png",":left_right_arrow:":"left_right_arrow.png",":arrow_up_down:":"arrow_up_down.png",":arrow_up_small:":"arrow_up_small.png",":arrows_clockwise:":"arrows_clockwise.png",":arrows_counterclockwise:":"arrows_counterclockwise.png",":rewind:":"rewind.png",":fast_forward:":"fast_forward.png",":information_source:":"information_source.png",":ok:":"ok.png",":twisted_rightwards_arrows:":"twisted_rightwards_arrows.png",":repeat:":"repeat.png",":repeat_one:":"repeat_one.png",":new:":"new.png",":top:":"top.png",":up:":"up.png",":cool:":"cool.png",":free:":"free.png",":ng:":"ng.png",":cinema:":"cinema.png",":koko:":"koko.png",":signal_strength:":"signal_strength.png",":u5272:":"u5272.png",":u5408:":"u5408.png",":u55b6:":"u55b6.png",":u6307:":"u6307.png",":u6708:":"u6708.png",":u6709:":"u6709.png",":u6e80:":"u6e80.png",":u7121:":"u7121.png",":u7533:":"u7533.png",":u7a7a:":"u7a7a.png",":u7981:":"u7981.png",":sa:":"sa.png",":restroom:":"restroom.png",":mens:":"mens.png",":womens:":"womens.png",":baby_symbol:":"baby_symbol.png",":no_smoking:":"no_smoking.png",":parking:":"parking.png",":wheelchair:":"wheelchair.png",":metro:":"metro.png",":baggage_claim:":"baggage_claim.png",":accept:":"accept.png",":wc:":"wc.png",":potable_water:":"potable_water.png",":put_litter_in_its_place:":"put_litter_in_its_place.png",":secret:":"secret.png",":congratulations:":"congratulations.png",":m:":"m.png",":passport_control:":"passport_control.png",":left_luggage:":"left_luggage.png",":customs:":"customs.png",":ideograph_advantage:":"ideograph_advantage.png",":cl:":"cl.png",":sos:":"sos.png",":id:":"id.png",":no_entry_sign:":"no_entry_sign.png",":underage:":"underage.png",":no_mobile_phones:":"no_mobile_phones.png",":do_not_litter:":"do_not_litter.png",":non-potable_water:":"non-potable_water.png",":no_bicycles:":"no_bicycles.png",":no_pedestrians:":"no_pedestrians.png",":children_crossing:":"children_crossing.png",":no_entry:":"no_entry.png",":eight_spoked_asterisk:":"eight_spoked_asterisk.png",":sparkle:":"sparkle.png",":eight_pointed_black_star:":"eight_pointed_black_star.png",":heart_decoration:":"heart_decoration.png",":vs:":"vs.png",":vibration_mode:":"vibration_mode.png",":mobile_phone_off:":"mobile_phone_off.png",":chart:":"chart.png",":currency_exchange:":"currency_exchange.png",":aries:":"aries.png",":taurus:":"taurus.png",":gemini:":"gemini.png",":cancer:":"cancer.png",":leo:":"leo.png",":virgo:":"virgo.png",":libra:":"libra.png",":scorpius:":"scorpius.png",":sagittarius:":"sagittarius.png",":capricorn:":"capricorn.png",":aquarius:":"aquarius.png",":pisces:":"pisces.png",":ophiuchus:":"ophiuchus.png",":six_pointed_star:":"six_pointed_star.png",":negative_squared_cross_mark:":"negative_squared_cross_mark.png",":a:":"a.png",":b:":"b.png",":ab:":"ab.png",":o2:":"o2.png",":diamond_shape_with_a_dot_inside:":"diamond_shape_with_a_dot_inside.png",":recycle:":"recycle.png",":end:":"end.png",":back:":"back.png",":on:":"on.png",":soon:":"soon.png",":clock1:":"clock1.png",":clock130:":"clock130.png",":clock10:":"clock10.png",":clock1030:":"clock1030.png",":clock11:":"clock11.png",":clock1130:":"clock1130.png",":clock12:":"clock12.png",":clock1230:":"clock1230.png",":clock2:":"clock2.png",":clock230:":"clock230.png",":clock3:":"clock3.png",":clock330:":"clock330.png",":clock4:":"clock4.png",":clock430:":"clock430.png",":clock5:":"clock5.png",":clock530:":"clock530.png",":clock6:":"clock6.png",":clock630:":"clock630.png",":clock7:":"clock7.png",":clock730:":"clock730.png",":clock8:":"clock8.png",":clock830:":"clock830.png",":clock9:":"clock9.png",":clock930:":"clock930.png",":heavy_dollar_sign:":"heavy_dollar_sign.png",":copyright:":"copyright.png",":registered:":"registered.png",":tm:":"tm.png",":x:":"x.png",":heavy_exclamation_mark:":"heavy_exclamation_mark.png",":bangbang:":"bangbang.png",":interrobang:":"interrobang.png",":o:":"o.png",":heavy_multiplication_x:":"heavy_multiplication_x.png",":heavy_plus_sign:":"heavy_plus_sign.png",":heavy_minus_sign:":"heavy_minus_sign.png",":heavy_division_sign:":"heavy_division_sign.png",":white_flower:":"white_flower.png",":100:":"100.png",":heavy_check_mark:":"heavy_check_mark.png",":ballot_box_with_check:":"ballot_box_with_check.png",":radio_button:":"radio_button.png",":link:":"link.png",":curly_loop:":"curly_loop.png",":wavy_dash:":"wavy_dash.png",":part_alternation_mark:":"part_alternation_mark.png",":trident:":"trident.png",":black_small_square:":"black_small_square.png",":white_small_square:":"white_small_square.png",":black_medium_small_square:":"black_medium_small_square.png",":white_medium_small_square:":"white_medium_small_square.png",":black_medium_square:":"black_medium_square.png",":white_medium_square:":"white_medium_square.png",":black_large_square:":"black_square.png",":white_large_square:":"white_large_square.png",":white_check_mark:":"white_check_mark.png",":black_square_button:":"black_square_button.png",":white_square_button:":"white_square_button.png",":black_circle:":"black_circle.png",":white_circle:":"white_circle.png",":red_circle:":"red_circle.png",":large_blue_circle:":"large_blue_circle.png",":large_blue_diamond:":"large_blue_diamond.png",":large_orange_diamond:":"large_orange_diamond.png",":small_blue_diamond:":"small_blue_diamond.png",":small_orange_diamond:":"small_orange_diamond.png",":small_red_triangle:":"small_red_triangle.png",":small_red_triangle_down:":"small_red_triangle_down.png",":shipit:":"shipit.png"}}'
+
+export default JSON.parse(str)
diff --git a/src/utils/emoji.js b/src/utils/emoji.js
new file mode 100644
index 0000000..a526cd0
--- /dev/null
+++ b/src/utils/emoji.js
@@ -0,0 +1,30 @@
+import data from './emoji-data.js'
+let emojiData = {}
+Object.values(data).forEach(item => {
+  emojiData = {
+    ...emojiData,
+    ...item
+  }
+})
+
+/**
+ *
+ *
+ * @export
+ * @param {string} value
+ * @returns {string}
+ */
+
+export function emoji (value) {
+  if (!value) return
+  Object.keys(emojiData).forEach(item => {
+    value = value.replace(new RegExp(item, 'g'), createIcon(item))
+  })
+  return value
+}
+
+function createIcon (item) {
+  const value = emojiData[item]
+  const path = process.env.NODE_ENV === 'development' ? '../../static/img/emoji/' : './static/img/emoji/'
+  return `<img src=${path}${value} width="16px" height="16px">`
+}
diff --git a/src/utils/index.js b/src/utils/index.js
new file mode 100644
index 0000000..11ff135
--- /dev/null
+++ b/src/utils/index.js
@@ -0,0 +1,501 @@
+/* eslint-disable no-useless-escape */
+/* eslint-disable camelcase */
+/**
+ * Created by jiachenpan on 16/11/18.
+ */
+
+/** 获取最大 z-index 的值 */
+// import {
+//   PopupManager
+// } from 'element-ui/lib/utils/popup'
+
+/**
+ * 时间操作
+ * @param
+ */
+/** 时间戳转date */
+import moment from 'moment'
+import { ResouceUrl } from '@/utils/baseconfig'
+
+export function parseTime (time, cFormat) {
+  if (arguments.length === 0) {
+    return null
+  }
+  const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
+  let date
+  if (typeof time === 'object') {
+    date = time
+  } else {
+    if (('' + time).length === 10) time = parseInt(time) * 1000
+    date = new Date(time)
+  }
+  const formatObj = {
+    y: date.getFullYear(),
+    m: date.getMonth() + 1,
+    d: date.getDate(),
+    h: date.getHours(),
+    i: date.getMinutes(),
+    s: date.getSeconds(),
+    a: date.getDay()
+  }
+  const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
+    let value = formatObj[key]
+    // Note: getDay() returns 0 on Sunday
+    if (key === 'a') {
+      return ['日', '一', '二', '三', '四', '五', '六'][value]
+    }
+    if (result.length > 0 && value < 10) {
+      value = '0' + value
+    }
+    return value || 0
+  })
+  return time_str
+}
+
+export function formatTime (time, option) {
+  time = +time * 1000
+  const d = new Date(time)
+  const now = Date.now()
+
+  const diff = (now - d) / 1000
+
+  if (diff < 30) {
+    return '刚刚'
+  } else if (diff < 3600) {
+    // less 1 hour
+    return Math.ceil(diff / 60) + '分钟前'
+  } else if (diff < 3600 * 24) {
+    return Math.ceil(diff / 3600) + '小时前'
+  } else if (diff < 3600 * 24 * 2) {
+    return '1天前'
+  }
+  if (option) {
+    return parseTime(time, option)
+  } else {
+    return (
+      d.getMonth() +
+      1 +
+      '月' +
+      d.getDate() +
+      '日' +
+      d.getHours() +
+      '时' +
+      d.getMinutes() +
+      '分'
+    )
+  }
+}
+
+export function isExternal (path) {
+  return /^(https?:|mailto:|tel:)/.test(path)
+}
+
+/** 压缩文件
+ * quality压缩百分比 0.3
+ */
+export function compressImage (file, quality, callback) {
+  // quality 设置为0.3
+  quality = quality || 0.3
+  const reader = new FileReader()
+  reader.onload = function (event) {
+    var result = event.target.result
+    if (file.size > 204800 && file.type !== 'image/gif' && quality < 1) { // 大于200Kb
+      const img = new Image()
+      img.src = result
+      img.onload = function () {
+        // 如果图片大于四百万像素,计算压缩比并将大小压至400万以下
+        var width = img.width
+        var height = img.height
+
+        var ratio
+        if ((ratio = width * height / 4000000) > 1) {
+          ratio = Math.sqrt(ratio)
+          width /= ratio
+          height /= ratio
+        } else {
+          ratio = 1
+        }
+        var canvas = document.createElement('canvas')
+        canvas.width = width
+        canvas.height = height
+        // 铺底色
+        var ctx = canvas.getContext('2d')
+        ctx.fillStyle = '#fff'
+        ctx.fillRect(0, 0, canvas.width, canvas.height)
+        // 如果图片像素大于100万则使用瓦片绘制
+        var count
+        if ((count = width * height / 1000000) > 1) {
+          count = ~~(Math.sqrt(count) + 1)
+          // 计算要分成多少块瓦片
+          // 计算每块瓦片的宽和高
+          var nw = ~~(width / count)
+          var nh = ~~(height / count)
+          var tCanvas = document.createElement('canvas')
+          tCanvas.width = nw
+          tCanvas.height = nh
+          for (var i = 0; i < count; i++) {
+            for (var j = 0; j < count; j++) {
+              var tctx = tCanvas.getContext('2d')
+              tctx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh)
+
+              ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh)
+            }
+          }
+          tCanvas.width = tCanvas.height = 0
+        } else {
+          ctx.drawImage(img, 0, 0, width, height)
+        }
+        // 进行最小压缩
+        var ndata = canvas.toDataURL('image/jpeg', quality)
+        canvas.width = canvas.height = 0
+        callback(ndata)
+      }
+    } else { // 小于200K不需要压缩 直接返回
+      callback(result)
+    }
+  }
+  reader.readAsDataURL(file)
+}
+
+/** 根据date URL 创建blob 用于上传 */
+export function createBlob (result) {
+  var arr = result.split(',')
+  var mime = arr[0].match(/:(.*?)/)[1]
+  var bstr = atob(arr[1])
+  var n = bstr.length
+  var u8arr = new Uint8Array(n)
+  while (n--) {
+    u8arr[n] = bstr.charCodeAt(n)
+  }
+  return new Blob([u8arr], {
+    type: mime
+  })
+}
+
+/** 获取file大小的名称 */
+export function fileSize (size) {
+  var size_int = size
+  if (typeof size === 'string' && size.constructor === String) {
+    size_int = parseInt(size)
+  }
+  var formatSize
+  if (parseInt(size_int / 1024 / 1024) > 0) {
+    formatSize = (size_int / 1024 / 1024).toFixed(2) + 'MB'
+  } else if (parseInt(size_int / 1024) > 0) {
+    formatSize = (size_int / 1024).toFixed(2) + 'kB'
+  } else {
+    formatSize = size_int + 'Byte'
+  }
+  return formatSize
+}
+export function getMaxIndex () {
+  let arr = [...document.getElementsByTagName('div')].map(e => +window.getComputedStyle(e).zIndex || 0)
+  return arr.length ? Math.max(...arr) + 1 : 0
+  // return PopupManager.nextZIndex()
+}
+
+/** 深拷贝 */
+export function objDeepCopy (source) {
+  if (typeof source === 'object') {
+    var sourceCopy = source instanceof Array ? [] : {}
+    for (var item in source) {
+      if (!source[item]) {
+        sourceCopy[item] = source[item]
+      } else {
+        sourceCopy[item] = typeof source[item] === 'object' ? objDeepCopy(source[item]) : source[item]
+      }
+    }
+    return sourceCopy
+  }
+  return source
+}
+/** 获取文件类型图标 */
+export function getTypeIcon (file) {
+  console.log(file)
+  if (file.indexOf('image') !== -1) {
+    return require('@/assets/img/file_img.png')
+  } else if (file.indexOf('audio') !== -1 || file.indexOf('video') !== -1) {
+    return require('@/assets/img/file_video.png')
+  } else {
+    var index = file.lastIndexOf('.')
+    var ext = file.substr(index + 1)
+    if (arrayContain(['xlsx', 'xls', 'XLSX', 'XLS'], ext)) {
+      return require('@/assets/img/file_excle.png')
+    } else if (arrayContain(['doc', 'docx', 'DOC', 'DOCX'], ext)) {
+      return require('@/assets/img/file_word.png')
+    } else if (arrayContain(['rar', 'zip'], ext)) {
+      return require('@/assets/img/file_zip.png')
+    } else if (ext === 'pdf') {
+      return require('@/assets/img/file_pdf.png')
+    } else if (ext === 'ppt' || ext === 'pptx') {
+      return require('@/assets/img/file_ppt.png')
+    } else if (arrayContain(['txt', 'text'], ext)) {
+      return require('@/assets/img/file_txt.png')
+    }
+  }
+  return require('@/assets/img/file_unknown.png')
+}
+
+/** 获取文件类型图标 */
+export function getFileTypeIcon (file) {
+  console.log(file)
+  if (file.type.indexOf('image') !== -1) {
+    return require('@/assets/img/file_img.png')
+  } else if (file.type.indexOf('audio') !== -1 || file.type.indexOf('video') !== -1) {
+    return require('@/assets/img/file_video.png')
+  } else {
+    var index = file.name.lastIndexOf('.')
+    var ext = file.name.substr(index + 1)
+    if (arrayContain(['xlsx', 'xls', 'XLSX', 'XLS'], ext)) {
+      return require('@/assets/img/file_excle.png')
+    } else if (arrayContain(['doc', 'docx', 'DOC', 'DOCX'], ext)) {
+      return require('@/assets/img/file_word.png')
+    } else if (arrayContain(['rar', 'zip'], ext)) {
+      return require('@/assets/img/file_zip.png')
+    } else if (ext === 'pdf') {
+      return require('@/assets/img/file_pdf.png')
+    } else if (ext === 'ppt' || ext === 'pptx') {
+      return require('@/assets/img/file_ppt.png')
+    } else if (arrayContain(['txt', 'text'], ext)) {
+      return require('@/assets/img/file_txt.png')
+    }
+  }
+  return require('@/assets/img/file_unknown.png')
+}
+
+export function getFileTypeIconWithSuffix (ext) {
+  if (arrayContain(['jpg', 'png', 'gif'], ext)) {
+    return require('@/assets/img/file_img.png')
+  } else if (arrayContain(['mp4', 'mp3', 'avi'], ext)) {
+    return require('@/assets/img/file_excle.png')
+  } else if (arrayContain(['xlsx', 'xls', 'XLSX', 'XLS'], ext)) {
+    return require('@/assets/img/file_excle.png')
+  } else if (arrayContain(['doc', 'docx', 'DOC', 'DOCX'], ext)) {
+    return require('@/assets/img/file_word.png')
+  } else if (arrayContain(['rar', 'zip'], ext)) {
+    return require('@/assets/img/file_zip.png')
+  } else if (ext === 'pdf') {
+    return require('@/assets/img/file_pdf.png')
+  } else if (ext === 'ppt' || ext === 'pptx') {
+    return require('@/assets/img/file_ppt.png')
+  } else if (arrayContain(['txt', 'text'], ext)) {
+    return require('@/assets/img/file_txt.png')
+  }
+  return require('@/assets/img/file_unknown.png')
+}
+
+function arrayContain (array, string) {
+  return array.some((item) => {
+    return item === string
+  })
+}
+
+/** 判断输入的是number */
+export function regexIsNumber (nubmer) {
+  var regex = /^[0-9]+.?[0-9]*/
+  if (!regex.test(nubmer)) {
+    return false
+  }
+  return true
+}
+
+/** 判断输入的是crm数字 数字的整数部分须少于12位,小数部分须少于4位 */
+export function regexIsCRMNumber (nubmer) {
+  var regex = /^([-+]?\d{1,12})(\.\d{0,4})?$/
+  if (!regex.test(nubmer)) {
+    return false
+  }
+  return true
+}
+
+/** 判断输入的是货币 货币的整数部分须少于10位,小数部分须少于2位 */
+export function regexIsCRMMoneyNumber (nubmer) {
+  var regex = /^([-+]?\d{1,10})(\.\d{0,2})?$/
+  if (!regex.test(nubmer)) {
+    return false
+  }
+  return true
+}
+
+/** 判断输入的是电话 */
+export function regexIsCRMMobile (mobile) {
+  var regex = /^(\+?0?\d{2,4}\-?)?\d{6,11}$/
+  if (!regex.test(mobile)) {
+    return false
+  }
+  return true
+}
+
+/** 判断输入的是邮箱 */
+export function regexIsCRMEmail (email) {
+  var regex = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/
+  if (!regex.test(email)) {
+    return false
+  }
+  return true
+}
+
+export function getDateFromTimestamp (time) {
+  var times = 0
+  if (time.length === 13) {
+    times = parseInt(time)
+  } else {
+    times = parseInt(time) * 1000
+  }
+  return new Date(times) // 如果date为13位不需要乘1000
+}
+
+/**
+ *
+ * @param {*} timestamp 时间戳
+ * @param {*} format 格式化
+ */
+export function timestampToFormatTime (timestamp, format) {
+  if (timestamp && timestamp.toString().length >= 10) {
+    return moment(getDateFromTimestamp(timestamp.toString())).format(format)
+  }
+  return ''
+}
+/**
+ *
+ * @param {*} format 格式化字符串
+ */
+export function formatTimeToTimestamp (format) {
+  if (format && format.length > 0) {
+    var timeValue = moment(format)
+      .valueOf()
+      .toString()
+    return timeValue.length > 10 ? timeValue.substr(0, 10) : timeValue
+  }
+  return ''
+}
+
+/** image 下载 */
+/**
+ *
+ * @param {*} data url
+ * @param {*} filename 名称
+ */
+export function downloadImage (data, filename) {
+  var httpindex = data.indexOf('http')
+  if (httpindex === 0) {
+    const image = new Image()
+    // 解决跨域 canvas 污染问题
+    image.setAttribute('crossOrigin', 'anonymous')
+    image.onload = function () {
+      const canvas = document.createElement('canvas')
+      canvas.width = image.width
+      canvas.height = image.height
+      const context = canvas.getContext('2d')
+      context.drawImage(image, 0, 0, image.width, image.height)
+      const dataURL = canvas.toDataURL('image/png')
+      // 生成一个 a 标签
+      const a = document.createElement('a')
+      // 创建一个点击事件
+      const event = new MouseEvent('click')
+      // 将 a 的 download 属性设置为我们想要下载的图片的名称,若 name 不存在则使用'图片'作为默认名称
+      a.download = filename || '图片'
+      // 将生成的 URL 设置为 a.href 属性
+      var blob = dataURLtoBlob(dataURL)
+      a.href = URL.createObjectURL(blob)
+      // 触发 a 的点击事件
+      a.dispatchEvent(event)
+    }
+    image.src = data
+  } else {
+    // 生成一个 a 标签
+    const a = document.createElement('a')
+    // 创建一个点击事件
+    const event = new MouseEvent('click')
+    // 将 a 的 download 属性设置为我们想要下载的图片的名称,若 name 不存在则使用'图片'作为默认名称
+    a.download = filename || '图片'
+    // 将生成的 URL 设置为 a.href 属性
+    a.href = data
+    // 触发 a 的点击事件
+    a.dispatchEvent(event)
+  }
+}
+/**
+ * path  和 name
+ */
+export function downloadFile (data) {
+  var a = document.createElement('a')
+  a.href = ResouceUrl + data.path
+  a.download = data.name ? data.name : '文件'
+  a.target = '_black'
+  document.body.appendChild(a)
+  a.click()
+  document.body.removeChild(a)
+}
+
+export function dataURLtoBlob (dataurl) {
+  // eslint-disable-next-line one-var
+  var arr = dataurl.split(','),
+    mime = arr[0].match(/:(.*?);/)[1],
+    bstr = atob(arr[1]),
+    n = bstr.length,
+    u8arr = new Uint8Array(n)
+  while (n--) {
+    u8arr[n] = bstr.charCodeAt(n)
+  }
+  return new Blob([u8arr], {
+    type: mime
+  })
+}
+
+export function getBase64Image (img) {
+  var canvas = document.createElement('canvas')
+  canvas.width = img.width
+  canvas.height = img.height
+  var ctx = canvas.getContext('2d')
+  ctx.drawImage(img, 0, 0, img.width, img.height)
+  var ext = img.src.substring(img.src.lastIndexOf('.') + 1).toLowerCase()
+  var dataURL = canvas.toDataURL('image/' + ext)
+  return dataURL
+}
+
+// 获取绑定参数
+export function guid () {
+  function S4 () {
+    return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)
+  }
+  return (S4() + S4() + S4() + S4() + S4() + S4() + S4() + S4())
+}
+
+/**
+ * 金额格式化 增加千分符
+ * @param {*} val
+ */
+export function moneyFormat (val) {
+  if (!val) return '0.00'
+  const i = Math.floor(val)
+  const d = val.split('.')[1] || '00'
+  return i.toLocaleString('en-US') + '.' + d
+}
+
+/**
+ * 下载excel
+ */
+export function downloadExcelWithResData (res) {
+  let fileName = res.headers['content-disposition'].split('filename=')[1]
+  if (!fileName) {
+    fileName = res.headers['content-disposition'].split('UTF-8\'\'')[1]
+  }
+  fileName = fileName ? fileName.replace(/\"/g, '') : 'file.xlsx'
+  fileName = decodeURI(fileName) || ''
+  downloadFileWithBuffer(res.data, fileName, 'application/vnd.ms-excel;charset=utf-8')
+}
+
+export function downloadFileWithBuffer (data, name, type) {
+  var blob = new Blob([data], {
+    type: type || ''
+  })
+  var downloadElement = document.createElement('a')
+  var href = window.URL.createObjectURL(blob) // 创建下载的链接
+  downloadElement.href = href
+  downloadElement.download = name // 下载后文件名
+  document.body.appendChild(downloadElement)
+  downloadElement.click() // 点击下载
+  document.body.removeChild(downloadElement) // 下载完成移除元素
+  window.URL.revokeObjectURL(href) // 释放掉blob对象
+}
diff --git a/src/utils/request.js b/src/utils/request.js
new file mode 100644
index 0000000..a44ea6e
--- /dev/null
+++ b/src/utils/request.js
@@ -0,0 +1,113 @@
+import axios from 'axios'
+import {
+  Message,
+  MessageBox
+} from 'element-ui'
+import {
+  removeAuth
+} from '@/utils/auth'
+// import qs from 'qs'
+import Lockr from 'lockr'
+
+var showLoginMessageBox = false
+axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8'
+// 创建axios实例
+console.log(process.env)
+const service = axios.create({
+  baseURL: 'http://api.crm.urlink.com.cn/api/',
+  // baseURL: process.env.BASE_API, // api 的 base_url
+  // baseURL: 'http://192.168.0.107:8080/api',
+  timeout: 600000 // 请求超时时间
+})
+// request拦截器
+service.interceptors.request.use(
+  config => {
+    const flag = config.headers['Content-Type'] && config.headers['Content-Type'].indexOf('application/json') !== -1
+    if (!flag) {
+      const mult = config.headers['Content-Type'] && config.headers['Content-Type'].indexOf('multipart/form-data') !== -1
+      if (mult) {
+        config.data = config.data
+      } else {
+        // config.data = qs.stringify(config.data)
+        config.data = config.data
+      }
+    }
+    config.headers['token'] = Lockr.get('Admin-Token')
+    let url = config.url
+    url += url.indexOf('?') >= 0 ? '&' : '?'
+    url += 'r=' + (Math.random() * 100000 + 1)
+    config.url = url
+    return config
+  },
+  error => {
+    console.log(error)
+    // Do something with request error
+    return Promise.reject(error)
+  }
+)
+
+// response 拦截器
+service.interceptors.response.use(
+  response => {
+    /**
+     * code为非200是抛错
+     */
+    const res = response.data
+    if (response.status === 200 && response.config.responseType === 'blob') { // 文件类型特殊处理
+      return response
+    } else if (res && !res.ErrorCode) {
+      return response
+    } else if (res.ErrorCode !== 0) {
+      // 302登录已失效
+      if (res.ErrorCode === 302 || res.ErrorCode === 401) {
+        if (!showLoginMessageBox) {
+          showLoginMessageBox = true
+          MessageBox.confirm(
+            '你已被登出,请重新登录',
+            '确定登出', {
+              showCancelButton: false,
+              showClose: false,
+              confirmButtonText: '重新登录',
+              type: 'warning',
+              callback: action => {
+                showLoginMessageBox = false
+                if (action === 'confirm') {
+                  removeAuth().then(() => {
+                    let rout = window.location.href
+                    let a = rout.lastIndexOf('/')
+                    rout = rout.substring(0, a)
+                    window.location.href = rout + '/login'
+                    // location.reload() // 为了重新实例化vue-router对象 避免bug
+                  }).catch(() => {
+                    location.reload()
+                  })
+                }
+              }
+            }
+          )
+        }
+      } else if (res.ErrorCode === 200) {
+        return response
+      } else {
+        if (res.Message) {
+          Message({
+            message: res.Message,
+            type: 'error'
+          })
+        }
+      }
+      return Promise.reject(res)
+    } else {
+      return res
+    }
+  },
+  error => {
+    Message({
+      message: '网络请求失败,请稍候再试',
+      type: 'error'
+    })
+    return Promise.reject(error)
+  }
+)
+
+export default service
diff --git a/src/utils/types.js b/src/utils/types.js
new file mode 100644
index 0000000..237372e
--- /dev/null
+++ b/src/utils/types.js
@@ -0,0 +1,11 @@
+export function isString (obj) {
+  return Object.prototype.toString.call(obj) === '[object String]'
+}
+
+export function isObject (obj) {
+  return Object.prototype.toString.call(obj) === '[object Object]'
+}
+
+export function isArray (obj) {
+  return Object.prototype.toString.call(obj) === '[object Array]'
+}
diff --git a/src/utils/validate.js b/src/utils/validate.js
new file mode 100644
index 0000000..8f112c8
--- /dev/null
+++ b/src/utils/validate.js
@@ -0,0 +1,27 @@
+/**
+ * Created by jiachenpan on 16/11/18.
+ */
+
+/* 合法uri */
+export function validateURL (textval) {
+  const urlregex = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
+  return urlregex.test(textval)
+}
+
+/* 小写字母 */
+export function validateLowerCase (str) {
+  const reg = /^[a-z]+$/
+  return reg.test(str)
+}
+
+/* 大写字母 */
+export function validateUpperCase (str) {
+  const reg = /^[A-Z]+$/
+  return reg.test(str)
+}
+
+/* 大小写字母 */
+export function validatAlphabets (str) {
+  const reg = /^[A-Za-z]+$/
+  return reg.test(str)
+}
diff --git a/src/views/401.vue b/src/views/401.vue
new file mode 100644
index 0000000..8cbd558
--- /dev/null
+++ b/src/views/401.vue
@@ -0,0 +1,129 @@
+<template>
+  <div class="error-container">
+    <div class="errPage-container">
+      <el-button
+        icon="arrow-left"
+        class="pan-back-btn"
+        @click="back">返回</el-button>
+      <el-row>
+        <el-col :span="12">
+          <h1 class="text-jumbo text-ginormous">Oops!</h1>
+          <h2>你没有权限去该页面</h2>
+          <h6>如有不满请联系你领导</h6>
+          <ul class="list-unstyled">
+            <li>或者你可以去:</li>
+            <li class="link-type">
+              <router-link to="workbench/index">回首页</router-link>
+            </li>
+            <li><a
+              href="#"
+              @click.prevent="dialogVisible=true">点我看图</a></li>
+          </ul>
+        </el-col>
+        <el-col :span="12">
+          <img
+            src="@/assets/401_images/401.gif"
+            width="313"
+            height="428"
+            alt="Girl has dropped her ice cream.">
+        </el-col>
+      </el-row>
+      <el-dialog
+        :visible.sync="dialogVisible"
+        title="随便看">
+        <img
+          src="@/assets/401_images/1.gif"
+          class="pan-img">
+      </el-dialog>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'Page401',
+  data () {
+    return {
+      dialogVisible: false
+    }
+  },
+  methods: {
+    back () {
+      // this.$router.go(-1)
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+
+.error-container {
+  width: 100%;
+  height: 100%;
+  min-height: 560px;
+  background: #fff;
+  .errPage-container {
+    // transform: translate(-40%,-30%);
+    width: 800px;
+    max-width: 100%;
+    margin: 0 auto;
+    background: #fff;
+    padding-top: 100px;
+    .pan-back-btn {
+      background: #008489;
+      color: #fff;
+      border: none !important;
+    }
+    .pan-gif {
+      margin: 0 auto;
+      display: block;
+    }
+    .pan-img {
+      display: block;
+      margin: 0 auto;
+      width: 100%;
+    }
+    .text-jumbo {
+      font-size: 60px;
+      font-weight: 700;
+      color: #484848;
+    }
+    .list-unstyled {
+      font-size: 14px;
+      li {
+        padding-bottom: 5px;
+      }
+      a {
+        color: #008489;
+        text-decoration: none;
+        &:hover {
+          text-decoration: underline;
+        }
+      }
+    }
+    h2 {
+      font-size: 1.5em;
+      margin-block-start: 0.83em;
+      margin-block-end: 0.83em;
+      margin-inline-start: 0px;
+      margin-inline-end: 0px;
+      font-weight: bold;
+    }
+    h6 {
+      display: block;
+      font-size: 0.67em;
+      margin-block-start: 2.33em;
+      margin-block-end: 2.33em;
+      margin-inline-start: 0px;
+      margin-inline-end: 0px;
+      font-weight: bold;
+    }
+    li {
+      list-style: unset;
+    }
+    ul {
+      padding-inline-start: 40px;
+    }
+  }
+}
+</style>
diff --git a/src/views/404.vue b/src/views/404.vue
new file mode 100644
index 0000000..95045f0
--- /dev/null
+++ b/src/views/404.vue
@@ -0,0 +1,88 @@
+<template>
+  <div class="wrapper">
+    <div class="http404-container">
+      <img
+        class="pic"
+        src="@/assets/404_images/404.png"
+        alt="">
+      <div class="title">抱歉,您要访问的页面丢失了</div>
+      <div class="desc">请检查您输入的网址是否正确,请点击以下按钮返回首页</div>
+      <div
+        class="btn"
+        @click="handleBack">
+        返回首页
+      </div>
+    </div>
+
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'Page404',
+  methods: {
+    handleBack () {
+      this.$router.push('/')
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.wrapper {
+  position: relative;
+}
+
+.http404-container {
+  position: relative;
+  top: 50%;
+  transform: translateY(-50%);
+  .pic {
+    width: 600px;
+    display: block;
+    margin: 0 auto;
+  }
+  .title {
+    width: 100%;
+    text-align: center;
+    font-size: 24px;
+    color: #111;
+    line-height: 38px;
+    margin-top: 77px;
+  }
+  .desc {
+    width: 100%;
+    font-size: 18px;
+    color: #777;
+    text-align: center;
+    line-height: 38px;
+    margin-top: 8px;
+  }
+  .btn {
+    width: 125px;
+    height: 44px;
+    text-align: center;
+    font-size: 14px;
+    color: #fefefe;
+    line-height: 44px;
+    background: #4D88FF;
+    border-radius: 6px;
+    margin: 50px auto 0;
+    cursor: pointer;
+  }
+}
+
+@media screen and (max-width: 1500px) {
+  .http404-container {
+    .pic {
+      width: 500px;
+    }
+    .title {
+      margin-top: 50px;
+    }
+    .btn {
+      margin-top: 40px;
+    }
+  }
+}
+</style>
diff --git a/src/views/OAManagement/addressBook/department.vue b/src/views/OAManagement/addressBook/department.vue
new file mode 100644
index 0000000..f562b46
--- /dev/null
+++ b/src/views/OAManagement/addressBook/department.vue
@@ -0,0 +1,104 @@
+<template>
+  <div class="department">
+    <el-collapse
+      v-model="activeNames"
+      @change="handleChange">
+      <el-collapse-item
+        v-for="(item, index) in depData"
+        :name="index"
+        :key="index">
+        <template slot="title">
+          <span class="title">{{ item.name }} ({{ item.userList.length }}人)</span>
+        </template>
+        <div
+          v-for="(k, j) in item.userList"
+          :key="j"
+          class="k-list">
+          <div class="list-right">
+            <div class="k-realname">{{ k.realname.substring(0, 6) }}</div>
+            <div class="content">
+              <div v-if="k.deptName">
+                <img
+                  src="@/assets/img/structure.png"
+                  alt="">
+                <span>{{ k.deptName }}</span>
+              </div>
+              <div v-if="k.postName">
+                <img
+                  src="@/assets/img/post.png"
+                  alt="">
+                <span>{{ k.postName }}</span>
+              </div>
+              <div v-if="k.mobile">
+                <img
+                  src="@/assets/img/mobile.png"
+                  alt="">
+                <span>{{ k.mobile }}</span>
+              </div>
+            </div>
+          </div>
+        </div>
+      </el-collapse-item>
+    </el-collapse>
+  </div>
+</template>
+
+<script>
+export default {
+  props: {
+    depData: Array
+  },
+  data () {
+    return {
+      activeNames: []
+    }
+  },
+  mounted () {},
+  methods: {
+    handleChange (val, key) {}
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.department {
+  padding: 0 30px;
+  flex: 1;
+  overflow: auto;
+  margin-bottom: 20px;
+  .el-collapse /deep/ {
+    border: 0;
+    .el-collapse-item__wrap {
+      border: 0;
+      margin-top: 10px;
+      .el-collapse-item__content {
+        padding-bottom: 0;
+      }
+    }
+    .el-collapse-item__header {
+      position: relative;
+      .title {
+        padding-left: 25px;
+        color: #999;
+      }
+      .el-collapse-item__arrow {
+        position: absolute;
+        left: 0;
+        color: #999;
+      }
+    }
+    .el-collapse-item__header.is-active {
+      border-color: #ebeef5;
+    }
+  }
+  .staff-data {
+    margin-top: 20px;
+  }
+  .item-title {
+    border-bottom: 1px solid #eee;
+    padding-bottom: 10px;
+    color: #777;
+    font-size: 12px;
+  }
+}
+</style>
diff --git a/src/views/OAManagement/addressBook/index.vue b/src/views/OAManagement/addressBook/index.vue
new file mode 100644
index 0000000..133c129
--- /dev/null
+++ b/src/views/OAManagement/addressBook/index.vue
@@ -0,0 +1,187 @@
+<template>
+  <div class="address-book oa-bgcolor">
+    <div class="header">
+      <el-tabs v-model="activeName">
+        <el-tab-pane
+          label="员工"
+          name="1">
+          <el-input
+            v-model="userInput"
+            placeholder="搜索成员"
+            prefix-icon="el-icon-search"
+            @blur="blurFun"
+            @keyup.enter.native="blurFun"/>
+          <v-staff
+            v-loading="staffLoading"
+            :staff-data="staffData"/>
+        </el-tab-pane>
+        <el-tab-pane
+          label="部门"
+          name="2">
+          <el-input
+            v-model="depInput"
+            placeholder="搜索成员"
+            prefix-icon="el-icon-search"
+            @blur="blurFun"/>
+          <v-department :dep-data="depData"/>
+        </el-tab-pane>
+      </el-tabs>
+    </div>
+  </div>
+</template>
+
+<script>
+// import {
+//   addresslist,
+//   queryListNameByDept
+// } from '@/api/oamanagement/addressBook'
+import VStaff from './staff'
+import VDepartment from './department'
+export default {
+  components: {
+    VStaff,
+    VDepartment
+  },
+  data () {
+    return {
+      activeName: '1',
+      staffData: [],
+      depData: [],
+      userInput: '',
+      depInput: '',
+      staffLoading: true
+    }
+  },
+  created () {
+    // 员工
+    this.dataUserFun()
+    // 部门
+    this.dataDepFun()
+  },
+  methods: {
+    dataUserFun () {
+      this.staffLoading = true
+      // addresslist({
+      //   search: this.userInput
+      // }).then(res => {
+      //   const words = [
+      //     '#',
+      //     'A',
+      //     'B',
+      //     'C',
+      //     'D',
+      //     'E',
+      //     'F',
+      //     'G',
+      //     'H',
+      //     'I',
+      //     'J',
+      //     'K',
+      //     'L',
+      //     'M',
+      //     'N',
+      //     'O',
+      //     'P',
+      //     'Q',
+      //     'R',
+      //     'S',
+      //     'T',
+      //     'U',
+      //     'V',
+      //     'W',
+      //     'X',
+      //     'Y',
+      //     'Z'
+      //   ]
+
+      //   for (const key of words) {
+      //     const list = res.data[key]
+      //     if (list) {
+      //       this.staffData.push({
+      //         letter: key,
+      //         list: list
+      //       })
+      //     }
+      //   }
+      //   this.staffLoading = false
+      // })
+    },
+    dataDepFun (search) {
+      // queryListNameByDept({
+      //   name: this.depInput
+      // }).then(res => {
+      //   this.depData = res.data
+      // })
+    },
+    blurFun () {
+      this.staffData = []
+      this.activeName === '1' ? this.dataUserFun() : this.dataDepFun()
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+@import '../styles/tabs.scss';
+.address-book {
+  .header {
+    height: 100%;
+    .el-tabs /deep/ {
+      height: 100%;
+      display: flex;
+      flex-direction: column;
+      .el-tabs__content {
+        flex: 1;
+        display: flex;
+        flex-direction: column;
+        .el-tab-pane {
+          display: flex;
+          flex-direction: column;
+          flex: 1;
+          min-height: 0;
+        }
+        .el-input {
+          width: 230px;
+          margin: 10px 30px;
+        }
+        .k-list {
+          margin-bottom: 10px;
+          .list-right,
+          .header-circle {
+            display: inline-block;
+          }
+          .header-circle {
+            width: 42px;
+            height: 42px;
+            margin-right: 10px;
+            vertical-align: middle;
+          }
+          .list-right {
+            vertical-align: middle;
+            .content {
+              color: #777;
+              img,
+              span {
+                vertical-align: middle;
+              }
+            }
+            .content > div {
+              display: inline-block;
+              margin-right: 15px;
+            }
+            .k-realname {
+              font-size: 14px;
+              margin-right: 15px;
+              width: 96px;
+            }
+            .k-realname,
+            .content {
+              display: inline-block;
+            }
+          }
+        }
+      }
+    }
+  }
+}
+</style>
diff --git a/src/views/OAManagement/addressBook/staff.vue b/src/views/OAManagement/addressBook/staff.vue
new file mode 100644
index 0000000..c5c7e34
--- /dev/null
+++ b/src/views/OAManagement/addressBook/staff.vue
@@ -0,0 +1,75 @@
+<template>
+  <div class="staff">
+    <div
+      v-for="(item, index) in staffData"
+      :key="index"
+      class="staff-data">
+      <div class="item-title">{{ item.letter }}</div>
+      <div
+        v-for="(k, j) in item.list"
+        :key="j"
+        class="k-list">
+        <div class="list-right">
+          <div class="k-realname">{{ k.realname.substring(0, 6) }}</div>
+          <div class="content">
+            <div v-if="k.deptName">
+              <img
+                src="@/assets/img/structure.png"
+                alt="">
+              <span>{{ k.deptName }}</span>
+            </div>
+            <div v-if="k.postName">
+              <img
+                src="@/assets/img/post.png"
+                alt="">
+              <span>{{ k.postName }}</span>
+            </div>
+            <div v-if="k.mobile">
+              <img
+                src="@/assets/img/mobile.png"
+                alt="">
+              <span>{{ k.mobile }}</span>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  props: {
+    staffData: Array
+  },
+  data () {
+    return {}
+  },
+  created () {},
+  methods: {
+    handleClick () {}
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.staff {
+  padding: 0 30px;
+  flex: 1;
+  overflow: auto;
+  margin-bottom: 20px;
+  .staff-data {
+    margin-top: 15px;
+  }
+  .item-title {
+    border-bottom: 1px solid #eee;
+    padding-bottom: 10px;
+    color: #777;
+    margin-bottom: 13px;
+    font-size: 12px;
+  }
+  .k-realname {
+    margin-bottom: 8px;
+  }
+}
+</style>
diff --git a/src/views/OAManagement/components/fileCell/index.vue b/src/views/OAManagement/components/fileCell/index.vue
new file mode 100644
index 0000000..94a50bb
--- /dev/null
+++ b/src/views/OAManagement/components/fileCell/index.vue
@@ -0,0 +1,124 @@
+<template>
+  <flexbox class="cell">
+    <img
+      class="cell-head"
+      src="@/assets/img/relevance_file.png"
+      alt>
+    <div
+      :class="{'cursor-pointer' :cursorPointer}"
+      class="cell-body">
+      <span>{{ data.name.length > 20 ? data.name.substring(0, 20) + '...' : data.name }}</span>
+      <span class="size">({{ data.size }})</span>
+    </div>
+    <div class="cell-foot">
+      <el-button
+        type="primary"
+        icon="el-icon-download"
+        @click="downloadClick">下载</el-button>
+      <i
+        v-if="showDelete"
+        class="el-icon-delete"
+        @click="deleteClick"/>
+    </div>
+  </flexbox>
+</template>
+
+<script type="text/javascript">
+import { downloadFile } from '@/utils'
+// import { crmFileDelete } from '@/api/common'
+
+export default {
+  name: 'FileCell',
+  props: {
+    cellIndex: Number,
+    data: Object,
+    showFoot: {
+      type: Boolean,
+      default: true
+    },
+    cursorPointer: {
+      type: Boolean,
+      default: false
+    },
+    showDelete: {
+      type: Boolean,
+      default: false
+    },
+    module_id: [String, Number]
+  },
+  data () {
+    return {}
+  }, // 附件展示效果
+  computed: {},
+  watch: {},
+  mounted () {},
+
+  beforeDestroy () {},
+  methods: {
+    downloadClick () {
+      downloadFile({ path: this.data.filePath, name: this.data.name })
+    },
+    deleteClick () {
+      this.$confirm('确定删除?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          // crmFileDelete({
+          //   id: this.data.fileId
+          // })
+          //   .then(res => {
+          //     this.$message.success('操作成功')
+          //     this.$emit('delete', this.cellIndex, this.data)
+          //   })
+          //   .catch(() => {})
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.cell {
+  padding: 8px;
+  background-color: #f5f7fa;
+  border-radius: 2px;
+  position: relative;
+  margin-bottom: 5px;
+
+  .cell-head {
+    display: block;
+    width: 16px;
+    height: 16px;
+    margin-right: 5px;
+  }
+
+  .cell-body {
+    flex: 1;
+    color: #4D88FF;
+    font-size: 13px;
+    .size {
+      color: #ccc;
+    }
+  }
+
+  .cell-foot {
+    margin-right: 8px;
+    cursor: pointer;
+    i {
+      color: #ccc;
+      padding: 0 2px;
+    }
+  }
+}
+
+.cursor-pointer {
+  cursor: pointer;
+}
+</style>
diff --git a/src/views/OAManagement/components/relatedBusinessCell/index.vue b/src/views/OAManagement/components/relatedBusinessCell/index.vue
new file mode 100644
index 0000000..cbe1fc0
--- /dev/null
+++ b/src/views/OAManagement/components/relatedBusinessCell/index.vue
@@ -0,0 +1,115 @@
+<template>
+  <flexbox class="cell">
+    <i
+      :class="'wukong-' + type"
+      class="cell-head wukong"/>
+    <div
+      :class="{'cursor-pointer' :cursorPointer}"
+      class="cell-body"
+      @click="bodyClick">
+      {{ getShowName() }}
+    </div>
+    <img
+      v-if="showFoot"
+      class="cell-foot"
+      style="cursor: pointer;"
+      src="@/assets/img/cancel_associated.png"
+      @click="footClick" >
+  </flexbox>
+</template>
+
+<script type="text/javascript">
+export default {
+  name: 'RelatedBusinessCell',
+  props: {
+    type: {
+      type: String,
+      default: ''
+    },
+    cellIndex: Number,
+    data: Object,
+    showFoot: {
+      type: Boolean,
+      default: true
+    },
+    cursorPointer: {
+      type: Boolean,
+      default: true
+    }
+  },
+  data () {
+    return {}
+  }, // 相关CRM等类型展示布局
+  computed: {
+    typeName () {
+      if (this.type === 'customer') {
+        return '客户'
+      } else if (this.type === 'contacts') {
+        return '联系人'
+      } else if (this.type === 'business') {
+        return '商机'
+      } else if (this.type === 'contract') {
+        return '合同'
+      }
+      return ''
+    }
+  },
+  watch: {},
+  mounted () {},
+
+  beforeDestroy () {},
+  methods: {
+    footClick () {
+      this.$emit('unbind', this.type, this.cellIndex, this.data)
+    },
+    bodyClick () {
+      this.$emit('detail', this.type, this.cellIndex, this.data)
+    },
+    getShowName (item) {
+      return (
+        this.typeName +
+        '-' +
+        (this.data.name ||
+          this.data.businessName ||
+          this.data.customerName ||
+          this.data.number)
+      )
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.cell {
+  padding: 8px;
+  background-color: #f5f7fa;
+  border-radius: 2px;
+  position: relative;
+  margin-bottom: 5px;
+
+  .cell-head {
+    display: block;
+    width: 15px;
+    height: 15px;
+    margin-right: 8px;
+    color: #6394e5;
+    font-size: 14px;
+  }
+
+  .cell-body {
+    flex: 1;
+    color: #4D88FF;
+    font-size: 12px;
+  }
+
+  .cell-foot {
+    display: block;
+    width: 24px;
+    padding: 0 4px;
+    margin-right: 8px;
+  }
+}
+
+.cursor-pointer {
+  cursor: pointer;
+}
+</style>
diff --git a/src/views/OAManagement/examine/components/content.vue b/src/views/OAManagement/examine/components/content.vue
new file mode 100644
index 0000000..ca50fcc
--- /dev/null
+++ b/src/views/OAManagement/examine/components/content.vue
@@ -0,0 +1,222 @@
+<template>
+  <div
+    v-loading="loading"
+    class="content">
+    <div class="select-box">
+      <div class="select-group">
+        <label>审核状态</label>
+        <el-select
+          v-model="checkStatus"
+          size="small"
+          placeholder="请选择"
+          @change="searchBtn">
+          <el-option
+            v-for="item in statusOptions"
+            :key="item.key"
+            :label="item.label"
+            :value="item.key"/>
+        </el-select>
+      </div>
+      <div class="select-group">
+        <label>发起时间</label>
+        <el-date-picker
+          v-model="betweenTime"
+          type="daterange"
+          style="padding: 0px 10px;width: 250px;"
+          range-separator="-"
+          value-format="yyyy-MM-dd"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          @change="searchBtn"/>
+      </div>
+    </div>
+    <examine-section
+      :id="'examine-list-box' + by"
+      :list="list"
+      class="list-box"
+      @handle="searchBtn">
+      <p
+        slot="load"
+        class="load">
+        <el-button
+          :loading="loadMoreLoading"
+          type="text">{{ loadMoreLoading ? '加载更多' : '没有更多了' }}</el-button>
+      </p>
+    </examine-section>
+  </div>
+</template>
+
+<script>
+// import {
+//   oaExamineMyCreateIndex,
+//   oaExamineMyExamineIndex
+// } from '@/api/oamanagement/examine'
+import ExamineSection from './examineSection'
+
+export default {
+  components: {
+    ExamineSection
+  },
+  props: {
+    // 类型 my我发起的,examine我审批的
+    by: String,
+    // 审批类型ID
+    categoryId: [String, Number]
+  },
+  data () {
+    return {
+      loading: false,
+      loadMoreLoading: true,
+      checkStatus: this.by === 'examine' ? '1' : '',
+      betweenTime: [],
+      list: [],
+      // 判断是否发请求
+      isPost: false,
+      page: 1
+    }
+  },
+  computed: {
+    statusOptions () {
+      if (this.by === 'examine') {
+        return [
+          { label: '待我审批的', key: '1' },
+          { label: '我已审批的', key: '2' }
+        ] // 1待我审批的、2我已审批的
+      } else {
+        return [
+          { label: '全部', key: '' },
+          { label: '待审', key: '0' },
+          { label: '审批中', key: '3' },
+          { label: '通过', key: '1' },
+          { label: '失败', key: '2' },
+          { label: '撤回', key: '4' }
+        ]
+      }
+    }
+  },
+  watch: {
+    categoryId: function (params) {
+      this.page = 1
+      this.list = []
+      this.getList()
+    }
+  },
+  mounted () {
+    // 分批次加载
+    const dom = document.getElementById('examine-list-box' + this.by)
+    dom.onscroll = () => {
+      const scrollOff = dom.scrollTop + dom.clientHeight - dom.scrollHeight
+      // 滚动条到底部的条件
+      if (Math.abs(scrollOff) < 10 && this.loadMoreLoading === true) {
+        if (!this.isPost) {
+          this.isPost = true
+          this.page++
+          this.getList()
+        } else {
+          this.loadMoreLoading = false
+        }
+      }
+    }
+
+    this.getList()
+  },
+  methods: {
+    /** 获取列表数据 */
+    getList () {
+      this.loading = true
+      const params = {
+        page: this.page,
+        limit: 15,
+        categoryId: this.categoryId
+      }
+      if (this.by === 'examine') {
+        params.status = this.checkStatus
+      } else {
+        params.checkStatus = this.checkStatus
+      }
+
+      if (this.betweenTime && this.betweenTime.length > 0) {
+        params.startTime = this.betweenTime[0]
+        params.endTime = this.betweenTime[1]
+      }
+
+      // const request = {
+      //   my: oaExamineMyCreateIndex,
+      //   examine: oaExamineMyExamineIndex
+      // }[this.by]
+      // request(params)
+      //   .then(res => {
+      //     this.list = this.list.concat(res.data.list)
+      //     if (res.data.list.length < 15) {
+      //       this.loadMoreLoading = false
+      //     } else {
+      //       this.loadMoreLoading = true
+      //     }
+      //     this.isPost = false
+      //     this.loading = false
+      //   })
+      //   .catch(() => {
+      //     this.isPost = false
+      //     this.loading = false
+      //   })
+    },
+    // 搜索
+    searchBtn () {
+      this.list = []
+      this.page = 1
+      this.getList()
+    },
+    // 重置
+    resetBtn () {
+      this.checkStatus = 'all'
+      this.betweenTime = []
+      this.$emit('reset')
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+@import '../../styles/content.scss';
+.content {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  overflow-y: auto;
+  .select-box {
+    margin: 10px 0 20px;
+    .select-group {
+      margin-right: 20px;
+      display: inline-block;
+      label {
+        @include color9;
+        margin-right: 10px;
+      }
+      .el-select {
+        width: 116px;
+        height: 30px;
+      }
+    }
+    .btn-box {
+      float: right;
+      margin-right: 10px;
+    }
+  }
+  .list-box {
+    overflow: auto;
+    padding-right: 30px;
+  }
+}
+
+.load {
+  color: #999;
+  font-size: 13px;
+  margin: 0 auto 15px;
+  text-align: center;
+  .el-button,
+  .el-button:focus {
+    color: #ccc;
+    cursor: auto;
+  }
+}
+</style>
diff --git a/src/views/OAManagement/examine/components/examineCategorySelect.vue b/src/views/OAManagement/examine/components/examineCategorySelect.vue
new file mode 100644
index 0000000..d14d1da
--- /dev/null
+++ b/src/views/OAManagement/examine/components/examineCategorySelect.vue
@@ -0,0 +1,148 @@
+<template>
+  <el-dialog
+    :visible.sync="showDialog"
+    title="审批类型"
+    width="500px"
+    @close="closeView">
+    <div class="title">请选择您的审批类型(管理后台可自定义配置审批类型)</div>
+    <div
+      v-loading="loading"
+      class="categorys">
+      <flexbox
+        wrap="wrap"
+        align="stretch">
+        <div
+          v-for="(item, index) in categorys"
+          :key="index"
+          class="category-item"
+          @click="selectCategorys(item)">
+          <i
+            :class="item.iconClass"
+            class="wukong"/>
+          {{ item.title }}
+        </div>
+      </flexbox>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+// import { oaExamineCategoryList } from '@/api/oamanagement/examine'
+
+export default {
+  name: 'ExamineCategorySelect',
+  components: {},
+  props: {
+    show: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    return {
+      loading: false,
+      showDialog: false,
+      categorys: []
+    }
+  },
+  watch: {
+    show: function (val) {
+      this.showDialog = val
+      if (this.categorys && this.categorys.length === 0) {
+        this.getDetail()
+      }
+    }
+  },
+  mounted () {},
+  methods: {
+    // 审批类型列表
+    getDetail () {
+      this.loading = true
+      // oaExamineCategoryList()
+      //   .then(res => {
+      //     this.loading = false
+      //     this.categorys = res.data.map(item => {
+      //       item.iconClass = this.getCategoryIcon(item.categoryId)
+      //       return item
+      //     })
+      //   })
+      //   .catch(() => {
+      //     this.loading = false
+      //   })
+    },
+    // 审批类型选择
+    selectCategorys (item) {
+      this.$emit('select', item)
+      this.$emit('close')
+    },
+    // 关闭操作
+    closeView () {
+      this.$emit('close')
+    },
+
+    /**
+     * 获取图标
+     */
+    getCategoryIcon (categoryId) {
+      // 系统审批
+      categoryId = parseInt(categoryId)
+      if (categoryId <= 6) {
+        return [
+          'wukong-examine-category-ordinary',
+          'wukong-examine-category-leave',
+          'wukong-examine-category-business',
+          'wukong-examine-category-overtime',
+          'wukong-examine-category-billing',
+          'wukong-examine-category-borrowing'
+        ][categoryId - 1]
+      } else {
+        return [
+          'wukong-examine-category-one',
+          'wukong-examine-category-two',
+          'wukong-examine-category-three',
+          'wukong-examine-category-four',
+          'wukong-examine-category-five',
+          'wukong-examine-category-six',
+          'wukong-examine-category-seven',
+          'wukong-examine-category-eight',
+          'wukong-examine-category-nine'
+        ][categoryId % 9]
+      }
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.title {
+  position: absolute;
+  left: 25px;
+  top: 55px;
+  font-size: 12px;
+  color: #ccc;
+}
+
+.categorys {
+  height: 250px;
+  overflow-y: auto;
+  .category-item {
+    padding: 5px 10px;
+    border-radius: 3px;
+    border: 1px solid #e6e6e6;
+    color: #727272;
+    font-size: 12px;
+    margin: 5px 7px;
+    cursor: pointer;
+
+    .wukong {
+      color: #ff6a00;
+      margin-right: 2px;
+    }
+  }
+
+  .category-item:hover {
+    color: #ff6a00;
+    border-color: #ff6a00;
+  }
+}
+</style>
diff --git a/src/views/OAManagement/examine/components/examineCell.vue b/src/views/OAManagement/examine/components/examineCell.vue
new file mode 100644
index 0000000..20ca1b9
--- /dev/null
+++ b/src/views/OAManagement/examine/components/examineCell.vue
@@ -0,0 +1,304 @@
+<template>
+  <div class="list">
+    <div class="list-content">
+      <flexbox class="header">
+        <div
+          v-photo="data.createUser"
+          v-lazy:background-image="$options.filters.filterUserLazyImg(data.createUser.img)"
+          class="div-photo head-img"/>
+        <div class="name-time">
+          <span class="name">{{ data.createUser.realname }}</span>
+          <span class="time">{{ data.createtime }}</span>
+        </div>
+        <div class="rt-setting">
+          <span
+            :style="{ 'background-color': getStatusColor(data.examineStatus) }"
+            class="bg-color"/>
+          <span class="dep">
+            <span>{{ data.categoryTitle }} - </span>
+            <span>{{ getStatusName(data.examineStatus) }}</span>
+          </span>
+          <!-- 编辑 -->
+          <el-dropdown
+            v-if="data.permission && (data.permission.isChecked || data.permission.isUpdate || data.permission.isDelete)"
+            trigger="click"
+            @command="handleCommand">
+            <i
+              style="color:#CDCDCD; cursor: pointer;"
+              class="el-icon-arrow-down el-icon-more"/>
+            <el-dropdown-menu slot="dropdown">
+              <el-dropdown-item
+                v-if="data.permission && data.permission.isChecked"
+                command="withdraw">撤回</el-dropdown-item>
+              <el-dropdown-item
+                v-if="data.permission && data.permission.isUpdate"
+                command="edit">编辑</el-dropdown-item>
+              <el-dropdown-item
+                v-if="data.permission && data.permission.isDelete"
+                command="delete">删除</el-dropdown-item>
+            </el-dropdown-menu>
+          </el-dropdown>
+        </div>
+      </flexbox>
+      <div
+        class="row"
+        @click="checkDetail(data)">
+        <p
+          v-if="data.content"
+          class="text">{{ data.content }}</p>
+        <p
+          v-if="data.causeTitle"
+          class="title">{{ data.causeTitle }}</p>
+      </div>
+      <div
+        v-if="data.file.length > 0 || data.img.length > 0"
+        class="accessory">
+        <!-- 图片 -->
+        <div class="upload-img-box">
+          <div
+            v-for="(imgItem, k) in data.img"
+            :key="k"
+            class="img-list"
+            @click="imgZoom(data.img, k)">
+            <img v-lazy="imgItem.filePath">
+          </div>
+        </div>
+        <!-- 附件 -->
+        <div class="accessory-box">
+          <file-cell
+            v-for="(file, fileIndex) in data.file"
+            :key="fileIndex"
+            :data="file"
+            :cell-index="fileIndex"/>
+        </div>
+      </div>
+      <!-- 关联业务 -->
+      <div
+        v-if="relatedListData.contacts.length > 0 || relatedListData.customer.length > 0 || relatedListData.business.length > 0 || relatedListData.contract.length > 0"
+        class="related-business">
+        <div class="label">关联业务</div>
+        <div
+          v-for="(items, key) in relatedListData"
+          :key="key">
+          <related-business-cell
+            v-for="(item, itemIndex) in items"
+            :data="item"
+            :cell-index="itemIndex"
+            :type="key"
+            :key="itemIndex"
+            :show-foot="false"
+            @click.native="checkRelatedDetail(key, item)"/>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<script type="text/javascript">
+import RelatedBusinessCell from '@/views/OAManagement/components/relatedBusinessCell'
+import FileCell from '@/views/OAManagement/components/fileCell'
+
+export default {
+  name: 'ExamineCell', // 审批cell
+  components: {
+    RelatedBusinessCell,
+    FileCell
+  },
+  mixins: [],
+  props: {
+    data: Object
+  },
+  data () {
+    return {}
+  },
+  computed: {
+    relatedListData () {
+      return {
+        contacts: this.data.contactsList || [],
+        customer: this.data.customerList || [],
+        business: this.data.businessList || [],
+        contract: this.data.contractList || []
+      }
+    }
+  },
+  watch: {},
+  mounted () {},
+  methods: {
+    // 获取状态名称  0 未审核 1 审核通过 2 审核拒绝 3 审核中 4 已撤回
+    getStatusName (status) {
+      if (status === 0) {
+        return '待审'
+      } else if (status === 1) {
+        return '审核通过'
+      } else if (status === 2) {
+        return '审核拒绝'
+      } else if (status === 3) {
+        return '审核中'
+      } else if (status === 4) {
+        return '撤回'
+      }
+      return ''
+    },
+    getStatusColor (status) {
+      if (status === 0) {
+        return '#F3A633'
+      } else if (status === 1) {
+        return '#93E06D'
+      } else if (status === 2) {
+        return '#FF0000'
+      } else if (status === 3) {
+        return '#F3A633'
+      } else if (status === 4) {
+        return '#FF0000'
+      }
+      return ''
+    },
+    // 放大图片
+    imgZoom (images, k) {
+      this.$bus.emit('preview-image-bus', {
+        index: k,
+        data: images.map(function (item, index, array) {
+          return {
+            url: item.filePath,
+            name: item.name
+          }
+        })
+      })
+    },
+    // 编辑 删除 撤回
+    handleCommand (command) {
+      this.$emit('on-handle', { type: command, data: { item: this.data } })
+    },
+    // 查看详情
+    checkDetail (data) {
+      this.$emit('on-handle', { type: 'view', data: { item: this.data } })
+    },
+    // 关联详情
+    checkRelatedDetail (type, data) {
+      this.$emit('on-handle', {
+        type: 'related-detail',
+        data: { type: type, item: data }
+      })
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+@import '../../styles/content.scss';
+
+.list {
+  margin-bottom: 20px;
+  vertical-align: middle;
+  .list-content {
+    padding: 0 10px 10px 0;
+    .header {
+      margin-bottom: 15px;
+      @include color9;
+      font-size: 12px;
+      .head-img {
+        width: 35px;
+        height: 35px;
+        border-radius: 17.5px;
+      }
+      .name-time {
+        display: inline-block;
+        margin-left: 13px;
+        flex: 1;
+        .name {
+          font-size: 15px;
+          color: #333333;
+          display: block;
+          margin-bottom: 5px;
+        }
+      }
+      .rt-setting {
+        float: right;
+        line-height: 30px;
+        .dep {
+          color: #333333;
+          margin-right: 20px;
+        }
+        img {
+          width: 16px;
+          @include cursor;
+          @include v-align;
+        }
+        .bg-color {
+          display: inline-block;
+          width: 10px;
+          height: 10px;
+          border-radius: 50%;
+          margin-right: 5px;
+        }
+      }
+    }
+    .row {
+      white-space: pre-wrap;
+      word-wrap: break-word;
+      letter-spacing: 0.5px;
+      line-height: 18px;
+      cursor: pointer;
+      color: #4D88FF;
+      .text {
+        padding-bottom: 10px;
+      }
+      .title {
+        @include color9;
+        font-size: 13px;
+        padding-bottom: 10px;
+      }
+    }
+    .accessory {
+      .upload-img-box {
+        margin: 10px 0;
+        .img-list {
+          display: inline-block;
+          position: relative;
+          margin-right: 10px;
+          width: 80px;
+          height: 60px;
+          line-height: 60px;
+          cursor: pointer;
+          img {
+            width: 80px;
+            height: 60px;
+          }
+          .img-hover {
+            position: absolute;
+            top: 0;
+            right: 0;
+            left: 0;
+            bottom: 0;
+            background-color: rgba(0, 0, 0, 0.5);
+            text-align: center;
+            font-size: 12px;
+            color: #fff;
+            display: none;
+            span {
+              @include cursor;
+              display: inline-block;
+            }
+          }
+        }
+        .img-list:hover {
+          .img-hover {
+            display: inline-block;
+          }
+        }
+      }
+    }
+    .related-business {
+      margin: 15px 0;
+      .label {
+        font-size: 13px;
+        margin-bottom: 7px;
+        color: #666;
+      }
+    }
+  }
+}
+.list:not(:last-child) {
+  .list-content {
+    border-bottom: 1px solid #e6e6e6;
+  }
+}
+</style>
diff --git a/src/views/OAManagement/examine/components/examineCreateView.vue b/src/views/OAManagement/examine/components/examineCreateView.vue
new file mode 100644
index 0000000..553fb8d
--- /dev/null
+++ b/src/views/OAManagement/examine/components/examineCreateView.vue
@@ -0,0 +1,1096 @@
+<template>
+  <create-view
+    :loading="loading"
+    :body-style="{ height: '100%'}">
+    <flexbox
+      direction="column"
+      align="stretch"
+      class="crm-create-container">
+      <flexbox class="crm-create-header">
+        <div style="flex:1;font-size:17px;color:#333;">{{ title }}</div>
+        <img
+          class="close"
+          src="@/assets/img/task_close.png"
+          @click="hidenView" >
+      </flexbox>
+      <div class="crm-create-flex">
+        <!-- 基本信息 -->
+        <create-sections title="基本信息">
+          <flexbox
+            direction="column"
+            align="stretch">
+            <div class="crm-create-body">
+              <el-form
+                ref="crmForm"
+                :model="crmForm"
+                label-position="top"
+                class="crm-create-box">
+                <el-form-item
+                  v-for="(item, index) in crmForm.crmFields"
+                  :key="item.key"
+                  :prop="'crmFields.' + index + '.value'"
+                  :class="{ 'crm-create-block-item': item.showblock, 'crm-create-item': !item.showblock }"
+                  :rules="crmRules[item.key]"
+                  :style="{'padding-left': getPaddingLeft(item, index), 'padding-right': getPaddingRight(item, index)}">
+                  <div
+                    slot="label"
+                    style="display: inline-block;">
+                    <div style="margin:5px 0;font-size:12px;word-wrap:break-word;word-break:break-all;">
+                      {{ item.data.name }}
+                      <span style="color:#999;">
+                        {{ item.data.inputTips ? '('+item.data.inputTips+')':'' }}
+                      </span>
+                    </div>
+                  </div>
+                  <!-- 员工 和部门 为多选(radio=false)  relation 相关合同商机使用-->
+                  <component
+                    :is="item.data.formType | typeToComponentName"
+                    :value="item.value"
+                    :index="index"
+                    :item="item"
+                    :relation="item.relation"
+                    :radio="false"
+                    :disabled="item.disabled"
+                    @value-change="fieldValueChange"/>
+                </el-form-item>
+              </el-form>
+            </div>
+          </flexbox>
+        </create-sections>
+        <!-- 图片附件 -->
+        <div class="img-accessory">
+          <div class="img-box">
+            <el-upload
+              ref="imageUpload"
+              :action="crmFileSaveUrl"
+              :headers="httpHeader"
+              :data="{type: 'img', batchId: batchId}"
+              :on-preview="handleFilePreview"
+              :before-remove="beforeRemove"
+              :on-success="imgFileUploadSuccess"
+              :file-list="imgFileList"
+              name="file"
+              multiple
+              accept="image/*"
+              list-type="picture-card">
+              <p class="add-img">
+                <span class="el-icon-picture"/>
+                <span>添加图片</span>
+              </p>
+              <i class="el-icon-plus"/>
+            </el-upload>
+          </div>
+          <p class="add-accessory">
+            <el-upload
+              ref="fileUpload"
+              :action="crmFileSaveUrl"
+              :headers="httpHeader"
+              :data="{type: 'file', batchId: batchId}"
+              :on-preview="handleFilePreview"
+              :before-remove="handleFileRemove"
+              :on-success="fileUploadSuccess"
+              :file-list="fileList"
+              name="file"
+              multiple
+              accept="*.*">
+              <p>
+                <img
+                  src="@/assets/img/relevance_file.png"
+                  alt="">
+                添加附件
+              </p>
+            </el-upload>
+          </p>
+        </div>
+        <!-- 关联业务 -->
+        <related-business
+          :selected-infos="relatedBusinessInfo"
+          class="related-business"
+          @value-change="relativeValueChange"/>
+        <!-- 审核信息 -->
+        <create-sections
+          v-if="showExamine"
+          title="审核信息">
+          <div
+            v-if="examineInfo.examineType===1 || examineInfo.examineType===2"
+            slot="header"
+            class="examine-type">{{ examineInfo.examineType===1 ? '固定审批流' : '授权审批人' }}</div>
+          <create-examine-info
+            ref="examineInfo"
+            :types-id="categoryId"
+            types="oa_examine"
+            @value-change="examineValueChange"/>
+        </create-sections>
+      </div>
+
+      <div class="handle-bar">
+        <el-button
+          class="handle-button"
+          @click.native="hidenView">取消</el-button>
+        <el-button
+          class="handle-button"
+          type="primary"
+          @click.native="saveField()">保存</el-button>
+      </div>
+    </flexbox>
+  </create-view>
+</template>
+<script type="text/javascript">
+// import { filedGetField } from '@/api/customermanagement/common'
+// import { OaExamineGetField } from '@/api/oamanagement/examine'
+// import { crmFileDelete, crmFileSaveUrl } from '@/api/common'
+import axios from 'axios'
+// import { oaExamineSaveAndUpdate } from '@/api/oamanagement/examine'
+
+import CreateView from '@/components/CreateView'
+import CreateSections from '@/components/CreateSections'
+import CreateExamineInfo from '@/components/Examine/CreateExamineInfo'
+import XhExpenses from './xhExpenses' // 报销事项
+import XhLeaves from './xhLeaves' // 出差事项
+import RelatedBusiness from './relatedBusiness'
+
+import {
+  regexIsCRMNumber,
+  regexIsCRMMoneyNumber,
+  regexIsCRMMobile,
+  regexIsCRMEmail,
+  guid,
+  objDeepCopy
+} from '@/utils'
+
+import {
+  XhInput,
+  XhTextarea,
+  XhSelect,
+  XhMultipleSelect,
+  XhDate,
+  XhDateTime,
+  XhUserCell,
+  XhStructureCell,
+  XhFiles,
+  CrmRelativeCell
+} from '@/components/CreateCom'
+
+export default {
+  name: 'ExamineCreateView', // 所有新建效果的view
+  components: {
+    CreateView,
+    CreateSections,
+    CreateExamineInfo, // 审核信息
+    XhInput,
+    XhTextarea,
+    XhSelect,
+    XhMultipleSelect,
+    XhDate,
+    XhDateTime,
+    XhUserCell,
+    XhStructureCell,
+    XhFiles,
+    CrmRelativeCell,
+    XhExpenses,
+    XhLeaves,
+    RelatedBusiness
+  },
+  filters: {
+    /** 根据type 找到组件 */
+    typeToComponentName (formType) {
+      if (
+        formType === 'text' ||
+        formType === 'number' ||
+        formType === 'floatnumber' ||
+        formType === 'mobile' ||
+        formType === 'email'
+      ) {
+        return 'XhInput'
+      } else if (formType === 'textarea') {
+        return 'XhTextarea'
+      } else if (formType === 'select') {
+        return 'XhSelect'
+      } else if (formType === 'checkbox') {
+        return 'XhMultipleSelect'
+      } else if (formType === 'date') {
+        return 'XhDate'
+      } else if (formType === 'datetime') {
+        return 'XhDateTime'
+      } else if (formType === 'user') {
+        return 'XhUserCell'
+      } else if (formType === 'structure') {
+        return 'XhStructureCell'
+      } else if (formType === 'file') {
+        return 'XhFiles'
+      } else if (
+        formType === 'contacts' ||
+        formType === 'customer' ||
+        formType === 'contract' ||
+        formType === 'business'
+      ) {
+        return 'CrmRelativeCell'
+      } else if (formType === 'examine_cause') {
+        return 'XhExpenses'
+      } else if (formType === 'business_cause') {
+        return 'XhLeaves'
+      }
+    }
+  },
+  props: {
+    // 类型ID
+    categoryId: {
+      type: [String, Number],
+      default: ''
+    },
+    type: [String, Number],
+    // 类型名称
+    categoryTitle: {
+      type: String,
+      default: ''
+    },
+    /**
+     * save:添加、update:编辑(action_id)、read:详情、index:列表
+     * relative: 相关 添加
+     */
+    action: {
+      type: Object,
+      default: () => {
+        return {
+          type: 'save',
+          id: ''
+        }
+      }
+    }
+  },
+  data () {
+    return {
+      // 标题展示名称
+      title: '',
+      loading: false,
+      // 自定义字段验证规则
+      crmRules: {},
+      // 自定义字段信息表单
+      crmForm: {
+        crmFields: []
+      },
+      batchId: guid(),
+      // 图片附件
+      imgFileList: [],
+      fileList: [],
+      // 审批信息
+      examineInfo: {},
+      relatedBusinessInfo: {} // 关联业务信息
+    }
+  },
+  computed: {
+    /** 审批 下展示审批人信息 */
+    showExamine () {
+      return true
+    },
+    // crmFileSaveUrl () {
+    //   return crmFileSaveUrl
+    // },
+    httpHeader () {
+      return {
+        'Admin-Token': axios.defaults.headers['Admin-Token']
+      }
+    }
+  },
+  watch: {},
+  mounted () {
+    // 获取title展示名称
+    document.body.appendChild(this.$el)
+    this.title = this.getTitle()
+    this.getField()
+
+    if (this.action.type === 'update') {
+      this.batchId = this.action.data.batchId
+    }
+  },
+  destroyed () {
+    // remove DOM node after destroy
+    if (this.$el && this.$el.parentNode) {
+      this.$el.parentNode.removeChild(this.$el)
+    }
+  },
+  methods: {
+    // 关联业务的值更新
+    relativeValueChange (data) {
+      this.relatedBusinessInfo = data.value
+    },
+    // 审批信息值更新
+    examineValueChange (data) {
+      this.examineInfo = data
+    },
+    // 字段的值更新
+    fieldValueChange (data) {
+      let item = this.crmForm.crmFields[data.index]
+      item.value = data.value
+
+      // 出差事项
+      if (item.data.formType === 'business_cause' && item.value.update) {
+        for (let index = 0; index < this.crmForm.crmFields.length; index++) {
+          const element = this.crmForm.crmFields[index]
+          if (element.key === 'duration') {
+            element.value = item.value.duration
+            break
+          }
+        }
+        // 报销
+      } else if (item.data.formType === 'examine_cause' && item.value.update) {
+        for (let index = 0; index < this.crmForm.crmFields.length; index++) {
+          const element = this.crmForm.crmFields[index]
+          if (element.key === 'money') {
+            element.value = item.value.money
+            break
+          }
+        }
+      }
+
+      // 无事件的处理 后期可换成input实现
+      if (
+        item.data.formType === 'user' ||
+        item.data.formType === 'structure' ||
+        item.data.formType === 'file'
+      ) {
+        this.$refs.crmForm.validateField('crmFields.' + data.index + '.value')
+      }
+    },
+    // 获取自定义字段
+    getField () {
+      this.loading = true
+      // 获取自定义字段的更新时间
+      let params = {}
+      params.label = 10
+      params.id = this.categoryId
+
+      // 进行编辑操作
+      if (this.action.type === 'update') {
+        params.examineId = this.action.id
+        params.isDetail = 2 // 1详情 2 编辑
+      }
+
+      // const request = {
+      //   update: OaExamineGetField,
+      //   save: filedGetField
+      // }[this.action.type]
+      // request(params)
+      //   .then(res => {
+      //     this.getcrmRulesAndModel(res.data)
+      //     if (this.action.type === 'update') {
+      //       this.getUpdateOtherInfo()
+      //     }
+      //     this.loading = false
+      //   })
+      //   .catch(() => {
+      //     this.loading = false
+      //   })
+    },
+    // 更新图片附件关联业务信息
+    getUpdateOtherInfo () {
+      this.imgFileList = this.action.data.img.map(function (item, index, array) {
+        item.url = item.filePath
+        return item
+      })
+      this.fileList = this.action.data.file.map(function (item, index, array) {
+        item.url = item.filePath
+        return item
+      })
+      this.relatedBusinessInfo = {
+        contacts: this.action.data.contactsList,
+        customer: this.action.data.customerList,
+        business: this.action.data.businessList,
+        contract: this.action.data.contractList
+      } // 关联业务信息
+    },
+    // 根据自定义字段获取自定义字段规则
+    getcrmRulesAndModel (list) {
+      let showStyleIndex = -1
+      for (let index = 0; index < list.length; index++) {
+        const item = list[index]
+        showStyleIndex += 1
+        /**
+         *
+         * 规则数据
+         */
+        let tempList = []
+        // 验证必填
+        if (item.isNull === 1) {
+          if (item.formType === 'business_cause') {
+            let validateFunction = (rule, value, callback) => {
+              if (!value.list) {
+                this.$message.error('请完善明细')
+                callback(new Error('请完善明细'))
+              } else {
+                let hasError = false
+                for (let index = 0; index < value.list.length; index++) {
+                  const item = value.list[index]
+                  const keys = [
+                    'startAddress',
+                    'endAddress',
+                    'startTime',
+                    'endTime',
+                    'duration'
+                  ]
+                  for (let keyIndex = 0; keyIndex < keys.length; keyIndex++) {
+                    const key = keys[keyIndex]
+                    if (!item[key]) {
+                      hasError = true
+                      this.$message.error('请完善明细')
+                      callback(new Error('请完善明细'))
+                      break
+                    }
+                  }
+                }
+                if (!hasError) {
+                  callback()
+                }
+              }
+            }
+
+            tempList.push({
+              validator: validateFunction,
+              trigger: []
+            })
+          } else if (item.formType === 'examine_cause') {
+            let validateFunction = (rule, value, callback) => {
+              if (!value.list) {
+                this.$message.error('请完善明细')
+                callback(new Error('请完善明细'))
+              } else {
+                let hasError = false
+                for (let index = 0; index < value.list.length; index++) {
+                  const item = value.list[index]
+                  const keys = [
+                    'startAddress',
+                    'endAddress',
+                    'startTime',
+                    'endTime',
+                    'traffic',
+                    'stay',
+                    'diet',
+                    'other'
+                  ]
+                  for (let keyIndex = 0; keyIndex < keys.length; keyIndex++) {
+                    const key = keys[keyIndex]
+                    if (!item[key]) {
+                      hasError = true
+                      this.$message.error('请完善明细')
+                      callback(new Error('请完善明细'))
+                      break
+                    }
+                  }
+                }
+                if (!hasError) {
+                  callback()
+                }
+              }
+            }
+
+            tempList.push({
+              validator: validateFunction,
+              trigger: []
+            })
+          } else {
+            tempList.push({
+              required: true,
+              message: item.name + '不能为空',
+              trigger: ['blur', 'change']
+            })
+          }
+        }
+
+        // 特殊字符
+        if (item.formType === 'number') {
+          let validateCRMNumber = (rule, value, callback) => {
+            if (!value || value === '' || regexIsCRMNumber(value)) {
+              callback()
+            } else {
+              callback(new Error('数字的整数部分须少于12位,小数部分须少于4位'))
+            }
+          }
+          tempList.push({
+            validator: validateCRMNumber,
+            item: item,
+            trigger: ['blur']
+          })
+        } else if (item.formType === 'floatnumber') {
+          let validateCRMMoneyNumber = (rule, value, callback) => {
+            if (!value || value === '' || regexIsCRMMoneyNumber(value)) {
+              callback()
+            } else {
+              callback(new Error('货币的整数部分须少于10位,小数部分须少于2位'))
+            }
+          }
+          tempList.push({
+            validator: validateCRMMoneyNumber,
+            item: item,
+            trigger: ['blur']
+          })
+        } else if (item.formType === 'mobile') {
+          let validateCRMMobile = (rule, value, callback) => {
+            if (!value || value === '' || regexIsCRMMobile(value)) {
+              callback()
+            } else {
+              callback(new Error('手机格式有误'))
+            }
+          }
+          tempList.push({
+            validator: validateCRMMobile,
+            item: item,
+            trigger: ['blur']
+          })
+        } else if (item.formType === 'email') {
+          let validateCRMEmail = (rule, value, callback) => {
+            if (!value || value === '' || regexIsCRMEmail(value)) {
+              callback()
+            } else {
+              callback(new Error('邮箱格式有误'))
+            }
+          }
+          tempList.push({
+            validator: validateCRMEmail,
+            item: item,
+            trigger: ['blur']
+          })
+        }
+
+        this.crmRules[item.fieldName || item.name] = tempList
+
+        /**
+         *
+         *
+         *
+         *
+         *
+         *
+         *
+         *
+         * 表单数据
+         */
+        if (item.formType === 'datetime') {
+          // 返回的时间戳  要处理为格式化时间(编辑的时候)
+          // 关联产品信息比较多 用字典接收
+          let params = {}
+
+          if (this.action.type === 'update') {
+            params['value'] = item.value || ''
+          } else {
+            params['value'] = item.defaultValue // 加入默认值 可能编辑的时候需要调整
+          }
+
+          params['key'] = item.fieldName || item.name
+          params['data'] = item
+          params['disabled'] = false // 是否可交互
+          params['styleIndex'] = showStyleIndex
+          this.crmForm.crmFields.push(params)
+        } else if (
+          item.formType === 'examine_cause' ||
+          item.formType === 'business_cause'
+        ) {
+          // 报销事项
+          let params = {}
+
+          if (this.action.type === 'update') {
+            const list = item.value.map(function (element, index, array) {
+              if (element.img) {
+                element.imgList = element.img.map(function (file, index, array) {
+                  file.url = file.filePath
+                  return file
+                })
+              } else {
+                element.imgList = []
+              }
+              return element
+            })
+            params['value'] = { list: list } // 编辑的值 在value字段
+          } else {
+            params['value'] = {} // 加入默认值 可能编辑的时候需要调整
+          }
+          params['key'] = item.fieldName || item.name
+          params['data'] = item
+          params['disabled'] = false // 是否可交互
+          params['showblock'] = true // 展示整行效果
+          if (index % 2 === 0) {
+            showStyleIndex = -1
+          }
+          this.crmForm.crmFields.push(params)
+        } else if (
+          // 出差审批 差旅报销
+          (item.fieldName === 'duration' && this.type === 3) ||
+          (item.fieldName === 'money' && this.type === 5)
+        ) {
+          // 报销事项
+          let params = {}
+
+          if (this.action.type === 'update') {
+            params['value'] = item.value // 编辑的值 在value字段
+          } else {
+            params['value'] = item.defaultValue || '' // 加入默认值 可能编辑的时候需要调整
+          }
+          params['key'] = item.fieldName || item.name
+          params['data'] = item
+          params['disabled'] = true // 是否可交互
+          params['styleIndex'] = showStyleIndex
+          this.crmForm.crmFields.push(params)
+        } else {
+          let params = {}
+          if (this.action.type === 'update') {
+            params['value'] = item.value // 编辑的值 在value字段
+          } else {
+            if (
+              item.formType === 'user' ||
+              item.formType === 'structure' ||
+              item.formType === 'file' ||
+              item.formType === 'category' ||
+              item.formType === 'customer' ||
+              item.formType === 'business' ||
+              item.formType === 'contract'
+            ) {
+              params['value'] = item.defaultValue
+                ? objDeepCopy(item.defaultValue)
+                : []
+            } else {
+              params['value'] = item.defaultValue || ''
+            }
+          }
+          params['key'] = item.fieldName || item.name
+          params['data'] = item
+          params['disabled'] = false // 是否可交互
+          params['styleIndex'] = showStyleIndex
+          this.crmForm.crmFields.push(params)
+        }
+      }
+    },
+    // 保存数据
+    saveField () {
+      this.$refs.crmForm.validate(valid => {
+        if (valid) {
+          if (this.showExamine) {
+            /** 验证审批数据 */
+            this.$refs.examineInfo.validateField(() => {
+              const params = {
+                oaExamine: { categoryId: this.categoryId },
+                oaExamineRelation: {},
+                field: [],
+                oaExamineTravelList: []
+              }
+              this.getSubmiteParams(this.crmForm.crmFields, params)
+              if (this.examineInfo.examineType === 2) {
+                params['checkUserId'] = this.examineInfo.value[0].userId
+              }
+              this.submiteParams(params)
+            })
+          } else {
+            const params = {
+              oaExamine: { categoryId: this.categoryId },
+              oaExamineRelation: {},
+              field: [],
+              oaExamineTravelList: []
+            }
+            this.getSubmiteParams(this.crmForm.crmFields, params)
+            this.submiteParams(params)
+          }
+        } else {
+          return false
+        }
+      })
+    },
+    /** 上传 */
+    submiteParams (params) {
+      /** 注入关联参数 */
+      for (const key in this.relatedBusinessInfo) {
+        const list = this.relatedBusinessInfo[key]
+        params.oaExamineRelation[key + 'Ids'] = list
+          .map(function (item, index, array) {
+            return item[key + 'Id']
+          })
+          .join(',')
+      }
+
+      params.oaExamine['batchId'] = this.batchId
+
+      this.loading = true
+      if (this.action.type === 'update') {
+        params.oaExamine.examineId = this.action.id
+      }
+      // oaExamineSaveAndUpdate(params)
+      //   .then(res => {
+      //     this.loading = false
+      //     this.hidenView()
+      //     this.$message.success('操作成功')
+      //     // 回到保存成功
+      //     this.$emit('save-success')
+      //   })
+      //   .catch(() => {
+      //     this.loading = false
+      //   })
+    },
+    /** 拼接上传传输 */
+    getSubmiteParams (array, params) {
+      for (let index = 0; index < array.length; index++) {
+        const element = array[index]
+        if (element.key === 'cause') {
+          if (element.data.formType === 'business_cause') {
+            params.oaExamineTravelList = element.value.list
+            // params['duration'] = element.value.duration
+          } else if (element.data.formType === 'examine_cause') {
+            let causeList = []
+            for (let index = 0; index < element.value.list.length; index++) {
+              const cause = element.value.list[index]
+              let causeCopy = Object.assign({}, cause)
+              delete causeCopy['imgList']
+              params.oaExamineTravelList.push(causeCopy)
+            }
+            params[element.key] = causeList
+          }
+        } else {
+          if (element.data.fieldType === 1) {
+            params.oaExamine[element.key] = this.getRealParams(element)
+          } else {
+            element.data.value = this.getRealParams(element)
+            params.field.push(element.data)
+          }
+        }
+      }
+      return params
+    },
+    // 图片和附件
+    // 上传图片
+    imgFileUploadSuccess (response, file, fileList) {
+      this.imgFileList = fileList
+    },
+    // 查看图片
+    handleFilePreview (file) {
+      if (file.response || file.fileId) {
+        let perviewFile
+        if (file.response) {
+          perviewFile = file.response
+        } else {
+          perviewFile = {
+            url: file.filePath,
+            name: file.name
+          }
+        }
+        this.$bus.emit('preview-image-bus', {
+          index: 0,
+          data: [perviewFile]
+        })
+      }
+    },
+    beforeRemove (file, fileList) {
+      if (file.response || file.fileId) {
+        // let fileId
+        // if (file.response) {
+        //   fileId = file.response.fileId
+        // } else {
+        //   fileId = file.fileId
+        // }
+        this.$confirm('您确定要删除该文件吗?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+          .then(() => {
+            // crmFileDelete({
+            //   id: fileId
+            // })
+            //   .then(res => {
+            //     this.$message.success('操作成功')
+            //     let removeIndex = this.getFileIndex(
+            //       this.$refs.imageUpload.uploadFiles,
+            //       fileId
+            //     )
+            //     if (removeIndex !== -1) {
+            //       this.$refs.imageUpload.uploadFiles.splice(removeIndex, 1)
+            //     }
+            //     removeIndex = this.getFileIndex(this.imgFileList, fileId)
+            //     if (removeIndex !== -1) {
+            //       this.imgFileList.splice(removeIndex, 1)
+            //     }
+            //   })
+            //   .catch(() => {})
+          })
+          .catch(() => {
+            this.$message({
+              type: 'info',
+              message: '已取消操作'
+            })
+          })
+        return false
+      } else {
+        return true
+      }
+    },
+    // 附件索引
+    getFileIndex (files, fileId) {
+      let removeIndex = -1
+      for (let index = 0; index < files.length; index++) {
+        const item = files[index]
+        let itemFileId
+        if (item.response) {
+          itemFileId = item.response.fileId
+        } else {
+          itemFileId = item.fileId
+        }
+        if (itemFileId === fileId) {
+          removeIndex = index
+          break
+        }
+      }
+      return removeIndex
+    },
+    fileUploadSuccess (response, file, fileList) {
+      this.fileList = fileList
+    },
+    handleFileRemove (file, fileList) {
+      if (file.response || file.fileId) {
+        // let fileId
+        // if (file.response) {
+        //   fileId = file.response.fileId
+        // } else {
+        //   fileId = file.fileId
+        // }
+        this.$confirm('您确定要删除该文件吗?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+          .then(() => {
+            // crmFileDelete({
+            //   id: fileId
+            // })
+            //   .then(res => {
+            //     this.$message.success('操作成功')
+            //     let removeIndex = this.getFileIndex(
+            //       this.$refs.fileUpload.uploadFiles,
+            //       fileId
+            //     )
+            //     if (removeIndex !== -1) {
+            //       this.$refs.fileUpload.uploadFiles.splice(removeIndex, 1)
+            //     }
+            //     removeIndex = this.getFileIndex(this.fileList, fileId)
+            //     if (removeIndex !== -1) {
+            //       this.fileList.splice(removeIndex, 1)
+            //     }
+            //   })
+            //   .catch(() => {})
+          })
+          .catch(() => {
+            this.$message({
+              type: 'info',
+              message: '已取消操作'
+            })
+          })
+        return false
+      } else {
+        return true
+      }
+    },
+    // 关联客户 联系人等数据要特殊处理
+    getRealParams (element) {
+      if (
+        element.key === 'customerId' ||
+        element.key === 'contactsId' ||
+        element.key === 'businessId' ||
+        element.key === 'leadsId' ||
+        element.key === 'contractId'
+      ) {
+        if (element.value.length) {
+          return element.value[0][element.key]
+        } else {
+          return ''
+        }
+      } else if (element.key === 'categoryId') {
+        if (element.value.length) {
+          return element.value[element.value.length - 1]
+        } else {
+          return ''
+        }
+      } else if (
+        element.data.formType === 'user' ||
+        element.data.formType === 'structure'
+      ) {
+        return element.value
+          .map(function (item, index, array) {
+            return element.data.formType === 'user' ? item.userId : item.id
+          })
+          .join(',')
+      } else if (element.data.formType === 'file') {
+        if (element.value && element.value.length > 0) {
+          return element.value[0].batchId
+        }
+        return ''
+      } else if (element.data.formType === 'checkbox') {
+        if (element.value && element.value.length > 0) {
+          return element.value.join(',')
+        }
+        return ''
+      }
+
+      return element.value
+    },
+    hidenView () {
+      this.$emit('hiden-view')
+    },
+    // 根据类型获取标题展示名称
+    getTitle () {
+      return this.action.type === 'update'
+        ? '编辑' + this.categoryTitle
+        : '新建' + this.categoryTitle
+    },
+    // 获取左边padding
+    getPaddingLeft (item, index) {
+      if (item.showblock && item.showblock === true) {
+        return '0'
+      }
+      return item.styleIndex % 2 === 0 ? '0' : '25px'
+    },
+    // 获取左边padding
+    getPaddingRight (item, index) {
+      if (item.showblock && item.showblock === true) {
+        return '0'
+      }
+      return item.styleIndex % 2 === 0 ? '25px' : '0'
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.crm-create-container {
+  position: relative;
+  height: 100%;
+}
+
+.crm-create-flex {
+  position: relative;
+  overflow-x: hidden;
+  overflow-y: auto;
+  flex: 1;
+}
+
+.crm-create-header {
+  height: 40px;
+  margin-bottom: 20px;
+  padding: 0 10px;
+  flex-shrink: 0;
+  .close {
+    display: block;
+    width: 40px;
+    height: 40px;
+    margin-right: -10px;
+    padding: 10px;
+    cursor: pointer;
+  }
+}
+
+.crm-create-body {
+  flex: 1;
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+
+/** 将其改变为flex布局 */
+.crm-create-box {
+  display: flex;
+  flex-wrap: wrap;
+  padding: 0 10px;
+}
+
+.crm-create-item {
+  flex: 0 0 45%;
+  flex-shrink: 0;
+  // overflow: hidden;
+  padding-bottom: 10px;
+}
+
+// 图片 附件
+.img-accessory {
+  padding: 0 20px;
+  font-size: 12px;
+  img {
+    width: 16px;
+    vertical-align: middle;
+  }
+  .img-box /deep/ .el-upload {
+    width: 80px;
+    height: 80px;
+    line-height: 90px;
+  }
+  .img-box /deep/ .el-upload-list {
+    .el-upload-list__item {
+      width: 80px;
+      height: 80px;
+    }
+  }
+  .img-box {
+    position: relative;
+    margin-top: 40px;
+    .add-img {
+      position: absolute;
+      left: 0;
+      top: -30px;
+      height: 20px;
+      line-height: 20px;
+      margin-bottom: 10px;
+      color: #4D88FF;
+    }
+  }
+  .add-accessory {
+    margin-top: 25px;
+    margin-bottom: 20px;
+    color: #4D88FF;
+  }
+}
+
+// 占用一整行
+.crm-create-block-item {
+  flex: 0 0 100%;
+  flex-shrink: 0;
+  padding-bottom: 10px;
+}
+
+.el-form-item /deep/ .el-form-item__label {
+  line-height: normal;
+  font-size: 13px;
+  color: #333333;
+  position: relative;
+  padding-left: 8px;
+  padding-bottom: 0;
+}
+
+.el-form /deep/ .el-form-item {
+  margin-bottom: 0px;
+}
+
+.el-form /deep/ .el-form-item.is-required .el-form-item__label:before {
+  content: '*';
+  color: #f56c6c;
+  margin-right: 4px;
+  position: absolute;
+  left: 0;
+  top: 5px;
+}
+
+.handle-bar {
+  position: relative;
+  .handle-button {
+    float: right;
+    margin-top: 5px;
+    margin-right: 20px;
+  }
+}
+
+// 审核信息 里的审核类型
+.examine-type {
+  font-size: 12px;
+  color: white;
+  background-color: #fd715a;
+  padding: 0 8px;
+  margin-left: 5px;
+  height: 16px;
+  line-height: 16px;
+  border-radius: 8px;
+  transform: scale(0.8, 0.8);
+}
+
+.related-business {
+  padding: 0 20px;
+}
+</style>
diff --git a/src/views/OAManagement/examine/components/examineDetail.vue b/src/views/OAManagement/examine/components/examineDetail.vue
new file mode 100644
index 0000000..4fae072
--- /dev/null
+++ b/src/views/OAManagement/examine/components/examineDetail.vue
@@ -0,0 +1,586 @@
+<template>
+  <slide-view
+    v-loading="loading"
+    :listener-ids="['workbench-main-container']"
+    :no-listener-class="noListenerClass"
+    :body-style="{padding: '10px 30px', height: '100%'}"
+    class="d-view"
+    @side-close="hideView">
+    <flexbox
+      orient="vertical"
+      style="height: 100%;">
+      <flexbox class="detail-header">
+        <div class="header-name">{{ categoryName }}</div>
+        <img
+          class="header-close"
+          src="@/assets/img/task_close.png"
+          @click="hideView" >
+      </flexbox>
+      <div class="detail-body">
+        <!-- 基本信息 -->
+        <flexbox
+          :gutter="0"
+          align="stretch"
+          wrap="wrap">
+          <flexbox-item
+            v-for="(item, index) in list"
+            v-if="item.formType !== 'examine_cause' && item.formType !== 'business_cause'"
+            :span="0.5"
+            :key="index"
+            class="b-cell">
+            <!-- <flexbox v-if="item.formType === 'user'"
+                     align="stretch"
+                     class="b-cell-b">
+              <div class="b-cell-name">{{item.name}}</div>
+              <div class="b-cell-value">
+                <flexbox :gutter="0"
+                         wrap="wrap"
+                         style="padding: 0px 10px 10px 0px;">
+                  <div v-for="(item, index) in item.value"
+                       :key="index">
+                    {{item.realname}}&nbsp;&nbsp;
+                  </div>
+                </flexbox>
+              </div>
+            </flexbox>
+
+            <flexbox v-else-if="item.formType === 'structure'"
+                     align="stretch"
+                     class="b-cell-b">
+              <div class="b-cell-name">{{item.name}}</div>
+              <div class="b-cell-value">
+                <flexbox :gutter="0"
+                         wrap="wrap"
+                         style="padding: 0px 10px 10px 0px;">
+                  <div v-for="(item, index) in item.value"
+                       :key="index">
+                    {{item.name}}&nbsp;&nbsp;
+                  </div>
+                </flexbox>
+              </div>
+            </flexbox> -->
+
+            <flexbox
+              v-if="item.formType === 'checkbox'"
+              align="stretch"
+              class="b-cell-b">
+              <div class="b-cell-name">{{ item.name }}</div>
+              <div class="b-cell-value">
+                <flexbox
+                  :gutter="0"
+                  wrap="wrap"
+                  style="padding: 0px 10px 10px 0px;">
+                  <div
+                    v-for="(item, index) in item.value"
+                    :key="index">
+                    {{ item }}&nbsp;&nbsp;
+                  </div>
+                </flexbox>
+              </div>
+            </flexbox>
+
+            <flexbox
+              v-else-if="item.formType === 'file'"
+              align="stretch"
+              class="b-cell-b">
+              <div class="b-cell-name">{{ item.name }}</div>
+              <div class="b-cell-value">
+                <flexbox
+                  v-for="(file, index) in item.value"
+                  :key="index"
+                  class="f-item">
+                  <img
+                    class="f-img"
+                    src="@/assets/img/relevance_file.png" >
+                  <div class="f-name">{{ file.name.length > 15 ? (file.name.substring(0, 15) + '...'): file.name+'('+file.size+')' }}</div>
+                  <el-button
+                    type="text"
+                    @click.native="handleFile('preview', item.value, index)">预览</el-button>
+                  <el-button
+                    type="text"
+                    @click.native="handleFile('download', file, index)">下载</el-button>
+                </flexbox>
+              </div>
+            </flexbox>
+
+            <flexbox
+              v-else
+              align="stretch"
+              class="b-cell-b">
+              <div class="b-cell-name">{{ item.name }}</div>
+              <div class="b-cell-value">{{ item.value }}</div>
+            </flexbox>
+          </flexbox-item>
+        </flexbox>
+        <!-- 图片 附件 -->
+        <div
+          v-if="fileList.length > 0 || imgList.length > 0"
+          class="accessory">
+          <!-- 图片 -->
+          <div class="upload-img-box">
+            <div
+              v-for="(imgItem, k) in imgList"
+              :key="k"
+              class="img-list"
+              @click="imgZoom(imgList, k)">
+              <img
+                v-lazy="imgItem.filePath"
+                :key="imgItem.filePath">
+            </div>
+          </div>
+          <!-- 附件 -->
+          <div class="accessory-box">
+            <file-cell
+              v-for="(file, fileIndex) in fileList"
+              :key="fileIndex"
+              :data="file"
+              :cell-index="fileIndex"/>
+          </div>
+        </div>
+        <!-- 行程 报销 -->
+        <create-sections
+          v-if="type && type === 3 && travelList && travelList.length > 0"
+          title="行程"
+          class="create-sections">
+          <el-table
+            :data="travelList"
+            style="font-size: 13px;"
+            align="center"
+            header-align="center">
+            <el-table-column
+              v-for="(item, index) in travelField"
+              :key="index"
+              :prop="item.prop"
+              :label="item.label"
+              show-overflow-tooltip>
+              <template
+                slot="header"
+                slot-scope="scope">
+                <div class="table-head-name">{{ scope.column.label }}</div>
+              </template>
+            </el-table-column>
+          </el-table>
+        </create-sections>
+        <create-sections
+          v-if="type && type === 5 && travelList && travelList.length > 0"
+          title="报销"
+          class="create-sections">
+          <el-table
+            :data="travelList"
+            style="font-size: 13px;"
+            align="center"
+            header-align="center">
+            <el-table-column
+              v-for="(item, index) in expensesField"
+              :key="index"
+              :prop="item.prop"
+              :label="item.label"
+              show-overflow-tooltip>
+              <template
+                slot="header"
+                slot-scope="scope">
+                <div class="table-head-name">{{ scope.column.label }}</div>
+              </template>
+            </el-table-column>
+            <el-table-column
+              label="发票"
+              width="50">
+              <template slot-scope="scope">
+                <flexbox justify="center">
+                  <el-button
+                    type="text"
+                    @click.native="handleFile('preview', scope.row.img, 0)">{{ scope.row.img.length }}张</el-button>
+                </flexbox>
+              </template>
+            </el-table-column>
+          </el-table>
+        </create-sections>
+        <!-- 关联业务 -->
+        <create-sections
+          v-if="relatedListData.contacts.length > 0 || relatedListData.customer.length > 0 || relatedListData.business.length > 0 || relatedListData.contract.length > 0"
+          title="关联业务"
+          class="create-sections">
+          <div class="related-business create-sections-content">
+            <div
+              v-for="(items, key) in relatedListData"
+              :key="key">
+              <related-business-cell
+                v-for="(item, itemIndex) in items"
+                :data="item"
+                :cell-index="itemIndex"
+                :type="key"
+                :key="itemIndex"
+                :show-foot="false"
+                @click.native="checkRelatedDetail(key, item)"/>
+            </div>
+          </div>
+        </create-sections>
+        <!-- 审核信息 -->
+        <create-sections
+          title="审核信息"
+          class="create-sections">
+          <examine-info
+            :id="id"
+            :record-id="detail.examineRecordId"
+            class="create-sections-content"
+            examine-type="oa_examine"
+            @on-handle="examineHandle"/>
+        </create-sections>
+      </div>
+    </flexbox>
+    <c-r-m-full-screen-detail
+      :visible.sync="showRelatedDetail"
+      :crm-type="relatedCRMType"
+      :id="relatedID"/>
+  </slide-view>
+</template>
+
+<script>
+// import { oaExamineRead, OaExamineGetField } from '@/api/oamanagement/examine'
+import SlideView from '@/components/SlideView'
+import CreateSections from '@/components/CreateSections'
+import ExamineInfo from '@/components/Examine/ExamineInfo'
+import RelatedBusinessCell from '@/views/OAManagement/components/relatedBusinessCell'
+import FileCell from '@/views/OAManagement/components/fileCell'
+import { downloadFile } from '@/utils'
+
+export default {
+  /** 审批详情 */
+  name: 'ExamineDetail',
+  components: {
+    SlideView,
+    CreateSections,
+    ExamineInfo,
+    RelatedBusinessCell,
+    CRMFullScreenDetail: () =>
+      import('@/views/clients/components/CRMFullScreenDetail.vue'),
+    FileCell
+  },
+  props: {
+    // 详情信息id
+    id: [String, Number],
+    noListenerClass: {
+      type: Array,
+      default: () => {
+        return ['list-box']
+      }
+    }
+  },
+  data () {
+    return {
+      loading: false,
+      categoryId: '',
+      type: '',
+      detail: {
+        examineRecordId: ''
+      },
+      list: [], // 基本信息
+      categoryName: '',
+
+      fileList: [],
+      imgList: [],
+
+      travelList: [],
+      travelField: [
+        { prop: 'vehicle', label: '交通工具' },
+        { prop: 'trip', label: '单程往返' },
+        { prop: 'startAddress', label: '出发城市' },
+        { prop: 'endAddress', label: '目的城市' },
+        { prop: 'startTime', label: '开始时间' },
+        { prop: 'endTime', label: '结束时间' },
+        { prop: 'duration', label: '时长(天)' },
+        { prop: 'description', label: '备注' }
+      ],
+      expensesField: [
+        { prop: 'startAddress', label: '出发城市' },
+        { prop: 'endAddress', label: '目的城市' },
+        { prop: 'startTime', label: '开始时间' },
+        { prop: 'endTime', label: '结束时间' },
+        { prop: 'traffic', label: '交通费(元)' },
+        { prop: 'stay', label: '住宿费(元)' },
+        { prop: 'diet', label: '餐饮费(元)' },
+        { prop: 'other', label: '其他费用(元)' },
+        { prop: 'description', label: '费用明细描述' }
+      ],
+
+      // 相关详情的查看
+      relatedID: '',
+      relatedCRMType: '',
+      showRelatedDetail: false
+    }
+  },
+  computed: {
+    relatedListData () {
+      return {
+        contacts: this.detail.contactsList || [],
+        customer: this.detail.customerList || [],
+        business: this.detail.businessList || [],
+        contract: this.detail.contractList || []
+      }
+    }
+  },
+  watch: {
+    id: function (val) {
+      this.getDetial()
+    }
+  },
+  mounted () {
+    this.getDetial()
+  },
+  methods: {
+    // 获取基础信息
+    getBaseInfo () {
+      this.loading = true
+      // OaExamineGetField({
+      //   examineId: this.id,
+      //   isDetail: 1 // 1详情 2 编辑
+      // })
+      //   .then(res => {
+      //     this.list = res.data
+      //     this.loading = false
+      //   })
+      //   .catch(() => {
+      //     this.loading = false
+      //   })
+    },
+    getDetial () {
+      this.loading = true
+      // oaExamineRead({
+      //   examineId: this.id
+      // })
+      //   .then(res => {
+      //     this.loading = false
+      //     this.categoryId = res.data.categoryId
+      //     this.type = res.data.type
+      //     this.getBaseInfo()
+      //     this.detail = res.data
+      //     this.categoryName = this.detail.category
+
+      //     this.fileList = this.detail.file
+      //     this.imgList = this.detail.img
+
+      //     this.travelList = this.detail.examineTravelList
+      //   })
+      //   .catch(() => {
+      //     this.loading = false
+      //   })
+    },
+    //* * 点击关闭按钮隐藏视图 */
+    hideView () {
+      this.$emit('hide-view')
+    },
+    // 查看关联业务详情
+    checkRelatedDetail (crmType, item) {
+      this.relatedID = item[crmType + 'Id']
+      this.relatedCRMType = crmType
+      this.showRelatedDetail = true
+    },
+    /**
+     * 附件查看
+     */
+    handleFile (type, files, index) {
+      if (type === 'preview') {
+        if (files && files.length > 0) {
+          var previewList = files.map(element => {
+            element.url = element.filePath
+            return element
+          })
+          this.$bus.emit('preview-image-bus', {
+            index: index,
+            data: previewList
+          })
+        }
+      } else if (type === 'download') {
+        downloadFile({ path: files.filePath, name: files.name })
+      }
+    },
+    // 放大图片
+    imgZoom (images, k) {
+      this.$bus.emit('preview-image-bus', {
+        index: k,
+        data: images.map(function (item, index, array) {
+          return {
+            url: item.filePath,
+            name: item.name
+          }
+        })
+      })
+    },
+    downloadFile (file) {
+      downloadFile({ path: file.filePath, name: file.name })
+    },
+    // 审批操作
+    examineHandle (data) {
+      this.$store.dispatch('GetOAMessageNum', 'examine')
+      this.$emit('on-examine-handle', data)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../../styles/content.scss';
+
+.detail-header {
+  position: relative;
+  min-height: 60px;
+  .header-name {
+    font-size: 14px;
+    color: #333333;
+    flex: 1;
+  }
+  .header-close {
+    display: block;
+    width: 40px;
+    height: 40px;
+    margin-left: 20px;
+    padding: 10px;
+    cursor: pointer;
+  }
+}
+
+.create-sections {
+  padding: 5px 0;
+  /deep/ .section-header {
+    padding: 5px 0;
+  }
+}
+
+.create-sections-content {
+  padding: 0;
+}
+
+.related-business {
+  margin: 15px 0;
+  .label {
+    font-size: 13px;
+    margin-bottom: 7px;
+  }
+  p {
+    cursor: pointer;
+    color: #4D88FF;
+    background: #f5f7fa;
+    line-height: 30px;
+    margin-bottom: 5px;
+    font-size: 13px;
+    padding-left: 7px;
+    border-radius: 2px;
+    img {
+      width: 16px;
+      @include v-align;
+    }
+  }
+}
+
+.b-cell {
+  .b-cell-b {
+    width: auto;
+    padding: 8px;
+    line-height: 22px;
+    .b-cell-name {
+      width: 100px;
+      margin-right: 10px;
+      font-size: 13px;
+      flex-shrink: 0;
+      color: #777;
+    }
+    .b-cell-value {
+      font-size: 13px;
+      color: #333;
+    }
+    .b-cell-foot {
+      flex-shrink: 0;
+      display: block;
+      width: 15px;
+      height: 15px;
+      margin-left: 8px;
+    }
+  }
+}
+
+.f-item {
+  padding: 3px 0;
+  height: 25px;
+  .f-img {
+    position: block;
+    width: 15px;
+    height: 15px;
+    padding: 0 1px;
+    margin-right: 8px;
+  }
+  .f-name {
+    color: #666;
+    font-size: 12px;
+    margin-right: 10px;
+  }
+}
+
+// 图片 附件
+.accessory {
+  margin: 0 10px;
+  .upload-img-box {
+    margin: 10px 0;
+    .img-list {
+      display: inline-block;
+      position: relative;
+      margin-right: 10px;
+      width: 80px;
+      height: 60px;
+      line-height: 60px;
+      cursor: pointer;
+      img {
+        width: 80px;
+        height: 60px;
+      }
+      .img-hover {
+        position: absolute;
+        top: 0;
+        right: 0;
+        left: 0;
+        bottom: 0;
+        background-color: rgba(0, 0, 0, 0.5);
+        text-align: center;
+        font-size: 12px;
+        color: #fff;
+        display: none;
+        span {
+          @include cursor;
+          display: inline-block;
+        }
+      }
+    }
+    .img-list:hover {
+      .img-hover {
+        display: inline-block;
+      }
+    }
+  }
+}
+
+// 表头
+.table-head-name {
+  color: #909399;
+  font-size: 13px;
+  line-height: 23px;
+  padding: 0;
+}
+
+.detail-body {
+  flex: 1;
+  overflow-y: auto;
+  width: 100%;
+}
+
+.d-view {
+ position: fixed;
+  // width: 950px;
+  // top: 0px;
+  width: 100%;
+  top: 300px;
+  bottom: 0px;
+  right: 0px;
+  // background: #FFFFFF;
+  box-shadow: 0px -4px 12px 0px rgba(61, 121, 204, 0.2);
+  border-radius: 24px 24px 0px 0px;
+}
+</style>
diff --git a/src/views/OAManagement/examine/components/examineSection.vue b/src/views/OAManagement/examine/components/examineSection.vue
new file mode 100644
index 0000000..75e984b
--- /dev/null
+++ b/src/views/OAManagement/examine/components/examineSection.vue
@@ -0,0 +1,170 @@
+<template>
+  <div>
+    <examine-cell
+      v-for="(item, index) in list"
+      :key="index"
+      :data="item"
+      @on-handle="examineCellHandle"/>
+    <slot name="load"/>
+    <examine-detail
+      v-if="showDview"
+      :id="rowID"
+      class="d-view"
+      @on-examine-handle="handleResult('examine-detail')"
+      @hide-view="showDview=false"/>
+    <c-r-m-all-detail
+      :visible.sync="showRelatedDetail"
+      :crm-type="relatedCRMType"
+      :listener-ids="['workbench-main-container']"
+      :no-listener-ids="['examine-list-box']"
+      :id="relatedID"/>
+    <examine-handle
+      :show="showExamineHandle"
+      :id="rowID"
+      :record-id="rowData.examineRecordId"
+      :detail="rowData"
+      examine-type="oa_examine"
+      status="4"
+      @close="showExamineHandle = false"
+      @save="handleResult('examine-handle')"/>
+    <examine-create-view
+      v-if="isCreate"
+      :category-id="createInfo.categoryId"
+      :type="createInfo.type"
+      :category-title="createInfo.title"
+      :action="createAction"
+      @save-success="handleResult('edit')"
+      @hiden-view="isCreate = false"/>
+  </div>
+</template>
+
+<script>
+// import { oaExamineDelete } from '@/api/oamanagement/examine'
+import ExamineCell from './examineCell'
+import ExamineDetail from './examineDetail'
+import CRMAllDetail from '@/views/clients/components/CRMAllDetail'
+import ExamineHandle from '@/components/Examine/ExamineHandle' // 审批操作理由
+import ExamineCreateView from './examineCreateView'
+
+export default {
+  components: {
+    ExamineCell,
+    ExamineDetail,
+    CRMAllDetail,
+    ExamineHandle,
+    ExamineCreateView
+  },
+
+  props: {
+    list: Array
+  },
+
+  data () {
+    return {
+      // 控制详情展示
+      rowID: '',
+      rowData: {}, // 行全部信息
+      showDview: false,
+
+      // 相关详情的查看
+      relatedID: '',
+      relatedCRMType: '',
+      showRelatedDetail: false,
+
+      // 撤回操作
+      showExamineHandle: false,
+
+      // 编辑操作
+      isCreate: false, // 是编辑
+      createAction: { type: 'update' },
+      createInfo: {} // 编辑所需要的id 标题名信息
+    }
+  },
+
+  watch: {
+    list () {
+      this.showRelatedDetail = false
+      this.showDview = false
+    }
+  },
+
+  mounted () {},
+
+  methods: {
+    /**
+     * 操作
+     */
+    examineCellHandle (data) {
+      // 编辑
+      if (data.type === 'edit') {
+        const item = data.data.item
+        item.title = item.categoryName
+        this.createInfo = item
+        this.createAction = { type: 'update', id: item.examineId, data: item }
+        this.isCreate = true
+        // 删除
+      } else if (data.type === 'delete') {
+        this.$confirm('确定删除?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+          .then(() => {
+            // oaExamineDelete({
+            //   examineId: data.data.item.examineId
+            // }).then(res => {
+            //   this.searchBtn()
+            //   this.$message({
+            //     type: 'success',
+            //     message: '删除成功!'
+            //   })
+            // })
+          })
+          .catch(() => {
+            this.$message({
+              type: 'info',
+              message: '已取消删除'
+            })
+          })
+        // 撤回
+      } else if (data.type === 'withdraw') {
+        this.rowID = data.data.item.examineId
+        this.rowData = data.data.item
+        this.showExamineHandle = true
+        // 详情
+      } else if (data.type === 'view') {
+        this.showRelatedDetail = false
+        this.rowID = data.data.item.examineId
+        this.showDview = true
+      } else if (data.type === 'related-detail') {
+        this.showDview = false
+        this.relatedID = data.data.item[data.data.type + 'Id']
+        this.relatedCRMType = data.data.type
+        this.showRelatedDetail = true
+      }
+    },
+
+    /**
+     * 审批操作
+     */
+    handleResult (type) {
+      this.$emit('handle', type)
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.d-view {
+ position: fixed;
+  // width: 950px;
+  // top: 0px;
+  width: 100%;
+  top: 300px;
+  bottom: 0px;
+  right: 0px;
+  // background: #FFFFFF;
+  box-shadow: 0px -4px 12px 0px rgba(61, 121, 204, 0.2);
+  border-radius: 24px 24px 0px 0px;
+}
+</style>
diff --git a/src/views/OAManagement/examine/components/relatedBusiness.vue b/src/views/OAManagement/examine/components/relatedBusiness.vue
new file mode 100644
index 0000000..ac6ba9f
--- /dev/null
+++ b/src/views/OAManagement/examine/components/relatedBusiness.vue
@@ -0,0 +1,141 @@
+<template>
+  <div>
+    <el-popover
+      v-model="showPopover"
+      placement="bottom"
+      width="800"
+      popper-class="no-padding-popover"
+      trigger="click">
+      <crm-relative
+        v-if="showRelative"
+        ref="crmrelative"
+        :radio="false"
+        :selected-data="selectedData"
+        :show-types="showTypes"
+        @close="crmrelativeClose"
+        @changeCheckout="checkInfos"/>
+      <p
+        slot="reference"
+        class="add-file"
+        @click="showRelative = true">
+        <img
+          src="@/assets/img/relevance_business.png"
+          alt="">
+        关联业务
+      </p>
+    </el-popover>
+    <div class="related-business">
+      <div
+        v-for="(items, key) in selectedData"
+        :key="key">
+        <related-business-cell
+          v-for="(item, itemIndex) in items"
+          :data="item"
+          :cell-index="itemIndex"
+          :type="key"
+          :key="itemIndex"
+          :cursor-pointer="false"
+          @unbind="delRelevance"/>
+      </div>
+    </div>
+  </div>
+</template>
+<script type="text/javascript">
+import CrmRelative from '@/components/CreateCom/CrmRelative'
+import RelatedBusinessCell from '@/views/OAManagement/components/relatedBusinessCell'
+import { objDeepCopy } from '@/utils'
+
+export default {
+  name: 'RelatedBusiness', // 关联业务
+  components: {
+    CrmRelative,
+    RelatedBusinessCell
+  },
+  props: {
+    /** 已选信息 */
+    selectedInfos: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  data () {
+    return {
+      showTypes: ['customer', 'contacts', 'business', 'contract'],
+      // 业务弹窗
+      showRelative: false,
+      showPopover: false,
+      // 编辑时勾选
+      selectedData: {}
+    }
+  },
+  computed: {},
+  watch: {
+    selectedInfos: function (data) {
+      this.selectedData = data
+    }
+  },
+  mounted () {},
+  methods: {
+    delRelevance (field, index) {
+      this.$confirm('确认取消关联?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+        customClass: 'is-particulars'
+      })
+        .then(() => {
+          this.selectedData[field].splice(index, 1)
+          this.selectedData = objDeepCopy(this.selectedData)
+          this.submitValueChange()
+        })
+        .catch(() => {
+          this.$message.info('已取消操作')
+        })
+    },
+    getTypeName (type) {
+      if (type === 'customer') {
+        return '客户'
+      } else if (type === 'contacts') {
+        return '联系人'
+      } else if (type === 'business') {
+        return '商机'
+      } else if (type === 'contract') {
+        return '合同'
+      }
+    },
+    crmrelativeClose () {
+      this.showPopover = false
+    },
+    checkInfos (val) {
+      this.showPopover = false
+      this.selectedData = val.data
+      this.submitValueChange()
+    },
+    submitValueChange () {
+      this.$emit('value-change', {
+        index: this.index,
+        value: this.selectedData
+      })
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.add-file {
+  margin: 5px 0;
+  font-size: 13px;
+  color: #4D88FF;
+  cursor: pointer;
+  display: inline-block;
+  img {
+    vertical-align: middle;
+    width: 15px;
+  }
+}
+
+.related-business {
+  margin-top: 10px;
+}
+</style>
diff --git a/src/views/OAManagement/examine/components/xhExpenses.vue b/src/views/OAManagement/examine/components/xhExpenses.vue
new file mode 100644
index 0000000..49d2674
--- /dev/null
+++ b/src/views/OAManagement/examine/components/xhExpenses.vue
@@ -0,0 +1,408 @@
+<template>
+  <div>
+    <div
+      v-for="(item, index) in mainList"
+      :key="index"
+      class="expense-item">
+      <flexbox class="expense-item-head">
+        <div class="expense-item-head-title">报销费用明细({{ index+1 }})</div>
+        <i
+          v-if="index !== 0"
+          class="el-icon-delete expense-item-head-delete"
+          @click="deleteItems(index)"/>
+      </flexbox>
+      <flexbox
+        wrap="wrap"
+        align="stretch"
+        class="clauses">
+        <flexbox-item
+          v-for="(subItem, subIndex) in showItems"
+          :span="1/2"
+          :key="subIndex"
+          class="clauses-item">
+          <div class="clauses-item-title">
+            {{ subItem.name }}
+          </div>
+          <el-date-picker
+            v-if="subItem.formType === 'date'"
+            v-model="item[subItem.field]"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="选择日期"
+            @change="valueChange"/>
+          <el-input
+            v-else
+            v-model="item[subItem.field]"
+            @input="calculateValueChange(index, subIndex)"/>
+        </flexbox-item>
+        <flexbox-item
+          :span="1/2"
+          class="clauses-item">
+          <div class="sub-total">
+            合计(元):<span>{{ item['money'] }}</span>
+          </div>
+        </flexbox-item>
+      </flexbox>
+      <div class="description">
+        <div class="description-title">费用明细描述</div>
+        <el-input
+          v-model="item['description']"
+          :rows="3"
+          :maxlength="200"
+          type="textarea"
+          resize="none"
+          show-word-limit
+          @input="valueChange"/>
+      </div>
+      <div class="files">
+        <el-button
+          type="text"
+          class="add-files"
+          @click="addFiles(index)">上传发票图片</el-button>
+        <flexbox wrap="wrap">
+          <div
+            v-for="(imgItem, imgIndex) in item['imgList']"
+            :key="imgIndex"
+            :style="{ 'background-image': 'url('+imgItem.url+')' }"
+            class="img-item"
+            @mouseover="mouseImgOver(imgItem, imgIndex, item['imgList'])"
+            @mouseleave="mouseImgLeave(imgItem, imgIndex, item['imgList'])">
+            <div
+              v-if="imgItem.showDelete"
+              class="img-delete"
+              @click="deleteFile(imgItem, imgIndex, item['imgList'])">×</div>
+          </div>
+        </flexbox>
+      </div>
+    </div>
+    <div class="handle-bar">
+      <el-button
+        class="handle-bar-button"
+        type="text"
+        icon="el-icon-plus"
+        @click="addItems(index)">添加事项</el-button>
+        <!-- <div class="handle-bar-total">
+        合计(元):<span>{{totalMoney}}</span>
+      </div> -->
+    </div>
+    <input
+      id="imageFileInput"
+      type="file"
+      accept="image/*"
+      multiple
+      @change="uploadImageFile" >
+  </div>
+</template>
+<script type="text/javascript">
+// import { crmFileSave, crmFileDelete } from '@/api/common'
+import objMixin from '@/components/CreateCom/objMixin'
+import { guid } from '@/utils'
+
+export default {
+  name: 'XhExpenses', // 差旅报销事项
+  components: {},
+  mixins: [objMixin],
+  props: {},
+  data () {
+    return {
+      mainList: [],
+      imageIndex: -1,
+      totalMoney: '0', // 合计
+      showItems: [
+        {
+          field: 'startAddress',
+          name: '出发城市',
+          formType: 'text'
+        },
+        {
+          field: 'endAddress',
+          name: '目的城市',
+          formType: 'text'
+        },
+        {
+          field: 'startTime',
+          name: '开始时间',
+          formType: 'date'
+        },
+        {
+          field: 'endTime',
+          name: '结束时间',
+          formType: 'date'
+        },
+        {
+          field: 'traffic',
+          name: '交通费(元)',
+          formType: 'text'
+        },
+        {
+          field: 'stay',
+          name: '住宿费(元)',
+          formType: 'text'
+        },
+        {
+          field: 'diet',
+          name: '餐饮费(元)',
+          formType: 'text'
+        },
+        {
+          field: 'other',
+          name: '其他费用(元)',
+          formType: 'text'
+        }
+      ]
+    }
+  },
+  computed: {},
+  watch: {
+    value: function (val) {
+      this.dataValue = val
+      if (val.list && val.list.length > 0) {
+        this.mainList = val.list
+      } else {
+        this.mainList.push(this.getValueItem())
+      }
+    }
+  },
+  mounted () {
+    if (this.dataValue.list && this.dataValue.list.length > 0) {
+      this.mainList = this.dataValue.list
+    } else {
+      this.mainList.push(this.getValueItem())
+    }
+  },
+  methods: {
+    addFiles (index) {
+      this.imageIndex = index
+      document.getElementById('imageFileInput').click()
+    },
+    /** 图片选择出发 */
+    uploadImageFile (event) {
+      var files = event.target.files
+
+      for (let index = 0; index < files.length; index++) {
+        // const file = files[index]
+        // crmFileSave({
+        //   type: 'img',
+        //   file: file,
+        //   batchId: this.mainList[this.imageIndex].batchId
+        // })
+        //   .then(res => {
+        //     if (res) {
+        //       this.mainList[this.imageIndex].imgList.push(res)
+        //       this.submitValueChange()
+        //     }
+        //   })
+        //   .catch(() => {})
+      }
+      event.target.value = ''
+    },
+    /** 鼠标移入和移除 图片区域 */
+    mouseImgOver (item, index, items) {
+      item.showDelete = true
+      this.$set(items, index, item)
+    },
+    mouseImgLeave (item, index, items) {
+      item.showDelete = false
+      this.$set(items, index, item)
+    },
+    deleteFile (item, index, items) {
+      this.$confirm('您确定要删除该文件吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          // crmFileDelete({
+          //   id: item.fileId
+          // })
+          //   .then(res => {
+          //     items.splice(index, 1)
+          //     this.$message.success('操作成功')
+          //   })
+          //   .catch(() => {})
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消操作'
+          })
+        })
+    },
+    deleteItems (index) {
+      this.mainList.splice(index, 1)
+    },
+    addItems () {
+      this.mainList.push(this.getValueItem())
+    },
+    valueChange () {
+      this.submitValueChange(false)
+    },
+    // 值更新的回调
+    calculateValueChange (mainIndex, subIndex) {
+      if (subIndex < 2) {
+        this.submitValueChange(false)
+        return
+      }
+      var subTotal = 0
+      const calculateFields = ['traffic', 'stay', 'diet', 'other']
+      const mainItem = this.mainList[mainIndex]
+      calculateFields.forEach(field => {
+        subTotal = subTotal + parseFloat(mainItem[field] ? mainItem[field] : 0)
+      })
+      mainItem.money = subTotal
+
+      var total = 0
+      for (let index = 0; index < this.mainList.length; index++) {
+        const element = this.mainList[index]
+        total = total + parseFloat(element.money ? element.money : 0)
+      }
+      this.totalMoney = total
+
+      this.submitValueChange(true)
+    },
+    submitValueChange (update) {
+      this.$emit('value-change', {
+        index: this.index,
+        value: {
+          list: this.mainList,
+          update: update, // 是否更新总数
+          money: this.totalMoney
+        }
+      })
+    },
+    getValueItem () {
+      return {
+        startAddress: '',
+        endAddress: '',
+        startTime: '',
+        endTime: '',
+        traffic: '',
+        stay: '',
+        diet: '',
+        other: '',
+        money: '0',
+        description: '',
+        imgList: [],
+        batchId: guid()
+      }
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.expense-item {
+  border: 1px solid #e6e6e6;
+  border-radius: 2px;
+  padding-bottom: 15px;
+  margin-bottom: 10px;
+  &-head {
+    padding: 10px 20px;
+    background-color: #f5f5f5;
+    &-title {
+      height: auto;
+      font-size: 12px;
+      color: #333;
+      flex: 1;
+      line-height: normal;
+    }
+
+    &-delete {
+      padding: 0 10px;
+      color: #4D88FF;
+      font-size: 14px;
+    }
+  }
+}
+
+.clauses {
+  padding: 10px 10px;
+  &-item {
+    margin-left: 0 !important;
+    display: flex;
+    padding: 0 10px;
+    &-title {
+      width: 90px;
+      flex-shrink: 0;
+      font-size: 12px;
+      color: #333;
+    }
+  }
+}
+
+.sub-total {
+  font-size: 12px;
+  color: #333;
+}
+
+.description {
+  padding: 0 20px;
+  &-title {
+    font-size: 12px;
+    color: #333;
+  }
+}
+
+.el-input /deep/ .el-input__inner {
+  border-color: #ddd !important;
+}
+
+.el-select /deep/ .el-input__inner {
+  border-color: #ddd !important;
+}
+
+.el-textarea /deep/ .el-textarea__inner {
+  border-color: #ddd !important;
+}
+
+.handle-bar {
+  padding: 0 20px;
+  height: 29px;
+  &-button {
+    float: right;
+    border: none;
+    color: #4D88FF;
+  }
+  &-total {
+    margin-top: 10px;
+    text-align: left;
+    font-size: 13px;
+    color: #333;
+    span {
+      color: #666;
+    }
+  }
+}
+
+.files {
+  padding: 0 20px;
+}
+
+.img-item {
+  width: 98px;
+  height: 98px;
+  border: 1px solid #ccc;
+  display: inline-block;
+  margin: 0 4px 4px 0;
+  background-size: contain;
+  background-repeat: no-repeat;
+  background-position: center;
+  position: relative;
+  .img-delete {
+    position: absolute;
+    cursor: pointer;
+    top: 0;
+    right: 0;
+    width: 20px;
+    height: 20px;
+    line-height: 20px;
+    text-align: center;
+    font-size: 17px;
+    background-color: #666;
+    color: white;
+  }
+}
+
+#imageFileInput {
+  display: none;
+}
+</style>
diff --git a/src/views/OAManagement/examine/components/xhLeaves.vue b/src/views/OAManagement/examine/components/xhLeaves.vue
new file mode 100644
index 0000000..f9aa352
--- /dev/null
+++ b/src/views/OAManagement/examine/components/xhLeaves.vue
@@ -0,0 +1,278 @@
+<template>
+  <div>
+    <div
+      v-for="(item, index) in mainList"
+      :key="index"
+      class="expense-item">
+      <flexbox class="expense-item-head">
+        <div class="expense-item-head-title">行程明细({{ index+1 }})</div>
+        <i
+          v-if="index !== 0"
+          class="el-icon-delete expense-item-head-delete"
+          @click="deleteItems(index)"/>
+      </flexbox>
+      <flexbox
+        wrap="wrap"
+        align="stretch"
+        class="clauses">
+        <flexbox-item
+          v-for="(subItem, subIndex) in showItems"
+          :span="1/2"
+          :key="subIndex"
+          class="clauses-item">
+          <div class="clauses-item-title">
+            {{ subItem.name }}
+          </div>
+          <el-date-picker
+            v-if="subItem.formType === 'datetime'"
+            v-model="item[subItem.field]"
+            type="datetime"
+            value-format="yyyy-MM-dd HH:mm:ss"
+            placeholder="选择日期"
+            @change="valueChange"/>
+          <el-select
+            v-else-if="subItem.formType === 'select'"
+            v-model="item[subItem.field]"
+            placeholder="请选择"
+            @change="valueChange">
+            <el-option
+              v-for="(item, index) in subItem.data"
+              :key="index"
+              :label="item"
+              :value="item"/>
+          </el-select>
+          <el-input
+            v-else
+            v-model="item[subItem.field]"
+            @input="calculateValueChange(index, subIndex)"/>
+        </flexbox-item>
+      </flexbox>
+      <div class="description">
+        <div class="description-title">备注</div>
+        <el-input
+          v-model="item['description']"
+          :rows="3"
+          :maxlength="200"
+          type="textarea"
+          resize="none"
+          show-word-limit
+          @input="valueChange"/>
+      </div>
+    </div>
+    <div class="handle-bar">
+      <el-button
+        class="handle-bar-button"
+        type="text"
+        icon="el-icon-plus"
+        @click="addItems(index)">添加事项</el-button>
+        <!-- <div class="handle-bar-total">
+        总时长:<span>{{totalDuration}}</span>
+      </div> -->
+    </div>
+  </div>
+</template>
+<script type="text/javascript">
+import objMixin from '@/components/CreateCom/objMixin'
+
+export default {
+  name: 'XhLeaves', // 请假事项
+  components: {},
+  mixins: [objMixin],
+  props: {},
+  data () {
+    return {
+      mainList: [],
+      imageIndex: -1,
+      totalDuration: '0', // 合计
+      showItems: [
+        {
+          field: 'vehicle',
+          name: '交通工具',
+          formType: 'select',
+          data: ['飞机', '火车', '汽车', '其他']
+        },
+        {
+          field: 'trip',
+          name: '单程往返',
+          formType: 'select',
+          data: ['单程', '往返']
+        },
+        {
+          field: 'startAddress',
+          name: '出发城市',
+          formType: 'text'
+        },
+        {
+          field: 'endAddress',
+          name: '目的城市',
+          formType: 'text'
+        },
+        {
+          field: 'startTime',
+          name: '开始时间',
+          formType: 'datetime'
+        },
+        {
+          field: 'endTime',
+          name: '结束时间',
+          formType: 'datetime'
+        },
+        {
+          field: 'duration',
+          name: '时长(天)',
+          formType: 'text'
+        }
+      ]
+    }
+  },
+  computed: {},
+  watch: {
+    value: function (val) {
+      this.dataValue = val
+      if (val.list && val.list.length > 0) {
+        this.mainList = val.list
+      } else {
+        this.mainList.push(this.getValueItem())
+      }
+    }
+  },
+  mounted () {
+    if (this.dataValue.list && this.dataValue.list.length > 0) {
+      this.mainList = this.dataValue.list
+    } else {
+      this.mainList.push(this.getValueItem())
+    }
+  },
+  methods: {
+    deleteItems (index) {
+      this.mainList.splice(index, 1)
+    },
+    addItems () {
+      this.mainList.push(this.getValueItem())
+    },
+    valueChange () {
+      this.submitValueChange(false)
+    },
+    // 值更新的回调
+    calculateValueChange (mainIndex, subIndex) {
+      if (subIndex < 5) {
+        this.submitValueChange(false)
+        return
+      }
+      var total = 0
+      for (let index = 0; index < this.mainList.length; index++) {
+        const element = this.mainList[index]
+        total = total + parseFloat(element.duration ? element.duration : 0)
+      }
+      this.totalDuration = total
+
+      this.submitValueChange(true)
+    },
+    submitValueChange (update) {
+      this.$emit('value-change', {
+        index: this.index,
+        value: {
+          list: this.mainList,
+          update: update, // 是否更新总数
+          duration: this.totalDuration
+        }
+      })
+    },
+    getValueItem () {
+      return {
+        vehicle: '',
+        trip: '',
+        startAddress: '',
+        endAddress: '',
+        startTime: '',
+        endTime: '',
+        duration: ''
+      }
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.expense-item {
+  border: 1px solid #e6e6e6;
+  border-radius: 2px;
+  padding-bottom: 15px;
+  margin-bottom: 10px;
+  &-head {
+    padding: 10px 20px;
+    background-color: #f5f5f5;
+    &-title {
+      height: auto;
+      font-size: 12px;
+      color: #333;
+      flex: 1;
+      line-height: normal;
+    }
+
+    &-delete {
+      padding: 0 10px;
+      color: #4D88FF;
+      font-size: 14px;
+    }
+  }
+}
+
+.clauses {
+  padding: 10px 10px;
+  &-item {
+    margin-left: 0 !important;
+    display: flex;
+    padding: 0 10px;
+    &-title {
+      width: 90px;
+      flex-shrink: 0;
+      font-size: 12px;
+      color: #333;
+    }
+  }
+}
+
+.sub-total {
+  font-size: 12px;
+  color: #333;
+}
+
+.description {
+  padding: 0 20px;
+  &-title {
+    font-size: 12px;
+    color: #333;
+  }
+}
+
+.el-input /deep/ .el-input__inner {
+  border-color: #ddd !important;
+}
+
+.el-select /deep/ .el-input__inner {
+  border-color: #ddd !important;
+}
+
+.el-textarea /deep/ .el-textarea__inner {
+  border-color: #ddd !important;
+}
+
+.handle-bar {
+  padding: 0 20px;
+  height: 29px;
+  &-button {
+    float: right;
+    border: none;
+    color: #4D88FF;
+  }
+  &-total {
+    margin-top: 10px;
+    text-align: left;
+    font-size: 13px;
+    color: #333;
+    span {
+      color: #666;
+    }
+  }
+}
+</style>
diff --git a/src/views/OAManagement/examine/index.vue b/src/views/OAManagement/examine/index.vue
new file mode 100644
index 0000000..b22115c
--- /dev/null
+++ b/src/views/OAManagement/examine/index.vue
@@ -0,0 +1,197 @@
+<template>
+  <div class="journal oa-bgcolor">
+    <div class="btn-select">
+      <div class="select-group">
+        <label>审批类型</label>
+        <el-select
+          v-model="categoryType"
+          placeholder="请选择"
+          size="mini">
+          <el-option
+            v-for="item in categoryOptions"
+            :key="item.categoryId"
+            :label="item.title"
+            :value="item.categoryId"/>
+        </el-select>
+      </div>
+      <el-button
+        type="primary"
+        class="new-btn"
+        @click="newBtn">新建审批</el-button>
+    </div>
+    <el-tabs
+      v-model="activeName"
+      @tab-click="tabClick">
+      <el-tab-pane
+        v-for="(item, index) in tabsData"
+        :name="item.key"
+        :key="index">
+        <el-badge
+          slot="label"
+          :hidden="item.key !== 'examine' || messageOANum.examineNum === 0"
+          :max="99"
+          :value="messageOANum.examineNum">
+          <span>{{ item.label }}</span>
+        </el-badge>
+        <v-content
+          id="examine-list-box"
+          :by="item.key"
+          :category-id="categoryType"
+          :ref="'tabcontent' + item.key"
+          @reset="reset"
+          @edit="editDetail"/>
+      </el-tab-pane>
+    </el-tabs>
+    <examine-category-select
+      :show="showCategorySelect"
+      @select="selcetExamineCategory"
+      @close="showCategorySelect=false"/>
+    <examine-create-view
+      v-if="isCreate"
+      :category-id="createInfo.categoryId"
+      :type="createInfo.type"
+      :category-title="createInfo.title"
+      :action="createAction"
+      @save-success="createSaveSuccess"
+      @hiden-view="hideView"/>
+  </div>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+// import { oaExamineCategoryList } from '@/api/oamanagement/examine' // 审批类型数据
+import VContent from './components/content'
+import ExamineCategorySelect from './components/examineCategorySelect'
+import ExamineCreateView from './components/examineCreateView'
+
+export default {
+  components: {
+    VContent,
+    ExamineCategorySelect,
+    ExamineCreateView
+  },
+
+  data () {
+    return {
+      loading: false,
+      activeName: 'my',
+      tabsData: [
+        { label: '我发起的', key: 'my' },
+        { label: '我审批的', key: 'examine' }
+      ],
+      // 审批类型
+      categoryType: '',
+      categoryOptions: [],
+      // 新建
+      showCategorySelect: false,
+      isCreate: false, // 是创建
+      createAction: { type: 'save' },
+      createInfo: {} // 创建所需要的id 标题名信息
+    }
+  },
+
+  computed: {
+    ...mapGetters(['messageOANum'])
+  },
+
+  mounted () {
+    this.getExamineCategoryList()
+  },
+
+  methods: {
+    // 审批类型列表
+    getExamineCategoryList () {
+      this.loading = true
+      // oaExamineCategoryList()
+      //   .then(res => {
+      //     this.loading = false
+      //     this.categoryOptions = [{ categoryId: '', title: '全部' }].concat(
+      //       res.data
+      //     )
+      //   })
+      //   .catch(() => {
+      //     this.loading = false
+      //   })
+    },
+
+    // 重置按钮
+    reset () {
+      this.categoryType = ''
+    },
+
+    editDetail (item) {
+      item.title = item.categoryName
+      this.createInfo = item
+      this.createAction = { type: 'update', id: item.examineId, data: item }
+      this.isCreate = true
+    },
+
+    // 创建
+    newBtn () {
+      this.showCategorySelect = true
+    },
+
+    // 审批类型选择
+    selcetExamineCategory (item) {
+      this.createInfo = item
+      this.createAction = { type: 'save' }
+      this.isCreate = true
+    },
+
+    createSaveSuccess () {
+      this.$refs.tabcontentmy[0].searchBtn()
+    },
+
+    hideView () {
+      this.isCreate = false
+    },
+
+    tabClick (val) {}
+  }
+}
+</script>
+
+<style scoped lang="scss">
+@import '../styles/tabs.scss';
+
+.journal {
+  overflow: auto;
+  position: relative;
+  .btn-select {
+    position: absolute;
+    top: 10px;
+    right: 40px;
+    z-index: 999;
+    .select-group {
+      display: inline-block;
+      .el-select {
+        margin: 0 20px 0 10px;
+        width: 116px;
+      }
+    }
+  }
+  .el-tabs {
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+  }
+  .el-tabs /deep/ .el-tabs__content {
+    padding: 0 30px;
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    // overflow: auto;
+    .el-tab-pane {
+      flex: 1;
+      display: flex;
+      flex-direction: column;
+      overflow: hidden;
+    }
+  }
+}
+
+// 消息效果
+.el-badge /deep/ .el-badge__content.is-fixed {
+  top: 15px;
+}
+</style>
diff --git a/src/views/OAManagement/journal/content.vue b/src/views/OAManagement/journal/content.vue
new file mode 100644
index 0000000..5c1fb31
--- /dev/null
+++ b/src/views/OAManagement/journal/content.vue
@@ -0,0 +1,217 @@
+<template>
+  <div class="content">
+    <div class="select-box">
+      <div
+        v-if="selectAuthority"
+        class="select-group">
+        <label>发起人</label>
+        <el-select
+          v-model="fromData.createUserId"
+          size="small"
+          placeholder="请选择"
+          @change="selectChange">
+          <el-option
+            v-for="item in nameOptions"
+            :key="item.userId"
+            :label="item.realname"
+            :value="item.userId"/>
+        </el-select>
+      </div>
+      <div class="select-group">
+        <label>提交时间</label>
+        <el-date-picker
+          v-model="fromData.createTime"
+          type="date"
+          value-format="yyyy-MM-dd"
+          placeholder="选择日期"
+          @change="selectChange"/>
+      </div>
+      <div class="select-group">
+        <label>类型</label>
+        <el-select
+          v-model="fromData.categoryId"
+          size="small"
+          placeholder="请选择"
+          @change="selectChange">
+          <el-option
+            v-for="item in modelOptions"
+            :key="item.key"
+            :label="item.label"
+            :value="item.key"/>
+        </el-select>
+      </div>
+    </div>
+    <div
+      v-loading="journalLoading"
+      :id="'list-box' + activeName"
+      class="list-box">
+      <journal-cell
+        v-for="(item, index) in journalData"
+        :key="index"
+        :log-index="index"
+        :data="item"
+        class="list-cell"
+        @on-handle="jourecallCellHandle"/>
+      <slot name="load"/>
+      <div ref="blankClick"/>
+    </div>
+    <!-- 相关业务页面 -->
+    <c-r-m-all-detail
+      :visible.sync="showRelatedDetail"
+      :crm-type="relatedCRMType"
+      :listener-ids="['workbench-main-container']"
+      :no-listener-ids="['journal-list-box']"
+      :id="relatedID"
+      class="d-view"/>
+  </div>
+</template>
+
+<script>
+// API
+// import { journalDelete } from '@/api/oamanagement/journal'
+import CRMAllDetail from '@/views/clients/components/CRMAllDetail'
+import JournalCell from './journalCell'
+
+export default {
+  components: {
+    CRMAllDetail,
+    JournalCell
+  },
+  props: {
+    // 数据
+    journalData: Array,
+    depOptions: Array,
+    nameOptions: Array,
+    journalLoading: Boolean,
+    activeName: String
+  },
+  data () {
+    return {
+      // 筛选数据
+      fromData: {},
+      modelOptions: [
+        { label: '全部', key: '0' },
+        { label: '日报', key: '1' },
+        { label: '周报', key: '2' },
+        { label: '月报', key: '3' }
+      ],
+      // 相关详情的查看
+      relatedID: '',
+      relatedCRMType: '',
+      showRelatedDetail: false
+    }
+  },
+  computed: {
+    selectAuthority () {
+      return this.activeName !== 2 // 我发出的日志 的不展示
+    }
+  },
+  watch: {
+    activeName: function (val) {
+      this.fromData = {}
+    }
+  },
+  methods: {
+    selectChange (val, key) {
+      this.$emit('selectChange', this.fromData)
+    },
+    jourecallCellHandle (data) {
+      // 编辑按钮
+      if (data.type === 'edit') {
+        this.$emit('editBtn', data.data.item)
+        this.$refs.blankClick.click()
+        // 删除按钮
+      } else if (data.type === 'delete') {
+        this.$confirm('确定删除?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+          .then(() => {
+            // journalDelete({ logId: data.data.item.logId }).then(res => {
+            //   this.$message({
+            //     type: 'success',
+            //     message: '删除成功!'
+            //   })
+            //   for (const i in this.journalData) {
+            //     if (this.journalData[i].logId === data.data.item.logId) {
+            //       this.journalData.splice(i, 1)
+            //       break
+            //     }
+            //   }
+            // })
+          })
+          .catch(() => {
+            this.$message({
+              type: 'info',
+              message: '已取消删除'
+            })
+          })
+        // 相关详情
+      } else if (data.type === 'related-detail') {
+        this.relatedID = data.data.item.key
+        this.relatedCRMType = data.data.type
+        this.showRelatedDetail = true
+      }
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+@import '../styles/content.scss';
+.content {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  min-height: 0;
+  .select-box {
+    margin: 10px 0 20px;
+    max-width: 710px;
+    .select-group {
+      margin-right: 20px;
+      display: inline-block;
+      margin-bottom: 10px;
+      label {
+        @include color9;
+        margin-right: 5px;
+      }
+      .el-select,
+      .el-date-editor {
+        width: 140px;
+        height: 30px;
+      }
+    }
+    .group-btn {
+      float: right;
+      margin-right: 10px;
+    }
+  }
+  .list-box {
+    flex: 1;
+    overflow-y: auto;
+    padding-right: 30px;
+    margin-right: -30px;
+    position: relative;
+  }
+}
+
+.list-cell {
+  border: 1px solid #e6e6e6;
+  margin-bottom: 20px;
+  border-radius: 4px;
+}
+
+.d-view {
+ position: fixed;
+  // width: 950px;
+  // top: 0px;
+  width: 100%;
+  top: 300px;
+  bottom: 0px;
+  right: 0px;
+  // background: #FFFFFF;
+  box-shadow: 0px -4px 12px 0px rgba(61, 121, 204, 0.2);
+  border-radius: 24px 24px 0px 0px;
+}
+</style>
diff --git a/src/views/OAManagement/journal/index.vue b/src/views/OAManagement/journal/index.vue
new file mode 100644
index 0000000..1995a95
--- /dev/null
+++ b/src/views/OAManagement/journal/index.vue
@@ -0,0 +1,383 @@
+<template>
+  <div class="journal oa-bgcolor">
+    <el-button
+      type="primary"
+      class="new-btn"
+      @click="newBtn">写日志</el-button>
+    <el-tabs
+      v-model="activeName"
+      @tab-click="tabClick">
+      <el-tab-pane
+        v-for="(item, index) in tabsData"
+        :name="item.key"
+        :key="index">
+        <el-badge
+          slot="label"
+          :hidden="item.key !== '3' || messageOANum.logNum === 0"
+          :max="99"
+          :value="messageOANum.logNum">
+          <span>{{ item.label }}</span>
+        </el-badge>
+        <v-content
+          id="journal-list-box"
+          :ref="'log-list' + item.key"
+          :active-name="activeName"
+          :journal-data="journalData"
+          :dep-options="depOptions"
+          :name-options="nameOptions"
+          :journal-loading="journalLoading"
+          @selectChange="refreshLogList"
+          @editBtn="editBtn">
+          <p
+            slot="load"
+            class="load">
+            <el-button
+              :loading="loadMoreLoading"
+              type="text">{{ loadText }}</el-button>
+          </p>
+        </v-content>
+      </el-tab-pane>
+    </el-tabs>
+    <new-dialog
+      v-if="showNewDialog"
+      :form-data="formData"
+      :dialog-title="dialogTitle"
+      :img-file-list="imgFileList"
+      :accessory-file-list="accessoryFileList"
+      :new-loading="newLoading"
+      @close="newClose"
+      @submitBtn="submitBtn"/>
+  </div>
+</template>
+
+<script>
+import VContent from './content'
+import newDialog from './newDialog'
+import { mapGetters } from 'vuex'
+import { objDeepCopy } from '@/utils'
+
+// API
+import {
+  journalList,
+  journalAdd,
+  journalEdit
+} from '@/api/oamanagement/journal'
+import { depList, usersList } from '@/api/common'
+
+export default {
+  components: {
+    VContent,
+    newDialog
+  },
+  data () {
+    return {
+      activeName: '1',
+      tabsData: [
+        { label: '全部', key: '1' },
+        { label: '我发出的日志', key: '2' },
+        { label: '我收到的', key: '3' },
+        { label: '未读', key: '4' }
+      ],
+      // 日志数据
+      journalData: [],
+      // 显示新建页面
+      showNewDialog: false,
+      // 新建数据
+      formData: {},
+      // 弹出框标题
+      dialogTitle: '',
+      // 页数
+      pageNum: 1,
+      loadText: '加载更多',
+      loadMoreLoading: true,
+      // 判断是否还有数据
+      isPost: true,
+      // 图片数组
+      imgFileList: [],
+      // 附件数组
+      accessoryFileList: [],
+      nameOptions: [],
+      depOptions: [],
+      // 列表加loading
+      journalLoading: false,
+      newLoading: false,
+      // 列表容器
+      listBoxDom: null
+    }
+  },
+  computed: {
+    ...mapGetters(['messageOANum']),
+    byData () {
+      return { '1': '', '2': '1', '3': '2', '4': '3' }[this.activeName] // 1:我发出的 2:我收到的 3:未读的
+    }
+  },
+  watch: {
+    $route (to, from) {
+      this.$router.go(0)
+    }
+  },
+  beforeRouteUpdate (to, from, next) {
+    if (to.query.routerKey === 1) {
+      this.newBtn()
+    }
+    next()
+  },
+  mounted () {
+    this.initControlPage()
+    this.getLogList()
+    if (this.$route.query.routerKey === 1) {
+      this.newBtn()
+    }
+    // 部门列表
+    depList().then(res => {
+      this.depOptions = res.data
+    })
+    // 用户列表
+    usersList({ pageType: 0 }).then(res => {
+      this.nameOptions = res.data
+    })
+  },
+  methods: {
+    initControlPage () {
+      // 分批次加载
+      for (const dom of document.getElementsByClassName('list-box')) {
+        dom.onscroll = e => {
+          if (e && e.target.id === ('list-box' + this.activeName)) {
+            this.$bus.emit('journal-list-box-scroll', e.target)
+            const scrollOff = dom.scrollTop + dom.clientHeight - dom.scrollHeight
+            // 滚动条到底部的条件
+            if (Math.abs(scrollOff) < 10 && this.loadMoreLoading === true) {
+              if (!this.isPost) {
+                this.isPost = true
+                this.pageNum++
+                this.getLogList()
+              } else {
+                this.loadMoreLoading = false
+              }
+            }
+          }
+        }
+      }
+    },
+    // 数据
+    getLogList () {
+      const params = objDeepCopy(
+        this.$refs['log-list' + this.activeName][0].fromData
+      )
+      if (!params.createTime) {
+        delete params['createTime']
+      }
+      params.page = this.pageNum
+      params.limit = 5
+      if (this.byData) {
+        params.by = this.byData
+      }
+      this.journalLoading = true
+      journalList(params)
+        .then(res => {
+          this.journalLoading = false
+          if (res.data.lastPage === true) {
+            this.loadText = '没有更多了'
+            this.loadMoreLoading = false
+          } else {
+            this.loadText = '加载更多'
+            this.loadMoreLoading = true
+          }
+          for (const item of res.data.list) {
+            item.showComment = false
+          }
+
+          this.journalData = this.journalData.concat(res.data.list)
+          this.createInitAwaitMessage()
+          this.isPost = false
+        })
+        .catch(() => {
+          this.journalLoading = false
+          this.isPost = false
+        })
+    },
+    createInitAwaitMessage () {
+      if (!this.listBoxDom) {
+        this.$nextTick(() => {
+          this.listBoxDom = document.getElementsByClassName('list-box')[ parseInt(this.activeName) - 1 ]
+          this.$bus.emit(
+            'journal-list-box-scroll', document.getElementsByClassName('list-box')[ parseInt(this.activeName) - 1 ]
+          )
+        })
+      }
+    },
+    // 写日志
+    newBtn () {
+      this.dialogTitle = '写日志'
+      this.showNewDialog = true
+      this.formData = {}
+      this.imgFileList = []
+      this.accessoryFileList = []
+    },
+    tabClick (val) {
+      this.listBoxDom = null
+      this.refreshLogList()
+    },
+    // 刷新列表
+    refreshLogList () {
+      this.pageNum = 1
+      this.journalData = []
+      this.getLogList()
+    },
+    // 关闭新建页面
+    newClose () {
+      if (this.$route.query.routerKey === 1) {
+        this.$router.push('journal')
+      } else {
+        this.showNewDialog = false
+      }
+    },
+    // 新建提交
+    submitBtn (key, batchId, img, relevanceAll) {
+      this.newLoading = true
+      let obj = {}
+      if (!relevanceAll) {
+        obj = {}
+      } else {
+        obj = relevanceAll
+      }
+      // 获取部门
+      const dep = []
+      if (this.formData.depData) {
+        for (const j of this.formData.depData) {
+          dep.push(j.id)
+        }
+      }
+      // 获取员工
+      const staff = []
+      if (this.formData.sentWhoList) {
+        for (const h of this.formData.sentWhoList) {
+          staff.push(h.userId)
+        }
+      }
+
+      if (this.dialogTitle === '写日志') {
+        // 图片
+        const pramas = {
+          categoryId: key || '',
+          content: this.formData.content,
+          tomorrow: this.formData.tomorrow,
+          question: this.formData.question,
+          batchId: batchId,
+          // img: imgList,
+          sendUserIds: staff.join(','),
+          sendDeptIds: dep.join(','),
+          customerIds: obj.customerIds.join(','),
+          contactsIds: obj.contactsIds.join(','),
+          businessIds: obj.businessIds.join(','),
+          contractIds: obj.contractIds.join(',')
+        }
+        if (key) {
+          this.formData.categoryId = key
+        }
+        journalAdd(pramas)
+          .then(res => {
+            this.refreshLogList()
+            this.newLoading = false
+            this.$message.success('新建成功')
+            this.newClose()
+          })
+          .catch(() => {
+            this.newLoading = false
+            this.$message.error('新建失败')
+          })
+        // 编辑页面
+      } else {
+        const pramas = {
+          logId: this.formData.logId,
+          categoryId: key,
+          content: this.formData.content,
+          tomorrow: this.formData.tomorrow,
+          question: this.formData.question,
+          batchId: batchId,
+          sendUserIds: staff.join(','),
+          sendDeptIds: dep.join(','),
+          customerIds: obj.customerIds.join(','),
+          contactsIds: obj.contactsIds.join(','),
+          businessIds: obj.businessIds.join(','),
+          contractIds: obj.contractIds.join(',')
+        }
+        journalEdit(pramas)
+          .then(res => {
+            this.newClose()
+            this.refreshLogList()
+            this.$message.success('编辑成功')
+            this.newLoading = false
+          })
+          .catch(() => {
+            this.newLoading = false
+            this.$message.error('编辑失败')
+          })
+      }
+    },
+    // 编辑按钮
+    editBtn (val) {
+      this.dialogTitle = '编辑日志'
+      this.formData = val
+      this.imgFileList = val.img
+      // 附件
+      this.accessoryFileList = val.file
+
+      // 员工部门赋值
+      this.formData.depData = val.sendDeptList ? val.sendDeptList : []
+      this.formData.sentWhoList = val.sendUserList ? val.sendUserList : []
+      this.showNewDialog = true
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+@import '../styles/tabs.scss';
+
+.journal {
+  overflow: auto;
+  position: relative;
+  .new-btn {
+    position: absolute;
+    top: 10px;
+    right: 40px;
+    z-index: 999;
+  }
+  .el-tabs {
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+  }
+  .el-tabs /deep/ .el-tabs__content {
+    padding: 0 30px;
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    margin-bottom: 20px;
+    min-height: 0;
+    .el-tab-pane {
+      flex: 1;
+      display: flex;
+      flex-direction: column;
+      min-height: 0;
+    }
+  }
+  .load {
+    color: #999;
+    font-size: 13px;
+    margin: 0 auto 15px;
+    text-align: center;
+    .el-button,
+    .el-button:focus {
+      color: #ccc;
+      cursor: auto;
+    }
+  }
+}
+
+// 消息效果
+.el-badge /deep/ .el-badge__content.is-fixed {
+  top: 15px;
+}
+</style>
diff --git a/src/views/OAManagement/journal/journalCell.vue b/src/views/OAManagement/journal/journalCell.vue
new file mode 100644
index 0000000..448a48a
--- /dev/null
+++ b/src/views/OAManagement/journal/journalCell.vue
@@ -0,0 +1,814 @@
+<template>
+  <div
+    :id="'journal-cell' + logIndex"
+    class="list">
+    <div class="list-content">
+      <div class="header">
+        <div
+          v-photo="data.createUser"
+          v-lazy:background-image="$options.filters.filterUserLazyImg(data.createUser.img)"
+          :key="data.createUser.img"
+          class="div-photo head-img header-circle"/>
+        <div class="row">
+          <p class="row-title">
+            <span class="name">{{ data.createUser.realname }}</span>
+            <span
+              v-if="showWorkbench"
+              class="item-content">{{ data.actionContent }}</span>
+            <span
+              v-else
+              :style="{'color': data.isRead === 0 ? '#4D88FF' : '#ccc'}"
+              class="read">{{ data.isRead === 0 ? '未读' : '已读' }}</span>
+          </p>
+          <span class="time">{{ data.createTime | moment("YYYY-MM-DD HH:mm") }}</span>
+          <el-tooltip
+            :disabled="!(data.sendUserList.length > 0 || data.sendDeptList.length > 0)"
+            placement="bottom"
+            effect="light"
+            popper-class="tooltip-change-border">
+            <div slot="content">
+              <div class="members-dep-title">
+                <!-- hover员工 -->
+                <span v-if="data.sendUserList">
+                  <!-- 如果没有部门而且员工最后一个 - 不显示逗号 -->
+                  <span
+                    v-for="(k, i) in data.sendUserList"
+                    :key="i">
+                    {{ data.sendDeptList.length === 0 && i === data.sendUserList.length-1 ? k.realname : k.realname + "," }}
+                  </span>
+                </span>
+                <!-- hover部门 -->
+                <span
+                  v-for="(dep, depIndex) in data.sendDeptList"
+                  v-show="data.sendDeptList.legnth !== 0"
+                  :key="depIndex">
+                  {{ depIndex === data.sendDeptList.length-1 ? dep.name : dep.name+"," }}
+                </span>
+              </div>
+            </div>
+            <p
+              class="row-title"
+              style="display: inline-block;">
+              <span v-if="data.sendDeptList">{{ data.sendDeptList.length }} 个部门,</span>
+              <span v-if="data.sendUserList">{{ data.sendUserList.length }}个同事</span>
+            </p>
+          </el-tooltip>
+        </div>
+        <div
+          v-if="!showWorkbench && (data.permission && (data.permission.isUpdate || data.permission.isDelete))"
+          class="rt-setting">
+          <el-dropdown
+            trigger="click"
+            @command="handleCommand">
+            <i
+              style="color:#CDCDCD; cursor: pointer;"
+              class="el-icon-arrow-down el-icon-more"/>
+            <el-dropdown-menu slot="dropdown">
+              <el-dropdown-item
+                v-if="data.permission.isUpdate"
+                command="edit">编辑</el-dropdown-item>
+              <el-dropdown-item
+                v-if="data.permission.isDelete"
+                command="delete">删除</el-dropdown-item>
+            </el-dropdown-menu>
+          </el-dropdown>
+        </div>
+      </div>
+      <div class="text">
+        <p
+          v-if="data.content"
+          class="row">
+        <span class="title">{{ data.categoryId === 1 ? "今日工作内容" : data.categoryId === 2 ? "本周工作内容" : "本月工作内容" }}:</span>{{ data.content }}</p>
+        <p
+          v-if="data.tomorrow"
+          class="row">
+        <span class="title">{{ data.categoryId === 1 ? "明日工作内容" : data.categoryId === 2 ? "下周工作内容" : "下月工作内容" }}:</span>{{ data.tomorrow }}</p>
+        <p
+          v-if="data.question"
+          class="row">
+        <span class="title">遇到的问题:</span>{{ data.question }}</p>
+      </div>
+      <div class="accessory">
+        <div
+          v-if="data.img.length !== 0"
+          class="upload-img-box">
+          <div
+            v-for="(imgItem, k) in data.img"
+            :key="k"
+            class="img-list"
+            @click="imgZoom(data.img, k)">
+            <img
+              v-lazy="imgItem.filePath"
+              :key="imgItem.filePath">
+          </div>
+        </div>
+        <div
+          v-if="data.file.length !== 0"
+          class="accessory-box">
+          <file-cell
+            v-for="(file, fileIndex) in data.file"
+            :key="fileIndex"
+            :data="file"
+            :cell-index="fileIndex"/>
+        </div>
+      </div>
+      <!-- 关联业务 -->
+      <related-business
+        v-if="allDataShow"
+        :margin-left="'0'"
+        :alterable="false"
+        :all-data="allData"
+        @checkRelatedDetail="checkRelatedDetail"/>
+      <!-- 评论 -->
+      <div
+        v-if="replyList && replyList.length !== 0"
+        class="discuss">
+        <div class="border"/>
+        <div
+          v-for="(discussItem, k) in replyList"
+          :key="k"
+          class="discuss-list">
+          <div
+            v-photo="discussItem.user"
+            v-lazy:background-image="$options.filters.filterUserLazyImg(discussItem.user.img)"
+            :key="discussItem.user.img"
+            class="div-photo head-img header-circle"/>
+          <span class="name">{{ discussItem.user.realname }}</span>
+          <span class="time">{{ discussItem.createTime }}</span>
+          <div class="rt">
+            <span @click="discussDelete(discussItem, replyList, k)">删除</span>
+            <span @click="discussBtn(discussItem, -1)">回复</span>
+          </div>
+
+          <p class="reply-title">
+            <span v-html="emoji(discussItem.content)"/>
+          </p>
+
+          <!-- <p class="discuss-content"
+             v-html="emoji(discussItem.replyContent)"></p> -->
+
+          <div
+            v-if="discussItem.childCommentList && discussItem.childCommentList.length > 0"
+            class="children-reply">
+            <div
+              v-for="(childDiscussItem, k) in discussItem.childCommentList"
+              :key="k"
+              class="discuss-list">
+              <div
+                v-photo="childDiscussItem.user"
+                v-lazy:background-image="$options.filters.filterUserLazyImg(childDiscussItem.user.img)"
+                :key="childDiscussItem.user.img"
+                class="div-photo head-img header-circle"/>
+              <span class="name">{{ childDiscussItem.user.realname }}</span>
+              <span class="time">{{ childDiscussItem.createTime }}</span>
+              <div class="rt">
+                <span @click="discussDelete(childDiscussItem, discussItem.childCommentList, k)">删除</span>
+                <span @click="discussBtn(discussItem, k)">回复</span>
+              </div>
+              <p class="reply-title">
+                <template>
+                  <span>回复</span>
+                  <span
+                    v-if="childDiscussItem.replyUser"
+                    class="reply">@{{ childDiscussItem.replyUser.realname }}:</span>
+                </template>
+                <span v-html="emoji(childDiscussItem.content)"/>
+              </p>
+            </div>
+          </div>
+
+          <!-- 评论 -- 回复  -->
+          <div
+            v-if="discussItem.show"
+            class="comment-box">
+            <el-input
+              :rows="2"
+              v-model="childCommentsTextarea"
+              type="textarea"
+              placeholder="请输入内容"
+              @blur="blurFun"/>
+            <div class="btn-group">
+              <el-popover
+                v-model="childCommentsPopover"
+                placement="top"
+                width="400"
+                trigger="click">
+                <!-- 表情 -->
+                <emoji @select="childSelectEmoji"/>
+                <img
+                  slot="reference"
+                  src="@/assets/img/smiling_face.png"
+                  class="smiling-img">
+              </el-popover>
+              <div class="btn-box">
+                <el-button
+                  :loading="contentLoading"
+                  type="primary"
+                  @click="childCommentSubmit()">回复</el-button>
+                <el-button @click="discussItem.show= false">取消</el-button>
+              </div>
+            </div>
+          </div>
+          <div class="border"/>
+        </div>
+      </div>
+    </div>
+    <div class="footer">
+      <el-button
+        type="primary"
+        icon="el-icon-chat-line-round"
+        @click="commentBtn(data)">回复</el-button>
+        <!-- <img @click="commentBtn(item)" class="comment" src="@/assets/img/journal_comment.png"> -->
+    </div>
+    <!-- 底部评论 -->
+    <div
+      v-if="data.showComment"
+      class="comment-box">
+      <el-input
+        v-model="commentsTextarea"
+        :rows="3"
+        type="textarea"
+        placeholder="请输入内容"
+        @blur="blurFun"/>
+      <div class="btn-group">
+        <el-popover
+          v-model="commentsPopover"
+          placement="top"
+          width="400"
+          trigger="click">
+          <!-- 表情 -->
+          <emoji @select="selectEmoji"/>
+          <img
+            slot="reference"
+            src="@/assets/img/smiling_face.png"
+            class="smiling-img">
+        </el-popover>
+        <div class="btn-box">
+          <el-button
+            :loading="contentLoading"
+            type="primary"
+            @click="commentSubmit()">回复</el-button>
+          <el-button @click="data.showComment = false">取消</el-button>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<script type="text/javascript">
+// import xss from 'xss'
+import emoji from '@/components/emoji'
+// API
+// import { journalSetread } from '@/api/oamanagement/journal'
+
+// import {
+//   setCommentAPI,
+//   deleteCommentAPI,
+//   queryCommentListAPI
+// } from '@/api/oamanagement/common'
+
+// 关联业务 - 选中列表
+import relatedBusiness from '@/components/relatedBusiness'
+
+import { mapGetters } from 'vuex'
+import FileCell from '@/views/OAManagement/components/fileCell'
+
+export default {
+  name: 'JournalCell', // 日志cell
+  components: {
+    emoji,
+    relatedBusiness,
+    FileCell
+  },
+  mixins: [],
+  props: {
+    data: Object,
+    logIndex: {
+      type: Number,
+      default: 0
+    },
+    // 工作台操作动态展示
+    showWorkbench: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    return {
+      // 评论
+      commentsTextarea: '',
+      // 回复数据
+      childCommentsTextarea: '',
+      // 评论 -- 表情
+      commentsPopover: false,
+      replyChildComment: null, // 被评论对象
+      replyChildIndex: -1, // -1 是主评论 0以上为子评论
+      childCommentsPopover: false,
+      blurIndex: 0,
+      contentLoading: false,
+      // 父元素
+      parentTarget: null,
+      awaitMoment: false, // 等客户浏览
+      // 评论列表
+      replyList: []
+    }
+  },
+  computed: {
+    ...mapGetters(['userInfo']),
+    allData () {
+      const allData = {}
+      allData.business = this.data.businessList
+      allData.contacts = this.data.contactsList
+      allData.contract = this.data.contractList
+      allData.customer = this.data.customerList
+      return allData
+    },
+    allDataShow () {
+      if (
+        this.data.businessList.length !== 0 ||
+        this.data.contactsList.length !== 0 ||
+        this.data.contractList.length !== 0 ||
+        this.data.customerList.length !== 0
+      ) {
+        return true
+      } else {
+        return false
+      }
+    }
+  },
+  watch: {},
+  mounted () {
+    if (this.data.isRead === 0 && !this.showWorkbench) {
+      this.$bus.on('journal-list-box-scroll', target => {
+        this.observePreview(target)
+      })
+      this.observePreview(
+        document.getElementById('journal-cell' + this.logIndex).parentNode
+      )
+    }
+
+    this.replyList = this.data.replyList
+  },
+  beforeDestroy () {
+    this.$bus.off('journal-list-box-scroll')
+  },
+  methods: {
+    /**
+     * 观察预览
+     */
+    observePreview (target) {
+      if (this.data.isRead === 0) {
+        if (target) {
+          this.parentTarget = target
+        }
+        const ispreview = this.whetherPreview()
+        if (!this.awaitMoment && ispreview) {
+          this.awaitMoment = true
+          setTimeout(() => {
+            this.awaitMoment = false
+            const ispreview = this.whetherPreview()
+            if (ispreview) {
+              this.submiteIsRead()
+            }
+          }, 3000)
+        }
+      }
+    },
+
+    /**
+     * 是否预览
+     */
+    whetherPreview () {
+      const dom = this.parentTarget.children[this.logIndex]
+      if (this.parentTarget.getBoundingClientRect()) {
+        const offsetTop =
+          this.parentTarget.getBoundingClientRect().top -
+          dom.getBoundingClientRect().top
+        let ispreview = false
+        if (
+          offsetTop <= 0 &&
+          Math.abs(offsetTop) < this.parentTarget.clientHeight
+        ) {
+          ispreview = true
+        } else if (offsetTop > 0 && offsetTop < dom.clientHeight) {
+          ispreview = true
+        }
+        return ispreview
+      } else {
+        return false
+      }
+    },
+    submiteIsRead () {
+      // journalSetread({
+      //   logId: this.showWorkbench ? this.data.actionId : this.data.logId
+      // })
+      //   .then(res => {
+      //     this.$store.dispatch('GetOAMessageNum', 'log')
+      //     this.data.isRead = 1
+      //   })
+      //   .catch(() => {})
+    },
+
+    // 获取评论信息
+    getCommentList () {
+      // queryCommentListAPI({
+      //   typeId: this.data.logId,
+      //   type: 1
+      // })
+      //   .then(res => {
+      //     this.replyList = res.data
+      //   })
+      //   .catch(() => {})
+    },
+
+    verifyAwaitInfo () {},
+    // 编辑 删除
+    handleCommand (command) {
+      this.$emit('on-handle', { type: command, data: { item: this.data } })
+    },
+    checkRelatedDetail (type, data) {
+      this.$emit('on-handle', {
+        type: 'related-detail',
+        data: { type: type, item: data }
+      })
+    },
+    // 评论删除
+    discussDelete (val, items, index) {
+      this.$confirm('确定删除?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          // deleteCommentAPI({
+          //   commentId: val.commentId
+          // }).then(res => {
+          //   this.$message({
+          //     type: 'success',
+          //     message: '删除成功!'
+          //   })
+          //   items.splice(index, 1)
+          //   this.$emit('on-handle', {
+          //     type: 'discuss-delete',
+          //     data: { item: this.data }
+          //   })
+          // })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    },
+    // 回复 -- 显示输入框
+    discussBtn (item, index) {
+      if (item.show) {
+        this.$set(item, 'show', false)
+        this.replyChildComment = null
+      } else {
+        this.$set(item, 'show', true)
+        this.$set(item, 'showComment', false)
+        this.replyChildComment = item
+        this.replyChildIndex = index
+      }
+    },
+    // 子评论 回复 -- 提交
+    childCommentSubmit () {
+      if (this.replyChildComment && this.childCommentsTextarea) {
+        // var item =
+        //   this.replyChildIndex === -1
+        //     ? this.replyChildComment
+        //     : this.replyChildComment.childCommentList[this.replyChildIndex]
+        this.contentLoading = true
+        // setCommentAPI({
+        //   pid: item.userId,
+        //   typeId: item.typeId,
+        //   mainId: item.mainId === 0 ? item.commentId : item.mainId,
+        //   type: 2,
+        //   content: xss(this.childCommentsTextarea)
+        // })
+        //   .then(res => {
+        //     this.childCommentsPopover = false
+
+        //     res.data.user = this.userInfo
+        //     res.data.replyUser = item.user
+
+        //     this.replyChildComment.childCommentList.push(res.data)
+        //     this.$message.success('回复成功')
+        //     this.replyChildComment.show = false
+        //     this.replyChildComment = null
+
+        //     this.contentLoading = false
+        //     this.childCommentsTextarea = ''
+        //     this.$emit('on-handle', {
+        //       type: 'discuss-submit',
+        //       data: { item: this.data }
+        //     })
+        //   })
+        //   .catch(() => {
+        //     this.$message.error('回复失败')
+        //     this.contentLoading = false
+        //   })
+      }
+    },
+    // 评论 -- 提交
+    commentSubmit () {
+      if (this.commentsTextarea) {
+        this.contentLoading = true
+        // setCommentAPI({
+        //   typeId: this.showWorkbench ? this.data.actionId : this.data.logId,
+        //   type: 2, // 1 任务 2 日志
+        //   content: xss(this.commentsTextarea)
+        // })
+        //   .then(res => {
+        //     // 插入一条数据
+        //     this.$set(this.data, 'showComment', false)
+        //     res.data.childCommentList = []
+        //     res.data.show = false
+        //     res.data.user = this.userInfo
+
+        //     this.replyList.push(res.data)
+        //     this.commentsTextarea = ''
+        //     this.$message.success('回复成功')
+        //     this.contentLoading = false
+        //   })
+        //   .catch(() => {
+        //     this.$message.error('回复失败')
+        //     this.contentLoading = false
+        //   })
+      }
+    },
+    // 评论
+    commentBtn (item) {
+      if (item.showComment) {
+        this.$set(item, 'showComment', false)
+      } else {
+        if (this.replyChildComment) {
+          this.replyChildComment.show = false
+        }
+        this.$set(item, 'showComment', true)
+      }
+    },
+    // 评论选中功能
+    selectEmoji (val) {
+      const list = this.commentsTextarea.split('')
+      list.splice(this.blurIndex, 0, val)
+      this.commentsTextarea = list.join('')
+      this.commentsPopover = false
+    },
+    // 回复选中功能
+    childSelectEmoji (val) {
+      const list = this.childCommentsTextarea.split('')
+      list.splice(this.blurIndex, 0, val)
+      this.childCommentsTextarea = list.join('')
+      this.childCommentsPopover = false
+    },
+    blurFun (eve) {
+      this.blurIndex = eve.target.selectionEnd
+    },
+    // 放大图片
+    imgZoom (val, k) {
+      this.$bus.emit('preview-image-bus', {
+        index: k,
+        data: val.map(function (item, index, array) {
+          return {
+            url: item.filePath,
+            name: item.name
+          }
+        })
+      })
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+@import '../styles/content.scss';
+
+.list {
+  .list-content {
+    padding: 20px;
+    .header {
+      margin-bottom: 15px;
+      @include color9;
+      font-size: 12px;
+      .row {
+        display: inline-block;
+        vertical-align: middle;
+        margin-left: 10px;
+        .row-title {
+          margin-bottom: 7px;
+          @include v-align;
+        }
+        .el-tooltip {
+          margin-bottom: 0;
+        }
+        .el-popover__reference {
+          margin-bottom: 0;
+          cursor: pointer;
+          display: inline-block;
+        }
+      }
+      .head-img {
+        display: inline-block;
+        width: 35px;
+        height: 35px;
+        border-radius: 17.5px;
+        @include v-align;
+      }
+      .name,
+      .time,
+      .read,
+      .head-img {
+        @include v-align;
+      }
+      .read,
+      .time {
+        display: inline-block;
+        margin-right: 10px;
+      }
+      .name {
+        font-size: 15px;
+        margin: 0 10px 0 0;
+        color: #333333;
+      }
+      .rt-setting {
+        float: right;
+        line-height: 30px;
+        .dep {
+          color: #333333;
+          margin-right: 20px;
+        }
+        img {
+          width: 16px;
+          @include cursor;
+          @include v-align;
+        }
+      }
+    }
+    .text {
+      .row {
+        margin-bottom: 7px;
+        line-height: 22px;
+        font-size: 13px;
+        white-space: pre-wrap;
+        word-wrap: break-word;
+        .title {
+          width: 95px;
+          text-align: left;
+          display: inline-block;
+          @include color9;
+          font-size: 13px;
+        }
+      }
+    }
+    .accessory {
+      .upload-img-box {
+        margin: 10px 0;
+        .img-list {
+          display: inline-block;
+          position: relative;
+          margin-right: 10px;
+          width: 80px;
+          height: 60px;
+          line-height: 60px;
+          cursor: pointer;
+          img {
+            max-width: 80px;
+            max-height: 60px;
+          }
+        }
+      }
+    }
+    .discuss {
+      margin-top: 20px;
+      .border {
+        height: 1px;
+        background: #e6e6e6;
+        margin: 15px -20px;
+      }
+      .discuss-list {
+        .name,
+        .time,
+        .head-img {
+          @include v-align;
+        }
+        .head-img {
+          width: 25px;
+          height: 25px;
+          display: inline-block;
+          border-radius: 12.5px;
+        }
+        .name {
+          margin: 0 10px;
+          font-size: 15px;
+        }
+        .time {
+          color: #999;
+          font-size: 12px;
+          display: inline-block;
+          margin-top: 3px;
+        }
+
+        .reply-title {
+          color: #333;
+          font-size: 13px;
+          margin: 10px 0 10px 40px;
+          padding: 10px 10px 10px 40px;
+          white-space: pre-wrap;
+          word-wrap: break-word;
+          span {
+            letter-spacing: 0.5px;
+            line-height: 18px;
+          }
+          .reply {
+            color: #4D88FF;
+          }
+        }
+        .reply-title /deep/ img {
+          vertical-align: text-bottom;
+          margin: 0 2px;
+        }
+
+        .children-reply {
+          margin: 10px 0 10px 40px;
+        }
+
+        .rt {
+          margin-top: 4px;
+          color: #999;
+          margin-right: 0;
+          span {
+            margin-left: 10px;
+            cursor: pointer;
+          }
+        }
+        .discuss-content {
+          background: #f5f7fa;
+          color: #777;
+          line-height: 36px;
+          margin-left: 40px;
+          padding-left: 15px;
+        }
+        .discuss-content /deep/ img {
+          vertical-align: middle;
+          margin: 0 3px;
+        }
+        .border {
+          margin: 15px 0 15px 40px;
+        }
+        .comment-box {
+          margin-left: 40px;
+          padding: 0;
+          background: transparent;
+          margin-top: 15px;
+        }
+      }
+      .discuss-list:last-child {
+        .border {
+          display: none;
+        }
+      }
+    }
+  }
+  .footer {
+    background: #f4f7fd;
+    height: 40px;
+    line-height: 40px;
+    color: #ccc;
+    text-align: right;
+    padding-right: 20px;
+    img {
+      @include v-align;
+      @include cursor;
+    }
+    .comment {
+      margin-right: 15px;
+      color: #6c7a95;
+      font-size: 13px;
+      cursor: pointer;
+    }
+  }
+  .comment-box {
+    margin: 20px;
+    border: 1px solid #e6e6e6;
+    .btn-group {
+      padding: 0 20px 10px 10px;
+      overflow: hidden;
+      .btn-box {
+        float: right;
+      }
+    }
+    .btn-group /deep/ img {
+      cursor: pointer;
+    }
+    .el-textarea /deep/ .el-textarea__inner {
+      resize: none;
+      border: 0;
+    }
+  }
+}
+
+.wukong {
+  cursor: pointer;
+}
+</style>
diff --git a/src/views/OAManagement/journal/newDialog.vue b/src/views/OAManagement/journal/newDialog.vue
new file mode 100644
index 0000000..68b884f
--- /dev/null
+++ b/src/views/OAManagement/journal/newDialog.vue
@@ -0,0 +1,616 @@
+<template>
+  <create-view :body-style="{height: '100%'}">
+    <div
+      v-loading="newLoading"
+      class="new-journal">
+      <div
+        slot="header"
+        class="header">
+        <span class="text">{{ dialogTitle }}</span>
+        <img
+          class="el-icon-close rt"
+          src="@/assets/img/task_close.png"
+          alt=""
+          @click="close">
+      </div>
+      <div class="content">
+        <el-tabs
+          v-model="activeName"
+          @tab-click="tabClick">
+          <el-tab-pane
+            v-for="(item, index) in tabsData"
+            :label="item.label"
+            :name="item.key"
+            :key="index"/>
+        </el-tabs>
+        <div class="form">
+          <div
+            v-for="(item, index) in formList"
+            :key="index"
+            class="row-list">
+            <label class="item-label">{{ item.label }}:</label>
+            <el-input
+              :autosize="{ minRows: 4}"
+              v-model="formData[item.model]"
+              type="textarea"
+              placeholder="请输入内容"
+              resize="none"/>
+          </div>
+          <!-- 图片附件 -->
+          <div class="img-accessory">
+            <div class="img-box">
+              <el-upload
+                ref="imageUpload"
+                :action="crmFileSaveUrl"
+                :headers="httpHeader"
+                :data="{type: 'img', batchId: batchId}"
+                :on-preview="handleFilePreview"
+                :before-remove="beforeRemove"
+                :on-success="imgFileUploadSuccess"
+                :file-list="imageFileList"
+                name="file"
+                multiple
+                accept="image/*"
+                list-type="picture-card">
+                <p class="add-img">
+                  <span class="el-icon-picture"/>
+                  <span>添加图片</span>
+                </p>
+                <i class="el-icon-plus"/>
+              </el-upload>
+            </div>
+            <p class="add-accessory">
+              <el-upload
+                ref="fileUpload"
+                :action="crmFileSaveUrl"
+                :headers="httpHeader"
+                :data="{type: 'file', batchId: batchId}"
+                :on-preview="handleFilePreview"
+                :before-remove="handleFileRemove"
+                :on-success="fileUploadSuccess"
+                :file-list="fileList"
+                name="file"
+                multiple
+                accept="*.*">
+                <p>
+                  <img
+                    src="@/assets/img/relevance_file.png"
+                    alt="">
+                  添加附件
+                </p>
+              </el-upload>
+            </p>
+          </div>
+          <div class="sent-who">
+            <span class="label">发送给谁:</span>
+            <div
+              v-photo="k"
+              v-lazy:background-image="$options.filters.filterUserLazyImg(k.img)"
+              v-for="(k, j) in formData.sentWhoList"
+              :key="j"
+              class="div-photo k-img header-circle"/>
+            <span>
+              <span
+                v-for="(item, index) in formData.depData"
+                :key="index"
+                class="item-name">{{ item.name }}</span>
+            </span>
+            <members-dep
+              :user-checked-data="formData.sentWhoList"
+              :dep-checked-data="formData.depData"
+              :content-block="false"
+              @popoverSubmit="popoverSubmit">
+              <img
+                slot="membersDep"
+                class="sent-img"
+                src="@/assets/img/task_add.png">
+            </members-dep>
+          </div>
+          <related-business
+            :margin-left="'0'"
+            :all-data="allData"
+            @checkInfos="checkInfos"/>
+        </div>
+      </div>
+      <div class="btn-group">
+        <el-button
+          type="primary"
+          @click="submitBtn">提交</el-button>
+        <el-button @click="close">取消</el-button>
+      </div>
+    </div>
+  </create-view>
+</template>
+
+<script>
+import axios from 'axios'
+// import { crmFileDelete, crmFileSaveUrl } from '@/api/common'
+import { guid } from '@/utils'
+import CreateView from '@/components/CreateView'
+// 部门员工优化版
+import membersDep from '@/components/selectEmployee/membersDep'
+// 关联业务 - 选中列表
+import relatedBusiness from '@/components/relatedBusiness'
+export default {
+  components: {
+    CreateView,
+    membersDep,
+    relatedBusiness
+  },
+  props: {
+    formData: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    dialogTitle: {
+      type: String,
+      default: '写日志'
+    },
+    // 附件
+    accessoryFileList: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    imgFileList: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    newLoading: Boolean
+  },
+  data () {
+    return {
+      activeName: '1',
+      tabsData: [
+        { label: '日报', key: '1' },
+        { label: '周报', key: '2' },
+        { label: '月报', key: '3' }
+      ],
+      // 表格数据
+      formList: [],
+      dateList: [
+        { label: '今日工作内容', model: 'content' },
+        { label: '明日工作内容', model: 'tomorrow' },
+        { label: '遇到的问题', model: 'question' }
+      ],
+      weekList: [
+        { label: '本周工作内容', model: 'content' },
+        { label: '下周工作内容', model: 'tomorrow' },
+        { label: '遇到的问题', model: 'question' }
+      ],
+      monthList: [
+        { label: '本月工作内容', model: 'content' },
+        { label: '下月工作内容', model: 'tomorrow' },
+        { label: '遇到的问题', model: 'question' }
+      ],
+      batchId: guid(),
+      imageFileList: [],
+      fileList: [],
+      // 发送给谁
+      dialogVisible: false,
+      // 获取选择的数据id数组
+      relevanceAll: {},
+      allData: {}
+    }
+  },
+  computed: {
+    // crmFileSaveUrl () {
+    //   return crmFileSaveUrl
+    // },
+    httpHeader () {
+      return {
+        'Admin-Token': axios.defaults.headers['Admin-Token']
+      }
+    }
+  },
+  mounted () {
+    document.body.appendChild(this.$el)
+    this.formList = this.dateList
+
+    // 确定显示哪一种日志
+    if (this.formData.categoryId) {
+      switch (this.formData.categoryId) {
+        case 1:
+          this.tabsData = [{ label: '日报', key: '1' }]
+          this.formList = this.dateList
+          break
+        case 2:
+          this.tabsData = [{ label: '周报', key: '1' }]
+          this.formList = this.weekList
+          break
+        case 3:
+          this.tabsData = [{ label: '月报', key: '1' }]
+          this.formList = this.monthList
+          break
+      }
+    }
+
+    if (this.dialogTitle !== '写日志' && this.formData.batchId) {
+      this.batchId = this.formData.batchId
+    }
+
+    // 编辑时引用 - 自动勾选
+    var allData = {}
+    allData.business = this.formData.businessList
+      ? this.formData.businessList
+      : []
+    allData.contacts = this.formData.contactsList
+      ? this.formData.contactsList
+      : []
+    allData.contract = this.formData.contractList
+      ? this.formData.contractList
+      : []
+    allData.customer = this.formData.customerList
+      ? this.formData.customerList
+      : []
+    this.allData = allData
+    var relevanceAll = {}
+    relevanceAll.businessIds = this.formData.businessList
+      ? this.formData.businessList.map((item, index, array) => {
+        return item.businessId
+      })
+      : []
+    relevanceAll.contactsIds = this.formData.contactsList
+      ? this.formData.contactsList.map((item, index, array) => {
+        return item.contactsId
+      })
+      : []
+    relevanceAll.contractIds = this.formData.contractList
+      ? this.formData.contractList.map((item, index, array) => {
+        return item.contractId
+      })
+      : []
+    relevanceAll.customerIds = this.formData.customerList
+      ? this.formData.customerList.map((item, index, array) => {
+        return item.customerId
+      })
+      : []
+    this.relevanceAll = relevanceAll
+
+    this.imageFileList = this.imgFileList.map(function (item, index, array) {
+      item.url = item.filePath
+      return item
+    })
+    this.fileList = this.accessoryFileList.map(function (item, index, array) {
+      item.url = item.filePath
+      return item
+    })
+  },
+  destroyed () {
+    // remove DOM node after destroy
+    if (this.$el && this.$el.parentNode) {
+      this.$el.parentNode.removeChild(this.$el)
+    }
+  },
+  methods: {
+    close () {
+      if (this.$route.query.routerKey === 1) {
+        this.$router.go(-1)
+      } else {
+        this.$emit('close')
+      }
+    },
+    tabClick () {
+      switch (this.activeName) {
+        case '1':
+          this.formList = this.dateList
+          break
+        case '2':
+          this.formList = this.weekList
+          break
+        case '3':
+          this.formList = this.monthList
+          break
+      }
+    },
+    // 提交按钮
+    submitBtn () {
+      if (
+        this.formData.content ||
+        this.formData.tomorrow ||
+        this.formData.question
+      ) {
+        this.$emit(
+          'submitBtn',
+          this.activeName,
+          this.batchId,
+          this.imageFileList,
+          this.relevanceAll
+        )
+      } else {
+        this.$message.error('内容至少填写一项')
+      }
+    },
+    // 图片和附件
+    // 上传图片
+    imgFileUploadSuccess (response, file, fileList) {
+      this.imageFileList = fileList
+    },
+    // 查看图片
+    handleFilePreview (file) {
+      if (file.response || file.fileId) {
+        let perviewFile
+        if (file.response) {
+          perviewFile = file.response
+        } else {
+          perviewFile = {
+            url: file.filePath,
+            name: file.name
+          }
+        }
+        this.$bus.emit('preview-image-bus', {
+          index: 0,
+          data: [perviewFile]
+        })
+      }
+    },
+    beforeRemove (file, fileList) {
+      if (file.response || file.fileId) {
+        // let fileId
+        // if (file.response) {
+        //   fileId = file.response.fileId
+        // } else {
+        //   fileId = file.fileId
+        // }
+        this.$confirm('您确定要删除该文件吗?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+          .then(() => {
+            // crmFileDelete({
+            //   id: fileId
+            // })
+            //   .then(res => {
+            //     this.$message.success('操作成功')
+            //     var removeIndex = this.getFileIndex(
+            //       this.$refs.imageUpload.uploadFiles,
+            //       fileId
+            //     )
+            //     if (removeIndex !== -1) {
+            //       this.$refs.imageUpload.uploadFiles.splice(removeIndex, 1)
+            //     }
+            //     removeIndex = this.getFileIndex(this.imgFileList, fileId)
+            //     if (removeIndex !== -1) {
+            //       this.imgFileList.splice(removeIndex, 1)
+            //     }
+            //   })
+            //   .catch(() => {})
+          })
+          .catch(() => {
+            this.$message({
+              type: 'info',
+              message: '已取消操作'
+            })
+          })
+        return false
+      } else {
+        return true
+      }
+    },
+    // 附件索引
+    getFileIndex (files, fileId) {
+      var removeIndex = -1
+      for (let index = 0; index < files.length; index++) {
+        const item = files[index]
+        let itemFileId
+        if (item.response) {
+          itemFileId = item.response.fileId
+        } else {
+          itemFileId = item.fileId
+        }
+        if (itemFileId === fileId) {
+          removeIndex = index
+          break
+        }
+      }
+      return removeIndex
+    },
+    fileUploadSuccess (response, file, fileList) {
+      this.fileList = fileList
+    },
+    handleFileRemove (file, fileList) {
+      if (file.response || file.fileId) {
+        // let fileId
+        // if (file.response) {
+        //   fileId = file.response.fileId
+        // } else {
+        //   fileId = file.fileId
+        // }
+        this.$confirm('您确定要删除该文件吗?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+          .then(() => {
+            // crmFileDelete({
+            //   id: fileId
+            // })
+            //   .then(res => {
+            //     this.$message.success('操作成功')
+            //     var removeIndex = this.getFileIndex(
+            //       this.$refs.fileUpload.uploadFiles,
+            //       fileId
+            //     )
+            //     if (removeIndex !== -1) {
+            //       this.$refs.fileUpload.uploadFiles.splice(removeIndex, 1)
+            //     }
+            //     removeIndex = this.getFileIndex(this.fileList, fileId)
+            //     if (removeIndex !== -1) {
+            //       this.fileList.splice(removeIndex, 1)
+            //     }
+            //   })
+            //   .catch(() => {})
+          })
+          .catch(() => {
+            this.$message({
+              type: 'info',
+              message: '已取消操作'
+            })
+          })
+        return false
+      } else {
+        return true
+      }
+    },
+    popoverSubmit (members, dep) {
+      this.$set(this.formData, 'sentWhoList', members)
+      this.$set(this.formData, 'depData', dep)
+    },
+    // 取消
+    handleClose () {
+      this.dialogVisible = false
+    },
+    checkInfos (val) {
+      this.relevanceAll = val
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.new-journal {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+  .header {
+    height: 40px;
+    line-height: 40px;
+    padding: 0 0 0 10px;
+    .el-icon-close {
+      margin-right: 0;
+      width: 40px;
+      line-height: 40px;
+      padding: 10px;
+      cursor: pointer;
+    }
+    .text {
+      font-size: 17px;
+    }
+  }
+  .content {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    overflow: auto;
+    padding: 20px;
+  }
+  .btn-group {
+    text-align: right;
+    padding-right: 20px;
+  }
+  .content /deep/ .el-tabs {
+    .el-tabs__header {
+      .el-tabs__item {
+        height: 50px;
+        line-height: 50px;
+      }
+      .el-tabs__nav {
+        margin-left: 20px;
+        font-size: 13px;
+      }
+      .el-tabs__nav-wrap::after {
+        height: 1px;
+      }
+    }
+    .el-tabs__content {
+      padding: 0 20px;
+    }
+  }
+}
+
+.form {
+  flex: 1;
+  margin-top: 10px;
+  padding: 0 20px;
+  overflow-y: scroll;
+  .row-list {
+    margin-bottom: 20px;
+    padding-bottom: 10px;
+    .item-label {
+      margin-bottom: 9px;
+      display: block;
+      font-size: 12px;
+      // padding-bottom: 10px;
+    }
+    .el-textarea {
+      .el-textarea__inner {
+        resize: none;
+      }
+    }
+  }
+  .img-accessory {
+    font-size: 12px;
+    img {
+      vertical-align: middle;
+    }
+    .img-box /deep/ .el-upload {
+      width: 80px;
+      height: 80px;
+      line-height: 90px;
+    }
+    .img-box /deep/ .el-upload-list {
+      .el-upload-list__item {
+        width: 80px;
+        height: 80px;
+      }
+    }
+    .img-box {
+      position: relative;
+      margin-top: 40px;
+      .add-img {
+        position: absolute;
+        left: 0;
+        top: -30px;
+        height: 20px;
+        line-height: 20px;
+        margin-bottom: 10px;
+        color: #4D88FF;
+      }
+    }
+    .add-accessory {
+      margin-top: 25px;
+      margin-bottom: 20px;
+      color: #4D88FF;
+    }
+  }
+  .sent-who {
+    margin-bottom: 15px;
+    .label,
+    img,
+    .k-img {
+      vertical-align: middle;
+    }
+    .label {
+      margin-right: 15px;
+      font-size: 12px;
+    }
+    img {
+      cursor: pointer;
+    }
+    .item-name {
+      margin-right: 7px;
+    }
+    .k-img {
+      width: 25px;
+      height: 25px;
+      border-radius: 17.5px;
+      margin-right: 7px;
+    }
+    .must {
+      color: #f56c6c;
+      font-size: 12px;
+      margin-top: 5px;
+    }
+    .sent-img {
+      width: 24px;
+      height: 24px;
+    }
+  }
+}
+</style>
diff --git a/src/views/OAManagement/notice/details.vue b/src/views/OAManagement/notice/details.vue
new file mode 100644
index 0000000..0f66ab0
--- /dev/null
+++ b/src/views/OAManagement/notice/details.vue
@@ -0,0 +1,180 @@
+<template>
+  <create-view :body-style="{height: '100%'}">
+    <div class="details-box">
+      <div
+        slot="header"
+        class="header">
+        <span class="text">公告详情</span>
+        <span
+          class="el-icon-close rt"
+          @click="close"/>
+      </div>
+      <div class="content">
+        <div class="title">{{ titleList.title }}</div>
+        <div class="time">{{ titleList.createTime }}</div>
+        <div class="text">{{ titleList.content }}</div>
+      </div>
+      <div
+        v-if="btnShow"
+        class="btn-box">
+        <el-button
+          v-if="permissionUpdate"
+          type="primary"
+          @click="onEdit">编辑</el-button>
+        <el-button
+          v-if="permissionDelete"
+          type="danger"
+          @click="deleteFun">删除</el-button>
+      </div>
+    </div>
+    <v-edit
+      v-if="showEdit"
+      :form-data="formData"
+      :loading="loading"
+      @editSubmit="editSubmit"
+      @editClose="editClose"/>
+  </create-view>
+</template>
+
+<script>
+import CreateView from '@/components/CreateView'
+import VEdit from './edit'
+// API
+// import { noticeDelete, noticeAdd } from '@/api/oamanagement/notice'
+import { mapGetters } from 'vuex'
+
+export default {
+  components: {
+    CreateView,
+    VEdit
+  },
+  props: {
+    titleList: Object,
+    btnShow: {
+      type: Boolean,
+      default: true
+    }
+  },
+  data () {
+    return {
+      showEdit: false,
+      formData: {},
+      loading: false
+    }
+  },
+  computed: {
+    ...mapGetters(['oa']),
+    permissionUpdate () {
+      return this.oa && this.oa.announcement && this.oa.announcement.update
+    },
+    permissionDelete () {
+      return this.oa && this.oa.announcement && this.oa.announcement.delete
+    }
+  },
+  methods: {
+    onEdit () {
+      this.formData = Object.assign({}, this.titleList)
+      this.showEdit = true
+    },
+    close () {
+      this.$emit('close')
+    },
+    deleteFun () {
+      this.$confirm('确定删除?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          // noticeDelete({
+          //   id: this.titleList.announcementId
+          // }).then(res => {
+          //   this.$emit('deleteFun')
+          //   this.$message({
+          //     type: 'success',
+          //     message: '删除成功!'
+          //   })
+          // })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    },
+    // 编辑 -- 取消
+    editClose () {
+      this.showEdit = false
+    },
+    // 编辑 -- 确定
+    editSubmit () {
+      this.loading = true
+      // noticeAdd({
+      //   announcementId: this.formData.announcementId,
+      //   title: this.formData.title,
+      //   content: this.formData.content,
+      //   startTime: this.formData.startTime,
+      //   endTime: this.formData.endTime
+      // })
+      //   .then(res => {
+      //     this.$emit('editSubmit', this.formData)
+      //     this.editClose()
+      //     this.$message.success('公告编辑成功')
+      //     this.loading = false
+      //   })
+      //   .catch(() => {
+      //     this.loading = false
+      //     this.$message.error('公告编辑失败')
+      //   })
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+$size16: 16px;
+.details-box {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+  .header {
+    .text {
+      font-size: $size16;
+    }
+    .el-icon-close {
+      font-size: 20px;
+      color: #ccc;
+      margin-right: 0;
+      cursor: pointer;
+    }
+  }
+  .content {
+    margin-top: 10px;
+    flex: 1;
+    overflow: auto;
+    .title {
+      font-size: $size16;
+      text-align: center;
+    }
+    .time {
+      color: #999;
+      text-align: center;
+      font-size: 12px;
+      margin-top: 8px;
+    }
+    .text {
+      margin-top: 20px;
+      line-height: 24px;
+      color: #333;
+      padding: 0 20px;
+      white-space: pre-wrap;
+      word-wrap: break-word;
+    }
+  }
+  .btn-box {
+    text-align: right;
+    padding-right: 20px;
+  }
+}
+</style>
diff --git a/src/views/OAManagement/notice/edit.vue b/src/views/OAManagement/notice/edit.vue
new file mode 100644
index 0000000..c127881
--- /dev/null
+++ b/src/views/OAManagement/notice/edit.vue
@@ -0,0 +1,206 @@
+<template>
+  <create-view :body-style="{height: '100%'}">
+    <div
+      v-loading="loading"
+      class="details-box">
+      <div
+        slot="header"
+        class="header">
+        <span class="text">编辑公告</span>
+        <img
+          class="el-icon-close rt"
+          src="@/assets/img/task_close.png"
+          alt=""
+          @click="close">
+      </div>
+      <div class="content">
+        <el-form
+          ref="form"
+          :model="formData"
+          :rules="rules">
+          <el-form-item
+            v-for="(item, index) in formList"
+            :label="item.label"
+            :class="'el-form-item' + item.field"
+            :prop="item.field"
+            :key="index">
+            <template v-if="item.type === 'date'">
+              <el-date-picker
+                v-model="formData[item.field]"
+                type="date"
+                value-format="yyyy-MM-dd"
+                placeholder="选择日期"/>
+            </template>
+            <template v-else-if="item.type === 'textarea'">
+              <el-input
+                v-model="formData[item.field]"
+                type="textarea"
+                autosize
+                placeholder="请输入内容"/>
+            </template>
+            <el-input
+              v-else
+              v-model="formData[item.field]"/>
+          </el-form-item>
+        </el-form>
+      </div>
+      <div class="btn-box">
+        <el-button
+          type="primary"
+          @click="onSubmit">提交</el-button>
+        <el-button @click="close">取消</el-button>
+      </div>
+    </div>
+  </create-view>
+</template>
+
+<script>
+import CreateView from '@/components/CreateView'
+import { formatTimeToTimestamp } from '@/utils/index'
+
+export default {
+  components: {
+    CreateView
+  },
+  props: {
+    formData: Object,
+    loading: Boolean
+  },
+  data () {
+    var validateTime = (rule, value, callback) => {
+      if (
+        (rule.field === 'startTime' &&
+          !this.formData.startTime &&
+          this.formData.endTime) ||
+        (rule.field === 'endTime' &&
+          !this.formData.endTime &&
+          this.formData.startTime)
+      ) {
+        callback(new Error('请完善时间'))
+      } else if (this.formData.startTime && this.formData.endTime) {
+        if (
+          formatTimeToTimestamp(this.formData.startTime) >=
+          formatTimeToTimestamp(this.formData.endTime)
+        ) {
+          callback(new Error('开始时间必须小于结束时间'))
+        }
+      }
+      callback()
+    }
+    return {
+      formList: [
+        { label: '公告标题', field: 'title' },
+        { label: '开始时间', field: 'startTime', type: 'date' },
+        { label: '结束时间', field: 'endTime', type: 'date' },
+        { label: '公告正文', field: 'content', type: 'textarea' }
+      ],
+      rules: {
+        title: [
+          { required: true, message: '公告标题不能为空', trigger: 'blur' },
+          { max: 50, message: '公告标题长度最多为50个字符', trigger: 'blur' }
+        ],
+        content: [
+          { required: true, message: '公告正文不能为空', trigger: 'blur' }
+        ],
+        startTime: [
+          { required: true, message: '不能为空', trigger: 'blur' },
+          { validator: validateTime, trigger: 'blur' }
+        ],
+        endTime: [
+          { required: true, message: '不能为空', trigger: 'blur' },
+          { validator: validateTime, trigger: 'blur' }
+        ]
+      }
+    }
+  },
+  methods: {
+    onSubmit () {
+      this.$refs.form.validate(valid => {
+        if (valid) {
+          this.$emit('editSubmit')
+        } else {
+          return false
+        }
+      })
+    },
+    close () {
+      this.$emit('editClose')
+    },
+    inputChange () {
+      this.popoverVisible = true
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+$size16: 16px;
+.details-box {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+  .header {
+    line-height: 40px;
+    height: 40px;
+    padding: 0 0 0 10px;
+    .text {
+      font-size: 17px;
+    }
+    .el-icon-close {
+      margin-right: 0;
+      width: 40px;
+      line-height: 40px;
+      padding: 10px;
+      cursor: pointer;
+    }
+  }
+  .content {
+    padding: 15px 18px;
+    flex: 1;
+    overflow: auto;
+    padding-right: 20px;
+    .el-form /deep/ {
+      .el-form-item {
+        margin-bottom: 10px;
+        padding-bottom: 10px;
+        float: left;
+        width: 50%;
+        .el-form-item__label {
+          float: none;
+          font-size: 12px;
+        }
+        .el-input {
+          // width: 45%;
+          .el-input__inner {
+            vertical-align: bottom;
+          }
+        }
+        .el-date-editor {
+          vertical-align: bottom;
+          width: 100%;
+          .el-range-separator {
+            width: 7%;
+          }
+        }
+      }
+      .el-form-itemtitle,
+      .el-form-itemendTime {
+        padding-right: 25px;
+      }
+      .el-form-itemstartTime {
+        padding-left: 25px;
+      }
+      .el-form-itemstartTime {
+        margin-bottom: 11px;
+      }
+      .el-form-itemcontent {
+        width: 100%;
+      }
+    }
+  }
+  .btn-box {
+    text-align: right;
+    padding-right: 20px;
+  }
+}
+</style>
diff --git a/src/views/OAManagement/notice/index.vue b/src/views/OAManagement/notice/index.vue
new file mode 100644
index 0000000..fc2008b
--- /dev/null
+++ b/src/views/OAManagement/notice/index.vue
@@ -0,0 +1,267 @@
+<template>
+  <div
+    v-loading="loading"
+    class="notice oa-bgcolor">
+    <el-button
+      v-if="permissionSave"
+      type="primary"
+      class="new-btn"
+      @click="newBtn">新建公告</el-button>
+    <el-tabs v-model="activeName">
+      <el-tab-pane
+        label="公告"
+        name="first">
+        <div class="text-top">
+          <label class="text">公告状态</label>
+          <el-select
+            v-model="optionsValue"
+            placeholder="请选择"
+            size="small"
+            @change="selectChange">
+            <el-option
+              v-for="item in options"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"/>
+          </el-select>
+        </div>
+        <div id="notice-list-box" class="content">
+          <div class="list-box">
+            <notice-cell
+              v-for="(item, index) in listData"
+              :key="index"
+              :data="item"
+              :cell-index="index"
+              @handle="noticeHandle"/>
+            <p class="load">
+              <el-button
+                :loading="loadMoreLoading"
+                type="text">{{ loadText }}</el-button>
+            </p>
+          </div>
+        </div>
+      </el-tab-pane>
+    </el-tabs>
+    <!-- 详情 -->
+    <v-details
+      v-if="dialog"
+      :title-list="titleList"
+      @editSubmit="editSubmit"
+      @deleteFun="deleteFun"
+      @close="close"/>
+    <!-- 新建 -->
+    <new-dialog
+      v-if="showNewDialog"
+      @onSubmit="onSubmit"
+      @close="newClose"/>
+  </div>
+</template>
+
+<script>
+import VDetails from './details'
+import newDialog from './newDialog'
+import NoticeCell from './noticeCell'
+import { mapGetters } from 'vuex'
+// API
+// import { noticeList } from '@/api/oamanagement/notice'
+
+export default {
+  components: {
+    VDetails,
+    newDialog,
+    NoticeCell
+  },
+  data () {
+    return {
+      activeName: 'first',
+      // 公示下拉框
+      options: [
+        { value: '1', label: '公示中' },
+        { value: '2', label: '已结束' }
+      ],
+      optionsValue: '1',
+      // 公告列表
+      listData: [],
+      // 详情
+      dialog: false,
+      titleList: {},
+      // 新建
+      showNewDialog: false,
+      loading: true,
+      // 页数
+      pageNum: 1,
+      loadText: '加载更多',
+      loadMoreLoading: true,
+      // 判断是否还有数据
+      isPost: true
+    }
+  },
+  computed: {
+    ...mapGetters(['oa']),
+    permissionSave () {
+      return this.oa && this.oa.announcement && this.oa.announcement.save
+    }
+  },
+  watch: {
+    $route (to, from) {
+      this.$router.go(0)
+    }
+  },
+  mounted () {
+    this.noticeDataFun(1, this.pageNum)
+    // 分批次加载
+    document.getElementsByClassName('content')[0].onscroll = () => {
+      const dom = document.getElementsByClassName('content')[0]
+      const scrollOff = dom.scrollTop + dom.clientHeight - dom.scrollHeight
+      // 滚动条到底部的条件
+      if (Math.abs(scrollOff) < 10 && this.loadMoreLoading === true) {
+        if (!this.isPost) {
+          this.isPost = true
+          this.pageNum++
+          this.noticeDataFun(this.optionsValue, this.pageNum)
+        } else {
+          this.loadMoreLoading = false
+        }
+      }
+    }
+  },
+  methods: {
+    noticeDataFun (type, num) {
+      // noticeList({
+      //   type: type,
+      //   page: num,
+      //   limit: 15
+      // })
+      //   .then(res => {
+      //     for (const item of res.data.list) {
+      //       item.contentSub = item.content.substring(0, 150)
+      //     }
+      //     this.listData = this.listData.concat(res.data.list)
+      //     if (res.data.list.length === 0 || res.data.list.length !== 15) {
+      //       this.loadText = '没有更多了'
+      //       this.loadMoreLoading = false
+      //     } else {
+      //       this.loadText = '加载更多'
+      //       this.loadMoreLoading = true
+      //     }
+      //     this.loading = false
+      //     this.isPost = false
+      //   })
+      //   .catch(() => {
+      //     this.loadText = ''
+      //     this.loading = false
+      //     this.isPost = false
+      //   })
+    },
+    // 点击显示详情
+    noticeHandle (data) {
+      if (data.type === 'detail') {
+        this.titleList = data.value
+        this.dialog = true
+      }
+    },
+    close () {
+      this.dialog = false
+    },
+    // 删除
+    deleteFun () {
+      for (const i in this.listData) {
+        if (this.listData[i].announcementId === this.titleList.announcementId) {
+          this.listData.splice(i, 1)
+        }
+      }
+      this.close()
+    },
+    // 新建
+    newBtn () {
+      this.showNewDialog = true
+    },
+    // 新建关闭
+    newClose () {
+      this.showNewDialog = false
+    },
+    // 新建提交按钮
+    onSubmit (data) {
+      this.selectChange(this.optionsValue)
+      this.newClose()
+    },
+    // 编辑确定
+    editSubmit (val) {
+      this.selectChange(this.optionsValue)
+      this.close()
+    },
+    // 筛选状态
+    selectChange (type) {
+      this.loading = true
+      this.listData = []
+      this.pageNum = 1
+      this.noticeDataFun(type, this.pageNum)
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+@import '../styles/tabs.scss';
+.notice {
+  position: relative;
+  overflow: hidden;
+  display: flex;
+  flex-direction: column;
+  .new-btn {
+    position: absolute;
+    top: 10px;
+    right: 40px;
+    z-index: 999;
+  }
+  .text-top {
+    padding: 5px 0 15px;
+    .text {
+      margin-right: 10px;
+      color: #999;
+    }
+  }
+  .content {
+    .list-box {
+      margin-top: 20px;
+      padding-right: 20px;
+      .load {
+        color: #999;
+        font-size: 13px;
+        margin: 0 auto 15px;
+        text-align: center;
+        .el-button,
+        .el-button:focus {
+          color: #ccc;
+          cursor: auto;
+        }
+      }
+    }
+  }
+}
+.notice /deep/ .el-tabs {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  min-height: 0;
+  .el-tab-pane,
+  .el-tabs__content {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+  }
+  .el-tab-pane {
+    min-height: 0;
+  }
+  .el-tabs__content {
+    padding: 0 30px;
+    margin-bottom: 20px;
+    .content {
+      flex: 1;
+      overflow: auto;
+      padding-right: 30px;
+      margin-right: -30px;
+    }
+  }
+}
+</style>
diff --git a/src/views/OAManagement/notice/newDialog.vue b/src/views/OAManagement/notice/newDialog.vue
new file mode 100644
index 0000000..6abe12c
--- /dev/null
+++ b/src/views/OAManagement/notice/newDialog.vue
@@ -0,0 +1,340 @@
+<template>
+  <create-view :body-style="{height: '100%'}">
+    <div
+      v-loading="loading"
+      class="details-box">
+      <div
+        slot="header"
+        class="header">
+        <span class="text">新建公告</span>
+        <img
+          class="el-icon-close rt"
+          src="@/assets/img/task_close.png"
+          alt=""
+          @click="close">
+      </div>
+      <div class="content">
+        <el-form
+          ref="form"
+          :model="formData"
+          :rules="rules">
+          <el-form-item
+            v-for="(item, index) in formList"
+            :label="item.label"
+            :class="'el-form-item' + item.field"
+            :prop="item.field"
+            :key="index">
+            <template v-if="item.type === 'date'">
+              <el-date-picker
+                v-model="formData[item.field]"
+                type="date"
+                value-format="yyyy-MM-dd"
+                placeholder="选择日期"/>
+            </template>
+            <template v-else-if="item.type === 'textarea'">
+              <el-input
+                :autosize="{ minRows: 6}"
+                v-model="formData[item.field]"
+                type="textarea"
+                placeholder="请输入内容"/>
+            </template>
+            <template v-else-if="item.type =='plus'">
+              <members-dep
+                :popover-display="'block'"
+                :title="'通知部门'"
+                :user-checked-data="formData[item.field].staff"
+                :dep-checked-data="formData[item.field].dep"
+                @popoverSubmit="popoverSubmit">
+                <flexbox
+                  slot="membersDep"
+                  wrap="wrap"
+                  class="user-container">
+                  <div
+                    v-for="(item, index) in formData[item.field].staff"
+                    :key="'user' + index"
+                    class="user-item"
+                    @click.stop="deleteuser(index)">{{ item.realname }}
+                    <i class="delete-icon el-icon-close"/>
+                  </div>
+                  <div
+                    v-for="(item, index) in formData[item.field].dep"
+                    :key="'dep' + index"
+                    class="user-item"
+                    @click.stop="deleteDepuser(index)">{{ item.name }}
+                    <i class="delete-icon el-icon-close"/>
+                  </div>
+                  <div class="add-item">+添加</div>
+                </flexbox>
+              </members-dep>
+            </template>
+            <el-input
+              v-else
+              v-model="formData[item.field]"/>
+          </el-form-item>
+        </el-form>
+      </div>
+      <div class="btn-box">
+        <el-button
+          type="primary"
+          @click="onSubmit">提交</el-button>
+        <el-button @click="close">取消</el-button>
+      </div>
+    </div>
+  </create-view>
+</template>
+
+<script>
+import CreateView from '@/components/CreateView'
+
+import membersDep from '@/components/selectEmployee/membersDep'
+// API
+// import { noticeAdd } from '@/api/oamanagement/notice'
+import { formatTimeToTimestamp } from '@/utils/index'
+
+export default {
+  components: {
+    CreateView,
+    membersDep
+  },
+  data () {
+    var validateTime = (rule, value, callback) => {
+      if (
+        (rule.field === 'startTime' &&
+          !this.formData.startTime &&
+          this.formData.endTime) ||
+        (rule.field === 'endTime' &&
+          !this.formData.endTime &&
+          this.formData.startTime)
+      ) {
+        callback(new Error('请完善时间'))
+      } else if (this.formData.startTime && this.formData.endTime) {
+        if (
+          formatTimeToTimestamp(this.formData.startTime) >=
+          formatTimeToTimestamp(this.formData.endTime)
+        ) {
+          callback(new Error('开始时间必须小于结束时间'))
+        }
+      }
+      callback()
+    }
+    return {
+      formList: [
+        { label: '公告标题', field: 'title' },
+        { label: '通知部门', field: 'dep', type: 'plus' },
+        { label: '开始时间', field: 'startTime', type: 'date' },
+        { label: '结束时间', field: 'endTime', type: 'date' },
+        { label: '公告正文', field: 'content', type: 'textarea' }
+      ],
+      formData: { dep: { staff: [], dep: [] } },
+      rules: {
+        title: [
+          { required: true, message: '公告标题不能为空', trigger: 'blur' },
+          { max: 50, message: '公告标题长度最多为50个字符', trigger: 'blur' }
+        ],
+        content: [
+          { required: true, message: '公告正文不能为空', trigger: 'blur' }
+        ],
+        startTime: [
+          { required: true, message: '不能为空', trigger: 'blur' },
+          { validator: validateTime, trigger: 'blur' }
+        ],
+        endTime: [
+          { required: true, message: '不能为空', trigger: 'blur' },
+          { validator: validateTime, trigger: 'blur' }
+        ]
+      },
+      loading: false
+    }
+  },
+  methods: {
+    onSubmit () {
+      this.$refs.form.validate(valid => {
+        if (valid) {
+          this.loading = true
+          // noticeAdd({
+          //   title: this.formData.title,
+          //   content: this.formData.content,
+          //   startTime: this.formData.startTime,
+          //   endTime: this.formData.endTime,
+          //   deptIds: this.formData.dep.dep
+          //     .map(item => {
+          //       return item.id
+          //     })
+          //     .join(','),
+          //   ownerUserIds: this.formData.dep.staff
+          //     .map(item => {
+          //       return item.userId
+          //     })
+          //     .join(',')
+          // })
+          //   .then(res => {
+          //     this.$message.success('新建公告成功')
+          //     if (this.$route.query.routerKey === 1) {
+          //       this.$router.push('notice')
+          //     } else {
+          //       this.$emit('onSubmit')
+          //     }
+          //     this.loading = false
+          //   })
+          //   .catch(() => {
+          //     this.$message.error('新建公告失败')
+          //     this.loading = false
+          //   })
+        } else {
+          return false
+        }
+      })
+    },
+    close () {
+      if (this.$route.query.routerKey === 1) {
+        this.$router.go(-1)
+      } else {
+        this.$emit('close')
+      }
+    },
+    // 关闭按钮
+    popoverSubmit (members, dep) {
+      this.$set(this.formData, 'dep', { staff: members, dep: dep })
+    },
+    // 删除部门和用户
+    deleteuser (index) {
+      this.formData.dep.staff.splice(index, 1)
+    },
+    deleteDepuser (index) {
+      this.formData.dep.dep.splice(index, 1)
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.details-box {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+  .header {
+    line-height: 40px;
+    height: 40px;
+    padding: 0 0 0 10px;
+    .text {
+      font-size: 17px;
+    }
+    .el-icon-close {
+      margin-right: 0;
+      width: 40px;
+      line-height: 40px;
+      padding: 10px;
+      cursor: pointer;
+    }
+  }
+  .content {
+    padding: 15px 20px;
+    flex: 1;
+    overflow: auto;
+    .el-form /deep/ {
+      .el-form-item {
+        margin-bottom: 10px;
+        padding-bottom: 10px;
+        float: left;
+        width: 50%;
+        // .el-form-item__content {
+        //     line-height: 40px;
+        //     height: 40px;
+        // }
+        .el-form-item__content > .el-textarea {
+          margin-top: 6px;
+        }
+        .el-form-item__label {
+          float: none;
+          font-size: 12px;
+        }
+        .el-input {
+          // width: 45%;
+          .el-input__inner {
+            vertical-align: bottom;
+          }
+        }
+        .members-dep {
+          display: inline-block;
+          width: 100%;
+          position: relative;
+          .el-textarea {
+            cursor: pointer;
+            .el-textarea__inner {
+              resize: none;
+              min-height: 34px !important;
+              // height: 34px !important;
+              padding-right: 28px;
+              overflow: hidden;
+            }
+          }
+          .el-icon-plus {
+            position: absolute;
+            right: 7px;
+            top: 50%;
+            margin-top: -4px;
+          }
+        }
+        .el-date-editor {
+          vertical-align: bottom;
+          width: 100%;
+          .el-range-separator {
+            width: 7%;
+          }
+        }
+      }
+      .el-form-itemtitle,
+      .el-form-itemstartTime {
+        padding-right: 25px;
+      }
+      .el-form-itemdep,
+      .el-form-itemendTime {
+        padding-left: 25px;
+      }
+      .el-form-itemdep {
+        margin-bottom: 11px;
+      }
+      .el-form-itemcontent {
+        width: 100%;
+      }
+    }
+  }
+  .btn-box {
+    text-align: right;
+    padding-right: 20px;
+  }
+}
+
+.user-container {
+  margin-top: 3px;
+  min-height: 34px;
+  position: relative;
+  border-radius: 3px;
+  font-size: 12px;
+  border: 1px solid #ddd;
+  color: #333333;
+  padding: 5px;
+  line-height: 15px;
+  max-height: 105px;
+  overflow-y: auto;
+  .user-item {
+    padding: 5px;
+    background-color: #e2ebf9;
+    border-radius: 3px;
+    margin: 3px;
+    cursor: pointer;
+  }
+  .add-item {
+    padding: 5px;
+    color: #4D88FF;
+    cursor: pointer;
+  }
+  .delete-icon {
+    color: #999;
+    cursor: pointer;
+  }
+  &:hover {
+    border-color: #c0c4cc;
+  }
+}
+</style>
diff --git a/src/views/OAManagement/notice/noticeCell.vue b/src/views/OAManagement/notice/noticeCell.vue
new file mode 100644
index 0000000..35873d6
--- /dev/null
+++ b/src/views/OAManagement/notice/noticeCell.vue
@@ -0,0 +1,199 @@
+<template>
+  <div
+    :id="'notice-cell' + cellIndex"
+    class="list">
+    <div class="header">
+      <div
+        v-photo="data"
+        v-lazy:background-image="$options.filters.filterUserLazyImg(data.img)"
+        class="div-photo"/>
+      <div class="name-time">
+        <p class="name">{{ data.realname }}</p>
+        <p class="time">{{ data.createTime | moment("YYYY-MM-DD HH:mm") }}</p>
+      </div>
+    </div>
+    <div
+      class="title"
+      @click="rowFun(data)">{{ data.title }}</div>
+    <div
+      v-if="data.preShow"
+      class="data-content">{{ data.content }}</div>
+    <div
+      v-else
+      class="data-content">{{ data.contentSub }}</div>
+    <div
+      v-if="data.contentSub.length < data.content.length"
+      class="load-more">
+      <span
+        v-if="!data.loadMore"
+        @click="loadMoreBtn(data)">展开全文</span>
+      <span
+        v-else
+        @click="data.loadMore = false, data.preShow = false">收起全文</span>
+    </div>
+  </div>
+</template>
+
+<script>
+// import { noticeIsReadAPI } from '@/api/oamanagement/notice'
+
+export default {
+  components: {},
+
+  props: {
+    data: Object,
+    cellIndex: Number
+  },
+
+  data () {
+    return {
+      // 父元素
+      parentTarget: null,
+      awaitMoment: false // 等客户浏览
+    }
+  },
+
+  mounted () {
+    if (this.data.isRead === 0) {
+      this.$bus.on('notice-list-box-scroll', target => {
+        this.observePreview(target)
+      })
+      this.observePreview(
+        document.getElementById('notice-cell' + this.cellIndex).parentNode
+      )
+    }
+  },
+
+  beforeDestroy () {
+    this.$bus.off('notice-list-box-scroll')
+  },
+
+  methods: {
+    /**
+     * 观察预览
+     */
+    observePreview (target) {
+      if (this.data.isRead === 0) {
+        if (target) {
+          this.parentTarget = target
+        }
+        const ispreview = this.whetherPreview()
+        if (!this.awaitMoment && ispreview) {
+          this.awaitMoment = true
+          setTimeout(() => {
+            this.awaitMoment = false
+            const ispreview = this.whetherPreview()
+            if (ispreview) {
+              this.submiteIsRead()
+            }
+          }, 3000)
+        }
+      }
+    },
+
+    /**
+     * 是否预览
+     */
+    whetherPreview () {
+      const dom = this.parentTarget.children[this.cellIndex]
+      if (this.parentTarget.getBoundingClientRect()) {
+        const offsetTop =
+          this.parentTarget.getBoundingClientRect().top -
+          dom.getBoundingClientRect().top
+        let ispreview = false
+        if (
+          offsetTop <= 0 &&
+          Math.abs(offsetTop) < this.parentTarget.clientHeight
+        ) {
+          ispreview = true
+        } else if (offsetTop > 0 && offsetTop < dom.clientHeight) {
+          ispreview = true
+        }
+        return ispreview
+      } else {
+        return false
+      }
+    },
+
+    /**
+     * 提交已读
+     */
+    submiteIsRead () {
+      // noticeIsReadAPI({
+      //   announcementId: this.data.announcementId
+      // })
+      //   .then(res => {
+      //     this.$store.dispatch('GetOAMessageNum', 'announcement')
+      //     this.data.isRead = 1
+      //   })
+      //   .catch(() => {})
+    },
+
+    /**
+     * 点击显示详情
+     */
+    rowFun (val) {
+      this.$emit('handle', {
+        type: 'detail',
+        value: val
+      })
+    },
+
+    loadMoreBtn (val) {
+      this.$set(val, 'preShow', true)
+      this.$set(val, 'loadMore', true)
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.list {
+  margin-bottom: 30px;
+  padding-bottom: 30px;
+  border-bottom: 1px solid #e6e6e6;
+  .header {
+    margin-bottom: 15px;
+    .div-photo {
+      width: 35px;
+      height: 35px;
+      border-radius: 17.5px;
+      margin-right: 10px;
+    }
+    .name-time {
+      display: inline-block;
+      .time {
+        color: #999;
+        margin-top: 5px;
+        font-size: 12px;
+      }
+    }
+  }
+  .title {
+    cursor: pointer;
+    display: inline-block;
+  }
+  .data-content {
+    margin-top: 10px;
+    color: #999;
+    font-size: 12px;
+    line-height: 18px;
+    white-space: pre-wrap;
+    word-wrap: break-word;
+    background-color: #f0f7ff;
+    padding: 15px;
+    border-radius: 3px;
+    color: #333;
+    letter-spacing: 0.5px;
+  }
+  .load-more {
+    text-align: left;
+    margin-top: 15px;
+    span {
+      cursor: pointer;
+      font-size: 13px;
+      color: #8ab7f5;
+    }
+  }
+}
+</style>
diff --git a/src/views/OAManagement/schedule/components/createSchedule.vue b/src/views/OAManagement/schedule/components/createSchedule.vue
new file mode 100644
index 0000000..64e6cdf
--- /dev/null
+++ b/src/views/OAManagement/schedule/components/createSchedule.vue
@@ -0,0 +1,647 @@
+<template>
+  <div
+    :style="{ 'z-index': zIndex }"
+    class="create-schedule">
+    <div
+      v-loading="loading"
+      class="add-schedule">
+      <div
+        slot="header"
+        class="header">
+        <span class="text">{{ text }}</span>
+        <img
+          class="el-icon-close rt"
+          src="@/assets/img/task_close.png"
+          alt=""
+          @click="close">
+      </div>
+      <div class="content">
+        <el-form
+          ref="form"
+          :model="formData"
+          :rules="rules">
+          <el-form-item
+            v-for="(item, index) in formList"
+            :prop="item.field"
+            :class="'el-form-item'+'-'+item.field"
+            :style="{'width': item.width}"
+            :label="item.label"
+            :key="index">
+            <template v-if="item.type === 'time'">
+              <el-date-picker
+                v-model="formData[item.field]"
+                type="datetime"
+                value-format="yyyy-MM-dd HH:mm:ss"
+                placeholder="选择日期时间"/>
+            </template>
+            <template v-else-if="item.type === 'textarea'">
+              <el-input
+                :autosize="{ minRows: 6}"
+                v-model="formData[item.field]"
+                type="textarea"
+                placeholder="请输入内容"/>
+            </template>
+            <template v-else-if="item.type === 'participant'">
+              <el-popover
+                placement="bottom-end"
+                width="280"
+                trigger="click">
+                <xh-user
+                  ref="xhuser"
+                  :selected-data="colleaguesList"
+                  @changeCheckout="changeCheckout"/>
+                <div
+                  slot="reference"
+                  class="select-box">
+                  <span
+                    v-for="(item, index) in colleaguesList"
+                    :key="index"
+                    class="select-box-span">
+                    {{ item.realname }}
+                    <span
+                      class="el-icon-close"
+                      @click.stop="selectDelect(item, index)"/>
+                  </span>
+                  <span class="el-icon-plus"/>
+                </div>
+              </el-popover>
+            </template>
+            <template v-else-if="item.type === 'select'">
+              <el-select
+                v-model="formData[item.field]"
+                placeholder="请选择">
+                <el-option
+                  v-for="item in options"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value"/>
+              </el-select>
+            </template>
+            <template v-else-if="item.type === 'color'">
+              <el-input
+                v-model="formData[item.field]"
+                placeholder="请输入内容">
+                <i
+                  slot="prefix"
+                  class="el-input__icon">
+                  <span
+                    :style="{'background': formData.color}"
+                    class="bg-color"/>
+                </i>
+              </el-input>
+              <div class="color-box">
+                <span
+                  v-for="(item, index) in colorList"
+                  :key="index"
+                  :style="{'background': item}"
+                  @click="changeColor(item)"/>
+              </div>
+            </template>
+            <el-input
+              v-else
+              v-model="formData[item.field]"/>
+          </el-form-item>
+        </el-form>
+        <!-- 关联业务 -->
+        <related-business
+          :all-data="allData"
+          @checkInfos="checkInfos"/>
+      </div>
+      <div class="footer">
+        <el-button
+          type="primary"
+          @click="onSubmit">保存</el-button>
+        <el-button @click="close">取消</el-button>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+// API
+// import { scheduleAdd, scheduleEdit } from '@/api/oamanagement/schedule'
+// 关联业务 - 选中列表
+import relatedBusiness from '@/components/relatedBusiness'
+import XhUser from '@/components/CreateCom/XhUser'
+import { getMaxIndex, formatTimeToTimestamp } from '@/utils/index'
+
+export default {
+  components: {
+    relatedBusiness,
+    XhUser
+  },
+  props: {
+    formData: {
+      type: Object,
+      default: () => {
+        return {
+          color: ''
+        }
+      }
+    },
+    text: {
+      type: String,
+      default: '创建日程'
+    },
+    appendToBody: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    var validateTime = (rule, value, callback) => {
+      if (this.formData.startTime && this.formData.endTime) {
+        if (
+          formatTimeToTimestamp(this.formData.startTime) >=
+          formatTimeToTimestamp(this.formData.endTime)
+        ) {
+          callback(new Error('开始时间必须小于结束时间'))
+        }
+      }
+      callback()
+    }
+    return {
+      zIndex: getMaxIndex(),
+      formList: [
+        { label: '主题', field: 'title', type: 'color' },
+        { label: '开始时间', field: 'startTime', type: 'time' },
+        { label: '结束时间', field: 'endTime', type: 'time' },
+        { label: '参与人', field: 'ownerUserIds', type: 'participant' },
+        { label: '备注', field: 'remark', type: 'textarea', width: '100%' }
+      ],
+      // 提醒
+      options: [
+        {
+          value: 0,
+          label: '无'
+        },
+        {
+          value: 1,
+          label: '准时提醒'
+        },
+        {
+          value: 2,
+          label: '5分钟前'
+        },
+        {
+          value: 3,
+          label: '15分钟前'
+        },
+        {
+          value: 4,
+          label: '30分钟前'
+        },
+        {
+          value: 5,
+          label: '一个小时前'
+        },
+        {
+          value: 6,
+          label: '二个小时前'
+        },
+        {
+          value: 7,
+          label: '一天前'
+        },
+        {
+          value: 8,
+          label: '二天前'
+        },
+        {
+          value: 9,
+          label: '一周前'
+        }
+      ],
+      // 上传的附件列表
+      fileList: [],
+      loading: false,
+      colorList: [
+        '#3E8EF7',
+        '#11C06C',
+        '#0BB2D4',
+        '#EB6709',
+        '#FF4C52',
+        '#526069',
+        '#9262F4'
+      ],
+      rules: {
+        title: [
+          { required: true, message: '主题不能为空', trigger: 'blur' },
+          { max: 50, message: '主题长度最多为50个字符', trigger: 'blur' }
+        ],
+        startTime: [
+          { required: true, message: '开始时间不能为空', trigger: 'blur' },
+          { validator: validateTime, trigger: 'blur' }
+        ],
+        endTime: [
+          { required: true, message: '结束时间不能为空', trigger: 'blur' },
+          { validator: validateTime, trigger: 'blur' }
+        ]
+      },
+      // 获取选择的数据id数组
+      relevanceAll: {},
+      allData: {},
+      // 负责人弹出框
+      colleaguesList: []
+    }
+  },
+  created () {},
+  mounted () {
+    if (this.appendToBody) {
+      document.body.appendChild(this.$el)
+    }
+    // 编辑时引用 - 自动勾选
+    this.allData.business = this.formData.businessList
+      ? this.formData.businessList
+      : []
+    this.allData.contacts = this.formData.contactsList
+      ? this.formData.contactsList
+      : []
+    this.allData.contract = this.formData.contractList
+      ? this.formData.contractList
+      : []
+    this.allData.customer = this.formData.customerList
+      ? this.formData.customerList
+      : []
+    if (this.formData.ownerList) {
+      this.colleaguesList = [].concat(this.formData.ownerList)
+    }
+    if (this.text === '创建日程') {
+      this.$set(this.formData, 'color', '#3E8EF7')
+    }
+  },
+
+  beforeDestroy () {
+    if (this.appendToBody && this.$el && this.$el.parentNode) {
+      this.$el.parentNode.removeChild(this.$el)
+    }
+  },
+  methods: {
+    close () {
+      if (this.$route.query.routerKey === 1) {
+        this.$router.go(-1)
+      } else {
+        this.$emit('closeDialog')
+      }
+    },
+    checkInfos (val) {
+      this.relevanceAll = val
+    },
+    onSubmit () {
+      this.$refs.form.validate(valid => {
+        if (valid) {
+          this.loading = true
+          // const data = this.formData
+          const ownerUserIds = []
+          for (const item of this.colleaguesList) {
+            ownerUserIds.push(item.userId)
+          }
+          if (this.text === '创建日程') {
+            // scheduleAdd({
+            //   title: data.title,
+            //   startTime: data.startTime,
+            //   endTime: data.endTime,
+            //   ownerUserIds: ownerUserIds.join(','),
+            //   remark: data.remark,
+            //   color: data.color,
+            //   customerIds: this.relevanceAll.customerIds
+            //     ? this.relevanceAll.customerIds.join(',')
+            //     : [],
+            //   contactsIds: this.relevanceAll.contactsIds
+            //     ? this.relevanceAll.contactsIds.join(',')
+            //     : [],
+            //   businessIds: this.relevanceAll.businessIds
+            //     ? this.relevanceAll.businessIds.join(',')
+            //     : [],
+            //   contractIds: this.relevanceAll.contractIds
+            //     ? this.relevanceAll.contractIds.join(',')
+            //     : []
+            // })
+            //   .then(res => {
+            //     if (this.$route.query.routerKey === 1) {
+            //       this.$router.push('schedule')
+            //     } else {
+            //       this.$emit('onSubmit')
+            //     }
+            //     this.loading = false
+            //   })
+            //   .catch(() => {
+            //     this.loading = false
+            //   })
+          } else {
+            const list = {
+              customerIds: [],
+              contractIds: [],
+              contactsIds: [],
+              businessIds: []
+            }
+            // 客户
+            if (this.allData.customer) {
+              for (const item of this.allData.customer) {
+                list.customerIds.push(item.customerId)
+              }
+            }
+            // 合同
+            if (this.allData.contract) {
+              for (const item of this.allData.contract) {
+                list.contractIds.push(item.contractId)
+              }
+            }
+            // 联系人
+            if (this.allData.contacts) {
+              for (const item of this.allData.contacts) {
+                list.contactsIds.push(item.contactsId)
+              }
+            }
+            // 关联商机
+            if (this.allData.business) {
+              for (const item of this.allData.business) {
+                list.businessIds.push(item.businessId)
+              }
+            }
+            // const ids =
+            //   JSON.stringify(this.relevanceAll) === '{}'
+            //     ? list
+            //     : this.relevanceAll
+            // scheduleEdit({
+            //   eventId: data.eventId,
+            //   title: data.title,
+            //   startTime: data.startTime,
+            //   endTime: data.endTime,
+            //   ownerUserIds: ownerUserIds.join(','),
+            //   remark: data.remark,
+            //   color: data.color,
+            //   customerIds: ids.customerIds.join(','),
+            //   contactsIds: ids.contactsIds.join(','),
+            //   businessIds: ids.businessIds.join(','),
+            //   contractIds: ids.contractIds.join(',')
+            // })
+            //   .then(res => {
+            //     this.$emit('onSubmit')
+            //     this.loading = false
+            //   })
+            //   .catch(() => {
+            //     this.loading = false
+            //   })
+          }
+        } else {
+          return false
+        }
+      })
+    },
+    // 附件 -- 上传
+    httpRequest (file) {
+      this.fileList.push(file.file)
+    },
+    // 附件 -- 删除
+    onRemove (file) {
+      for (const i in this.fileList) {
+        if (this.fileList[i].uid === file.uid) {
+          this.fileList.splice(i, 1)
+        }
+      }
+    },
+    changeColor (val) {
+      this.$set(this.formData, 'color', val)
+    },
+    changeCheckout (data) {
+      this.colleaguesList = data.data
+    },
+    // 删除选择员工
+    selectDelect (value, index) {
+      this.$refs.xhuser[0].cancelCheckItem(value)
+      this.colleaguesList.splice(index, 1)
+    }
+  }
+}
+</script>
+<style scoped lang="scss">
+.create-schedule {
+  background: #f5f6f9;
+  position: fixed;
+  top: 0;
+  right: 0;
+  left: 0;
+  bottom: 0;
+  z-index: 100;
+  padding: 40px 0;
+  .add-schedule {
+    display: flex;
+    flex-direction: column;
+    height: 100%;
+    width: 700px;
+    margin: 0 auto;
+    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+    z-index: 100;
+    padding: 20px;
+    border-radius: 4px;
+    border: 1px solid #ebeef5;
+    background-color: #fff;
+    .header {
+      line-height: 40px;
+      height: 40px;
+      padding: 0 0 0 10px;
+      .text {
+        font-size: 17px;
+      }
+      .el-icon-close {
+        margin-right: 0;
+        width: 40px;
+        line-height: 40px;
+        padding: 10px;
+        cursor: pointer;
+      }
+    }
+    .content {
+      flex: 1;
+      overflow: auto;
+      .el-form /deep/ {
+        padding: 20px 20px 0;
+        overflow: hidden;
+        .el-form-item {
+          margin-bottom: 10px;
+          padding-bottom: 10px;
+          width: 50%;
+          float: left;
+          .el-date-editor {
+            width: 100%;
+            .el-range-separator {
+              width: 7%;
+            }
+          }
+          // .el-form-item__content>.el-input {
+          //     width: 45%;
+          // }
+          .el-form-item__content {
+            .el-select {
+              width: 100%;
+              .el-input--suffix {
+                .el-input__inner {
+                  height: 34px !important;
+                }
+              }
+            }
+            .el-input__inner {
+              vertical-align: bottom;
+            }
+          }
+          .el-form-item__label {
+            float: none;
+            font-size: 12px;
+          }
+          .el-textarea {
+            margin-top: 8px;
+            .el-textarea__inner {
+              resize: none;
+            }
+          }
+          .reinvent {
+            background: #f5f5f5;
+            margin-left: 20px;
+            padding: 20px;
+            font-size: 12px;
+            margin-top: 10px;
+            .top-nav {
+              // margin-left: 50px;
+              .el-select {
+                width: 178px;
+                margin: 0 5px 0 26px;
+              }
+              .checkbox-box {
+                margin-left: 53px;
+                line-height: normal;
+                margin-top: 10px;
+                .el-checkbox-group {
+                  .el-checkbox + .el-checkbox {
+                    margin-left: 15px;
+                  }
+                }
+              }
+            }
+            .end-time {
+              margin-top: 15px;
+              .title {
+                float: left;
+                // line-height: normal;
+              }
+              .radio-box {
+                margin-left: 53px;
+                width: 178px;
+                .el-radio-group {
+                  .never {
+                    margin-top: 3px;
+                  }
+                  p {
+                    margin-bottom: 10px;
+                  }
+                  .radio-epetition {
+                    .el-select {
+                      width: 80px;
+                      margin: 0 5px;
+                    }
+                  }
+                  .radio-end-time {
+                    .el-date-editor {
+                      width: 150px;
+                      margin-left: 5px;
+                    }
+                  }
+                }
+              }
+              .result {
+                margin-left: 26px;
+                display: inline-block;
+              }
+            }
+            .el-input__inner {
+              vertical-align: middle !important;
+            }
+          }
+          .color-box {
+            margin-top: 10px;
+            line-height: normal;
+            span {
+              display: inline-block;
+              width: 18px;
+              height: 18px;
+              margin-right: 25px;
+              border-radius: 50%;
+              cursor: pointer;
+            }
+            span:last-child {
+              margin: 0;
+            }
+          }
+          .bg-color {
+            width: 15px;
+            height: 15px;
+            border-radius: 50%;
+            display: inline-block;
+            vertical-align: middle;
+          }
+          .el-input__prefix {
+            margin-top: 3px;
+            margin-left: 3px;
+          }
+        }
+        .el-form-item-ownerUserIds,
+        .el-form-item-startTime,
+        .el-form-item-remind_time {
+          padding-right: 25px;
+        }
+
+        .el-form-item-endTime,
+        .el-form-item-address {
+          padding-left: 25px;
+          padding-right: 0;
+        }
+        .el-form-item-title {
+          width: 100%;
+          margin-bottom: 5px;
+          .el-form-item__content {
+            width: 50%;
+            padding-right: 25px;
+          }
+        }
+        .select-box {
+          border: 1px solid #e6e6e6;
+          min-height: 34px;
+          line-height: 34px;
+          border-radius: 3px;
+          cursor: pointer;
+          display: inline-block;
+          width: 100%;
+          vertical-align: bottom;
+          position: relative;
+          padding-right: 36px;
+        }
+        .select-box > .el-icon-plus {
+          position: absolute;
+          top: 50%;
+          right: 0;
+          transform: translateY(-50%);
+          line-height: 34px;
+          font-size: 16px;
+          font-weight: 600;
+          color: #aaa;
+          padding-right: 10px;
+        }
+        .select-box > .select-box-span {
+          background: #eff3fc;
+          margin: 0 5px;
+          height: 27px;
+          line-height: 28px;
+          font-size: 12px;
+          color: #333;
+          padding: 0 5px;
+          display: inline-block;
+        }
+      }
+    }
+    .footer {
+      text-align: right;
+      padding-right: 20px;
+    }
+  }
+}
+</style>
diff --git a/src/views/OAManagement/schedule/components/details.vue b/src/views/OAManagement/schedule/components/details.vue
new file mode 100644
index 0000000..271fa0e
--- /dev/null
+++ b/src/views/OAManagement/schedule/components/details.vue
@@ -0,0 +1,234 @@
+<template>
+  <div class="details">
+    <el-dialog
+      :title="listData.title"
+      :visible.sync="dialogVisible"
+      :modal="false"
+      :before-close="handleClose"
+      width="400px"
+      top="30vh">
+      <div class="content">
+        <div
+          v-for="(item, index) in list"
+          :key="index"
+          class="list-data">
+          <label>{{ item.label }}:</label>
+          <span v-if="item.type=='time' && listData.time">{{ listData[item.value] }}</span>
+          <span v-else-if="item.type=='createTime'">{{ listData[item.value] }}</span>
+          <span
+            v-else-if="item.type=='ownerList'"
+            class="owner-list">
+            <span
+              v-for="(k, j) in listData[item.value]"
+              :key="j">
+              <el-tooltip
+                placement="bottom"
+                effect="light"
+                popper-class="tooltip-change-border">
+                <div slot="content">
+                  <span>{{ k.realname }}</span>
+                </div>
+                <div
+                  v-photo="k"
+                  v-lazy:background-image="$options.filters.filterUserLazyImg(k.img)"
+                  class="div-photo header-circle"/>
+              </el-tooltip>
+            </span>
+          </span>
+          <span v-else-if="item.type=='remindtype'">{{ listData.remindtypeText }}</span>
+          <span v-else-if="item.type=='createUser'">{{ listData.createUser.realname }}</span>
+          <span v-else-if="item.type=='bz'">{{ listData[item.value] }}</span>
+        </div>
+        <!-- 关联业务 -->
+        <related-business
+          :margin-left="'0'"
+          :alterable="false"
+          :all-data="allData"
+          :alterable-color="'#666'"
+          @checkRelatedDetail="checkRelatedDetail"/>
+      </div>
+      <span
+        v-if="btnShow"
+        slot="footer"
+        class="dialog-footer">
+        <el-button
+          v-if="listData.permission && listData.permission.isUpdate === 1"
+          type="primary"
+          @click="editBtn">编辑</el-button>
+        <el-button
+          v-if="listData.permission && listData.permission.isDelete === 1"
+          type="danger"
+          @click="deleteClose">删除</el-button>
+      </span>
+    </el-dialog>
+    <c-r-m-full-screen-detail
+      :visible.sync="showRelatedDetail"
+      :crm-type="relatedCRMType"
+      :id="relatedID"/>
+  </div>
+</template>
+
+<script>
+// import { scheduleDelete } from '@/api/oamanagement/schedule'
+// 关联业务 - 选中列表
+import relatedBusiness from '@/components/relatedBusiness'
+import CRMFullScreenDetail from '@/views/clients/components/CRMFullScreenDetail'
+export default {
+  components: {
+    relatedBusiness,
+    CRMFullScreenDetail
+  },
+  props: {
+    dialogVisible: Boolean,
+    listData: Object,
+    // 是否显示编辑删除按钮
+    btnShow: {
+      type: Boolean,
+      default: true
+    }
+  },
+  data () {
+    return {
+      list: [
+        { label: '开始时间', value: 'startTime', type: 'time' },
+        { label: '结束时间', value: 'endTime', type: 'time' },
+        { label: '参与人', value: 'ownerList', type: 'ownerList' },
+        { label: '创建人', value: 'realname', type: 'createUser' },
+        { label: '创建时间', value: 'createTime', type: 'createTime' },
+        { label: '备注', value: 'remark', type: 'bz' }
+      ],
+      allData: {},
+      // 相关详情的查看
+      relatedID: '',
+      relatedCRMType: '',
+      showRelatedDetail: false
+    }
+  },
+  created () {
+    const newVal = this.listData
+    this.allData.business = newVal.businessList ? newVal.businessList : ''
+    this.allData.contacts = newVal.contactsList ? newVal.contactsList : ''
+    this.allData.contract = newVal.contractList ? newVal.contractList : ''
+    this.allData.customer = newVal.customerList ? newVal.customerList : ''
+    switch (newVal.remindtype) {
+      case 0:
+        newVal.remindtypeText = '无'
+        break
+      case 1:
+        newVal.remindtypeText = '准时提醒'
+        break
+      case 2:
+        newVal.remindtypeText = '5分钟前'
+        break
+      case 3:
+        newVal.remindtypeText = '15分钟前'
+        break
+      case 4:
+        newVal.remindtypeText = '30分钟前'
+        break
+      case 5:
+        newVal.remindtypeText = '一个小时前'
+        break
+      case 6:
+        newVal.remindtypeText = '二个小时前'
+        break
+      case 7:
+        newVal.remindtypeText = '一天前'
+        break
+      case 8:
+        newVal.remindtypeText = '二天前'
+        break
+      case 9:
+        newVal.remindtypeText = '一周前'
+        break
+    }
+  },
+  methods: {
+    handleClose () {
+      this.$emit('handleClose')
+    },
+    deleteClose () {
+      this.$confirm('确定删除?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          // scheduleDelete({ eventId: this.listData.eventId }).then(res => {
+          //   this.$emit('deleteClose', this.listData)
+          //   this.$message({
+          //     type: 'success',
+          //     message: '删除成功!'
+          //   })
+          // })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    },
+    editBtn () {
+      this.$emit('editBtn', this.listData)
+    },
+    checkRelatedDetail (crmType, item) {
+      this.relatedID = item.key
+      this.relatedCRMType = crmType
+      this.showRelatedDetail = true
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.details /deep/ .el-dialog {
+  box-shadow: 0px 1px 8px 0px rgba(0, 0, 0, 0.3);
+  .el-dialog__header {
+    padding-left: 25px;
+    padding-right: 40px;
+  }
+  .el-dialog__body {
+    padding: 0 30px 30px;
+    .content {
+      padding-left: 5px;
+      padding-top: 5px;
+      .text {
+        font-size: 16px;
+        margin-bottom: 15px;
+      }
+      .list-data {
+        margin-bottom: 15px;
+        font-size: 13px;
+        color: #333;
+        label {
+          width: 70px;
+          display: inline-block;
+          text-align: left;
+          color: #666;
+        }
+        .owner-list {
+          display: inline-block;
+          vertical-align: middle;
+          span {
+            display: inline-block;
+          }
+          .div-photo {
+            width: 25px;
+            height: 25px;
+            margin-right: 10px;
+          }
+        }
+      }
+      .list-data:nth-child(3) {
+        label {
+          vertical-align: middle;
+        }
+      }
+      .related-business > span {
+        display: none;
+      }
+    }
+  }
+}
+</style>
diff --git a/src/views/OAManagement/schedule/index.vue b/src/views/OAManagement/schedule/index.vue
new file mode 100644
index 0000000..b869b6c
--- /dev/null
+++ b/src/views/OAManagement/schedule/index.vue
@@ -0,0 +1,394 @@
+<template>
+  <div class="task-calendars">
+    <div class="add-btn">
+      <el-button
+        type="primary"
+        @click="newTask">
+        创建日程
+      </el-button>
+    </div>
+    <div
+      ref="hoverDialog"
+      class="hover-dialog">
+      <div class="img-content">
+        <span>{{ hoverDialogList.startTime | moment("YYYY-MM-DD") }}</span>
+        <span v-if="hoverDialogList.endTime"> - {{ hoverDialogList.endTime | moment("YYYY-MM-DD") }}</span>
+      </div>
+      <div>
+        {{ hoverDialogList.text }}
+      </div>
+    </div>
+    <!-- 日历 -->
+    <div
+      v-loading="loading"
+      id="calendar"/>
+    <!-- 新建日程 -->
+    <create-schedule
+      v-if="showDialog"
+      :text="newText"
+      :form-data="formData"
+      @onSubmit="onSubmit"
+      @closeDialog="closeDialog"/>
+    <!-- 详情 -->
+    <v-details
+      v-if="dialogVisible"
+      :dialog-visible="dialogVisible"
+      :list-data="listData"
+      @editBtn="editBtn"
+      @deleteClose="deleteClose"
+      @handleClose="handleClose"/>
+  </div>
+</template>
+
+<script>
+import $ from 'jquery'
+import 'fullcalendar'
+import zhLocal from 'fullcalendar/dist/locale/zh-cn'
+import createSchedule from './components/createSchedule'
+import VDetails from './components/details'
+// API
+import {
+  scheduleList
+} from '@/api/oamanagement/schedule'
+
+import { timestampToFormatTime } from '@/utils'
+
+export default {
+  components: {
+    createSchedule,
+    VDetails
+  },
+  data () {
+    return {
+      showDialog: false,
+      hoverDialogList: {},
+      dialogVisible: false,
+      formData: {
+        checkList: []
+      },
+      newtext: '',
+      loading: true,
+      // 详情数据
+      listData: {}
+    }
+  },
+  watch: {
+    $route (to, from) {
+      this.$router.go(0)
+    }
+  },
+  created () {
+    const _this = this
+    $(function () {
+      _this.listFun()
+    })
+  },
+  methods: {
+    // 初始化日历任务
+    listFun () {
+      const _this = this
+      $('#calendar').fullCalendar({
+        height: document.documentElement.clientHeight - 101,
+        nextDayThreshold: '00:00:00',
+        locale: zhLocal,
+        dayClick: function (date, jsEvent, view) {
+          _this.newText = '创建日程'
+          _this.showDialog = true
+          _this.formData = {
+            startTime: timestampToFormatTime(
+              date._d.getTime(),
+              'YYYY-MM-DD HH:mm:ss'
+            ),
+            endTime: timestampToFormatTime(
+              date._d.getTime(),
+              'YYYY-MM-DD HH:mm:ss'
+            )
+          }
+        },
+        // 点击显示详情
+        eventClick: function (val, key) {
+          const list = []
+          list.push(val.startTime, val.endTime)
+          val.time = list
+          _this.listData = val
+          _this.showParticulars(val)
+        },
+        header: {
+          left: 'today,   agendaDay,agendaWeek,month',
+          center: 'prevYear,prev, title, next,nextYear',
+          right: ''
+        },
+        eventMouseover: function (event, jsEvent, view) {
+          _this.$refs.hoverDialog.style.display = 'block'
+          _this.$refs.hoverDialog.style.width =
+            document.getElementsByClassName('fc-day')[0].offsetWidth + 'px'
+          _this.$refs.hoverDialog.style.left =
+            jsEvent.currentTarget.offsetLeft - 5 + 'px'
+          _this.$refs.hoverDialog.style.top =
+            jsEvent.clientY - jsEvent.offsetY - 60 + 'px'
+          _this.hoverDialogList = {
+            time: event.start._i,
+            startTime: event.startTime,
+            endTime: event.endTime,
+            text: event.title,
+            color: event.color,
+            priority: event.priority
+          }
+        },
+        eventMouseout: function (event, jsEvent, view) {
+          _this.$refs.hoverDialog.style.display = 'none'
+        },
+        events: function (start, end, timezone, callback) {
+          _this.loading = true
+          const startTime = timestampToFormatTime(
+            parseInt(start._i / 1000),
+            'YYYY-MM-DD'
+          )
+          const endTime = timestampToFormatTime(
+            parseInt(end._i / 1000),
+            'YYYY-MM-DD'
+          )
+          scheduleList({
+            startTime: startTime,
+            endTime: endTime
+          })
+            .then(res => {
+              const list = res.data.map(item => {
+                item.start = item.startTime
+                item.end = item.endTime
+                item.color = item.color
+                item.textColor = '#333'
+                return item
+              })
+              callback(list)
+              _this.loading = false
+            })
+            .catch(() => {
+              _this.loading = false
+            })
+        }
+      })
+    },
+    // 详情数据
+    showParticulars (val) {
+      this.dialogVisible = true
+    },
+    // 详情关闭
+    handleClose () {
+      this.dialogVisible = false
+    },
+    // 详情删除
+    deleteClose (val) {
+      $('#calendar').fullCalendar('refetchEvents')
+      this.handleClose()
+    },
+    // 详情编辑
+    editBtn (val) {
+      this.newText = '编辑日程'
+      val.startTime = val.startTime
+      val.endTime = val.endTime
+      this.formData = val
+      this.handleClose()
+      this.showDialog = true
+    },
+    // 新建按钮
+    newTask () {
+      this.newText = '创建日程'
+      this.showDialog = true
+      this.formData = {
+        checkList: []
+      }
+    },
+    // 新建日程关闭按钮
+    closeDialog () {
+      this.showDialog = false
+    },
+    // 新建提交
+    onSubmit (data, file) {
+      if (this.newText === '创建日程') {
+        this.$message.success('新建成功')
+        $('#calendar').fullCalendar('refetchEvents')
+        this.closeDialog()
+      } else {
+        this.$message.success('编辑成功')
+        $('#calendar').fullCalendar('refetchEvents')
+        this.closeDialog()
+      }
+    }
+  }
+}
+</script>
+
+<style>
+@import 'fullcalendar/dist/fullcalendar.css';
+</style>
+
+<style lang="scss" scoped>
+.task-calendars {
+  position: relative;
+  border: 1px solid #e6e6e6;
+  border-radius: 4px;
+  .hover-dialog {
+    display: none;
+    padding: 15px;
+    z-index: 99;
+    position: absolute;
+    background: #fff;
+    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+    border-left: 2px solid transparent;
+    .img-content {
+      color: #999;
+      margin-bottom: 10px;
+      font-size: 12px;
+      img {
+        vertical-align: middle;
+      }
+    }
+  }
+  .add-btn {
+    position: absolute;
+    top: 14px;
+    right: 40px;
+  }
+  #calendar {
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+    background: #fff;
+  }
+  #calendar /deep/ .fc-license-message {
+    display: none !important;
+  }
+  #calendar /deep/ .fc-toolbar {
+    padding-top: 1em;
+    .fc-left {
+      padding-left: 20px;
+      .fc-button-group {
+        .fc-button {
+          text-shadow: none;
+        }
+        .fc-state-default {
+          background: #f0f0f0;
+          padding: 0 1.2em;
+          border: 0;
+          margin-right: 3px;
+        }
+        .fc-state-down {
+          box-shadow: none;
+          text-shadow: none;
+        }
+        .fc-state-active {
+          background: #4D88FF;
+          color: #fff;
+        }
+      }
+      .fc-today-button {
+        background: #fff;
+        margin-right: 50px;
+      }
+    }
+    .fc-center {
+      margin-left: -277px;
+      h2 {
+        font-size: 20px;
+        font-weight: normal;
+        margin-top: 5px;
+      }
+      .fc-prevYear-button,
+      .fc-prev-button,
+      .fc-next-button,
+      .fc-nextYear-button {
+        background: none;
+        border: 0;
+        color: #aaa;
+        outline: none;
+        box-shadow: none;
+      }
+      .fc-button-group {
+        .fc-prev-button .fc-icon-left-single-arrow:after,
+        .fc-next-button .fc-icon-right-single-arrow:after {
+          font-size: 160%;
+          font-weight: none;
+        }
+      }
+    }
+  }
+  #calendar /deep/ .fc-view-container {
+    .fc-body {
+      .fc-row {
+        .fc-day {
+          border-color: #e9e9e9;
+        }
+        .fc-bg {
+          .fc-sat,
+          .fc-sun {
+            background: #fbfbfb;
+          }
+          .fc-today {
+            background: none;
+          }
+        }
+        .fc-content-skeleton {
+          .fc-today {
+            .fc-day-number {
+              background: #4D88FF;
+              border-radius: 50%;
+              padding: 3px;
+              color: #fff;
+              min-width: 16px;
+              text-align: center;
+            }
+          }
+          .fc-day-grid-event {
+            border: 0 !important;
+            border-radius: 23px;
+            margin-left: 5px;
+            margin-right: 5px;
+            .fc-content {
+              color: #fff;
+              .fc-time {
+                display: none;
+              }
+              .fc-title {
+                float: left;
+                width: 100%;
+                overflow: hidden;
+                white-space: nowrap;
+                text-overflow: ellipsis;
+              }
+            }
+          }
+        }
+        .fc-day-number {
+          margin: 5px;
+        }
+        .fc-day-grid-event {
+          border-left: 2px solid #ff9668 !important;
+          border-radius: 0;
+          margin-left: 0;
+          margin-right: 0;
+          padding: 2px 15px;
+        }
+      }
+    }
+    .fc-body > tr > .fc-widget-content {
+      border: 0;
+    }
+    .fc-head {
+      .fc-head-container {
+        border: 0;
+        border-bottom: 1px solid #ddd;
+      }
+    }
+  }
+  #calendar /deep/ .fc-day-header {
+    background: #f5f5f5;
+    border-width: 0;
+    font-weight: normal;
+    span {
+      height: 50px;
+      line-height: 50px;
+    }
+  }
+}
+</style>
diff --git a/src/views/OAManagement/styles/content.scss b/src/views/OAManagement/styles/content.scss
new file mode 100644
index 0000000..7165896
--- /dev/null
+++ b/src/views/OAManagement/styles/content.scss
@@ -0,0 +1,24 @@
+@mixin v-align {
+    vertical-align: middle;
+}
+@mixin cursor {
+    cursor: pointer;
+}
+@mixin color9 {
+    color: #999;
+}
+.popover-btn-group {
+    margin: -12px;
+    padding: 10px 0;
+    p {
+        font-size: 13px;
+        height: 26px;
+        line-height: 26px;
+        padding-left: 20px;
+        @include cursor;
+    }
+}
+.popover-btn-group p:hover {
+    background: #F7F8FA;
+    color: #4D88FF;
+}
\ No newline at end of file
diff --git a/src/views/OAManagement/styles/tabs.scss b/src/views/OAManagement/styles/tabs.scss
new file mode 100644
index 0000000..57cbeb3
--- /dev/null
+++ b/src/views/OAManagement/styles/tabs.scss
@@ -0,0 +1,22 @@
+.el-tabs /deep/ .el-tabs__header {
+    margin: 0 15px 15px;
+    .el-tabs__item {
+        height: 50px;
+        line-height: 50px;
+    }
+    .el-tabs__nav {
+        margin-left: 15px;
+    }
+    .el-tabs__nav-wrap::after {
+        height: 1px;
+    }
+}
+.oa-bgcolor {
+    background: #fff;
+    height: 100%;
+    width: 920px;
+    // width: 100%;
+    // margin: 0 auto;
+    border: 1px solid #E6E6E6;
+    border-radius: 4px;
+}
\ No newline at end of file
diff --git a/src/views/OAManagement/task/components/myTask.vue b/src/views/OAManagement/task/components/myTask.vue
new file mode 100644
index 0000000..6bb35ef
--- /dev/null
+++ b/src/views/OAManagement/task/components/myTask.vue
@@ -0,0 +1,283 @@
+<template>
+  <div class="my-task">
+    <slot name="searchInput"/>
+    <div class="select-box">
+      <!-- 筛选 -->
+      <div
+        v-if="listType === 'subtask'"
+        class="select-group">
+        <label>任务类型</label>
+        <el-select
+          v-model="fromData.type"
+          placeholder="请选择"
+          @change="selectChange">
+          <el-option
+            v-for="item in subordinateOption"
+            :key="item.key"
+            :label="item.label"
+            :value="item.key"/>
+        </el-select>
+      </div>
+      <div
+        v-else
+        class="select-group">
+        <label>任务类型</label>
+        <el-select
+          v-model="fromData.type"
+          placeholder="请选择"
+          @change="selectChange">
+          <el-option
+            v-for="item in typeOptions"
+            :key="item.key"
+            :label="item.label"
+            :value="item.key"/>
+        </el-select>
+      </div>
+      <div class="select-group">
+        <label>状态</label>
+        <el-select
+          v-model="fromData.status"
+          placeholder="请选择"
+          @change="selectChange">
+          <el-option
+            v-for="item in statusOptions"
+            :key="item.key"
+            :label="item.label"
+            :value="item.key"/>
+        </el-select>
+      </div>
+      <div class="select-group">
+        <label>优先级</label>
+        <el-select
+          v-model="fromData.priority"
+          placeholder="请选择"
+          @change="selectChange">
+          <el-option
+            v-for="item in priorityOptions"
+            :key="item.key"
+            :label="item.label"
+            :value="item.key"/>
+        </el-select>
+      </div>
+      <div class="select-group">
+        <label>截止时间</label>
+        <el-select
+          v-model="fromData.date"
+          placeholder="请选择"
+          @change="selectChange">
+          <el-option
+            v-for="item in timeOptions"
+            :key="item.key"
+            :label="item.label"
+            :value="item.key"/>
+        </el-select>
+      </div>
+      <div
+        v-if="listType === 'subtask'"
+        class="select-group">
+        <label class="min-width">负责人</label>
+        <el-select
+          v-model="fromData.subUser"
+          placeholder="请选择"
+          @change="selectChange">
+          <el-option
+            v-for="item in subUserListData"
+            :key="item.userId"
+            :label="item.realname"
+            :value="item.userId"/>
+        </el-select>
+      </div>
+    </div>
+    <div class="list-box-container">
+      <div class="list-box">
+        <task-cell
+          v-for="(item, index) in list"
+          :key="index"
+          :data="item"
+          :data-index="index"
+          @on-handle="taskCellHandle"/>
+      </div>
+      <p class="load">
+        <el-button
+          :loading="loadMoreLoading"
+          type="text">{{ loadMoreLoading ? '加载更多' : '没有更多了' }}</el-button>
+      </p>
+    </div>
+    <!-- 详情 -->
+    <particulars
+      v-if="taskDetailShow"
+      ref="particulars"
+      :id="taskID"
+      :detail-index="detailIndex"
+      @on-handle="detailHandle"
+      @close="closeBtn"/>
+  </div>
+</template>
+
+<script>
+import particulars from '../components/particulars'
+import listTaskDetail from '../mixins/listTaskDetail.js'
+import TaskCell from './taskCell'
+
+export default {
+  components: {
+    TaskCell,
+    particulars
+  },
+  mixins: [listTaskDetail],
+  props: {
+    listType: '',
+    list: Array,
+    // 负责人
+    subUserListData: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    loadMoreLoading: false
+  },
+  data () {
+    return {
+      fromData: {
+        type: '0',
+        status: '1',
+        priority: '',
+        date: '',
+        subUser: ''
+      },
+      // 任务类型
+      typeOptions: [
+        { label: '全部', key: '0' },
+        { label: '我负责的', key: '1' },
+        { label: '我创建的', key: '2' },
+        { label: '我参与的', key: '3' }
+      ],
+      // 下属任务类型
+      subordinateOption: [
+        { label: '全部', key: '0' },
+        { label: '下属负责的', key: '1' },
+        { label: '下属创建的', key: '2' },
+        { label: '下属参与的', key: '3' }
+      ],
+      // 状态
+      statusOptions: [
+        { label: '全部', key: '' },
+        { label: '正在进行', key: '1' },
+        { label: '已完成', key: '5' }
+      ],
+      // 优先级
+      priorityOptions: [
+        { label: '全部', key: '' },
+        { label: '高', key: '3' },
+        { label: '中', key: '2' },
+        { label: '低', key: '1' },
+        { label: '无', key: '0' }
+      ],
+      // 截至时间
+      timeOptions: [
+        { label: '全部', key: '' },
+        { label: '今天到期', key: '1' },
+        { label: '明天到期', key: '2' },
+        { label: '一周到期', key: '3' },
+        { label: '一个月到期', key: '4' }
+      ]
+    }
+  },
+  mounted () {
+    document
+      .getElementById('workbench-main-container')
+      .addEventListener('click', this.taskShowHandle, false)
+  },
+  methods: {
+    selectChange (val, key) {
+      this.$emit('selectChange', { type: this.listType, data: this.fromData })
+    },
+    // 点击空白处关闭详情
+    taskShowHandle (e) {
+      if (
+        this.$refs.particulars &&
+        !this.$refs.particulars.$el.contains(e.target)
+      ) {
+        let hidden = true
+        const items = document.getElementsByClassName('list-box')
+        for (let index = 0; index < items.length; index++) {
+          const element = items[index]
+          if (element.contains(e.target)) {
+            hidden = false
+            break
+          }
+        }
+        this.taskDetailShow = !hidden
+      }
+    },
+    taskCellHandle (data) {
+      if (data.type === 'view') {
+        this.showDetailView(data.data.item, data.data.index)
+      }
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.my-task {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  overflow-y: hidden;
+  .wukong {
+    vertical-align: middle;
+  }
+  .select-box {
+    margin-top: 22px;
+    margin-bottom: 20px;
+    // margin-right: -33px;
+    max-width: 855px;
+    overflow: hidden;
+    .select-group {
+      margin-bottom: 12px;
+      width: 190px;
+      float: left;
+      label {
+        color: #999;
+        margin-right: 10px;
+      }
+      .el-select /deep/ {
+        width: 116px;
+        .el-input__inner {
+          height: 30px;
+          line-height: 30px;
+        }
+      }
+      .min-width {
+        width: 56px;
+        display: inline-block;
+      }
+    }
+    .select-group:nth-child(2) {
+      padding-left: 15px;
+    }
+    .select-submit {
+      float: right;
+      margin-right: 10px;
+    }
+  }
+  .list-box-container {
+    flex: 1;
+    overflow-y: auto;
+  }
+}
+
+.load {
+  color: #999;
+  font-size: 13px;
+  margin: 0 auto 15px;
+  text-align: center;
+  .el-button,
+  .el-button:focus {
+    color: #ccc;
+    cursor: auto;
+  }
+}
+</style>
diff --git a/src/views/OAManagement/task/components/newDialog.vue b/src/views/OAManagement/task/components/newDialog.vue
new file mode 100644
index 0000000..b32efa3
--- /dev/null
+++ b/src/views/OAManagement/task/components/newDialog.vue
@@ -0,0 +1,443 @@
+<template>
+  <div class="my-task-dialog">
+    <el-dialog
+      v-loading="newLoading"
+      :visible.sync="newDialogVisible"
+      :show-close="false"
+      :close-on-click-modal="false"
+      :before-close="handleClose"
+      title="新建任务"
+      width="700px">
+      <img
+        class="el-icon-close"
+        src="@/assets/img/task_close.png"
+        alt=""
+        @click="handleClose">
+      <el-form
+        ref="form"
+        :model="formInline"
+        :rules="rules">
+        <el-form-item
+          v-for="(item, index) in formList"
+          :class="'el-form-item'+ '-' + item.field"
+          :label="item.label"
+          :prop="item.field"
+          :key="index">
+          <el-input
+            v-if="item.type === 'textarea'"
+            :autosize="{ minRows: 4}"
+            v-model="formInline[item.field]"
+            type="textarea"/>
+          <el-date-picker
+            v-else-if="item.type === 'time'"
+            v-model="formInline[item.field]"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="选择日期"/>
+          <div
+            v-else-if="item.type === 'priority'"
+            class="priority-box">
+            <el-radio-group
+              v-model="formInline[item.field]"
+              fill="red"
+              text-color="#FFF">
+              <el-radio :label="3">高</el-radio>
+              <el-radio :label="2">中</el-radio>
+              <el-radio :label="1">低</el-radio>
+              <el-radio :label="0">无</el-radio>
+            </el-radio-group>
+          </div>
+          <div
+            v-else-if="item.type === 'popover'"
+            class="type-popover">
+            <el-popover
+              placement="bottom-end"
+              width="280"
+              trigger="click">
+              <xh-user
+                ref="xhuser"
+                :radio="radio"
+                :selected-data="colleaguesList"
+                @changeCheckout="changeCheckout"/>
+              <div
+                slot="reference"
+                class="select-box">
+                <span
+                  v-for="(item, index) in colleaguesList"
+                  :key="index"
+                  class="select-box-span">
+                  {{ item.realname }}
+                  <span
+                    class="el-icon-close"
+                    @click.stop="selectDelect(item, index)"/>
+                </span>
+                <span class="el-icon-plus"/>
+              </div>
+            </el-popover>
+          </div>
+          <el-input
+            v-else
+            v-model="formInline[item.field]"/>
+        </el-form-item>
+        <related-business
+          :all-data="allData"
+          :margin-left="'0'"
+          @checkInfos="checkInfos"/>
+      </el-form>
+      <span
+        slot="footer"
+        class="dialog-footer">
+        <el-button
+          type="primary"
+          @click="dialogVisibleSubmit">保存</el-button>
+        <el-button @click="handleClose">取消</el-button>
+      </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+// 关联业务 - 选中列表
+import relatedBusiness from '@/components/relatedBusiness'
+import XhUser from '@/components/CreateCom/XhUser'
+
+export default {
+  components: {
+    relatedBusiness,
+    XhUser
+  },
+  props: {
+    newDialogVisible: Boolean,
+    newLoading: Boolean
+  },
+  data () {
+    return {
+      formInline: {
+        priority: 0
+      },
+      formList: [
+        { label: '任务名称', field: 'name' },
+        { label: '负责人', field: 'mainUserId', type: 'popover' },
+        { label: '开始时间', field: 'startTime', type: 'time' },
+        { label: '结束时间', field: 'stopTime', type: 'time' },
+        { label: '优先级', field: 'priority', type: 'priority' },
+        { label: '任务描述', field: 'description', type: 'textarea' }
+      ],
+      // 上传附件
+      uploadFile: [],
+      // 负责人弹出框
+      colleaguesList: [],
+      popoverModel: false,
+      rules: {
+        name: [
+          { required: true, message: '任务名称不能为空', trigger: 'blur' },
+          { max: 50, message: '任务名称长度最多为50个字符', trigger: 'blur' }
+        ]
+      },
+      // 获取选择的数据id数组
+      relevanceAll: {},
+      allData: {},
+      radio: true
+    }
+  },
+  watch: {
+    newDialogVisible (value) {
+      if (!value) {
+        this.formInline = {
+          priority: 0
+        }
+      }
+    }
+  },
+  created () {},
+  methods: {
+    handleClose () {
+      this.$emit('handleClose')
+    },
+    dialogVisibleSubmit () {
+      this.$refs.form.validate(valid => {
+        if (valid) {
+          var formInlineCopy = Object.assign({}, this.formInline)
+          formInlineCopy = {
+            mainUserId:
+              this.colleaguesList.length === 0
+                ? ''
+                : this.colleaguesList[0].userId,
+            startTime: this.formInline.startTime,
+            stopTime: this.formInline.stopTime,
+            description: this.formInline.description,
+            priority: this.formInline.priority,
+            name: this.formInline.name,
+            customerIds:
+              this.relevanceAll.customerIds &&
+              this.relevanceAll.customerIds.length
+                ? ',' + this.relevanceAll.customerIds.join(',') + ','
+                : '',
+            contactsIds:
+              this.relevanceAll.contactsIds &&
+              this.relevanceAll.contactsIds.length
+                ? ',' + this.relevanceAll.contactsIds.join(',') + ','
+                : '',
+            businessIds:
+              this.relevanceAll.businessIds &&
+              this.relevanceAll.businessIds.length
+                ? ',' + this.relevanceAll.businessIds.join(',') + ','
+                : '',
+            contractIds:
+              this.relevanceAll.contractIds &&
+              this.relevanceAll.contractIds.length
+                ? ',' + this.relevanceAll.contractIds.join(',') + ','
+                : ''
+          }
+          this.$emit('dialogVisibleSubmit', formInlineCopy)
+        } else {
+          return false
+        }
+      })
+    },
+    checkInfos (val) {
+      this.relevanceAll = val
+    },
+    changeCheckout (data) {
+      this.colleaguesList = data.data
+    },
+    // 删除选择员工
+    selectDelect (value, index) {
+      if (this.radio) {
+        // 如果单选告知删除
+        this.$refs.xhuser[0].changeCheckout([])
+      }
+      this.colleaguesList.splice(index, 1)
+    }
+  }
+}
+</script>
+<style scoped lang="scss">
+.my-task-dialog /deep/ .el-dialog {
+  padding: 20px;
+  .el-dialog__header {
+    padding: 0 0 0 10px;
+    .el-dialog__title {
+      display: inline-block;
+      height: 40px;
+      line-height: 40px;
+      font-size: 17px;
+    }
+    .el-dialog__headerbtn {
+      display: none;
+    }
+  }
+  .el-dialog__body {
+    img.el-icon-close {
+      position: absolute;
+      top: 20px;
+      right: 20px;
+      width: 40px;
+      height: 40px;
+      padding: 10px;
+    }
+    .el-form {
+      overflow: auto;
+      flex: 1;
+      padding: 20px;
+      .el-date-editor {
+        vertical-align: bottom;
+      }
+      .el-radio-group {
+        vertical-align: super;
+      }
+      .el-textarea {
+        margin-top: 7px;
+      }
+      .el-form-item-name,
+      .el-form-item-startTime {
+        padding-right: 25px;
+      }
+      .el-form-item-mainUserId,
+      .el-form-item-stopTime {
+        padding-left: 25px;
+      }
+      .el-form-item-priority,
+      .el-form-item-description,
+      .el-form-item-time {
+        width: 100%;
+      }
+    }
+  }
+}
+</style>
+
+<style lang="scss" scoped>
+.my-task-dialog /deep/ .el-dialog__wrapper {
+  background: #f5f6f9;
+  padding: 40px 0;
+  overflow: hidden;
+}
+.my-task-dialog /deep/ .el-dialog {
+  height: 100%;
+  margin-top: 0 !important;
+  /* margin-bottom: 40px; */
+  display: flex;
+  flex-direction: column;
+  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+}
+.my-task-dialog /deep/ .el-dialog .el-dialog__body {
+  padding: 0;
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  overflow: hidden;
+}
+.my-task-dialog /deep/ .el-dialog .el-dialog__footer {
+  margin-right: 20px;
+}
+.colleagues-list p {
+  height: 34px;
+  line-height: 34px;
+  padding-left: 20px;
+  cursor: pointer;
+  margin: 0 -12px;
+}
+.colleagues-list p:hover {
+  -webkit-box-shadow: 0 0 8px 2px #eee;
+  box-shadow: 0 0 8px 2px #eee;
+  background: 0 0;
+}
+.el-form /deep/ .el-form-item {
+  margin-bottom: 10px;
+  padding-bottom: 6px;
+  width: 50%;
+  display: inline-block;
+}
+.my-task-dialog /deep/ .el-form-item__content > .el-date-editor {
+  width: 100%;
+}
+.my-task-dialog /deep/ .el-form-item__content .el-input .el-input__inner {
+  vertical-align: middle;
+}
+.my-task-dialog /deep/ .el-form-item__content .el-select {
+  width: 100%;
+}
+.my-task-dialog /deep/ .el-form-item__content .el-textarea .el-textarea__inner {
+  resize: none;
+}
+.select-box {
+  border: 1px solid #e6e6e6;
+  height: 34px;
+  line-height: 34px;
+  border-radius: 3px;
+  cursor: pointer;
+  display: inline-block;
+  width: 100%;
+  vertical-align: middle;
+}
+
+.select-box > .el-icon-plus {
+  float: right;
+  line-height: 34px;
+  font-size: 16px;
+  font-weight: 600;
+  color: #aaa;
+  padding-right: 10px;
+}
+.select-box > .select-box-span {
+  background: #eff3fc;
+  margin: 0 5px;
+  height: 27px;
+  line-height: 28px;
+  font-size: 12px;
+  color: #333;
+  padding: 0 5px;
+  display: inline-block;
+}
+.my-task-dialog /deep/ .el-form-item__label {
+  display: block;
+  width: 100%;
+  text-align: left;
+  font-size: 12px;
+}
+.my-task-dialog /deep/ .el-range-separator {
+  width: auto;
+}
+.priority-box /deep/ .el-radio {
+  margin-left: 0;
+  width: 34px;
+  height: 34px;
+  line-height: 32px;
+  margin-right: 14px;
+  text-align: center;
+}
+.priority-box /deep/ .el-radio .el-radio__input {
+  display: none;
+}
+.priority-box /deep/ .el-radio .el-radio__label {
+  padding: 0;
+  width: 100%;
+  height: 100%;
+  display: inline-block;
+  text-align: center;
+  border-radius: 50%;
+  font-size: 12px;
+  cursor: pointer;
+  border: 1px solid #ccc;
+  color: #cccccc;
+}
+.priority-box /deep/ .el-radio:nth-child(2) .el-radio__label {
+  border: 1px solid #ff9668;
+  color: #ff9668;
+}
+.priority-box /deep/ .el-radio:nth-child(3) .el-radio__label {
+  border: 1px solid #8bb5f0;
+  color: #8bb5f0;
+}
+.priority-box /deep/ .el-radio:nth-child(1) .el-radio__label {
+  border: 1px solid #ed6363;
+  color: #ed6363;
+}
+.priority-box
+  /deep/
+  .el-radio:nth-child(4)
+  .el-radio__input.is-checked
+  + .el-radio__label {
+  color: #fff;
+  background: #cccccc;
+  border-color: #cccccc;
+}
+.priority-box
+  /deep/
+  .el-radio:nth-child(2)
+  .el-radio__input.is-checked
+  + .el-radio__label {
+  color: #fff;
+  background: #ff9668;
+  border-color: #ff9668;
+}
+.priority-box
+  /deep/
+  .el-radio:nth-child(3)
+  .el-radio__input.is-checked
+  + .el-radio__label {
+  color: #fff;
+  background: #8bb5f0;
+  border-color: #8bb5f0;
+}
+.priority-box
+  /deep/
+  .el-radio:nth-child(1)
+  .el-radio__input.is-checked
+  + .el-radio__label {
+  color: #fff;
+  background: #ed6363;
+  border-color: #ed6363;
+}
+.upload-demo {
+  display: inline-block;
+}
+.img-text-color {
+  margin-top: 20px;
+  color: #4D88FF;
+}
+.img-center {
+  vertical-align: middle;
+}
+</style>
diff --git a/src/views/OAManagement/task/components/particulars.vue b/src/views/OAManagement/task/components/particulars.vue
new file mode 100644
index 0000000..d8e6a44
--- /dev/null
+++ b/src/views/OAManagement/task/components/particulars.vue
@@ -0,0 +1,2080 @@
+<template>
+  <!-- <div class="particulars-common"> -->
+  <transition name="slide-fade">
+    <el-card
+      v-loading="loading"
+      :style="{ 'z-index': zIndex }"
+      class="particulars-common">
+      <!-- 头部信息 -->
+      <div
+        v-if="taskData"
+        slot="header"
+        class="clear-fix">
+        <div class="img-box-grop">
+          <div>
+            <el-popover
+              v-model="priorityVisible"
+              placement="bottom-start"
+              width="200"
+              trigger="click">
+              <div class="particulars-priority-box">
+                <p
+                  v-for="(item, index) in particularsList"
+                  :key="index"
+                  @click="priorityBtn(item, taskData.priority)">
+                  <span :style="{'border-color': item.color, 'background': item.id === taskData.priority ? item.color: 'transparent', 'color': item.id === taskData.priority ? '#fff': item.color}">{{ item.label }}</span>
+                </p>
+              </div>
+              <span slot="reference">
+                <i class="wukong wukong-lightning"/>
+                <span>优先级</span>
+              </span>
+            </el-popover>
+          </div>
+          <div>
+            <tag-index
+              :placement="'bottom'"
+              :task-data="taskData">
+              <div slot="editIndex">
+                <i class="wukong wukong-label"/>
+                <span>标签</span>
+              </div>
+            </tag-index>
+          </div>
+          <div
+            v-if="taskData.pid === 0"
+            @click="addSubtasksBtn">
+            <i class="wukong wukong-sub-task"/>
+            <span>子任务</span>
+          </div>
+          <div>
+            <el-upload
+              :http-request="httpRequest"
+              class="upload-demo"
+              action="https://jsonplaceholder.typicode.com/posts/"
+              multiple
+              list-type="picture">
+              <i class="wukong wukong-file"/>
+              <span>附件</span>
+            </el-upload>
+          </div>
+          <div>
+            <el-popover
+              placement="bottom"
+              width="80"
+              trigger="click">
+              <div class="more-btn-group">
+                <p @click="moreDelete">删 除</p>
+              </div>
+              <span slot="reference">
+                <img src="@/assets/img/task_ellipsis.png">
+              </span>
+            </el-popover>
+          </div>
+          <div class="task-close-img">
+            <img
+              src="@/assets/img/task_close.png"
+              @click="closeBtn">
+          </div>
+        </div>
+      </div>
+      <div
+        v-if="taskData"
+        class="body-content">
+        <slot name="extraContent"/>
+        <div class="card-content-box">
+          <el-checkbox
+            v-model="taskData.checked"
+            @change="titleCheckbox"/>
+          <div class="card-content">
+            <div class="card-content-row margin-bottom-15">
+              <div class="priority-data-name">
+                <div
+                  v-show="!nameVinput"
+                  :style="{'text-decoration': taskData.checked ? 'line-through' : 'none'}"
+                  class="title-text">
+                  {{ taskData.name }}
+                  <span
+                    class="el-icon-edit-outline"
+                    @click="nameVinput = true, taskDataName = taskData.name"/>
+                </div>
+                <div
+                  v-show="nameVinput"
+                  class="show-input">
+                  <el-input
+                    v-model="taskDataName"
+                    :maxlength="50"
+                    size="medium"/>
+                  <div class="btn-box">
+                    <el-button
+                      type="primary"
+                      size="mini"
+                      @click="nameVShow(taskDataName)">保 存</el-button>
+                    <el-button
+                      size="mini"
+                      @click="nameVinput = false">取 消</el-button>
+                  </div>
+                </div>
+              </div>
+              <div class="card-row-right">
+                <flexbox class="text-right">
+                  <div class="color-label user-name-label"> 负责人: </div>
+                  <div
+                    v-if="taskData.mainUser"
+                    class="bg-position">
+                    <el-tooltip
+                      placement="bottom"
+                      effect="light"
+                      popper-class="tooltip-change-border">
+                      <div slot="content">
+                        <span>{{ taskData.mainUser.realname }}</span>
+                      </div>
+                      <div
+                        v-photo="taskData.mainUser"
+                        v-lazy:background-image="$options.filters.filterUserLazyImg(taskData.mainUser.img)"
+                        class="div-photo main-user-name"/>
+                    </el-tooltip>
+                    <img
+                      src="@/assets/img/delete_task.png"
+                      class="el-icon-close"
+                      alt=""
+                      @click="editMainUser('')">
+                  </div>
+                  <template v-else>
+                    <el-popover
+                      placement="bottom"
+                      width="280"
+                      trigger="click">
+                      <xh-user
+                        ref="xhuser"
+                        radio
+                        @changeCheckout="editMainUser"/>
+                      <i
+                        slot="reference"
+                        class="wukong wukong-addition-task"/>
+                    </el-popover>
+                  </template>
+                </flexbox>
+              </div>
+            </div>
+            <div
+              v-if="taskData.labelList"
+              class="card-content-row  margin-bottom-25">
+              <div class="particulars-priority-copy">
+                <template v-show="taskData.labelList.length !== 0">
+                  <span
+                    v-for="(item, index) in taskData.labelList"
+                    :style="{'background': item.color ? item.color : '#ccc'}"
+                    :key="index"
+                    class="item-color">
+                    {{ item.labelName }}
+                  </span>
+                </template>
+                <div class="add-tag">
+                  <tag-index
+                    :placement="'right'"
+                    :task-data="taskData">
+                    <div slot="editIndex">
+                      <span class="el-icon-plus"/>
+                      <span class="label">标签</span>
+                    </div>
+                  </tag-index>
+                </div>
+              </div>
+              <div class="card-row-right">
+                <div class="text-right">
+                  <span class="color-label"> 截止日期: </span>
+                  <div class="time-top">
+                    <el-date-picker
+                      ref="endTime"
+                      :class="{ 'no-time-top': !taskData.stopTime }"
+                      v-model="taskData.stopTime"
+                      :clearable="false"
+                      type="date"
+                      value-format="yyyy-MM-dd"
+                      placeholder=""
+                      @change="endTimeChange"/>
+                    <img
+                      v-if="taskData.stopTime"
+                      src="@/assets/img/delete_task.png"
+                      class="el-icon-close time-top-close"
+                      alt=""
+                      @click.stop="deleteTimeTop(taskData.stopTime)">
+                  </div>
+                </div>
+              </div>
+            </div>
+            <div class="add-description">
+              <div v-show="!addDescriptionShow">
+                <div
+                  v-if="taskData.description"
+                  @click="addDescriptionShow = true; addDescriptionTextarea = taskData.description">{{ taskData.description }}</div>
+                <div
+                  v-else
+                  class="no-description">
+                  <span class="color-label">暂无描述</span>
+                  <el-button
+                    type="text"
+                    icon="el-icon-plus"
+                    @click="addDescriptionShow = true">添加描述</el-button>
+                </div>
+              </div>
+              <div v-show="addDescriptionShow">
+                <el-input
+                  :autosize="{ minRows: 2}"
+                  v-model="addDescriptionTextarea"
+                  type="textarea"
+                  placeholder="请输入内容"/>
+                <div class="btn-box">
+                  <el-button
+                    type="primary"
+                    size="mini"
+                    @click="addDescriptionSubmit">保 存</el-button>
+                  <el-button
+                    type="text"
+                    size="mini"
+                    @click="addDescriptionShow = false">取 消</el-button>
+                </div>
+              </div>
+            </div>
+            <div class="card-content-row card-content-row-column">
+              <flexbox>
+                <div class="color-label participant">
+                  <i class="wukong wukong-user"/>
+                  <span>参与人: </span>
+                </div>
+                <div
+                  v-if="taskData.ownerUserList"
+                  class="participant-class">
+                  <span
+                    v-for="(item, index) in taskData.ownerUserList"
+                    :key="index"
+                    class="owner-list">
+                    <el-tooltip
+                      placement="bottom"
+                      effect="light"
+                      popper-class="tooltip-change-border">
+                      <div slot="content">
+                        <span>{{ item.realname }}</span>
+                      </div>
+                      <div
+                        v-photo="item"
+                        v-lazy:background-image="$options.filters.filterUserLazyImg(item.img)"
+                        :key="item.img"
+                        class="div-photo item-img"/>
+                    </el-tooltip>
+                    <img
+                      src="@/assets/img/delete_task.png"
+                      class="el-icon-close"
+                      @click="deleteOwnerList(item, index)">
+                  </span>
+                </div>
+                <members-dep
+                  :close-dep="true"
+                  :content-block="false"
+                  :user-checked-data="taskData.ownerUserList"
+                  @popoverSubmit="editOwnerList">
+                  <i
+                    slot="membersDep"
+                    class="wukong wukong-addition-task"/>
+                </members-dep>
+              </flexbox>
+            </div>
+            <div class="card-content-row card-content-row-column margin-bottom-30">
+              <span class="color-label participant">
+                <i class="wukong wukong-relevance"/>
+                <span>关联业务</span>
+              </span>
+              <!-- 关联业务 -->
+              <related-business
+                :margin-left="'0'"
+                :is-task="true"
+                :all-data="allData"
+                :task-id="taskData.taskId"
+                @checkRelatedDetail="checkRelatedDetail"
+                @checkInfos="checkInfos"/>
+            </div>
+            <div class="card-content-row card-content-row-column">
+              <div class="display-flex sub-task margin-bottom-7">
+                <span class="color-label participant">
+                  <i class="wukong wukong-sub-task"/>
+                  <span>子任务</span>
+                </span>
+                <template v-if="taskData.childTask.length !== 0">
+                  <span class="color-label sub-task-progress"> ({{ subTaskProgress }}/{{ taskData.childTask.length }}) </span>
+                  <el-progress
+                    :percentage="subTaskProgress/taskData.childTask.length*100"
+                    :stroke-width="10"/>
+                </template>
+                <template v-else>
+                  <span class="color-label sub-task-progress"> ({{ subTaskProgress }}/{{ taskData.childTask.length }}) </span>
+                  <el-progress :percentage="0"/>
+                </template>
+              </div>
+              <template v-if="taskData.childTask.length !== 0">
+                <div
+                  v-for="(item, index) in taskData.childTask"
+                  :key="index"
+                  class="card-related-matters subtasks-box">
+                  <div
+                    v-if="!item.showEdit"
+                    class="show-edit">
+                    <div
+                      style="display: inline-block;"
+                      @click.stop>
+                      <el-checkbox
+                        v-model="item.checked"
+                        @change="subtasksCheckbox(item, $event)"/>
+                    </div>
+                    <span
+                      :style="{'text-decoration': item.checked ? 'line-through' : 'none'}"
+                      class="item-name">{{ item.name }}</span>
+                    <!-- 编辑和删除 -->
+                    <div class="edit-del-box">
+                      <i
+                        class="wukong wukong-edit-task"
+                        @click="editSubTask(item)"/>
+                      <i
+                        class="wukong wukong-delete-task"
+                        @click="deleteSubTask(item)"/>
+                    </div>
+                    <div class="rt">
+                      <flexbox class="rt-box">
+                        <div
+                          v-if="item.stopTime"
+                          class="bg-color task-bg-color">{{ item.stopTime | moment("MM-DD") }} 截止</div>
+                        <div
+                          v-photo="item.mainUser"
+                          v-lazy:background-image="$options.filters.filterUserLazyImg(item.mainUser.img)"
+                          v-if="item.mainUser"
+                          :key="item.mainUser.img"
+                          class="div-photo"/>
+                      </flexbox>
+                    </div>
+                  </div>
+                  <sub-task
+                    v-else
+                    :sub-task-com="'edit'"
+                    :time="item.stopTime"
+                    :sub-data="item"
+                    :text="item.name"
+                    :task-id="subTaskID"
+                    :checkbox-data="item.checked"
+                    :task-data="taskData"
+                    @on-handle="handleSubTasksBlock($event, item)"/>
+                </div>
+              </template>
+              <div
+                v-if="addSubtasks"
+                class="add-subtasks"
+                @click="addSubtasks = false">
+                <span class="el-icon-plus"/>
+                <span>添加子任务</span>
+              </div>
+              <sub-task
+                v-else
+                :sub-task-com="'new'"
+                :task-data="taskData"
+                @on-handle="handleSubTasksBlock"/>
+            </div>
+            <div
+              v-if="fileList.length !== 0"
+              class="card-content-row card-content-row-column">
+              <span class="color-label participant class-file">
+                <i class="wukong wukong-file"/>
+                <span>附件</span>
+              </span>
+              <div class="accessory-box">
+                <file-cell
+                  v-for="(file, fileIndex) in fileList"
+                  :key="fileIndex"
+                  :data="file"
+                  :cell-index="fileIndex"
+                  :module_id="id"
+                  :show-delete="true"
+                  @delete="accessoryDeleteFun"/>
+              </div>
+            </div>
+          </div>
+        </div>
+        <div class="border"/>
+        <!-- 底部内容 -->
+        <div class="card-footers">
+          <div class="footer-title">
+            <span @click="footerTitle(0)">
+              <i
+                v-if="isComment"
+                class="wukong wukong-comment-task"
+                style="color: #4D88FF;"/>
+              <i
+                v-else
+                class="wukong wukong-comment-task"/>
+              <span
+                :style="{'color': isComment ? '#4D88FF' : '#666'}"
+                class="cursor-pointer">评论</span>
+            </span>
+            <span class="title-border"/>
+            <span @click="footerTitle(1)">
+              <i
+                v-if="isComment"
+                class="wukong wukong-activity-task"
+                style="font-size: 18px;"/>
+              <i
+                v-else
+                class="wukong wukong-activity-task"
+                style="color: #4D88FF; font-size: 18px;"/>
+              <span
+                :style="{'color': isComment ? '#666' : '#4D88FF'}"
+                class="cursor-pointer"
+                @click="footerTitle(isComment)">活动</span>
+            </span>
+          </div>
+          <div
+            v-loading="commentsLoading"
+            class="footer-content-box">
+            <div class="footer-content">
+              <div
+                v-if="commentsActivities"
+                class="add-comments">
+                <div class="footer-img">
+                  <div
+                    v-photo="userInfo"
+                    v-lazy:background-image="$options.filters.filterUserLazyImg(userInfo.img)"
+                    :key="userInfo.img"
+                    class="div-photo"/>
+                </div>
+                <div class="comments-con">
+                  <div
+                    v-clickoutside="commentsSubmit"
+                    v-if="addComments"
+                    class="comments-box">
+                    <el-input
+                      ref="commentsTextareaRef"
+                      :rows="4"
+                      v-model="commentsTextarea"
+                      type="textarea"
+                      placeholder="添加评论"
+                      @blur="blurFun"/>
+                    <div class="btn-group">
+                      <el-popover
+                        v-model="commentsPopover"
+                        placement="top"
+                        width="400"
+                        trigger="click">
+                        <!-- 表情 -->
+                        <emoji @select="selectEmoji"/>
+                        <img
+                          slot="reference"
+                          src="@/assets/img/smiling_face.png"
+                          class="smiling-img">
+                      </el-popover>
+                      <el-button
+                        type="primary"
+                        class="rt"
+                        @click="commentsSub">发布</el-button>
+                    </div>
+                  </div>
+                  <div
+                    v-else
+                    class="footer-bg"
+                    @click="addComments = true">添加评论</div>
+
+                  <!-- 评论 -->
+                  <div
+                    v-if="replyList && replyList.length !== 0"
+                    class="discuss">
+                    <div
+                      v-for="(discussItem, k) in replyList"
+                      :key="k"
+                      class="discuss-list">
+                      <div
+                        v-photo="discussItem.user"
+                        v-lazy:background-image="$options.filters.filterUserLazyImg(discussItem.user.img)"
+                        :key="discussItem.user.img"
+                        class="div-photo head-img header-circle"/>
+                      <span class="name">{{ discussItem.user.realname }}</span>
+                      <span class="time">{{ discussItem.createTime }}</span>
+                      <div class="rt">
+                        <span @click="discussDelete(discussItem, replyList, k)">删除</span>
+                        <span @click="discussBtn(discussItem, -1)">回复</span>
+                      </div>
+
+                      <p class="reply-title">
+                        <span v-html="emoji(discussItem.content)"/>
+                      </p>
+
+                      <!-- <p class="discuss-content"
+                         v-html="emoji(discussItem.reply_content)"></p> -->
+
+                      <div
+                        v-if="discussItem.childCommentList && discussItem.childCommentList.length > 0"
+                        class="children-reply">
+                        <div
+                          v-for="(childDiscussItem, k) in discussItem.childCommentList"
+                          :key="k"
+                          class="discuss-list">
+                          <div
+                            v-photo="childDiscussItem.user"
+                            v-lazy:background-image="$options.filters.filterUserLazyImg(childDiscussItem.user.img)"
+                            :key="childDiscussItem.user.img"
+                            class="div-photo head-img header-circle"/>
+                          <span class="name">{{ childDiscussItem.user.realname }}</span>
+                          <span class="time">{{ childDiscussItem.createTime }}</span>
+                          <div class="rt">
+                            <span @click="discussDelete(childDiscussItem, discussItem.childCommentList, k)">删除</span>
+                            <span @click="discussBtn(discussItem, k)">回复</span>
+                          </div>
+                          <p class="reply-title">
+                            <template>
+                              <span>回复</span>
+                              <span
+                                v-if="childDiscussItem.replyUser"
+                                class="reply">@{{ childDiscussItem.replyUser.realname }}:</span>
+                            </template>
+                            <span v-html="emoji(childDiscussItem.content)"/>
+                          </p>
+                        </div>
+                      </div>
+
+                      <!-- 评论 -- 回复  -->
+                      <div
+                        v-if="discussItem.show"
+                        class="comment-box">
+                        <el-input
+                          :rows="2"
+                          v-model="childCommentsTextarea"
+                          type="textarea"
+                          placeholder="请输入内容"
+                          @blur="blurFun"/>
+                        <div class="btn-group">
+                          <el-popover
+                            v-model="childCommentsPopover"
+                            placement="top"
+                            width="400"
+                            trigger="click">
+                            <!-- 表情 -->
+                            <emoji @select="selectEmojiChild"/>
+                            <img
+                              slot="reference"
+                              src="@/assets/img/smiling_face.png"
+                              class="smiling-img">
+                          </el-popover>
+                          <div class="btn-box">
+                            <el-button
+                              :loading="contentLoading"
+                              type="primary"
+                              @click="childCommentSubmit()">回复</el-button>
+                            <el-button @click="discussItem.show= false">取消</el-button>
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+              </div>
+              <div
+                v-else
+                class="activity-box">
+                <template v-if="activityList.length !== 0">
+                  <div
+                    v-for="(item, index) in activityList"
+                    :key="index"
+                    class="activity-list">
+                    <div
+                      v-photo="item"
+                      v-lazy:background-image="$options.filters.filterUserLazyImg(item.img)"
+                      :key="item.img"
+                      class="div-photo"/>
+                    <span class="activity-name">{{ item.realname }}</span>
+                    <span>{{ item.content }}</span>
+                    <span class="activity-time">{{ item.createTime }}</span>
+                  </div>
+                </template>
+              </div>
+            </div>
+          </div>
+        </div>
+        <slot/>
+      </div>
+      <div
+        v-if="taskData && taskData.createUser"
+        class="tip">
+        <span>{{ taskData.createUser.realname }} 创建于 {{ taskData.createTime }}</span>
+      </div>
+
+      <c-r-m-full-screen-detail
+        :visible.sync="showRelatedDetail"
+        :crm-type="relatedCRMType"
+        :id="relatedID"/>
+    </el-card>
+  </transition>
+  <!-- </div> -->
+</template>
+
+<script type="text/javascript">
+// import {
+//   editTask,
+//   editTaskRelation,
+//   deleteTask,
+//   detailsTask,
+//   readLoglist
+// } from '@/api/oamanagement/task'
+// import {
+//   setCommentAPI,
+//   deleteCommentAPI,
+//   queryCommentListAPI
+// } from '@/api/oamanagement/common'
+// import { crmFileSave } from '@/api/common'
+
+import membersDep from '@/components/selectEmployee/membersDep'
+import tagIndex from './tag/tagIndex'
+import subTask from './subTask'
+// emoji
+// import xss from 'xss'
+import emoji from '@/components/emoji'
+// 关联业务 - 选中列表
+import relatedBusiness from '@/components/relatedBusiness'
+import XhUser from '@/components/CreateCom/XhUser'
+import FileCell from '@/views/OAManagement/components/fileCell'
+import CRMFullScreenDetail from '@/views/clients/components/CRMFullScreenDetail'
+import { mapGetters } from 'vuex'
+import { getMaxIndex } from '@/utils'
+
+export default {
+  components: {
+    membersDep,
+    emoji,
+    relatedBusiness,
+    XhUser,
+    tagIndex,
+    CRMFullScreenDetail,
+    subTask,
+    FileCell
+  },
+  props: {
+    id: [String, Number],
+    detailIndex: Number,
+    appendToBody: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    return {
+      zIndex: getMaxIndex(),
+      // 评论 - 活动
+      // 评论 - 活动显示的内容
+      commentsActivities: true,
+      // 评论框
+      commentsTextarea: '',
+      // 回复
+      childCommentsTextarea: '',
+      // 评论 - 是否弹出表情
+      // 回复的一行用户数据
+      replyChildComment: null, // 被评论对象
+      replyChildIndex: -1, // -1 是主评论 0以上为子评论
+      contentLoading: false, // 回复按钮loading
+      commentsPopover: false,
+      // 回复弹出框
+      childCommentsPopover: false,
+      // 紧急弹出框
+      priorityVisible: false,
+      // 优先级列表
+      particularsList: [
+        { id: 3, label: '高', color: '#ED6363' },
+        { id: 2, label: '中', color: '#FF9668' },
+        { id: 1, label: '低', color: '#8bb5f0' },
+        { id: 0, label: '无', color: '#ccc' }
+      ],
+      // 是否显示子任务
+      addSubtasks: true,
+      // 任务名称和编辑切换
+      nameVinput: false,
+      // 任务名
+      taskDataName: '',
+      // 是否显示描述
+      addDescriptionShow: false,
+      // 描述内容
+      addDescriptionTextarea: '',
+      // 子任务进度
+      subTaskProgress: 0,
+      blurIndex: 0,
+      // 是否显示评论框
+      addComments: false,
+      allData: {},
+      isComment: true,
+      commentsLoading: false,
+      // 相关详情的查看
+      relatedID: '',
+      relatedCRMType: '',
+      showRelatedDetail: false,
+      // 子任务ID
+      subTaskID: null,
+      // 任务详情
+      loading: false,
+      taskData: null,
+      activityList: [],
+      fileList: [],
+      // 评论列表
+      replyList: []
+    }
+  },
+  computed: {
+    ...mapGetters(['userInfo'])
+  },
+  watch: {
+    id: function (val) {
+      this.initInfo()
+      this.getDetail()
+      this.getActivityList()
+      this.getCommentList()
+    }
+  },
+  mounted () {
+    if (this.appendToBody) {
+      document.body.appendChild(this.$el)
+    }
+    if (this.id) {
+      this.getDetail()
+      this.getActivityList()
+      this.getCommentList()
+    }
+  },
+
+  beforeDestroy () {
+    if (this.appendToBody && this.$el && this.$el.parentNode) {
+      this.$el.parentNode.removeChild(this.$el)
+    }
+  },
+  methods: {
+    initInfo () {
+      this.taskData = null
+      this.subTaskProgress = 0
+      // 设置关联项列表
+      this.allData = {
+        business: [],
+        contacts: [],
+        contract: [],
+        customer: []
+      }
+
+      this.taskData = null
+      this.activityList = []
+      this.fileList = []
+    },
+    // 基础详情
+    getDetail () {
+      this.loading = true
+      // detailsTask({ taskId: this.id })
+      //   .then(res => {
+      //     const taskData = res.data
+      //     taskData.checked = taskData.status === 5
+
+      //     if (taskData.childTask) {
+      //       for (const item of taskData.childTask) {
+      //         if (item.status === 5) {
+      //           item.checked = true
+      //           this.subTaskProgress++
+      //         } else {
+      //           item.checked = false
+      //         }
+      //       }
+      //     }
+      //     this.fileList = res.data.file
+      //     this.allData = {
+      //       business: taskData.businessList || [],
+      //       contacts: taskData.contactsList || [],
+      //       contract: taskData.contractList || [],
+      //       customer: taskData.customerList || []
+      //     }
+      //     this.taskData = taskData
+      //     this.loading = false
+      //   })
+      //   .catch(() => {
+      //     this.loading = false
+      //     this.closeBtn()
+      //   })
+    },
+    // 获取活动信息
+    getActivityList () {
+      // readLoglist({
+      //   taskId: this.id
+      // })
+      //   .then(res => {
+      //     this.activityList = res.data
+      //   })
+      //   .catch(() => {})
+    },
+
+    // 获取评论信息
+    getCommentList () {
+      // queryCommentListAPI({
+      //   typeId: this.id,
+      //   type: 1
+      // })
+      //   .then(res => {
+      //     this.replyList = res.data
+      //   })
+      //   .catch(() => {})
+    },
+
+    // 主题勾选
+    titleCheckbox (val) {
+      this.taskData.checked = val
+      // editTask({
+      //   taskId: this.id,
+      //   status: this.taskData.checked ? 5 : 1
+      // })
+      //   .then(res => {
+      //     this.$emit('on-handle', {
+      //       type: 'title-check',
+      //       value: val,
+      //       index: this.detailIndex
+      //     })
+      //     this.$store.dispatch('GetOAMessageNum', 'task')
+      //   })
+      //   .catch(() => {
+      //     this.$emit('on-handle', {
+      //       type: 'title-check',
+      //       value: !this.taskData.checked,
+      //       index: this.detailIndex
+      //     })
+      //     this.taskData.checked = !this.taskData.checked
+      //   })
+    },
+    closeBtn () {
+      this.$emit('close')
+    },
+    // 评论 - 活动 切换功能
+    footerTitle (key) {
+      switch (key) {
+        case 0:
+          this.commentsActivities = true
+          this.isComment = true
+          break
+        case 1:
+          this.commentsActivities = false
+          this.isComment = false
+          break
+      }
+    },
+    // 紧急按钮
+    priorityBtn (value, def) {
+      this.taskData.priority = value.id
+      // editTask({
+      //   taskId: this.id,
+      //   priority: value.id
+      // })
+      //   .then(res => {
+      //     this.$emit('on-handle', {
+      //       type: 'change-priority',
+      //       value: value,
+      //       index: this.detailIndex
+      //     })
+      //     this.priorityVisible = false
+      //   })
+      //   .catch(() => {
+      //     this.$message.error('编辑失败')
+      //     this.taskData.priority = def
+      //   })
+    },
+    // 更多 ———— 删除和规定按钮
+    moreDelete () {
+      this.$confirm('此操作将永久删除该任务, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+        customClass: 'is-particulars'
+      })
+        .then(() => {
+          // deleteTask({
+          //   taskId: this.id
+          // })
+          //   .then(res => {
+          //     this.$message.success('删除成功')
+          //     this.$emit('on-handle', {
+          //       type: 'delete',
+          //       index: this.detailIndex
+          //     })
+          //     this.$emit('close')
+          //   })
+          //   .catch(() => {})
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    },
+    // 附件 -- 上传
+    httpRequest (val) {
+      // crmFileSave({
+      //   file: val.file,
+      //   batchId: this.taskData.batchId
+      // })
+      //   .then(res => {
+      //     this.fileList.push(res)
+      //     // this.$emit('httpRequest', this.taskData)
+      //     this.$message.success('上传成功')
+      //   })
+      //   .catch(() => {})
+    },
+    // 附件删除
+    accessoryDeleteFun (index, item) {
+      this.fileList.splice(index, 1)
+    },
+    // 子任务添加
+    addSubtasksBtn () {
+      this.addSubtasks = !this.addSubtasks
+    },
+    // 子任务 -- 勾选
+    subtasksCheckbox (val, e) {
+      if (e) {
+        this.$set(val, 'checked', true)
+        this.subTaskProgress++
+      } else {
+        this.$set(val, 'checked', false)
+        this.subTaskProgress--
+      }
+      this.$emit('on-handle', {
+        type: 'change-sub-task',
+        value: {
+          subdonecount: this.subTaskProgress,
+          allcount: this.taskData.childTask.length
+        },
+        index: this.detailIndex
+      })
+      // editTask({
+      //   taskId: val.taskId,
+      //   status: e ? 5 : 1
+      // })
+      //   .then(res => {})
+      //   .catch(() => {
+      //     this.$message.error('子任务标记失败')
+      //     if (e) {
+      //       this.$set(val, 'checked', false)
+      //       this.subTaskProgress--
+      //     } else {
+      //       this.$set(val, 'checked', true)
+      //       this.subTaskProgress++
+      //     }
+      //     this.$emit('on-handle', {
+      //       type: 'change-sub-task',
+      //       value: {
+      //         subdonecount: this.subTaskProgress,
+      //         allcount: this.taskData.childTask.length
+      //       },
+      //       index: this.detailIndex
+      //     })
+      //     // this.$emit('', val, e)
+      //   })
+    },
+    /**
+     * 参与人操作
+     */
+    // 提交按钮
+    editOwnerList (users, dep) {
+      this.taskData.ownerUserList = []
+      // editTask({
+      //   taskId: this.id,
+      //   ownerUserId: users
+      //     .map(item => {
+      //       return item.userId
+      //     })
+      //     .join(',')
+      // })
+      //   .then(res => {
+      //     this.taskData.ownerUserList = users
+      //   })
+      //   .catch(() => {})
+    },
+    // 参与人删除按钮
+    deleteOwnerList (item, index) {
+      // editTask({
+      //   taskId: this.id,
+      //   ownerUserId: this.taskData.ownerUserList
+      //     .filter(userItem => {
+      //       return userItem.userId !== item.userId
+      //     })
+      //     .map(item => {
+      //       return item.userId
+      //     })
+      //     .join(',')
+      // })
+      //   .then(res => {
+      //     this.taskData.ownerUserList.splice(index, 1)
+      //   })
+      //   .catch(() => {})
+    },
+    // 编辑负责人
+    editMainUser (val) {
+      // editTask({
+      //   taskId: this.id,
+      //   mainUserId: val ? val.data[0].userId : ''
+      // })
+      //   .then(res => {
+      //     if (val) {
+      //       this.$set(this.taskData, 'mainUser', val.data[0])
+      //     } else {
+      //       this.$set(this.taskData, 'mainUser', null)
+      //     }
+      //   })
+      //   .catch(() => {})
+    },
+    // 编辑任务名
+    nameVShow (val) {
+      // editTask({
+      //   name: val,
+      //   taskId: this.id
+      // })
+      //   .then(res => {
+      //     this.nameVinput = false
+      //     this.$emit('on-handle', {
+      //       type: 'change-name',
+      //       value: val,
+      //       index: this.detailIndex
+      //     })
+      //     this.taskData.name = val
+      //   })
+      //   .catch(() => {})
+    },
+    // 截至日期API
+    endTimeChange (val) {
+      // editTask({
+      //   stopTime: val,
+      //   taskId: this.id
+      // })
+      //   .then(res => {
+      //     // val.substring(5)
+      //     this.$emit('on-handle', {
+      //       type: 'change-stop-time',
+      //       value: val,
+      //       index: this.detailIndex
+      //     })
+      //   })
+      //   .catch(() => {})
+    },
+    // 描述提交按钮
+    addDescriptionSubmit () {
+      // editTask({
+      //   taskId: this.id,
+      //   description: this.addDescriptionTextarea
+      // })
+      //   .then(res => {
+      //     this.addDescriptionShow = false
+      //     this.$set(this.taskData, 'description', this.addDescriptionTextarea)
+      //   })
+      //   .catch(() => {})
+    },
+    // 评论选中功能
+    selectEmoji (val) {
+      const list = this.commentsTextarea.split('')
+      list.splice(this.blurIndex, 0, val)
+      this.commentsTextarea = list.join('')
+      this.commentsPopover = false
+    },
+    // 评论回复 -- 选中功能
+    selectEmojiChild (val) {
+      const list = this.childCommentsTextarea.split('')
+      list.splice(this.blurIndex, 0, val)
+      this.childCommentsTextarea = list.join('')
+      this.childCommentsPopover = false
+    },
+    // 评论发布
+    commentsSub () {
+      if (this.commentsTextarea) {
+        this.commentsLoading = true
+        // setCommentAPI({
+        //   typeId: this.id,
+        //   type: 1,
+        //   content: xss(this.commentsTextarea)
+        // })
+        //   .then(res => {
+        //     res.data.childCommentList = []
+        //     res.data.show = false
+        //     res.data.user = this.userInfo
+        //     this.replyList.push(res.data)
+        //     this.commentsTextarea = ''
+        //     // this.$emit('commentsSet', 'add')
+        //     this.$emit('on-handle', {
+        //       type: 'change-comments',
+        //       value: 'add',
+        //       index: this.detailIndex
+        //     })
+        //     this.commentsLoading = false
+        //   })
+        //   .catch(() => {
+        //     this.commentsLoading = false
+        //   })
+      }
+    },
+    // 回复评论
+    childCommentSubmit () {
+      if (this.replyChildComment && this.childCommentsTextarea) {
+        // let item =
+        //   this.replyChildIndex === -1
+        //     ? this.replyChildComment
+        //     : this.replyChildComment.childCommentList[this.replyChildIndex]
+        // setCommentAPI({
+        //   pid: item.userId,
+        //   typeId: item.typeId,
+        //   mainId: item.mainId === 0 ? item.commentId : item.mainId,
+        //   type: 1,
+        //   content: xss(this.childCommentsTextarea)
+        // })
+        //   .then(res => {
+        //     this.childCommentsPopover = false
+        //     res.data.user = this.userInfo
+        //     res.data.replyUser = item.user
+        //     this.replyChildComment.childCommentList.push(res.data)
+        //     this.replyChildComment.show = false
+        //     this.replyChildComment = null
+        //     this.childCommentsTextarea = ''
+        //     this.$emit('on-handle', {
+        //       type: 'change-comments',
+        //       value: 'add',
+        //       index: this.detailIndex
+        //     })
+        //   })
+        //   .catch(() => {})
+      }
+    },
+    // 删除评论
+    discussDelete (val, items, index) {
+      this.$confirm('确定删除?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+        customClass: 'is-particulars'
+      })
+        .then(() => {
+          // deleteCommentAPI({
+          //   commentId: val.commentId
+          // })
+          //   .then(res => {
+          //     items.splice(index, 1)
+          //     this.$emit('on-handle', {
+          //       type: 'change-comments',
+          //       value: 'delete',
+          //       index: this.detailIndex
+          //     })
+          //     // this.$emit('commentsSet', 'delete')
+          //   })
+          //   .catch(() => {})
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    },
+    // 点击回复按钮
+    discussBtn (item, index) {
+      if (item.show) {
+        this.$set(item, 'show', false)
+        this.replyChildComment = null
+      } else {
+        this.$set(item, 'show', true)
+        this.$set(item, 'showComment', false)
+        this.replyChildComment = item
+        this.replyChildIndex = index
+      }
+    },
+    blurFun (eve) {
+      this.blurIndex = eve.target.selectionEnd
+    },
+    // 关联业务提交按钮
+    checkInfos (val) {
+      // editTaskRelation({
+      //   taskId: this.id,
+      //   customerIds:
+      //     val.customerIds && val.customerIds.length
+      //       ? ',' + val.customerIds.join(',') + ','
+      //       : '',
+      //   contactsIds:
+      //     val.contactsIds && val.contactsIds.length
+      //       ? ',' + val.contactsIds.join(',') + ','
+      //       : '',
+      //   businessIds:
+      //     val.businessIds && val.businessIds.length
+      //       ? ',' + val.businessIds.join(',') + ','
+      //       : '',
+      //   contractIds:
+      //     val.contractIds && val.contractIds.length
+      //       ? ',' + val.contractIds.join(',') + ','
+      //       : ''
+      // })
+      //   .then(res => {
+      //     this.$message.success('关联成功')
+      //   })
+      //   .catch(() => {})
+    },
+    commentsSubmit (event) {
+      this.addComments = false
+    },
+    checkRelatedDetail (crmType, item) {
+      this.relatedID = item.key
+      this.relatedCRMType = crmType
+      this.showRelatedDetail = true
+    },
+    deleteSubTask (val) {
+      this.$confirm('此操作将永久删除该任务, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+        customClass: 'is-particulars'
+      })
+        .then(() => {
+          // deleteTask({
+          //   taskId: val.taskId
+          // })
+          //   .then(res => {
+          //     const subData = this.taskData.childTask
+          //     for (const i in subData) {
+          //       if (subData[i].taskId === val.taskId) {
+          //         subData.splice(i, 1)
+          //         break
+          //       }
+          //     }
+          //     if (val.checked) {
+          //       this.subTaskProgress--
+          //       this.$emit('on-handle', {
+          //         type: 'change-sub-task',
+          //         value: {
+          //           subdonecount: this.subTaskProgress,
+          //           allcount: this.taskData.childTask.length
+          //         },
+          //         index: this.detailIndex
+          //       })
+          //     }
+          //     this.$message.success('子任务删除成功')
+          //   })
+          //   .catch(() => {
+          //     this.$message.error('子任务删除失败')
+          //   })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    },
+    editSubTask (val) {
+      this.subTaskID = val.taskId
+      const dataList = this.taskData.childTask
+      for (const i in dataList) {
+        if (dataList[i].taskId === val.taskId) {
+          this.$set(dataList[i], 'showEdit', true)
+        } else {
+          this.$set(dataList[i], 'showEdit', false)
+        }
+      }
+    },
+    handleSubTasksBlock (data, item) {
+      if (data.type === 'edit') {
+        this.$set(item, 'showEdit', false)
+      } else if (data.type === 'add') {
+        this.addSubtasks = true
+        if (data.result === 'success') {
+          this.$emit('on-handle', {
+            type: 'change-sub-task',
+            value: {
+              subdonecount: this.subTaskProgress,
+              allcount: this.taskData.childTask.length + 1
+            },
+            index: this.detailIndex
+          })
+        } else {
+          this.$emit('on-handle', {
+            type: 'change-sub-task',
+            value: {
+              subdonecount: this.subTaskProgress,
+              allcount: this.taskData.childTask.length - 1
+            },
+            index: this.detailIndex
+          })
+        }
+      } else if (data.type === 'cancel') {
+        if (item) {
+          this.$set(item, 'showEdit', false)
+        } else {
+          this.addSubtasks = true
+        }
+      }
+    },
+    // 删除截止时间
+    deleteTimeTop () {
+      // editTask({
+      //   taskId: this.id,
+      //   stopTime: ''
+      // })
+      //   .then(res => {
+      //     this.$set(this.taskData, 'stopTime', '')
+      //   })
+      //   .catch(() => {})
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.wukong {
+  vertical-align: middle;
+  color: #666;
+}
+.slide-fade-enter-active,
+.slide-fade-leave-active {
+  will-change: transform;
+  transition: all 0.35s ease;
+}
+.slide-fade-enter,
+.slide-fade-leave-to {
+  transform: translateX(100%);
+}
+.display-flex {
+  display: flex;
+}
+// 小手抓
+.cursor-pointer {
+  cursor: pointer;
+}
+// 时间背景
+.bg-color {
+  background: #f5f5f5;
+  padding: 4px 8px;
+  border-radius: 14px;
+}
+.task-bg-color {
+  background: #e6e6e6;
+}
+.border {
+  border-top: 1px solid #e6e6e6;
+  margin: 0 -20px;
+}
+
+.particulars-priority-box {
+  display: flex;
+  p {
+    flex: 1;
+    cursor: pointer;
+    display: inline-block;
+    text-align: center;
+    span {
+      color: #aaa;
+      font-size: 12px;
+      padding: 7px 10px;
+      text-align: center;
+      display: inline-block;
+      border-radius: 50%;
+      border: 1px solid transparent;
+    }
+  }
+}
+// 更多按钮
+.more-btn-group {
+  line-height: 34px;
+  font-size: 14px;
+  margin: 0 -12px;
+  p {
+    padding-left: 22px;
+    cursor: pointer;
+  }
+  p:hover {
+    background: #f7f8fa;
+    color: #4D88FF;
+  }
+}
+// 负责人
+.particulars-colleagues-list {
+  margin: 0 -12px;
+  p {
+    height: 34px;
+    line-height: 34px;
+    padding-left: 22px;
+    cursor: pointer;
+  }
+  p:hover {
+    -webkit-box-shadow: 0 0 8px 2px #eee;
+    box-shadow: 0 0 8px 2px #eee;
+    background: 0 0;
+  }
+}
+.particulars-common /deep/ .el-card__body {
+  flex: 1;
+  overflow: auto;
+  display: flex;
+  flex-direction: column;
+  padding-bottom: 90px;
+}
+.tip {
+  position: fixed;
+  right: 0px;
+  width: 926px;
+  bottom: 0;
+  overflow: hidden;
+  margin-top: 50px;
+  height: 40px;
+  line-height: 40px;
+  border-top: 1px solid #e6e6e6;
+  background: #fff;
+  color: #999;
+  z-index: 9;
+  span {
+    margin-left: 55px;
+  }
+}
+.particulars-common {
+  position: fixed;
+  top: 60px;
+  right: 0px;
+  width: 926px;
+  bottom: 0;
+  display: flex;
+  flex-direction: column;
+  .clear-fix {
+    overflow: auto;
+  }
+  .img-box-grop {
+    float: right;
+    color: #999;
+    .task-close-img {
+      padding-left: 30px;
+      img {
+        width: 18px;
+      }
+    }
+
+    .wukong {
+      color: #999;
+    }
+  }
+  .img-box-grop > div {
+    display: inline-block;
+    margin-right: 20px;
+    cursor: pointer;
+    img {
+      vertical-align: middle;
+    }
+    .upload-demo /deep/ .el-upload-list--picture {
+      display: none;
+    }
+  }
+  .card-content-box {
+    display: flex;
+    img {
+      vertical-align: middle;
+    }
+    .el-checkbox {
+      height: 20px;
+      margin-right: 0;
+    }
+    // 解决多选框样式
+    .el-checkbox /deep/ .el-checkbox__inner {
+      width: 20px;
+      height: 20px;
+    }
+    .el-checkbox /deep/ .el-checkbox__inner::after {
+      border-width: 2px;
+      height: 12px;
+      width: 5px;
+      left: 5px;
+    }
+    .card-content {
+      flex: 1;
+      padding: 0 15px;
+      .card-content-row {
+        margin-bottom: 35px;
+        display: flex;
+        .priority-data-name {
+          .title-text {
+            font-size: 17px;
+            color: #333;
+            .el-icon-edit-outline {
+              margin-left: 20px;
+              color: #4D88FF;
+              opacity: 0;
+              cursor: pointer;
+            }
+          }
+          .title-text:hover {
+            .el-icon-edit-outline {
+              opacity: 1;
+            }
+          }
+          .show-input {
+            width: 90%;
+            .btn-box {
+              margin-top: 10px;
+            }
+          }
+        }
+        .el-icon-circle-plus-outline {
+          width: 30px;
+          height: 30px;
+          color: #ccc;
+        }
+        .card-row-right {
+          width: 50%;
+          .text-right {
+            width: 60%;
+            float: right;
+            min-width: 200px;
+            min-height: 28px;
+            position: relative;
+            .el-icon-close {
+              opacity: 0;
+              margin-left: 10px;
+              color: #ccc;
+              cursor: pointer;
+            }
+            .el-popover__reference {
+              width: 20px;
+            }
+            .main-user-name {
+              width: 25px;
+              height: 25px;
+              border-radius: 12.5px;
+            }
+            .user-name-label {
+              width: 73px;
+              display: inline-block;
+            }
+
+            .bg-position {
+              position: relative;
+              display: inline-block;
+              .el-icon-close {
+                opacity: 0;
+                border-radius: 50%;
+                cursor: pointer;
+                position: absolute;
+                z-index: 3;
+                top: -7px;
+                right: -5px;
+              }
+            }
+            .wukong-addition-task {
+              cursor: pointer;
+            }
+
+            .time-top {
+              position: relative;
+              display: inline-block;
+              .time-top-close {
+                opacity: 0;
+                border-radius: 50%;
+                cursor: pointer;
+                position: absolute;
+                z-index: 3;
+                top: -7px;
+                right: -5px;
+              }
+            }
+
+            .time-top /deep/ .el-date-editor {
+              width: 115px;
+              input {
+                background-color: #f5f5f5;
+                border: none;
+                border-radius: 15px;
+                line-height: 30px;
+                height: 30px;
+                padding-right: 0;
+              }
+            }
+            .time-top /deep/ .no-time-top.el-date-editor {
+              width: 30px;
+              .el-input__prefix {
+                left: 2px;
+              }
+            }
+          }
+
+          .text-right:hover {
+            .el-icon-close {
+              opacity: 1;
+            }
+          }
+          .color-label {
+            margin-right: 10px;
+            vertical-align: middle;
+          }
+        }
+        .card-row-right:hover {
+          .el-icon-close {
+            opacity: 1;
+          }
+        }
+        .particulars-priority-copy {
+          .item-color {
+            padding: 0 10px;
+            color: #fff;
+            font-size: 12px;
+            margin-right: 5px;
+            border-radius: 3px;
+            display: inline-block;
+            height: 22px;
+            line-height: 22px;
+            margin-bottom: 5px;
+          }
+          .el-icon-plus,
+          .add-tag {
+            color: #999;
+          }
+          .el-icon-plus {
+            font-size: 13px;
+            padding-left: 6px;
+          }
+          .add-tag {
+            display: inline-block;
+            width: 83px;
+            height: 24px;
+            line-height: 24px;
+            background: rgba(245, 245, 245, 1);
+            border-radius: 3px;
+            cursor: pointer;
+            text-align: center;
+            font-size: 12px;
+          }
+          .label {
+            padding-right: 10px;
+          }
+        }
+        .class-file {
+          img {
+            margin: 0 5px;
+          }
+        }
+      }
+      .card-content-row-column {
+        flex-direction: column;
+        margin-right: 20px;
+        .accessory-box {
+          margin-top: 10px;
+        }
+        .participant {
+          color: #666;
+          img,
+          span {
+            vertical-align: middle;
+          }
+        }
+        .participant-class {
+          margin-left: 10px;
+          min-height: 28px;
+          .owner-list {
+            position: relative;
+            margin-right: 10px;
+            display: inline-block;
+            .item-img {
+              width: 25px;
+              height: 25px;
+              border-radius: 12.5px;
+            }
+            .el-icon-close {
+              opacity: 0;
+              color: #fff;
+              background: #ccc;
+              border-radius: 50%;
+              cursor: pointer;
+              position: absolute;
+              z-index: 3;
+              top: -7px;
+              right: -5px;
+            }
+          }
+          .owner-list:hover {
+            .el-icon-close {
+              opacity: 1;
+            }
+          }
+        }
+        .task-add-png {
+          display: inline-block;
+        }
+        .show-edit {
+          background: #f5f7fa;
+          height: 40px;
+          line-height: 40px;
+          // color: #4D88FF;
+          padding: 0 10px;
+          font-size: 13px;
+          .card-related-matters-right {
+            float: right;
+            margin-top: 8px;
+          }
+          .rt {
+            margin-right: 0;
+            .bg-color {
+              font-size: 12px;
+              padding: 0 8px !important;
+              vertical-align: middle;
+              height: 30px;
+              line-height: 30px;
+            }
+            .div-photo {
+              margin-top: 0 !important;
+            }
+            .rt-box {
+              height: 41.5px;
+            }
+          }
+        }
+        .display-flex {
+          margin-bottom: 10px;
+          span {
+            margin-right: 10px;
+          }
+        }
+        .el-progress {
+          flex: 1;
+          margin-left: 10px;
+        }
+        .el-progress /deep/ .el-progress-bar {
+          padding-right: 0;
+          .el-progress-bar__outer {
+            background: #f5f5f5;
+          }
+        }
+        .el-progress /deep/ .el-progress__text {
+          display: none;
+        }
+        .subtasks-box {
+          color: #333;
+          border-radius: 3px;
+          margin: 3px 0;
+          height: 40px;
+          // line-height: 40px;
+          // cursor: pointer;
+          // 解决多选框样式
+          .el-checkbox /deep/ .el-checkbox__inner {
+            width: 16px;
+            height: 16px;
+          }
+          .el-checkbox /deep/ .el-checkbox__inner::after {
+            border-width: 2px;
+            height: 10px;
+            width: 4px;
+            left: 4px;
+            top: 0;
+          }
+          .rt {
+            .div-photo {
+              margin-top: 7px;
+              width: 25px;
+              height: 25px;
+              border-radius: 12.5px;
+              margin-left: 10px;
+            }
+          }
+          .edit-del-box {
+            display: inline-block;
+            padding-left: 10px;
+            opacity: 0;
+            .wukong {
+              padding-left: 10px;
+              cursor: pointer;
+            }
+            .wukong:hover {
+              color: #4D88FF;
+            }
+          }
+          .item-name {
+            padding-left: 5px;
+          }
+        }
+        .subtasks-box:hover {
+          box-shadow: 0px 1px 4px 0px rgba(223, 227, 234, 1);
+          .edit-del-box {
+            opacity: 1;
+          }
+        }
+      }
+      .card-content-row > div {
+        flex: 1;
+      }
+      .card-content-row /deep/ .related-business {
+        margin: 10px 0;
+        .list {
+          margin: 0;
+          .item-list {
+            margin-bottom: 5px;
+            background: #f5f7fa;
+            border: 0;
+          }
+        }
+        .add-file {
+          display: inline-block;
+          background: #f5f7fa;
+          width: 100%;
+          height: 40px;
+          line-height: 40px;
+          padding-left: 8px;
+          margin: 0;
+        }
+      }
+      .add-subtasks {
+        color: #4D88FF;
+        cursor: pointer;
+        background: #f5f7fa;
+        height: 40px;
+        line-height: 40px;
+        margin-top: 10px;
+        padding-left: 12px;
+        font-size: 13px;
+      }
+      .add-description /deep/ {
+        margin-bottom: 20px;
+        position: relative;
+        cursor: pointer;
+        white-space: pre-wrap;
+        word-wrap: break-word;
+        .no-description {
+          color: #4D88FF;
+          .color-label {
+            color: #999;
+          }
+          button {
+            margin-left: 5px;
+          }
+        }
+        .btn-box {
+          margin-top: 10px;
+        }
+        .el-textarea /deep/.el-textarea__inner {
+          resize: none;
+        }
+      }
+      .margin-bottom-15 {
+        margin-bottom: 15px;
+      }
+      .margin-bottom-25 {
+        margin-bottom: 25px;
+      }
+      .margin-bottom-30 {
+        margin-bottom: 30px;
+      }
+      .margin-bottom-7 {
+        margin-bottom: 7px;
+      }
+    }
+    .color-label {
+      color: #666;
+    }
+    .sub-task {
+      .sub-task-progress {
+        line-height: 22px;
+      }
+      .el-progress {
+        line-height: 22px;
+      }
+    }
+  }
+  .card-footers {
+    margin-top: 20px;
+    .footer-title {
+      margin-bottom: 40px;
+      margin-left: 35px;
+      img,
+      span {
+        vertical-align: middle;
+        cursor: pointer;
+      }
+      .title-border {
+        border-right: 2px solid #ccc;
+        margin: 0 20px;
+      }
+    }
+    .footer-content-box {
+      display: flex;
+      .footer-content {
+        flex: 1;
+        .activity-box {
+          margin-left: 35px;
+          margin-right: 35px;
+          .activity-list {
+            margin-bottom: 15px;
+            color: #333;
+            .activity-time {
+              float: right;
+              color: #999;
+              font-size: 12px;
+            }
+            .activity-name {
+              color: #666;
+              margin: 0 5px;
+            }
+            .div-photo {
+              width: 25px;
+              height: 25px;
+              border-radius: 12.5px;
+              margin-right: 10px;
+              vertical-align: middle;
+            }
+          }
+        }
+        .comments-con > .comments-box {
+          margin-bottom: 10px;
+        }
+        .comments-box {
+          border: 1px solid #e6e6e6;
+          .el-textarea /deep/ .el-textarea__inner {
+            border: 0;
+            resize: none;
+          }
+          .btn-group {
+            overflow: hidden;
+            margin: 10px;
+            .smiling-img {
+              margin-top: 7px;
+            }
+            .rt {
+              margin-right: 10px;
+            }
+          }
+        }
+
+        .add-comments {
+          display: flex;
+          .footer-img {
+            margin-left: 35px;
+            margin-right: 20px;
+            .div-photo {
+              width: 42px;
+              height: 42px;
+              border-radius: 21px;
+              margin-top: 4px;
+            }
+          }
+          .comments-con {
+            flex: 1;
+            margin-right: 35px;
+            .footer-bg {
+              background: #f5f5f5;
+              height: 50px;
+              line-height: 50px;
+              padding-left: 24px;
+              color: #666;
+              cursor: pointer;
+              margin-bottom: 5px;
+            }
+          }
+        }
+      }
+    }
+  }
+  .title {
+    color: #333333;
+    font-size: 18px;
+  }
+  // 回到父任务
+  .parent-task {
+    margin-bottom: 15px;
+    .p-name {
+      margin-left: 10px;
+    }
+    .back {
+      margin-left: 35px;
+      color: #4D88FF;
+      cursor: pointer;
+    }
+  }
+}
+
+// 评论列表
+.discuss {
+  padding: 10px 0;
+  .discuss-list {
+    .name,
+    .time,
+    .head-img {
+      vertical-align: middle;
+    }
+    .head-img {
+      width: 25px;
+      height: 25px;
+      display: inline-block;
+      border-radius: 12.5px;
+    }
+    .name {
+      margin: 0 10px;
+      font-size: 15px;
+    }
+    .time {
+      color: #999;
+      font-size: 12px;
+      display: inline-block;
+      margin-top: 3px;
+    }
+
+    .reply-title {
+      color: #333;
+      font-size: 13px;
+      margin: 10px 0 10px 40px;
+      .reply {
+        color: #4D88FF;
+      }
+    }
+    .reply-title /deep/ img {
+      vertical-align: text-bottom;
+      margin: 0 2px;
+    }
+
+    .children-reply {
+      margin: 10px 0 10px 40px;
+    }
+
+    .rt {
+      margin-top: 4px;
+      color: #999;
+      margin-right: 0;
+      span {
+        margin-left: 10px;
+        cursor: pointer;
+      }
+    }
+    .discuss-content {
+      background: #f5f7fa;
+      color: #777;
+      line-height: 36px;
+      margin-left: 40px;
+      padding-left: 15px;
+    }
+    .discuss-content /deep/ img {
+      vertical-align: middle;
+      margin: 0 3px;
+    }
+    .border {
+      margin: 15px 0 15px 40px;
+    }
+    .comment-box {
+      margin-left: 40px;
+      padding: 0;
+      background: transparent;
+      margin-top: 15px;
+    }
+  }
+}
+
+// 评论框
+.comment-box {
+  margin: 20px;
+  border: 1px solid #e6e6e6;
+  .btn-group {
+    padding: 0 20px 10px 10px;
+    overflow: hidden;
+    .btn-box {
+      float: right;
+    }
+  }
+  .btn-group /deep/ img {
+    cursor: pointer;
+  }
+  .el-textarea /deep/ .el-textarea__inner {
+    resize: none;
+    border: 0;
+  }
+}
+</style>
diff --git a/src/views/OAManagement/task/components/subTask.vue b/src/views/OAManagement/task/components/subTask.vue
new file mode 100644
index 0000000..26b480d
--- /dev/null
+++ b/src/views/OAManagement/task/components/subTask.vue
@@ -0,0 +1,324 @@
+<template>
+  <div class="task-sub">
+    <div
+      v-clickoutside="subtasksSubmit"
+      class="subtasks-content">
+      <div class="checkbox-box subtasks-box">
+        <el-checkbox
+          v-model="checkboxData"
+          disabled/>
+      </div>
+      <div class="subtasks-content-box">
+        <el-input
+          :maxlength="50"
+          v-model="subtasksTextarea"
+          type="textarea"
+          autosize
+          placeholder="请输入内容"
+          @keyup.enter.native="subtasksSubmit"/>
+      </div>
+      <flexbox class="subtasks-content-png">
+        <div class="time">
+          <el-date-picker
+            ref="subtasksDate"
+            v-model="subtasksDate"
+            :style="{'width': subtasksDataText ? '54px': '28px'}"
+            type="date"
+            format="yyyy 年 MM 月 dd 日"
+            value-format="yyyy-MM-dd"
+            placeholder="选择日期"
+            @change="subtasksDateClick(subtasksDate)"/>
+          <span
+            v-if="subtasksDataText && subtasksDataText !== 0"
+            class="bg-color">{{ subtasksDataText | moment("MM-DD") }}</span>
+          <i
+            v-else
+            class="wukong wukong-time-task"
+            @click="subtasksDateFun"/>
+        </div>
+        <!-- 选择负责人 -->
+        <el-popover
+          placement="bottom-end"
+          width="280"
+          trigger="click">
+          <xh-user
+            ref="xhuser"
+            :selected-data="xhUserData"
+            radio
+            @changeCheckout="xhUserCheckout"/>
+          <div
+            slot="reference"
+            class="select-box">
+            <template v-if="subtaskChange">
+              <span
+                v-for="(item, index) in xhUserData"
+                :key="index">
+                <el-tooltip
+                  placement="bottom"
+                  effect="light"
+                  popper-class="tooltip-change-border">
+                  <div slot="content">
+                    <span>{{ item.realname }}</span>
+                  </div>
+                  <div
+                    v-photo="item"
+                    v-lazy:background-image="$options.filters.filterUserLazyImg(item.img)"
+                    class="div-photo"/>
+                </el-tooltip>
+              </span>
+            </template>
+            <i
+              v-else
+              class="wukong wukong-user"/>
+          </div>
+        </el-popover>
+      </flexbox>
+    </div>
+  </div>
+</template>
+
+<script>
+// import { addTask, editTask } from '@/api/oamanagement/task'
+import XhUser from '@/components/CreateCom/XhUser'
+
+export default {
+  components: {
+    XhUser
+  },
+  props: {
+    taskData: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    // 子任务输入内容
+    text: String,
+    time: [String, Number],
+    subData: Object,
+    subTaskCom: {
+      type: String,
+      default: ''
+    },
+    taskId: [Number, String],
+    checkboxData: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    return {
+      // 子任务选择时间
+      subtasksDate: '',
+      // 子任务数据
+      xhUserData: [],
+      subtasksDataText: null,
+      // 子任务人员
+      subtaskChange: false,
+      num: 0,
+      subtasksTextarea: '',
+      isNum: 0
+    }
+  },
+  watch: {},
+  created () {
+    if (this.subTaskCom === 'edit') {
+      this.subtasksTextarea = this.text ? this.text : ''
+      this.subtasksDataText = this.time
+      if (JSON.stringify(this.subData) !== '{}') {
+        if (this.subData.mainUser) {
+          this.subtaskChange = true
+          this.xhUserData = [this.subData.mainUser]
+        }
+      } else {
+        this.xhUserData = []
+        this.subtaskChange = false
+      }
+    }
+  },
+  methods: {
+    // 子任务 -- 选中时间
+    subtasksDateClick (val) {
+      this.subtasksDataText = val.substring(5)
+    },
+    subtasksSubmit (event) {
+      this.subtasksTextarea = this.subtasksTextarea.split(/[\n]/).join('')
+      if (this.subtasksTextarea && this.num === 0) {
+        this.num = 1
+        if (this.subTaskCom === 'new') {
+          this.$emit('on-handle', { type: 'add', result: 'success' })
+          // addTask({
+          //   pid: this.taskData.taskId,
+          //   name: this.subtasksTextarea,
+          //   stopTime: this.subtasksDate,
+          //   mainUserId:
+          //     this.xhUserData.length !== 0 ? this.xhUserData[0].userId : ''
+          // })
+          //   .then(res => {
+          //     this.taskData.childTask.push({
+          //       name: this.subtasksTextarea,
+          //       stopTime: this.subtasksDate,
+          //       taskId: res.data.taskId,
+          //       mainUser: this.xhUserData.length > 0 ? this.xhUserData[0] : null
+          //     })
+          //     this.$message.success('子任务创建成功')
+          //     // 创建成功 -- 清除选择
+          //     this.subtasksTextarea = ''
+          //     this.subtasksDataText = null
+          //     this.subtaskChange = false
+          //     this.num = 0
+          //   })
+          //   .catch(() => {
+          //     this.$emit('on-handle', { type: 'add', result: 'error' })
+          //     this.$message.error('子任务创建失败')
+          //     this.num = 0
+          //   })
+        } else if (this.subTaskCom === 'edit') {
+          if (
+            this.isNum === 1 ||
+            this.text !== this.subtasksTextarea ||
+            this.subtasksDataText !== this.time
+          ) {
+            this.$emit('on-handle', { type: 'edit', result: 'success' })
+            // editTask({
+            //   taskId: this.taskId,
+            //   stopTime: this.subtasksDate,
+            //   mainUserId:
+            //     this.xhUserData.length > 0 ? this.xhUserData[0].id : '',
+            //   name: this.subtasksTextarea
+            // })
+            //   .then(res => {
+            //     const dataList = this.taskData.childTask
+            //     for (const i in dataList) {
+            //       if (dataList[i].taskId === this.taskId) {
+            //         const list = dataList[i]
+            //         list.name = this.subtasksTextarea
+            //         list.stopTime = this.subtasksDate
+            //         list.mainUser =
+            //           this.xhUserData.length > 0 ? this.xhUserData[0] : null
+            //         dataList.splice(i, 1, list)
+            //         break
+            //       }
+            //     }
+            //     this.num = 0
+            //     this.$message.success('子任务编辑成功')
+            //   })
+            //   .catch(() => {
+            //     this.$emit('on-handle', { type: 'edit', result: 'error' })
+            //     this.$message.error('子任务编辑失败')
+            //     this.num = 0
+            //   })
+          } else {
+            this.$emit('on-handle', { type: 'cancel' })
+          }
+        }
+      } else {
+        this.$emit('on-handle', { type: 'cancel' })
+      }
+    },
+    xhUserCheckout (data) {
+      if (data.data.length !== 0) {
+        this.subtaskChange = true
+        if (this.xhUserData.length !== 0) {
+          this.$set(this.xhUserData[0], 'img', data.data[0].img)
+          this.$set(this.xhUserData[0], 'realname', data.data[0].realname)
+        } else {
+          this.xhUserData = data.data
+        }
+        this.isNum = 1
+      } else {
+        this.isNum = 0
+        this.subtaskChange = false
+      }
+    },
+    // 子任务 -- 时间弹框
+    subtasksDateFun () {
+      this.$refs.subtasksDate.change()
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.wukong {
+  color: #666;
+}
+.subtasks-content {
+  border: 1px solid #4D88FF;
+  border-radius: 3px;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  // margin-top: 10px;
+  height: 40px;
+  .subtasks-box {
+    line-height: 40px;
+  }
+  .subtasks-content-box {
+    flex: 1;
+    .el-textarea /deep/ .el-textarea__inner {
+      border-width: 0;
+      resize: none;
+    }
+  }
+  .subtasks-content-png {
+    width: auto;
+    img {
+      margin-right: 10px;
+      cursor: pointer;
+      vertical-align: middle;
+    }
+    .time {
+      display: inline-block;
+      position: relative;
+      vertical-align: middle;
+      .el-date-editor {
+        position: absolute;
+        right: 0;
+        width: 28px;
+        opacity: 0;
+        bottom: 0;
+        top: 0;
+      }
+      .el-date-editor /deep/ .el-input__inner {
+        padding: 0;
+        height: 100%;
+      }
+      .el-date-editor /deep/ .el-input__suffix {
+        display: none;
+      }
+      .el-date-editor /deep/ .el-input__prefix {
+        left: 0;
+        right: 0;
+      }
+      .bg-color {
+        padding: 2px 10px;
+      }
+      .wukong-time-task {
+        margin-right: 10px;
+        cursor: pointer;
+        vertical-align: middle;
+      }
+    }
+    .select-box {
+      display: inline-block;
+      .div-photo {
+        width: 24px;
+        height: 24px;
+        border-radius: 12px;
+      }
+      .wukong-user {
+        margin-right: 10px;
+        cursor: pointer;
+        vertical-align: middle;
+      }
+    }
+  }
+  .checkbox-box {
+    margin-left: 10px;
+  }
+  .subtask-popover-span {
+    padding: 0 10px 0 5px;
+  }
+}
+</style>
diff --git a/src/views/OAManagement/task/components/tag/editTag.vue b/src/views/OAManagement/task/components/tag/editTag.vue
new file mode 100644
index 0000000..02e84bb
--- /dev/null
+++ b/src/views/OAManagement/task/components/tag/editTag.vue
@@ -0,0 +1,134 @@
+<template>
+  <div class="edit-tag-dialog">
+    <div class="title">
+      <span
+        class="el-icon-arrow-left"
+        @click="back"/>
+      <span>标签管理</span>
+      <span
+        class="el-icon-close rt"
+        @click="close"/>
+    </div>
+    <div class="search">
+      <el-input
+        v-model="inputModel"
+        :maxlength="10"
+        size="mini"
+        placeholder="输入标签名,最多十个字符"/>
+    </div>
+    <div class="content">
+      <div
+        v-for="(item, index) in list"
+        :key="index"
+        class="tag-list">
+        <span
+          :style="{'background': item.color ? item.color: '#ccc'}"
+          class="tag-name">
+          {{ item.name.length > 10 ? item.name.substring(0, 10) + '...' : item.name }}
+        </span>
+        <div class="rt">
+          <span
+            class="el-icon-edit"
+            @click="editBtn(item)"/>
+          <span
+            class="el-icon-delete"
+            @click="deleteBtn(item)"/>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  props: {
+    editTagList: Array
+  },
+  data () {
+    return {
+      inputModel: '',
+      list: this.editTagList
+    }
+  },
+  watch: {
+    inputModel: function (newVal) {
+      this.list = this.editTagList.filter(item => {
+        return item.name.indexOf(newVal) > -1
+      })
+    }
+  },
+  methods: {
+    back () {
+      this.$emit('back')
+    },
+    close () {
+      this.$emit('close')
+    },
+    deleteBtn (item) {
+      this.$emit('deleteBtn', item)
+    },
+    editBtn (item) {
+      this.$emit('editBtn', item)
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.edit-tag-dialog {
+  overflow: hidden;
+  // position: absolute;
+  // top: 0;
+  // left: -110px;
+  // right: 0;
+  background: #fff;
+  min-height: 200px;
+  // box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
+  .title {
+    padding: 10px;
+    border-bottom: 1px solid#E6E6E6;
+    margin-bottom: 20px;
+    .el-icon-close {
+      margin-right: 0;
+      cursor: pointer;
+    }
+    .el-icon-arrow-left {
+      cursor: pointer;
+    }
+  }
+  .search {
+    .el-input {
+      width: 90%;
+      margin: 0 5%;
+    }
+    .el-input /deep/ .el-input__inner {
+      border-radius: 15px;
+    }
+  }
+  .content {
+    margin: 10px 0;
+    height: 196px;
+    overflow: auto;
+    .tag-list {
+      padding: 5px 5%;
+      .rt {
+        margin-right: 0;
+        color: #aaa;
+        span {
+          margin-right: 10px;
+          cursor: pointer;
+        }
+      }
+      .tag-name {
+        font-size: 12px;
+        border-radius: 3px;
+        padding: 3px 10px;
+        color: #fff;
+      }
+    }
+    .tag-list:hover {
+      background: #f7f8fa;
+    }
+  }
+}
+</style>
diff --git a/src/views/OAManagement/task/components/tag/newTag.vue b/src/views/OAManagement/task/components/tag/newTag.vue
new file mode 100644
index 0000000..e13d9e6
--- /dev/null
+++ b/src/views/OAManagement/task/components/tag/newTag.vue
@@ -0,0 +1,158 @@
+<template>
+  <div class="new-tag-dialog">
+    <div class="title">
+      <span
+        class="el-icon-arrow-left"
+        @click="back"/>
+      <span>{{ newTagTitle }}</span>
+      <span
+        class="el-icon-close rt"
+        @click="close"/>
+    </div>
+    <div class="search">
+      <el-input
+        v-model="input"
+        :maxlength="10"
+        size="mini"
+        placeholder="输入标签名,最多十个字符"/>
+      <span
+        :style="{'background': showBgColor}"
+        class="checked-color"/>
+    </div>
+    <div class="color-box">
+      <span
+        v-for="(item, index) in colorList"
+        :key="index"
+        :style="{'background': item}"
+        @click="changeColor(item)"/>
+    </div>
+    <div class="footer">
+      <el-button
+        type="primary"
+        size="medium"
+        @click="tagCreateSubmit">保存</el-button>
+      <el-button
+        size="medium"
+        @click="tagCancel">取消</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  props: {
+    newTagTitle: String,
+    newTagInput: String,
+    bgColorProps: String
+  },
+  data () {
+    return {
+      colorList: [
+        '#53D397',
+        '#20C1BD',
+        '#58DADA',
+        '#0FC9E7',
+        '#3498DB',
+        '#4586FF',
+        '#8983F3',
+        '#AEA1EA',
+        '#FF6699',
+        '#F24D70',
+        '#FF6F6F'
+      ],
+      input: this.newTagInput,
+      showBgColor: ''
+    }
+  },
+  watch: {
+    bgColorProps: function (color) {
+      this.showBgColor = color || '#53D397'
+    }
+  },
+  mounted () {
+    this.showBgColor = this.bgColorProps || '#53D397'
+  },
+  methods: {
+    back () {
+      this.$emit('back')
+    },
+    close () {
+      this.$emit('close')
+    },
+    // 点击变色
+    changeColor (val) {
+      this.$emit('changeColor', val)
+    },
+    // 创建按钮
+    tagCreateSubmit () {
+      this.$emit('tagCreateSubmit', this.input, this.showBgColor)
+    },
+    // 取消按钮
+    tagCancel () {
+      this.$emit('tagCancel')
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.new-tag-dialog {
+  overflow: hidden;
+  // position: absolute;
+  // top: 0;
+  // left: -110px;
+  // bottom: 0;
+  // right: 0;
+  background: #fff;
+  min-height: 200px;
+  // box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
+  margin: 0 -12px -12px;
+  .title {
+    padding: 10px;
+    border-bottom: 1px solid#E6E6E6;
+    margin-bottom: 20px;
+    .el-icon-close {
+      margin-right: 0;
+      cursor: pointer;
+    }
+    .el-icon-arrow-left {
+      cursor: pointer;
+    }
+  }
+  .search {
+    position: relative;
+    .el-input {
+      width: 90%;
+      margin: 0 5%;
+    }
+    .el-input /deep/ .el-input__inner {
+      padding-left: 40px;
+    }
+    .checked-color {
+      position: absolute;
+      left: 5%;
+      top: 0;
+      display: inline-block;
+      width: 20px;
+      height: 20px;
+      border-radius: 50%;
+      margin: 4px 10px;
+    }
+  }
+  .footer {
+    text-align: right;
+    margin: 20px;
+  }
+  .color-box {
+    margin: 10px 5%;
+    span {
+      display: inline-block;
+      width: 20px;
+      height: 20px;
+      margin-right: 5px;
+      border-radius: 50%;
+      cursor: pointer;
+    }
+  }
+}
+</style>
diff --git a/src/views/OAManagement/task/components/tag/tagIndex.vue b/src/views/OAManagement/task/components/tag/tagIndex.vue
new file mode 100644
index 0000000..58afe56
--- /dev/null
+++ b/src/views/OAManagement/task/components/tag/tagIndex.vue
@@ -0,0 +1,394 @@
+<template>
+  <div class="edit-index">
+    <el-popover
+      :placement="placement"
+      :width="popoverWidth"
+      v-model="tagShow"
+      trigger="click">
+      <div
+        v-if="tagContent === 0"
+        class="tag-popover-box">
+        <div class="tag-top">
+          <span>选择标签</span>
+          <span
+            class="el-icon-close rt cursor-pointer"
+            @click="tagShow = false"/>
+        </div>
+        <el-input
+          v-model="tagInputChange"
+          placeholder="搜索标签"
+          prefix-icon="el-icon-search"
+          size="small"/>
+        <div class="tag-content">
+          <div
+            v-for="(item, index) in particularsTagList"
+            :key="index"
+            class="tag-list"
+            @click="tagBtn(item, particularsTagList)">
+            <i
+              :style="{ 'color': item.color}"
+              class="wukong wukong-black-label"/>
+            <span class="item-label">{{ item.name }}</span>
+            <span
+              v-if="item.check"
+              class="el-icon-check rt"/>
+          </div>
+        </div>
+        <div class="tag-footer">
+          <p
+            class="footer-row cursor-pointer"
+            @click="createTagFun">
+            <span class="el-icon-plus"/>
+            <span>创建新标签</span>
+          </p>
+          <p
+            class="footer-row cursor-pointer"
+            @click="managementTag">
+            <span class="el-icon-setting"/>
+            <span>标签管理</span>
+          </p>
+        </div>
+      </div>
+      <!-- 新建标签页 -->
+      <new-tag
+        v-else-if="tagContent === 1"
+        :new-tag-title="newTagTitle"
+        :new-tag-input="newTagInput"
+        :bg-color-props="bgColorProps"
+        @changeColor="changeColor"
+        @close="tagClose"
+        @tagCreateSubmit="tagCreateSubmit"
+        @tagCancel="tagCancel"
+        @back="back"/>
+      <!-- 标签管理 -->
+      <editTag
+        v-else-if="tagContent === 2"
+        :edit-tag-list="editTagList"
+        @back="back"
+        @close="tagClose"
+        @editBtn="editBtn"
+        @deleteBtn="deleteBtn"/>
+      <!-- 标签管理 - 编辑 -->
+      <new-tag
+        v-else-if="tagContent === 3"
+        :new-tag-title="newTagTitle"
+        :new-tag-input="newTagInput"
+        :bg-color-props="bgColorProps"
+        @changeColor="changeColor"
+        @close="tagClose"
+        @tagCreateSubmit="tagCreateSubmit"
+        @tagCancel="tagCancel"
+        @back="back"/>
+      <span
+        slot="reference"
+        @click="referenceFun">
+        <slot name="editIndex"/>
+      </span>
+    </el-popover>
+  </div>
+</template>
+
+<script>
+import newTag from './newTag'
+import editTag from './editTag'
+// import { tagList,
+//   editTask,
+//   createTag,
+//   deleteTagAPI,
+//   editTagAPI
+// } from '@/api/oamanagement/task'
+
+export default {
+  components: {
+    newTag,
+    editTag
+  },
+  props: {
+    taskData: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    placement: String
+  },
+  data () {
+    return {
+      // 标签弹出框
+      tagShow: false,
+      // 显示tag页面
+      tagContent: 0,
+      // 标签筛选框
+      tagInputChange: '',
+      // 标签数据
+      particularsTagList: [],
+      // 新增、编辑标签标题
+      newTagTitle: '',
+      // 创建-编辑标签的输入框
+      newTagInput: '',
+      // 标签颜色
+      bgColorProps: '',
+      // 标签编辑ID
+      editTagId: '',
+      popoverWidth: '220'
+    }
+  },
+  watch: {
+    // 搜索标签
+    tagInputChange: function (newVal) {
+      this.particularsTagList = this.particularsTagListCopy.filter(item => {
+        return item.name.indexOf(newVal) > -1
+      })
+    }
+  },
+  mounted () {
+    this.tagListFun()
+  },
+  methods: {
+    // 创建新标签
+    createTagFun () {
+      this.newTagTitle = '创建新标签'
+      this.newTagInput = ''
+      this.tagContent = 1
+      this.popoverWidth = '330'
+    },
+    // 标签管理 -- 编辑
+    editBtn (val) {
+      this.editTagId = val.labelId
+      this.newTagTitle = '编辑标签'
+      this.tagContent = 3
+      this.bgColorProps = val.color
+      this.newTagInput = val.name
+    },
+    // 标签管理弹出框
+    managementTag () {
+      this.popoverWidth = '400'
+      this.tagContent = 2
+    },
+    // 标签点击变色
+    tagBtn (value, values) {
+      // 标签点击关联页面
+      // const labelIds = values.filter(item => {
+      //   if (value.check) {
+      //     return item.check && item.labelId !== value.labelId
+      //   } else {
+      //     return item.check || item.labelId === value.labelId
+      //   }
+      // })
+      if (value.check) {
+        // editTask({
+        //   taskId: this.taskData.taskId,
+        //   labelId: labelIds
+        //     .map(item => {
+        //       return item.labelId
+        //     })
+        //     .join(',')
+        // }).then(res => {
+        //   const list = this.taskData.labelList
+        //   for (const item in list) {
+        //     if (value.labelId === list[item].labelId) {
+        //       list.splice(item, 1)
+        //       break
+        //     }
+        //   }
+        //   value.check = false
+        // })
+      } else {
+        // editTask({
+        //   taskId: this.taskData.taskId,
+        //   labelId: labelIds
+        //     .map(item => {
+        //       return item.labelId
+        //     })
+        //     .join(',')
+        // }).then(res => {
+        //   value.check = true
+        //   value.labelName = value.name
+        //   this.taskData.labelList.push(value)
+        // })
+      }
+      // value.check = value.check ? false : true
+      for (const item in values) {
+        if (values[item].labelId === value.labelId) {
+          document.getElementsByClassName('tag-list')[item].style.background =
+            '#F7F8FA'
+        } else {
+          document.getElementsByClassName('tag-list')[item].style.background =
+            '#FFF'
+        }
+      }
+    },
+    // 标签点击变色
+    changeColor (val) {
+      this.bgColorProps = val
+    },
+    // 标签管理 -- 关闭按钮
+    tagClose () {
+      this.tagShow = false
+    },
+    // 创建新标签 -- 提交
+    tagCreateSubmit (val, color) {
+      // const _this = this
+      if (this.newTagTitle === '创建新标签') {
+        // createTag({
+        //   name: val,
+        //   color: color
+        // }).then(res => {
+        //   // 关闭标签页
+        //   this.tagClose()
+        //   // 刷新标签列表
+        //   this.tagListFun()
+        //   this.$message.success('创建成功')
+        // })
+      } else {
+        // editTagAPI({
+        //   name: val,
+        //   labelId: this.editTagId,
+        //   color: color
+        // }).then(res => {
+        //   for (const item of _this.editTagList) {
+        //     if (item.labelId === _this.editTagId) {
+        //       item.name = val
+        //       item.color = color
+        //     }
+        //   }
+        //   this.tagContent = 2
+        // })
+      }
+    },
+    // 创建新标签 -- 取消
+    tagCancel () {
+      if (this.newTagTitle === '创建新标签') {
+        // 关闭标签页
+        this.tagClose()
+        this.$message.info('已取消创建')
+      } else {
+        this.tagContent = 2
+      }
+    },
+    // 标签管理 ——— 返回上一页
+    back () {
+      if (this.newTagTitle === '创建新标签') {
+        this.tagContent = 0
+        this.popoverWidth = '220'
+      } else if (this.newTagTitle === '编辑标签' && this.tagContent === 3) {
+        this.tagContent = 2
+      } else if (this.tagContent === 2) {
+        this.tagContent = 0
+        this.popoverWidth = '220'
+      }
+    },
+    // 标签管理 ——— 删除按钮
+    deleteBtn (val) {
+      this.$confirm('确定删除?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+        customClass: 'is-particulars'
+      })
+        .then(() => {
+          this.tagShow = true
+          this.managementTag()
+          // deleteTagAPI({
+          //   labelId: val.labelId
+          // }).then(res => {
+          //   for (const i in this.editTagList) {
+          //     if (this.editTagList[i].labelId === val.labelId) {
+          //       this.editTagList.splice(i, 1)
+          //     }
+          //   }
+          //   this.$message({
+          //     type: 'success',
+          //     message: '删除成功!'
+          //   })
+          // })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+          this.tagShow = true
+          this.managementTag()
+        })
+    },
+    tagListFun () {
+      // 标签列表
+      // tagList().then(res => {
+      //   for (const item of res.data) {
+      //     if (this.taskData.labelList) {
+      //       for (const i of this.taskData.labelList) {
+      //         if (i.labelId === item.labelId) {
+      //           item.check = true
+      //           break
+      //         } else {
+      //           item.check = false
+      //         }
+      //       }
+      //     }
+      //   }
+      //   // 标签管理数据
+      //   this.editTagList = res.data
+      //   this.particularsTagList = res.data
+      //   // 用作搜索功能
+      //   this.particularsTagListCopy = res.data
+      // })
+    },
+    referenceFun () {
+      this.tagContent = 0
+      this.tagListFun()
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+// 标签按钮
+.tag-popover-box {
+  margin: 0 -12px;
+  .tag-top {
+    margin-bottom: 10px;
+    .el-icon-close {
+      margin-right: 0;
+    }
+  }
+  .el-input /deep/ .el-input__inner {
+    border-radius: 15px;
+  }
+  .tag-content {
+    margin-top: 10px;
+    height: 196px;
+    overflow: auto;
+    border-bottom: 1px solid #e6e6e6;
+    .tag-list {
+      cursor: pointer;
+      padding: 10px;
+      .el-icon-check {
+        margin-right: 0;
+      }
+    }
+    .tag-list:hover {
+      background: #f7f8fa;
+    }
+  }
+  .tag-footer {
+    color: #4D88FF;
+    .footer-row {
+      margin: 13px 0;
+    }
+  }
+}
+.tag-top,
+.tag-content,
+.tag-footer {
+  padding: 0 12px;
+}
+.tag-popover-box > .el-input {
+  width: auto;
+  margin: 0 12px;
+}
+
+.cursor-pointer {
+  cursor: pointer;
+}
+</style>
diff --git a/src/views/OAManagement/task/components/taskCell.vue b/src/views/OAManagement/task/components/taskCell.vue
new file mode 100644
index 0000000..a4f15b6
--- /dev/null
+++ b/src/views/OAManagement/task/components/taskCell.vue
@@ -0,0 +1,332 @@
+<template>
+  <div
+    ref="taskRow"
+    :style="{'border-left-color': data.priority === 1 ? '#8bb5f0' : data.priority === 2 ? '#FF9668' : data.priority === 3 ? '#ED6363': 'transparent'}"
+    class="list"
+    @click="rowFun(data)">
+    <div
+      ref="listLeft"
+      class="list-left">
+      <div
+        :class="data.checked ? 'title title-active' : 'title'"
+        @click.stop>
+        <el-checkbox
+          v-model="data.checked"
+          @change="taskOverClick(data)"/>
+      </div>
+      <el-tooltip
+        placement="bottom"
+        effect="light"
+        popper-class="task-tooltip tooltip-change-border">
+        <div slot="content">
+          <span>{{ data.name }}</span>
+        </div>
+        <span
+          ref="itemSpan"
+          :class="data.checked ? 'item-name-active' : 'item-name'">
+          {{ data.name }}
+        </span>
+      </el-tooltip>
+    </div>
+    <div class="list-right">
+      <div
+        v-if="data.labelList && data.labelList.length > 0"
+        class="tag-box">
+        <template v-if="data.labelList.length <= 2">
+          <div
+            v-for="(k, j) in data.labelList"
+            :key="j"
+            class="item-label">
+            <span
+              :style="{'background': k.color}"
+              class="k-name">{{ k.labelName }}</span>
+          </div>
+        </template>
+        <template v-else>
+          <span
+            :style="{'background': data.labelList[0].color}"
+            class="k-name">{{ data.labelList[0].labelName }}</span>
+          <span
+            :style="{'background': data.labelList[1].color}"
+            class="k-name">{{ data.labelList[1].labelName }}</span>
+          <el-tooltip
+            placement="top"
+            effect="light"
+            popper-class="tooltip-change-border task-tooltip">
+            <div
+              slot="content"
+              class="tooltip-content"
+              style="margin: 10px 10px 10px 0;">
+              <div
+                v-for="(k, j) in data.labelList"
+                :key="j"
+                class="item-label"
+                style="display: inline-block; margin-right: 10px;">
+                <span
+                  v-if="j >= 2"
+                  :style="{'background': k.color || '#ccc'}"
+                  class="k-name"
+                  style="border-radius: 3px; color: #FFF; padding: 3px 10px;">{{ k.labelName }}</span>
+              </div>
+            </div>
+            <span class="color-label-more">
+              <i>...</i>
+            </span>
+          </el-tooltip>
+        </template>
+      </div>
+      <div class="img-group">
+        <div
+          v-if="data.relationCount"
+          class="img-box">
+          <i class="wukong wukong-relevance"/>
+          <span>{{ data.relationCount }}</span>
+        </div>
+        <div
+          v-if="data.childAllCount > 0"
+          class="img-box">
+          <i class="wukong wukong-sub-task"/>
+          <span>{{ data.childWCCount }}/{{ data.childAllCount }}</span>
+        </div>
+        <div
+          v-if="data.fileCount"
+          class="img-box">
+          <i class="wukong wukong-file"/>
+          <span>{{ data.fileCount }}</span>
+        </div>
+        <div
+          v-if="data.commentCount"
+          class="img-box">
+          <i class="wukong wukong-comment-task"/>
+          <span>{{ data.commentCount }}</span>
+        </div>
+        <div
+          v-if="data.stopTime"
+          class="img-box">
+          <i
+            :style="{'color': data.isEnd === 1 && !data.checked ? 'red': '#999'}"
+            class="wukong wukong-time-task"/>
+          <span :style="{'color': data.isEnd === 1 && !data.checked ? 'red': '#999'}">{{ data.stopTime | moment("MM-DD") }} 截止</span>
+        </div>
+      </div>
+      <div class="item-own-box">
+        <el-tooltip
+          v-if="data.mainUser && data.mainUser.id"
+          placement="bottom"
+          effect="light"
+          popper-class="tooltip-change-border">
+          <div slot="content">
+            <span>{{ data.mainUser.realname }}</span>
+          </div>
+          <div
+            v-photo="data.mainUser"
+            v-lazy:background-image="$options.filters.filterUserLazyImg(data.mainUser.img)"
+            class="div-photo"/>
+        </el-tooltip>
+      </div>
+    </div>
+  </div>
+</template>
+<script type="text/javascript">
+// API
+// import { editTask } from '@/api/oamanagement/task'
+
+export default {
+  name: 'TaskCell', // 任务cell
+  components: {},
+  mixins: [],
+  props: {
+    data: Object,
+    dataIndex: Number
+  },
+  data () {
+    return {}
+  },
+  computed: {},
+  watch: {},
+  mounted () {},
+  methods: {
+    // 列表标记任务
+    taskOverClick (val) {
+      // editTask({
+      //   taskId: val.taskId,
+      //   status: val.checked ? 5 : 1
+      // })
+      //   .then(res => {
+      //     this.$store.dispatch('GetOAMessageNum', 'task')
+      //   })
+      //   .catch(() => {
+      //     val.checked = false
+      //   })
+    },
+    // 点击显示详情
+    rowFun (val) {
+      this.$emit('on-handle', {
+        type: 'view',
+        data: { item: this.data, index: this.dataIndex }
+      })
+    },
+    onmouseoverFun (item) {
+      if (
+        this.$refs.itemSpan.offsetWidth >
+        this.$refs.listLeft.offsetWidth - 21
+      ) {
+        this.$set(item, 'show', true)
+      } else {
+        this.$set(item, 'show', false)
+      }
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+@import '../../styles/content.scss';
+.list {
+  // padding-bottom: 12px;
+  // padding-top: 12px;
+  padding: 0 10px;
+  cursor: pointer;
+  border-bottom: 1px solid #e6e6e6;
+  border-left: 2px solid transparent;
+  border-radius: 2px;
+  // position: relative;
+  height: 51px;
+  line-height: 51px;
+  display: flex;
+  .header {
+    margin-bottom: 15px;
+    img {
+      width: 32px;
+      margin-right: 14px;
+      vertical-align: middle;
+    }
+    .name-time {
+      display: inline-block;
+      vertical-align: middle;
+      .time {
+        color: #999;
+        margin-top: 5px;
+        font-size: 12px;
+      }
+    }
+  }
+  .title {
+    cursor: pointer;
+    color: #333;
+    display: inline-block;
+    .el-checkbox {
+      padding-right: 7px;
+    }
+  }
+  .title-active {
+    color: #666;
+    text-decoration: line-through;
+    text-decoration-color: #aaa;
+  }
+  .img-group {
+    // margin-top: 6px;
+    color: #999;
+    font-size: 12px;
+    // margin-left: 27px;
+    vertical-align: middle;
+    display: inline-block;
+    .img-box {
+      display: inline-block;
+      margin-right: 6px;
+      img {
+        vertical-align: middle;
+        width: 16px;
+        height: 16px;
+      }
+      span {
+        vertical-align: middle;
+      }
+      .priority-btn {
+        width: 68px;
+        font-size: 12px;
+        display: inline-block;
+        text-align: center;
+        border-radius: 10px;
+        color: #fff;
+        height: 16px;
+        line-height: 16px;
+      }
+    }
+  }
+  .item-name-active {
+    color: #8f8f8f;
+    text-decoration: line-through;
+  }
+  .list-left,
+  .list-right {
+    display: inline-block;
+  }
+  .list-left {
+    // max-width: 60%;
+    flex: 1;
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    padding-right: 10px;
+  }
+  .list-right {
+    // position: absolute;
+    // right: 0;
+    // top: 50%;
+    // max-width: 40%;
+    // transform: translateY(-50%);
+    float: right;
+    .item-own-box {
+      display: inline-block;
+      vertical-align: middle;
+      .div-photo {
+        vertical-align: middle;
+        width: 24px;
+        height: 24px;
+        border-radius: 12px;
+        margin-left: 12px;
+      }
+    }
+    .tag-box {
+      display: inline-block;
+      .item-label {
+        display: inline-block;
+      }
+      .k-name {
+        display: inline-block;
+        height: 20px;
+        line-height: 20px;
+        padding: 0 10px;
+        border-radius: 3px;
+        color: #fff;
+        margin-right: 6px;
+        font-size: 12px;
+      }
+    }
+    .tag-box /deep/ .color-label-more {
+      background: #eee;
+      width: 34px;
+      height: 20px;
+      line-height: 20px;
+      text-align: center;
+      display: inline-block;
+      font-size: inherit;
+      font-weight: 700;
+      border-radius: 3px;
+      vertical-align: middle;
+      position: relative;
+      i {
+        position: absolute;
+        left: 50%;
+        line-height: 36px;
+        top: 0%;
+        height: 20px;
+        transform: translate(-50%, -50%);
+      }
+    }
+  }
+}
+.list:hover {
+  background: #fafafa;
+}
+</style>
diff --git a/src/views/OAManagement/task/index.vue b/src/views/OAManagement/task/index.vue
new file mode 100644
index 0000000..9f617e5
--- /dev/null
+++ b/src/views/OAManagement/task/index.vue
@@ -0,0 +1,266 @@
+<template>
+  <div class="task oa-bgcolor">
+    <div class="header">
+      <el-button
+        type="primary"
+        class="new-btn"
+        @click="newBtn">新建任务</el-button>
+      <el-tabs
+        v-model="activeName"
+        @tab-click="handleClick">
+        <el-tab-pane
+          v-for="(item, index) in tabData"
+          :label="item.label"
+          :name="item.key"
+          :key="index">
+          <my-task
+            v-loading="loading"
+            :list="listData"
+            :list-type="item.key"
+            :ref="item.key"
+            :sub-user-list-data="subUserListData"
+            :load-more-loading="loadMoreLoading"
+            @selectChange="selectChange">
+            <div
+              slot="searchInput"
+              class="search-input">
+              <el-input
+                v-model="searchValue"
+                size="medium"
+                placeholder="搜索任务名称"
+                suffix-icon="el-icon-search"
+                @input="searchChange"/>
+            </div>
+          </my-task>
+        </el-tab-pane>
+      </el-tabs>
+    </div>
+    <!-- 新增任务弹出框 newDialog-->
+    <new-dialog
+      :new-dialog-visible="dialogVisible"
+      :new-loading="newLoading"
+      @handleClose="handleClose"
+      @dialogVisibleSubmit="dialogVisibleSubmit"/>
+  </div>
+</template>
+
+<script>
+import myTask from './components/myTask'
+import newDialog from './components/newDialog'
+// import { taskListAPI, addTask } from '@/api/oamanagement/task'
+// import { usersList } from '@/api/common'
+
+export default {
+  components: {
+    myTask,
+    newDialog
+  },
+  data () {
+    return {
+      activeName: 'mytask',
+      activePramas: { status: '1', priority: '' },
+      tabData: [
+        { label: '我的任务', key: 'mytask' },
+        { label: '我下属的任务', key: 'subtask' }
+      ],
+      listData: [],
+      // 新建
+      dialogVisible: false,
+      newLoading: false,
+      loading: true,
+      // 输入框搜索
+      searchValue: '',
+      // 负责人
+      subUserListData: [],
+      // 页数
+      pageNum: 1,
+      loadText: '加载更多',
+      loadMoreLoading: true,
+      // 判断是否在请求数据
+      isPost: false
+    }
+  },
+  watch: {
+    $route (to, from) {
+      this.$router.go(0)
+    }
+  },
+  beforeRouteUpdate (to, from, next) {
+    if (to.query.routerKey === 1) {
+      this.newBtn()
+    }
+    next()
+  },
+  created () {
+    if (this.$route.query.routerKey === 1) {
+      this.newBtn()
+    }
+    // 负责人
+    this.subUserFun()
+  },
+  mounted () {
+    // 分批次加载
+    for (const dom of document.getElementsByClassName('list-box-container')) {
+      dom.onscroll = () => {
+        const scrollOff = dom.scrollTop + dom.clientHeight - dom.scrollHeight
+        // 滚动条到底部的条件
+        if (Math.abs(scrollOff) < 10 && this.loadMoreLoading === true) {
+          if (!this.isPost) {
+            this.isPost = true
+            this.pageNum++
+            this.getList()
+          } else {
+            this.loadMoreLoading = false
+          }
+        }
+      }
+    }
+    this.getList()
+  },
+  methods: {
+    // 负责人
+    subUserFun () {
+      // usersList({ pageType: 0 })
+      //   .then(res => {
+      //     this.subUserListData = res.data
+      //     this.subUserListData.unshift({
+      //       userId: '',
+      //       realname: ' 全部'
+      //     })
+      //   })
+      //   .catch(() => {})
+    },
+    handleClick () {
+      this.activePramas = this.$refs[this.activeName][0].fromData
+      this.refreshList()
+    },
+    newBtn () {
+      this.dialogVisible = true
+    },
+    // 新建关闭
+    handleClose (tip) {
+      if (tip === 'shortcut') {
+        this.$router.push('task')
+      } else {
+        if (this.$route.query.routerKey === 1) {
+          this.$router.go(-1)
+        } else {
+          this.dialogVisible = false
+        }
+      }
+    },
+    // 新建提交
+    dialogVisibleSubmit (val) {
+      this.newLoading = true
+      // addTask(val)
+      //   .then(res => {
+      //     this.refreshList()
+      //     this.handleClose('shortcut')
+      //     this.$message.success('新建成功')
+      //     this.newLoading = false
+      //     this.dialogVisible = false
+      //   })
+      //   .catch(() => {
+      //     this.newLoading = false
+      //     this.dialogVisible = false
+      //   })
+    },
+    selectChange (data) {
+      const params = {
+        status: data.data.status,
+        type: data.data.type,
+        priority: data.data.priority,
+        date: data.data.date
+      }
+      if (data.type === 'subtask') {
+        params.userId = data.data.subUser
+      } else {
+        params.userId = ''
+      }
+      this.activePramas = params
+
+      this.refreshList()
+    },
+    refreshList () {
+      this.pageNum = 1
+      this.listData = []
+      this.loadMoreLoading = true
+      this.getList()
+    },
+    searchChange () {
+      this.refreshList()
+    },
+    getList () {
+      this.loading = true
+      var params = this.activePramas
+      params.limit = 15
+      params.page = this.pageNum
+      params.search = this.searchValue
+      if (this.activeName === 'subtask') {
+        params.mold = 1
+      }
+      // taskListAPI(params)
+      //   .then(res => {
+      //     for (const item of res.data.list) {
+      //       if (item.status === 5) {
+      //         item.checked = true
+      //       }
+      //     }
+      //     this.listData = this.listData.concat(res.data.list)
+
+      //     if (res.data.list.length < 15) {
+      //       this.loadText = '没有更多了'
+      //       this.loadMoreLoading = false
+      //     } else {
+      //       this.loadText = '加载更多'
+      //       this.loadMoreLoading = true
+      //     }
+      //     this.isPost = false
+      //     this.loading = false
+      //   })
+      //   .catch(() => {
+      //     this.isPost = false
+      //     this.loading = false
+      //   })
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+@import '../styles/tabs.scss';
+
+.task {
+  .header {
+    position: relative;
+    height: 100%;
+    .new-btn {
+      position: absolute;
+      top: 10px;
+      right: 40px;
+      z-index: 9;
+    }
+    .el-tabs {
+      height: 100%;
+      display: flex;
+      flex-direction: column;
+    }
+    .el-tabs /deep/ .el-tabs__content {
+      padding: 0 30px;
+      flex: 1;
+      margin-bottom: 20px;
+      .el-tab-pane {
+        height: 100%;
+        display: flex;
+        flex-direction: column;
+        overflow-y: hidden;
+      }
+    }
+    .search-input {
+      .el-input {
+        width: 328px;
+      }
+    }
+  }
+}
+</style>
diff --git a/src/views/OAManagement/task/mixins/listTaskDetail.js b/src/views/OAManagement/task/mixins/listTaskDetail.js
new file mode 100644
index 0000000..63c4b56
--- /dev/null
+++ b/src/views/OAManagement/task/mixins/listTaskDetail.js
@@ -0,0 +1,64 @@
+export default {
+  components: {},
+  data () {
+    return {
+      // 详情数据
+      taskID: '',
+      detailIndex: -1,
+      taskDetailShow: false
+    }
+  },
+
+  mounted () {},
+
+  methods: {
+    // 关闭详情页
+    closeBtn () {
+      this.taskDetailShow = false
+    },
+    // 点击显示详情
+    showDetailView (val, index, result) {
+      this.taskID = val.taskId
+      this.detailIndex = index
+      this.taskDetailShow = true
+      if (result) {
+        result()
+      }
+    },
+    detailHandle (data) {
+      if (data.index === 0 || data.index) {
+        // 是否完成勾选
+        if (data.type === 'title-check') {
+          this.$set(this.list[data.index], 'checked', data.value)
+        } else if (data.type === 'delete') {
+          this.list.splice(data.index, 1)
+        } else if (data.type === 'change-stop-time') {
+          const stopTime = new Date(data.value).getTime() / 1000 + 86399
+          if (stopTime > new Date(new Date()).getTime() / 1000) {
+            this.list[data.index].isEnd = false
+          } else {
+            this.list[data.index].isEnd = true
+          }
+          this.list[data.index].stopTime = data.value
+        } else if (data.type === 'change-priority') {
+          this.list[data.index].priority = data.value.id
+        } else if (data.type === 'change-name') {
+          this.list[data.index].name = data.value
+        } else if (data.type === 'change-comments') {
+          const commentCount = this.list[data.index].commentCount
+          if (data.value === 'add') {
+            this.list[data.index].commentCount = commentCount + 1
+          } else {
+            this.list[data.index].commentCount = commentCount - 1
+          }
+        } else if (data.type === 'change-sub-task') {
+          this.list[data.index].childWCCount = data.value.subdonecount
+          this.list[data.index].childAllCount = data.value.allcount
+        }
+      }
+    }
+  },
+
+  deactivated: function () {}
+
+}
diff --git a/src/views/OAManagement/workbench/index.vue b/src/views/OAManagement/workbench/index.vue
new file mode 100644
index 0000000..36b8192
--- /dev/null
+++ b/src/views/OAManagement/workbench/index.vue
@@ -0,0 +1,247 @@
+<template>
+  <div class="workbench">
+    <div class="tabs-box">
+      <el-tabs
+        v-loading="loading"
+        v-model="activeName"
+        @tab-click="tabClick">
+        <el-tab-pane
+          v-for="(item, index) in tabsData"
+          :label="item.label"
+          :name="item.key"
+          :key="index">
+          <tab-journal
+            v-if="activeName === '1'"
+            :journal-data="listData">
+            <p
+              slot="load"
+              class="load">
+              <el-button
+                :loading="loadMoreLoading"
+                type="text">{{ loadText }}</el-button>
+            </p>
+          </tab-journal>
+          <tabs-content
+            v-else
+            :list-data="listData">
+            <p
+              slot="workbenchLoad"
+              class="load">
+              <el-button
+                :loading="loadMoreLoading"
+                type="text">{{ loadText }}</el-button>
+            </p>
+          </tabs-content>
+        </el-tab-pane>
+      </el-tabs>
+    </div>
+    <div class="right-content">
+      <div class="task">
+        <v-task/>
+      </div>
+      <div class="schedule">
+        <v-schedule
+          v-loading="scheduleLoading"
+          :calendar-arr="calendarArr"
+          @changeMonth="changeMonth"/>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import tabsContent from './tabsContent'
+import VTask from './task'
+import VSchedule from './schedule'
+import tabJournal from './tabsJournal'
+// API
+// import { workbenchList, eventList } from '@/api/oamanagement/workbench'
+// import moment from 'moment'
+
+export default {
+  components: {
+    tabsContent,
+    VTask,
+    VSchedule,
+    tabJournal
+  },
+  data () {
+    return {
+      activeName: 0,
+      tabsData: [
+        { label: '全部', key: '0' },
+        { label: '日志', key: '1' },
+        { label: '审批', key: '5' },
+        { label: '任务', key: '4' },
+        { label: '日程', key: '2' },
+        { label: '公告', key: '3' }
+      ],
+      // 列表数据
+      listData: [],
+      loading: true,
+      // 页数
+      loadMoreLoading: true,
+      pageNum: 1,
+      loadText: '加载更多',
+      isPost: false,
+      calendarArr: [],
+      // 日程加载
+      scheduleLoading: true
+    }
+  },
+  mounted () {
+    // 日程
+    // eventList({ month: moment(new Date()).format('YYYY-MM') })
+    //   .then(res => {
+    //     for (const item of res.data) {
+    //       if (item.status === 1) {
+    //         item.className = 'mark1'
+    //       }
+    //     }
+    //     this.calendarArr = res.data
+    //     this.scheduleLoading = false
+    //   })
+    //   .catch(() => {
+    //     this.scheduleLoading = false
+    //   })
+    this.workbenchData(this.activeName, this.pageNum)
+    // 分批次加载
+    for (const dom of document.getElementsByClassName('el-tabs__content')) {
+      dom.onscroll = () => {
+        const scrollOff = dom.scrollTop + dom.clientHeight - dom.scrollHeight
+        // 滚动条到底部的条件
+        if (Math.abs(scrollOff) < 10 && this.loadMoreLoading === true) {
+          if (!this.isPost) {
+            this.isPost = true
+            this.pageNum++
+            this.workbenchData(this.activeName, this.pageNum)
+          } else {
+            this.loadMoreLoading = false
+          }
+        }
+      }
+    }
+  },
+  methods: {
+    // 获取数据
+    workbenchData (type, page) {
+      // workbenchList({
+      //   type: type,
+      //   page: page,
+      //   limit: 15
+      // })
+      //   .then(res => {
+      //     this.listData = this.listData.concat(res.data.list)
+      //     if (res.data.lastPage === true) {
+      //       this.loadText = '没有更多了'
+      //       this.loadMoreLoading = false
+      //     } else {
+      //       this.loadText = '加载更多'
+      //       this.loadMoreLoading = true
+      //     }
+      //     this.isPost = false
+      //     this.loading = false
+      //   })
+      //   .catch(() => {
+      //     this.loadText = ''
+      //     this.loading = false
+      //     this.isPost = false
+      //   })
+    },
+    // tabs切换事件
+    tabClick (val) {
+      this.loading = true
+      this.listData = []
+      this.loadMoreLoading = true
+      this.pageNum = 1
+      this.workbenchData(this.activeName, this.pageNum)
+    },
+    // 切换上下月
+    changeMonth (monthDate) {
+      this.scheduleLoading = true
+      // eventList({ month: moment(monthDate).format('YYYY-MM') })
+      //   .then(res => {
+      //     for (const item of res.data) {
+      //       if (item.status === 1) {
+      //         item.className = 'mark1'
+      //       }
+      //     }
+      //     this.calendarArr = res.data
+      //     this.scheduleLoading = false
+      //     // 切换月份去掉背景
+      //     this.$nextTick(() => {
+      //       for (const item of document.getElementsByClassName('wh_item_date')) {
+      //         item.classList.remove('wh_chose_day')
+      //       }
+      //     })
+      //   })
+      //   .catch(() => {
+      //     this.scheduleLoading = false
+      //   })
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+@import '../styles/tabs.scss';
+
+$colorF: #fff;
+.workbench {
+  // margin: 0 auto;
+  height: 100%;
+  min-height: 720px;
+  // width: 100%;
+  width: 1160px;
+  display: flex;
+  .tabs-box {
+    width: 770px;
+    // width: 66%;
+    background: $colorF;
+    margin-right: 20px;
+    height: 100%;
+    border: 1px solid rgba(230, 230, 230, 1);
+    border-radius: 4px;
+    // padding: 0 20px;
+    .load {
+      color: #999;
+      font-size: 13px;
+      margin: 0 auto 15px;
+      text-align: center;
+      .el-button,
+      .el-button:focus {
+        color: #ccc;
+        cursor: auto;
+      }
+    }
+  }
+  .tabs-box /deep/ .el-tabs {
+    display: flex;
+    flex-direction: column;
+    height: 100%;
+    .el-tabs__content {
+      flex: 1;
+      overflow: auto;
+      margin-bottom: 20px;
+    }
+  }
+  .right-content {
+    width: 370px;
+    // width: 34%;
+    .task {
+      background: $colorF;
+      height: 300px;
+      margin-bottom: 20px;
+      border: 1px solid rgba(230, 230, 230, 1);
+      border-radius: 4px;
+    }
+    .schedule {
+      background: $colorF;
+      min-height: 400px;
+      padding: 0 20px;
+      border: 1px solid rgba(230, 230, 230, 1);
+      border-radius: 4px;
+    }
+  }
+}
+</style>
diff --git a/src/views/OAManagement/workbench/schedule.vue b/src/views/OAManagement/workbench/schedule.vue
new file mode 100644
index 0000000..20db265
--- /dev/null
+++ b/src/views/OAManagement/workbench/schedule.vue
@@ -0,0 +1,236 @@
+<template>
+  <div class="schedule-calendar">
+    <div class="title">
+      <span>日程</span>
+      <div
+        class="rt"
+        @click="addSchedule">
+        <span class="el-icon-plus"/>
+        <span>创建</span>
+      </div>
+    </div>
+    <div>
+      <Calendar
+        :mark-date-more="calendarArr"
+        @changeMonth="changeMonth"
+        @choseDay="clickDay"/>
+      <div v-loading="loading">
+        <div
+          v-for="(item, index) in scheduleList"
+          v-if="index < 1"
+          :key="index"
+          class="list"
+          @click="rowFun(item)">
+          <p class="list-title">{{ item.title }}</p>
+          <div>
+            <span class="time">{{ item.startTime }} - {{ item.endTime }}</span>
+            <span>{{ item.realnames }}</span>
+          </div>
+        </div>
+        <p
+          v-if="scheduleList.length >= 1"
+          class="see-more"
+          @click="seeMore">查看更多</p>
+      </div>
+    </div>
+    <!-- 新建日程 -->
+    <create-schedule
+      v-if="showDialog"
+      :text="newText"
+      :form-data="formData"
+      @onSubmit="onSubmit"
+      @closeDialog="closeDialog"/>
+  </div>
+</template>
+
+<script>
+import Calendar from 'vue-calendar-component'
+import createSchedule from '../schedule/components/createSchedule'
+// import { scheduleDayList } from '@/api/oamanagement/workbench'
+// import moment from 'moment'
+
+export default {
+  components: {
+    Calendar,
+    createSchedule
+  },
+  props: {
+    calendarArr: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    }
+  },
+  data () {
+    return {
+      // 日历事件
+      scheduleList: [],
+      currentMonthDate: new Date(),
+      // 新建日程
+      formData: {},
+      showDialog: false,
+      newText: '',
+      // 详情
+      dialogVisible: false,
+      loading: false
+    }
+  },
+  mounted () {
+    this.clickDay(new Date())
+  },
+  methods: {
+    // 点击哪一天
+    clickDay (date) {
+      this.loading = true
+      // scheduleDayList({ day: moment(date).format('YYYY-MM-DD') })
+      //   .then(res => {
+      //     this.scheduleList = res.data
+      //     for (const item of document.getElementsByClassName('wh_item_date')) {
+      //       item.classList.remove('wh_isToday')
+      //     }
+      //     this.loading = false
+      //   })
+      //   .catch(() => {
+      //     this.loading = false
+      //   })
+    },
+    // 查看更多
+    seeMore () {
+      this.$router.push('schedule')
+    },
+    // 创建日程
+    addSchedule () {
+      this.formData = {}
+      this.showDialog = true
+      this.newText = '创建日程'
+    },
+    // 关闭新建日程弹框
+    closeDialog () {
+      this.showDialog = false
+    },
+    onSubmit () {
+      this.$emit('changeMonth', this.currentMonthDate)
+      this.closeDialog()
+    },
+    // 查看详情
+    rowFun (val) {
+      this.dialogVisible = true
+    },
+    // 切换月份
+    changeMonth (val) {
+      this.scheduleList = []
+      this.currentMonthDate = new Date(val)
+      this.$emit('changeMonth', this.currentMonthDate)
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.schedule-calendar {
+  padding-bottom: 20px;
+  .title {
+    height: 44px;
+    line-height: 44px;
+    border-bottom: 1px solid #e6e6e6;
+    .rt {
+      color: #4D88FF;
+      margin-right: 0;
+      cursor: pointer;
+      .el-icon-plus {
+        font-weight: 700;
+      }
+    }
+  }
+  .list {
+    color: #999;
+    padding: 10px 11%;
+    font-size: 13px;
+    cursor: pointer;
+    .list-title {
+      margin-bottom: 5px;
+    }
+    .time {
+      margin-right: 10px;
+      font-size: 12px;
+    }
+  }
+  .see-more {
+    color: #999;
+    text-align: center;
+    cursor: pointer;
+  }
+}
+.schedule-calendar /deep/ .wh_container {
+  max-width: max-content;
+  .wh_content_all {
+    background: #fff;
+    .wh_top_changge {
+      text-align: center;
+      display: block;
+      margin: 15px 0 10px;
+      li {
+        color: #3c8be3;
+        display: inline-block;
+        height: 13px;
+        .wh_jiantou1,
+        .wh_jiantou2 {
+          border-color: #3c8be3;
+          width: 8px;
+          height: 8px;
+          margin-top: 4px;
+        }
+      }
+      .wh_content_li {
+        margin: 0 30px;
+        font-weight: 700;
+        font-size: 15px;
+      }
+    }
+    .wh_content {
+      justify-content: center;
+      .wh_content_item {
+        color: #333;
+        font-size: 14px;
+        margin-top: 3px;
+        height: 30px;
+        position: relative;
+        .wh_top_tag {
+          color: #bfbfbf;
+        }
+        .wh_item_date {
+          background: transparent;
+          width: 30px;
+          height: 30px;
+        }
+        .wh_item_date:hover {
+          background: transparent;
+          color: #3c8be3;
+        }
+        .wh_isToday,
+        .wh_isToday:hover {
+          background: #3487e2;
+          border-radius: 30px;
+          color: #fff;
+        }
+        .wh_chose_day,
+        .wh_chose_day:hover {
+          background: #3487e2;
+          border-radius: 40px;
+          color: #fff;
+        }
+        .mark1:after {
+          content: ' ';
+          background-color: #3c8be3;
+          width: 5px;
+          height: 5px;
+          position: absolute;
+          bottom: 0;
+          border-radius: 50%;
+        }
+      }
+    }
+  }
+}
+</style>
diff --git a/src/views/OAManagement/workbench/tabsContent.vue b/src/views/OAManagement/workbench/tabsContent.vue
new file mode 100644
index 0000000..04e9f0d
--- /dev/null
+++ b/src/views/OAManagement/workbench/tabsContent.vue
@@ -0,0 +1,262 @@
+<template>
+  <div class="tabs-content">
+    <div
+      v-for="(item, index) in listData"
+      :key="index"
+      class="list">
+      <template v-if="item.type === 1">
+        <tab-journal
+          :margin-defaults="true"
+          :journal-data="[item]"/>
+      </template>
+      <template v-else>
+        <div
+          v-photo="item.createUser"
+          v-lazy:background-image="$options.filters.filterUserLazyImg(item.createUser.img)"
+          class="div-photo"/>
+        <div class="img-text">
+          <div class="name-time">
+            <p class="name-behavior">
+              <span
+                v-if="item.createUser.realname"
+                class="name">{{ item.createUser.realname }}</span>
+              <span class="behavior">{{ item.actionContent }}</span>
+            </p>
+            <p class="time">{{ item.createTime }}</p>
+          </div>
+          <div class="log-title">
+            <img
+              v-if="item.type === 1"
+              src="@/assets/img/work_log.png">
+            <img
+              v-else-if="item.type === 2"
+              src="@/assets/img/work_schedule.png">
+            <img
+              v-else-if="item.type === 3"
+              src="@/assets/img/work_notice.png">
+            <img
+              v-else-if="item.type === 4"
+              src="@/assets/img/work_task.png">
+            <img
+              v-else-if="item.type === 5"
+              class="img-5"
+              src="@/assets/img/work_examine.png">
+            <span class="type-name">{{ item.typeName }}</span>
+          </div>
+          <div
+            v-if="item.title"
+            class="title">
+            <span
+              ref="taskRow"
+              @click="rowFun(item)">{{ item.title }}</span>
+          </div>
+        </div>
+      </template>
+    </div>
+    <slot name="workbenchLoad"/>
+    <!-- 公告详情 -->
+    <v-details
+      v-if="dialog"
+      :btn-show="false"
+      :title-list="titleList"
+      @close="close"/>
+    <!-- 日程详情 -->
+    <schedule-details
+      v-if="showScheduleDetails"
+      :btn-show="false"
+      :dialog-visible="dialogVisible"
+      :list-data="scheduleData"
+      @handleClose="scheduleClose"/>
+    <!-- 任务详情 -->
+    <particulars
+      v-if="taskDetailShow"
+      ref="particulars"
+      :id="taskID"
+      @close="taskDetailShow = false"/>
+    <!-- 审批详情 -->
+    <examine-detail
+      v-if="showExamine"
+      :id="examineData.id"
+      :no-listener-class="['tabs-content']"
+      @hide-view="showExamine=false"/>
+  </div>
+</template>
+
+<script>
+import VDetails from '../notice/details'
+import ScheduleDetails from '../schedule/components/details'
+import ExamineDetail from '../examine/components/examineDetail'
+// 任务详情
+import particulars from '../task/components/particulars'
+
+import tabJournal from './tabsJournal'
+export default {
+  components: {
+    VDetails,
+    ScheduleDetails,
+    particulars,
+    tabJournal,
+    ExamineDetail
+  },
+  props: {
+    listData: Array
+  },
+  data () {
+    return {
+      // 公告详情
+      dialog: false,
+      titleList: {},
+      // 日程详情
+      dialogVisible: false,
+      scheduleData: {},
+      // 任务 -- 详情数据
+      taskID: '',
+      taskDetailShow: false,
+      // 是否显示日程详情
+      showScheduleDetails: false,
+      // 是否显示审批
+      examineData: {},
+      showExamine: false
+    }
+  },
+  mounted () {
+    document
+      .getElementById('workbench-main-container')
+      .addEventListener('click', this.taskShowHandle, false)
+  },
+  methods: {
+    rowFun (val) {
+      switch (val.type) {
+        // 日程
+        case 2:
+          {
+            this.dialogVisible = true
+            this.scheduleData = val
+            const list = []
+            list.push(val.startTime, val.endTime)
+            this.scheduleData.time = list
+            this.showScheduleDetails = true
+          }
+          break
+        // 公告
+        case 3:
+          this.dialog = true
+          this.titleList = {
+            title: val.title,
+            createTime: val.createTime,
+            content: val.annContent
+          }
+          break
+        // 任务
+        case 4:
+          this.taskID = val.actionId
+          this.taskDetailShow = true
+          break
+        // 审批
+        case 5:
+          this.examineData = { id: val.actionId }
+          this.showExamine = true
+          break
+      }
+    },
+    // 点击空白处关闭详情
+    taskShowHandle (e) {
+      if (
+        this.$refs.particulars &&
+        !this.$refs.particulars.$el.contains(e.target)
+      ) {
+        let hidden = true
+        const items = document.getElementsByClassName('tabs-content')
+        for (let index = 0; index < items.length; index++) {
+          const element = items[index]
+          if (element.contains(e.target)) {
+            hidden = false
+            break
+          }
+        }
+        this.taskDetailShow = !hidden
+      }
+    },
+    // 公告详情关闭
+    close () {
+      this.dialog = false
+    },
+    // 日程详情关闭
+    scheduleClose () {
+      this.dialogVisible = false
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.tabs-content {
+  margin: 0 30px;
+  .list {
+    font-size: 13px;
+    padding: 20px 0;
+    border-bottom: 1px solid #f1f1f1;
+    .div-photo {
+      width: 35px;
+      height: 35px;
+      border-radius: 17.5px;
+      float: left;
+    }
+    .img-text {
+      margin-left: 50px;
+      .name-time {
+        display: inline-block;
+        .name-behavior {
+          margin-bottom: 6px;
+          .name {
+            margin-right: 10px;
+            color: #333;
+            font-size: 15px;
+          }
+          .behavior {
+            color: #666;
+          }
+        }
+        .time {
+          color: #999;
+          font-size: 12px;
+        }
+      }
+      .log-title {
+        float: right;
+        margin-top: 6px;
+        img,
+        .type-name {
+          vertical-align: middle;
+        }
+        .img-5 {
+          margin-bottom: 3px;
+        }
+      }
+      .title {
+        margin: 20px 0 0;
+        color: #4D88FF;
+        white-space: pre-wrap;
+        word-wrap: break-word;
+        letter-spacing: 0.5px;
+        line-height: 18px;
+        background-color: #f4f7fd;
+        padding: 10px;
+        border-radius: 2px;
+        span {
+          cursor: pointer;
+        }
+      }
+      .title :hover {
+        text-decoration: underline;
+      }
+    }
+  }
+  .list:last-child .title {
+    border: 0;
+  }
+  .list:first-child {
+    padding-top: 5px;
+  }
+}
+</style>
diff --git a/src/views/OAManagement/workbench/tabsJournal.vue b/src/views/OAManagement/workbench/tabsJournal.vue
new file mode 100644
index 0000000..782eed0
--- /dev/null
+++ b/src/views/OAManagement/workbench/tabsJournal.vue
@@ -0,0 +1,78 @@
+<template>
+  <div class="content">
+    <div id="journal-list-box" class="list-box">
+      <journal-cell
+        v-for="(item, index) in journalData"
+        :key="index"
+        :log-index="index"
+        :data="item"
+        :show-workbench="true"
+        :style="{margin: marginDefaults ? '0' : '0 20px 20px'}"
+        class="list-cell"
+        @on-handle="jourecallCellHandle"/>
+      <slot name="load"/>
+    </div>
+    <!-- 相关业务页面 -->
+    <c-r-m-all-detail
+      :visible.sync="showRelatedDetail"
+      :crm-type="relatedCRMType"
+      :listener-ids="['workbench-main-container']"
+      :no-listener-ids="['journal-list-box']"
+      :id="relatedID"
+      class="d-view"/>
+  </div>
+</template>
+
+<script>
+import JournalCell from '@/views/OAManagement/journal/journalCell'
+import CRMAllDetail from '@/views/clients/components/CRMAllDetail'
+
+export default {
+  components: {
+    CRMAllDetail,
+    JournalCell
+  },
+  props: {
+    // 数据
+    journalData: Array,
+    marginDefaults: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    return {
+      // 相关详情的查看
+      relatedID: '',
+      relatedCRMType: '',
+      showRelatedDetail: false
+    }
+  },
+  computed: {},
+  methods: {
+    jourecallCellHandle (data) {
+      this.relatedID = data.data.item.key
+      this.relatedCRMType = data.data.type
+      this.showRelatedDetail = true
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.content {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  .list-box {
+    flex: 1;
+    overflow: auto;
+  }
+}
+
+.list-cell {
+  border: 1px solid #e6e6e6;
+  margin-bottom: 20px;
+  border-radius: 4px;
+}
+</style>
diff --git a/src/views/OAManagement/workbench/task.vue b/src/views/OAManagement/workbench/task.vue
new file mode 100644
index 0000000..fb5f39a
--- /dev/null
+++ b/src/views/OAManagement/workbench/task.vue
@@ -0,0 +1,241 @@
+<template>
+  <div class="v-task">
+    <div class="title">任务</div>
+    <div
+      v-loading="loading"
+      :style="{'padding-right': list.length > 4 ? '7px' : '0'}"
+      class="content-box">
+      <template v-if="list.length !== 0">
+        <div
+          v-for="(item, index) in list"
+          ref="taskRow"
+          :key="index"
+          class="content"
+          @click="checkRowDetail(item, index)">
+          <div class="name-time">
+            <p
+              class="task-name"
+              @click.stop>
+              <el-checkbox
+                v-model="item.checked"
+                :disabled="item.checked"
+                @change="taskOverFun(item, index)"/>
+            </p>
+            <span :class="item.lineThrough ? 'item-name item-name-active': 'item-name'">
+              {{ item.name }}
+            </span>
+            <p
+              v-if="item.stop_time"
+              :style="{color: item.task_status === 2 ? 'red' : '#999'}"
+              class="time">
+              <span class="el-icon-time"/>
+              <span>{{ item.stop_time | moment("YYYY-MM-DD") }}</span>
+            </p>
+          </div>
+          <div class="rt">
+            <span
+              v-for="(k, j) in colorGroup"
+              v-if="item.priority === k.id"
+              :key="j"
+              :style="{background: k.color}"
+              class="type-color">
+              {{ k.label }}
+            </span>
+          </div>
+        </div>
+      </template>
+      <div
+        v-else-if="list.length === 0 && loading === false"
+        class="no-task">
+        <img
+          src="@/assets/img/no_task.png"
+          alt="">
+        <p>目前没有任务,快去<span
+          class="add"
+          @click="addTask">添加</span>吧!</p>
+      </div>
+    </div>
+    <!-- 详情 -->
+    <particulars
+      v-if="taskDetailShow"
+      ref="particulars"
+      :id="taskID"
+      :detail-index="detailIndex"
+      @on-handle="getList"
+      @close="closeBtn"/>
+  </div>
+</template>
+
+<script>
+import listTaskDetail from '../task/mixins/listTaskDetail.js'
+// API
+// import {
+//   editTask
+// } from '@/api/oamanagement/task'
+// import { taskListAPI } from '@/api/oamanagement/workbench'
+// 详情
+import particulars from '../task/components/particulars'
+
+export default {
+  components: {
+    particulars
+  },
+  mixins: [listTaskDetail],
+  data () {
+    return {
+      // 加载中
+      loading: false,
+      list: [],
+      colorGroup: [
+        { id: null, label: '', color: '' },
+        { id: 0, label: '无', color: '#ccc' },
+        { id: 1, label: '低', color: '#8bb5f0' },
+        { id: 2, label: '中', color: '#FF9668' },
+        { id: 3, label: '高', color: '#ED6363' }
+      ]
+    }
+  },
+  mounted () {
+    document
+      .getElementById('workbench-main-container')
+      .addEventListener('click', this.subtasksSubmit, false)
+    this.getList()
+  },
+  methods: {
+    getList () {
+      this.loading = true
+      // taskListAPI()
+      //   .then(res => {
+      //     for (const item of res.data) {
+      //       item.checked = false
+      //     }
+      //     this.list = res.data
+      //     this.loading = false
+      //   })
+      //   .catch(() => {
+      //     this.loading = false
+      //   })
+    },
+    // 点击空白处关闭详情
+    subtasksSubmit (e) {
+      if (
+        this.$refs.particulars &&
+        !this.$refs.particulars.$el.contains(e.target)
+      ) {
+        this.taskDetailShow = false
+      }
+    },
+    checkRowDetail (item, index) {
+      this.showDetailView(item, index)
+    },
+    // 列表标记任务
+    taskOverFun (item, index) {
+      // editTask({
+      //   taskId: item.taskId,
+      //   status: item.checked ? 5 : 1
+      // })
+      //   .then(res => {
+      //     if (item.checked) {
+      //       this.list.splice(index, 1)
+      //     }
+      //     this.$store.dispatch('GetOAMessageNum', 'task')
+      //   })
+      //   .catch(() => {
+      //     item.checked = !item.checked
+      //   })
+    },
+    addTask () {
+      this.$router.push({ path: 'task', query: { routerKey: 1 } })
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.v-task {
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  position: relative;
+  .title {
+    height: 44px;
+    line-height: 44px;
+    margin: 0 20px;
+    border-bottom: 1px solid #e6e6e6;
+  }
+  .content-box {
+    flex: 1;
+    overflow: hidden;
+    position: relative;
+    margin-bottom: 10px;
+    .content {
+      margin: 21px;
+      cursor: pointer;
+      overflow: hidden;
+      .name-time {
+        // width: 240px;
+        width: 89%;
+        float: left;
+        .task-name {
+          margin-bottom: 8px;
+          margin-right: 6px;
+          display: inline-block;
+        }
+        .time {
+          font-size: 12px;
+          padding-left: 27px;
+          .el-icon-time {
+            font-weight: 600;
+          }
+        }
+        .item-name {
+          width: 80%;
+          overflow: hidden;
+          white-space: nowrap;
+          text-overflow: ellipsis;
+          display: inline-block;
+          vertical-align: middle;
+        }
+        .item-name-active {
+          color: #666;
+          text-decoration: line-through;
+        }
+      }
+      .rt {
+        margin-right: 0;
+        float: left;
+        .type-color {
+          display: inline-block;
+          text-align: center;
+          width: 34px;
+          height: 34px;
+          line-height: 34px;
+          border-radius: 50%;
+          color: #fff;
+          font-size: 12px;
+        }
+      }
+    }
+  }
+  .content-box:hover {
+    overflow: auto;
+    padding-right: 0 !important;
+  }
+  .no-task {
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    text-align: center;
+    transform: translate(-50%, -50%);
+    // margin-top: 10px;
+    p {
+      color: #777;
+      margin-top: 10px;
+    }
+    .add {
+      color: #4D88FF;
+      cursor: pointer;
+    }
+  }
+}
+</style>
diff --git a/src/views/PWS/EwsAnalyze.vue b/src/views/PWS/EwsAnalyze.vue
new file mode 100644
index 0000000..de85409
--- /dev/null
+++ b/src/views/PWS/EwsAnalyze.vue
@@ -0,0 +1,411 @@
+<template>
+  <div class='customer'>
+    <c-r-m-list-head
+      ref="listHead"
+      title="EWS洞察分析"
+      main-title="PWS API" />
+    <el-form :inline="true" class="selectInline">
+      <el-form-item>
+          <el-input
+            class="search-container"
+            v-model="searchName"
+            placeholder="请输入客户CSN"
+            @keyup.enter.native="searchClick"/>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" @click="searchClick">查询</el-button>
+      </el-form-item>
+    </el-form>
+    <el-card class="el-card">
+      <el-table
+        v-loading="loading"
+        id="crm-table"
+        :data="tableData"
+        :height="tableHeight"
+        :cell-style="cellStyle"
+        class="n-table--border"
+        border
+        highlight-current-row
+        style="width: 100%"
+        @row-click="rowClick">
+        <el-table-column
+          v-for="(item, index) in fieldList"
+          :key="index"
+          :prop="item.field"
+          :label="item.name"
+          :formatter="fieldFormatter"
+          show-overflow-tooltip>
+          <template
+            slot="header"
+            slot-scope="scope">
+            <div class="table-head-name">{{ scope.column.label }}</div>
+          </template>
+        </el-table-column>
+      </el-table>
+    </el-card>
+  </div>
+</template>
+
+<script>
+import CRMListHead from '../clients/components/CRMListHead'
+import { InsightsMetrics } from '@/api/pwsApi/ewsAnalyze'
+
+export default {
+  name: 'EwsAnalyze',
+  components: {
+    CRMListHead
+  },
+  data () {
+    return {
+      searchName: '',
+      tableData: [],
+      tableHeight: document.documentElement.clientHeight - 360 + 44,
+      fieldList: [
+        { name: 'CustomerCSN', field: 'CustomerCSN', formType: 'text' },
+        { name: 'ContractNumber', field: 'ContractNumber', formType: 'text' },
+        { name: 'OwnerType', field: 'OwnerType', formType: 'text' },
+        { name: 'ProductLineCode', field: 'ProductLineCode', formType: 'text' },
+        { name: 'SeatsPurchased', field: 'SeatsPurchased', formType: 'text' },
+        { name: 'UsersAssigned', field: 'UsersAssigned', formType: 'text' },
+        { name: 'SeatsInUse', field: 'SeatsInUse', formType: 'text' },
+        { name: 'usersAssignedProRated', field: 'UsersAssignedProRated', formType: 'text' },
+        { name: 'SeatsInUseProRated', field: 'SeatsInUseProRated', formType: 'text' },
+        { name: 'PremiumFlag', field: 'PremiumFlag', formType: 'text' },
+        { name: 'TenantId', field: 'TenantId', formType: 'text' },
+        { name: 'ResellerCSN', field: 'ResellerCSN', formType: 'text' },
+        { name: 'ResellerName', field: 'ResellerName', formType: 'text' }
+      ],
+      crmType: 'ewsAnalyze',
+      loading: false
+    }
+  },
+  mounted () {
+    var self = this
+    /** 控制table的高度 */
+    window.onresize = () => {
+      self.updateTableHeight()
+    }
+  },
+  methods: {
+    searchClick () {
+      console.log(this.searchName)
+      this.getList()
+    },
+    getList () {
+      this.loading = true
+      let params = {
+        'CustomerCSN': this.searchName
+      }
+      InsightsMetrics(params)
+        .then(res => {
+          if (res.data.ErrorCode === 200) {
+            if (res.data.Result.length > 0) {
+              this.tableData = res.data.Result
+            } else {
+              this.tableData = []
+            }
+            this.loading = false
+          } else {
+            this.$message.error(res.data.Message)
+            this.loading = false
+          }
+        })
+        .catch(() => {
+          this.loading = false
+        })
+    },
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      if (
+        column.property === 'CustomerName' ||
+        column.property === 'businessCheck'
+      ) {
+        return { color: '#4D88FF', cursor: 'pointer' }
+      } else {
+        return ''
+      }
+    },
+    rowClick (row, column, event) {
+    },
+    // 列表信息格式化
+    fieldFormatter (row, column) {
+      if (column.property === 'PremiumFlag') {
+        switch (row[column.property]) {
+          case 'true':
+            row[column.property] = '1'
+            break
+          case 'false':
+            row[column.property] = '0'
+            break
+        }
+      }
+      if (row[column.property] === 'null') {
+        return '--'
+      }
+      return row[column.property] || '--'
+    },
+    updateTableHeight () {
+      var offsetHei = document.documentElement.clientHeight
+      // var removeHeight = Object.keys(this.filterObj).length > 0 ? 310 : 240
+      var removeHeight = 240
+      this.tableHeight = offsetHei - removeHeight
+    },
+    queryList (data) {
+      console.log(data)
+      this.headObj = data
+      this.getList(data)
+    }
+
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../clients/styles/table.scss';
+.selectInline{
+  background: #fff;
+  padding:20px;
+  margin-bottom: 10px;
+}
+.crm-create-container {
+  position: relative;
+  height: 100%;
+}
+
+.crm-create-flex {
+  position: relative;
+  overflow-x: hidden;
+  overflow-y: auto;
+  flex: 1;
+}
+
+.crm-create-header {
+  height: 40px;
+  margin-bottom: 20px;
+  padding: 0 10px;
+  flex-shrink: 0;
+  display: flex;
+  .close {
+    display: block;
+    // width: 15px;
+    // height: 15px;
+    margin-right: -10px;
+    padding: 10px;
+    cursor: pointer;
+  }
+}
+
+.crm-create-body {
+  flex: 1;
+  // overflow-x: hidden;
+  // overflow-y: auto;
+  max-height: 500px;
+}
+
+/** 将其改变为flex布局 */
+.crm-create-box {
+  display: flex;
+  flex-wrap: wrap;
+  padding: 0 10px;
+}
+
+.crm-create-item {
+  flex: 0 0 45%;
+  flex-shrink: 0;
+  // overflow: hidden;
+  padding-bottom: 30px;
+}
+
+// 占用一整行
+.crm-create-block-item {
+  flex: 0 0 100%;
+  flex-shrink: 0;
+  padding-bottom: 10px;
+}
+
+.el-form-item /deep/ .el-form-item__label {
+  // line-height: 32px;
+  font-size: 13px;
+  color: #333333;
+  position: relative;
+  padding-left: 8px;
+  padding-bottom: 0;
+}
+
+.el-form /deep/ .el-form-item {
+  margin-bottom: 0px;
+}
+
+.el-form /deep/ .el-form-item.is-required .el-form-item__label:before {
+  content: '*';
+  color: #f56c6c;
+  margin-right: 4px;
+  position: absolute;
+  left: 0;
+  top: 8px;
+}
+
+.handle-bar {
+  position: relative;
+  .handle-button {
+    float: right;
+    margin-top: 5px;
+    margin-right: 20px;
+  }
+}
+
+.el-button + .el-button {
+  margin-left: 0;
+}
+.container{
+  position: relative;
+  .popover-foot{
+    position: relative;
+    left: 38%;
+    width: 100%;
+    margin-bottom: 30px;
+  }
+}
+.content {
+  position: relative;
+  padding: 32px 40px;
+  display: flex;
+  flex-direction: column;
+  margin-bottom: 40px;
+  height: 355px;
+  overflow: hidden;
+  overflow-y: auto;
+  border-bottom: 1px solid #f1f1f1;
+  .content-wrap{
+    width: 100%;
+  }
+  .otherOpt{
+    margin-bottom: 15px;
+    width: 100%;
+  }
+  p{
+    margin-bottom: 36px;
+    font-size: 14px;
+    font-weight: 550;
+    color: #333;
+
+  }
+  .con-group{
+    margin-bottom: 28px;
+  }
+  .content-wrap /deep/.el-radio-group .el-radio{
+    margin-right: 64px;
+    margin-bottom: 12px;
+  }
+  .content-wrap /deep/.el-radio-group .el-radio .el-radio__label{
+    font-weight: 400;
+    color: #666666;
+    font-size: 14px;
+  }
+}
+.header {
+  padding: 16px 30px;
+  flex-shrink: 0;
+  border-bottom: 1px solid #F1F1F1;
+  .name {
+    font-size: 13px;
+    padding: 0 10px;
+    color: #333;
+  }
+  .detail {
+    font-size: 12px;
+    padding: 0 10px;
+    color: #aaaaaa;
+    border-left: 1px solid #aaaaaa;
+  }
+  .close {
+    position: absolute;
+    width: 40px;
+    height: 40px;
+    top: 5px;
+    right: 10px;
+    padding: 10px;
+  }
+}
+.customer{
+  // .xr-btn--orange{
+  //   background-color: #ff6a00;
+  //   border-color: #ff6a00;
+  // }
+  .customerName{
+    cursor:pointer;
+    // color: #ff6a00
+  }
+}
+</style>
+<style lang="scss">
+.customer{
+  /deep/.el-input .el-input-group__append{
+    // background-color: #ff7d00;
+    // border-color: #ff7d00;
+    // color: #fff;
+  }
+}
+/* 新建和编辑 */
+.new-dialog-title {
+  padding-left: 10px;
+  margin-bottom: 3px;
+  border-left: 2px solid #4D88FF;
+}
+.user-dialog{
+  height: 20vh;
+}
+.base-dialog{
+  height: 35vh;
+}
+.followDialog{
+  height: 35vh;
+}
+.new-cusDialog-form {
+  overflow-y: auto;
+  padding: 20px;
+  display: flex;
+  flex-wrap: wrap;
+}
+
+.new-cusDialog-form /deep/ .el-form-item {
+  // width: 50%;
+  margin: 0;
+  padding-bottom: 10px;
+}
+.new-cusDialog-form /deep/ .el-form-item .el-form-item__label {
+  line-height: normal;
+  font-size: 13px;
+  color: #333333;
+  position: relative;
+  padding-bottom: 8px;
+}
+.new-cusDialog-form /deep/ .crm-create-item.el-form-item .el-form-item__content {
+  width: 70%;
+}
+.new-cusDialog-form /deep/ .crm-create-block-item.el-form-item .el-form-item__content {
+  width: 90%;
+}
+.new-cusDialog-form /deep/ .crm-create-item.el-form-item .el-form-item__content .el-input.is-disabled .el-input__inner{
+  cursor: pointer;
+}
+.crm-create-item {
+  flex: 0 0 45%;
+  flex-shrink: 0;
+  // overflow: hidden;
+  padding-bottom: 10px;
+}
+
+// 占用一整行
+.crm-create-block-item {
+  flex: 0 0 100%;
+  flex-shrink: 0;
+  padding-bottom: 10px;
+}
+.nav-dialog-div {
+  margin-bottom: 20px;
+}
+.nav-dialog-div /deep/ .el-input {
+  width: auto;
+}
+</style>
diff --git a/src/views/PWS/Subscriptions.vue b/src/views/PWS/Subscriptions.vue
new file mode 100644
index 0000000..8efde5d
--- /dev/null
+++ b/src/views/PWS/Subscriptions.vue
@@ -0,0 +1,315 @@
+<template>
+  <div class='subscription'>
+    <c-r-m-list-head
+      ref="listHead"
+      title="订阅"
+      main-title="PWS API" />
+    <el-form :inline="true" :model="headObj" class="selectInline">
+      <el-form-item>
+          <span>开始时间:</span>
+          <el-date-picker
+            v-model="headObj.startDateSince"
+            type="date"
+            placeholder="选择开始日期"
+            value-format="yyyy-MM-dd"
+            :picker-options="pickerOptions">
+          </el-date-picker>
+      </el-form-item>
+      <el-form-item>
+          <span>截止时间:</span>
+          <el-date-picker
+            v-model="headObj.lastModifiedSince"
+            type="date"
+            placeholder="选择最后修改日期"
+            value-format="yyyy-MM-dd"
+            :picker-options="pickerOptions">
+          </el-date-picker>
+      </el-form-item>
+      <!-- <el-form-item>
+        <div style='display: flex;'>
+          <span style="margin-right: 12px">状态:</span>
+          <el-checkbox-group v-model="headObj.subscriptionStatus" style="display: flex; align-items: center;">
+            <el-checkbox label="活动"></el-checkbox>
+            <el-checkbox label="非活动"></el-checkbox>
+            <el-checkbox label="已过期"></el-checkbox>
+          </el-checkbox-group>
+        </div>
+      </el-form-item> -->
+      <el-form-item>
+        <el-button type="primary" @click="onSubmit('query')">新建导出任务</el-button>
+        <el-button @click="onSubmit('reset')">重置</el-button>
+      </el-form-item>
+    </el-form>
+    <el-card class="el-card">
+      <el-table
+        v-loading="loading"
+        id="crm-table"
+        :data="tableData"
+        :height="tableHeight"
+        :cell-style="cellStyle"
+        class="n-table--border"
+        border
+        highlight-current-row
+        style="width: 100%"
+        @row-click="rowClick">
+        <el-table-column
+          v-for="(item, index) in fieldList"
+          :key="index"
+          :prop="item.field"
+          :label="item.name"
+          :formatter="fieldFormatter"
+          show-overflow-tooltip>
+          <template
+            slot="header"
+            slot-scope="scope">
+            <div class="table-head-name">{{ scope.column.label }}</div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          prop="operation">
+          <template
+            title="hhhhhhhhh"
+            slot="header"
+            slot-scope="scope">
+            <div class="table-head-name">操作</div>
+          </template>
+          <template slot-scope="scope">
+            <span v-if="scope.row.TaskStatus === 0" style="font-size: 12px; color: #909398; font-weight: 500;">等待处理</span>
+            <span v-else-if="scope.row.TaskStatus === 1" style="font-size: 12px; color: #80BF50; font-weight: 500;">正在处理</span>
+            <span v-else-if="scope.row.TaskStatus === 2" style="font-size: 12px; color: #5B88F7; font-weight: 500;">导出完成</span>
+            <span v-else-if="scope.row.TaskStatus === 3" style="font-size: 12px; color: #DBA450; font-weight: 500;">导出失败</span>
+            <el-button style="margin-left: 12px" v-if="scope.row.TaskStatus === 2" size="mini" type="primary"  @click='exportFile(scope.row)'>导出</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="p-contianer" v-if='total>0'>
+        <el-pagination
+          :current-page="currentPage"
+          :page-sizes="pageSizes"
+          :page-size.sync="pageSize"
+          :total="total"
+          class="p-bar"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"/>
+      </div>
+    </el-card>
+    <c-r-m-export
+      :show="showCRMExport"
+      :crm-type="crmType"
+      :head-obj="exportHeadObj"
+      @close="showCRMExport=false"
+      @queryList='queryList'/>
+  </div>
+</template>
+
+<script>
+import { ExportSubscriptionsTask, GetSubscriptionsTask } from '@/api/pwsApi/subscriptions'
+import CRMListHead from '../clients/components/CRMListHead'
+import CRMExport from '../clients/components/CRMExport'
+export default {
+  name: 'Subscriptions',
+  components: {
+    CRMListHead,
+    CRMExport
+  },
+  data () {
+    return {
+      loading: false,
+      currentPage: 1,
+      // Lockr.get('crmPageSizes')
+      pageSize: 10,
+      pageSizes: [10, 30, 60, 100],
+      total: 0,
+      tableData: [],
+      tableHeight: document.documentElement.clientHeight - 360, // 表的高度
+      fieldList: [
+        { name: 'CreateTime', field: 'CreateTime', formType: 'text' },
+        { name: 'StartDateSince', field: 'StartDateSince', formType: 'text' },
+        { name: 'LastModifiedSince', field: 'LastModifiedSince', formType: 'text' }
+        // { name: '状态', field: 'SubscriptionStatus', formType: 'text' }
+      ],
+      // 导出
+      showCRMExport: false,
+      crmType: 'subscriptions',
+      headObj: {
+        startDateSince: '',
+        lastModifiedSince: '',
+        subscriptionStatus: []
+      },
+      exportHeadObj: {
+        taskId: ''
+      },
+      pickerOptions: {
+        disabledDate (time) {
+          return time.getTime(new Date()) > Date.now()
+        }
+      }
+    }
+  },
+  mounted () {
+    var self = this
+    /** 控制table的高度 */
+    window.onresize = () => {
+      self.updateTableHeight()
+    }
+    this.getList()
+  },
+  methods: {
+    getList () {
+      this.loading = true
+      let params = {
+        'PageIndex': this.currentPage,
+        'PageSize': this.pageSize
+      }
+      GetSubscriptionsTask(params)
+        .then(res => {
+          if (res.data.ErrorCode === 200) {
+            if (res.data.Result.Count > 0) {
+              this.tableData = res.data.Result.List
+            } else {
+              this.tableData = []
+            }
+            this.total = res.data.Result.Count
+            this.loading = false
+          } else {
+            this.$message.error(res.data.Message)
+            this.loading = false
+          }
+        })
+        .catch(() => {
+          this.loading = false
+        })
+    },
+    // 更改每页展示数量
+    handleSizeChange (val) {
+      // Lockr.set('crmPageSizes', val)
+      this.pageSize = val
+      this.getList()
+    },
+    // 更改当前页数
+    handleCurrentChange (val) {
+      this.currentPage = val
+      this.getList()
+    },
+    updateTableHeight () {
+      var offsetHei = document.documentElement.clientHeight
+      // var removeHeight = Object.keys(this.filterObj).length > 0 ? 310 : 240
+      var removeHeight = 240
+      this.tableHeight = offsetHei - removeHeight
+    },
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      return { textAlign: 'left' }
+    },
+    rowClick (row, column, event) {
+    },
+    queryList (data) {
+      console.log(data)
+    },
+    // 列表信息格式化
+    fieldFormatter (row, column) {
+      if (column.property === 'Status') {
+        switch (row[column.property]) {
+          case true:
+            row[column.property] = '是'
+            break
+          case false:
+            row[column.property] = '否'
+            break
+        }
+      }
+      return row[column.property] || '--'
+    },
+    onSubmit (val) {
+      if (val === 'query') {
+        if (this.headObj.startDateSince === '') {
+          this.$message.error('请选择导出任务的开始时间')
+          return
+        }
+        this.loading = true
+        // let status = ''
+        // this.headObj.subscriptionStatus.forEach((item) => {
+        //   if (status === '') {
+        //     status = item
+        //   } else {
+        //     status = status + ',' + item
+        //   }
+        // })
+        // this.headObj.subscriptionStatus = status
+        let params
+        if (this.headObj.lastModifiedSince === '') {
+          params = {
+            startDateSince: this.headObj.startDateSince
+          }
+        } else {
+          params = {
+            startDateSince: this.headObj.startDateSince,
+            lastModifiedSince: this.headObj.lastModifiedSince
+          }
+        }
+        ExportSubscriptionsTask(params)
+          .then(res => {
+            if (res.data.ErrorCode === 200) {
+              this.loading = false
+              this.getList()
+            } else {
+              this.$message.error(res.data.Message)
+              this.loading = false
+            }
+          })
+          .catch(() => {
+            this.loading = false
+          })
+      } else if (val === 'reset') {
+        this.headObj = {}
+      }
+    },
+    exportFile (item) {
+      console.log(item)
+      this.exportHeadObj.taskId = item.Id
+      // 需要设置参数 this.headObj
+      this.showCRMExport = true
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../clients/styles/table.scss';
+.subscription {
+  display: flex;
+  flex-direction: column;
+  .flex-box {
+    flex: 1;
+    padding: 20px;
+    border-radius: 4px;
+    border: 1px solid #EBEEF5;
+    background-color: #FFF;
+    overflow: hidden;
+    color: #303133;
+
+  }
+}
+.selectInline{
+  background: #fff;
+  padding:20px 20px 0;
+  margin-bottom: 10px;
+}
+.datePicker{
+  margin-top:3px;
+  .el-date-editor .el-range__icon{
+     line-height: 28px;
+  }
+}
+/** 分页布局 */
+.p-contianer {
+  position: relative;
+  background-color: white;
+  height: 44px;
+  .p-bar {
+    float: right;
+    margin: 5px 0 0 0;
+    font-size: 14px !important;
+  }
+}
+</style>
diff --git a/src/views/clients/business/BusinessDetail.vue b/src/views/clients/business/BusinessDetail.vue
new file mode 100644
index 0000000..b26468b
--- /dev/null
+++ b/src/views/clients/business/BusinessDetail.vue
@@ -0,0 +1,726 @@
+<template>
+  <slide-view
+    v-empty="!canShowDetail"
+    :listener-ids="listenerIDs"
+    :no-listener-ids="noListenerIDs"
+    :no-listener-class="noListenerClass"
+    :body-style="{padding: 0, height: '100%'}"
+    xs-empty-icon="nopermission"
+    xs-empty-text="暂无权限"
+    @side-close="hideView">
+    <flexbox
+      v-loading="loading"
+      v-if="canShowDetail"
+      direction="column"
+      align="stretch"
+      class="d-container">
+      <c-r-m-detail-head
+        :detail="detailData"
+        :head-details="headDetails"
+        :id="id"
+        crm-type="business"
+        @handle="detailHeadHandle"
+        @close="hideView">
+        <!--<div class="busi-line"/>-->
+      </c-r-m-detail-head>
+
+      <div class="tabs" style="margin-bottom:24px;">
+        <el-tabs
+          v-model="tabCurrentName"
+          @tab-click="handleClick">
+          <el-tab-pane
+            v-for="(item, index) in tabnames"
+            :key="index"
+            :label="item.label"
+            :name="item.name"/>
+        </el-tabs>
+      </div>
+
+       <!--:style="{'opacity' : detailData.isEnd !== 0 ? 1 : 1}"-->
+      <div
+        style="padding:10px 50px;margin-bottom:24px;">
+        <flexbox
+          class="busi-state">
+          <a
+            v-for="(item, index) in status"
+            :key="index">
+              <div
+                v-if="status.length -1 !=index"
+                slot="reference"
+                :class="item.class"
+                class="busi-state-item"
+                @click="handleStatuChange(item, index)">
+                {{ item.name }}
+                <div class="state-circle"/>
+                <div class="state-line"/>
+                <div class='state-info'>
+                  <el-button type="primary" @click="pushState" v-if="item.isPushing" style='margin-left:36px;'>推进</el-button>
+                  <div v-if="item.class === 'state-suc'" class='state-name'>{{item.UserName}}</div>
+                  <div v-if="item.class === 'state-suc'" class='state-name'>{{item.CreateTime}}</div>
+                </div>
+              </div>
+
+              <div
+                v-if="status.length -1 ==index"
+                :class="item.class"
+                class="busi-state-item"
+                style="margin-left:8px;">
+                <i
+                  :class="item.overIcon"
+                  style="margin-right:8px;"/>
+                {{ item.name }}
+                <div class="state-circle"/>
+                <div class='state-info'>
+                  <el-button type="primary" @click="pushState" v-if="item.isPushing" style='margin-left:36px;'>推进</el-button>
+                  <div v-if="item.class === 'state-suc'" class='state-name'>{{item.UserName}}</div>
+                  <div v-if="item.class === 'state-suc'" class='state-name'>{{item.CreateTime}}</div>
+                </div>
+              </div>
+          </a>
+        </flexbox>
+      </div>
+      <el-dialog
+        title="推进"
+        :visible.sync="isPushed"
+        width="20%"
+        append-to-body
+        :before-close="handleClose">
+        <div class='pushBody'>
+          <i class="el-icon-warning" style="color: #e6a23c;"></i>
+          <span>确定推进商机到</span>
+          <el-select v-model="pushStatus" placeholder="请选择">
+            <el-option
+              v-for="item in pushOptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value">
+            </el-option>
+          </el-select>
+          <span>阶段</span>
+        </div>
+        <span slot="footer" class="dialog-footer">
+          <el-button @click="handleClose" class='closePushBtn'>取 消</el-button>
+          <el-button type="primary" @click="surePush" class='surePushBtn'>确 定</el-button>
+        </span>
+      </el-dialog>
+      <div style="width:100%; height:8px; background: #F5F6FA;margin-bottom:48px;"></div>
+      <div
+        id="follow-log-content"
+        class="t-loading-content"
+        :style="'height:' + contentStyleObj.height">
+            <!--<c-r-m-base-info
+              :ref="tabnames[0].name"
+              class="scroll-item"
+              :detail="detailData"
+              :id="id"
+              crm-type="business" />
+            <business-follow
+              :ref="tabnames[1].name"
+              class="scroll-item"
+              :detail="detailData"
+              :id="id"
+              crm-type="business" />
+              <relative-offers
+              :ref="tabnames[2].name"
+              class="scroll-item"
+              :detail="detailData"
+              :id="id"
+              crm-type="business"/>
+            <relative-contract
+              :ref="tabnames[3].name"
+              class="scroll-item"
+              :detail="detailData"
+              :id="id"
+              crm-type="business" />
+            <relative-product
+              :ref="tabnames[4].name"
+              class="scroll-item"
+              :detail="detailData"
+              :id="id"
+              crm-type="business"/>
+            <relative-files
+              :ref="tabnames[5].name"
+              class="scroll-item"
+              :detail="detailData"
+              :id="id"
+              crm-type="business" />
+            <relative-handle
+            :ref="tabnames[6].name"
+            class="scroll-item"
+            :detail="detailData"
+            :id="id"
+            crm-type="customer" />-->
+        <keep-alive>
+          <component
+            :is="tabName"
+            :detail="detailData"
+            :id="id"
+            crm-type="business"/>
+        </keep-alive>
+      </div>
+    </flexbox>
+    <c-r-m-create-view
+      v-if="isCreate"
+      :action="{type: 'update', id: id, batchId: detailData.batchId}"
+      crm-type="business"
+      @save-success="editSaveSuccess"
+      @hiden-view="isCreate=false"/>
+  </slide-view>
+</template>
+
+<script>
+import {
+  GetSalesChanceDetail,
+  ChangeSalesChanceStage
+} from '@/api/customermanagement/business'
+
+import SlideView from '@/components/SlideView'
+import CRMDetailHead from '../components/CRMDetailHead'
+import BusinessFollow from './components/BusinessFollow' // 跟进记录
+import CRMBaseInfo from '../components/CRMBaseInfo' // 商机基本信息
+import RelativeContract from '../components/RelativeContract' // 相关合同
+import RelativeContacts from '../components/RelativeContacts' // 相关联系人
+import RelativeHandle from '../components/RelativeHandle' // 相关操作
+import RelativeTeam from '../components/RelativeTeam' // 相关团队
+import RelativeProduct from '../components/RelativeProduct' // 相关团队
+import RelativeFiles from '../components/RelativeFiles' // 相关附件
+import RelativeOffers from '../components/RelativeOffers' // 相关报价
+import RelativeSchedule from '../components/RelativeSchedule' // 相关待办事项
+import CRMCreateView from '../components/CRMCreateView' // 新建页面
+import RelativeApproval from '../components/RelativeApproval' // 相关商机流转跟踪记录
+
+import detail from '../mixins/detail'
+
+export default {
+  /** 客户管理 的 商机详情 */
+  name: 'BusinessDetail',
+  components: {
+    SlideView,
+    CRMDetailHead,
+    BusinessFollow,
+    CRMBaseInfo,
+    RelativeContract,
+    RelativeContacts,
+    RelativeHandle,
+    RelativeTeam,
+    RelativeProduct,
+    RelativeFiles,
+    CRMCreateView,
+    RelativeOffers,
+    RelativeSchedule,
+    RelativeApproval
+  },
+  mixins: [detail],
+  props: {
+    // 详情信息id
+    id: [String, Number],
+    // 监听的dom 进行隐藏详情
+    listenerIDs: {
+      type: Array,
+      default: () => {
+        return ['crm-main-container']
+      }
+    },
+    isFollow: {
+      type: Boolean,
+      default: false
+    },
+    // 不监听
+    noListenerIDs: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    noListenerClass: {
+      type: Array,
+      default: () => {
+        return ['el-table__body']
+      }
+    }
+  },
+  data () {
+    return {
+      loading: false, // 展示加载loading
+      crmType: 'business',
+      detailData: {}, // read 详情
+      headDetails: [
+        { title: '客户名称', value: '' },
+        { title: '预计成交金额(元)', value: '' },
+        { title: '商机状态', value: '' },
+        { title: '负责人', value: '' },
+        { title: '创建时间', value: '' }
+      ],
+      tabCurrentName: 'basicinfo',
+      /** 商机状态数据 */
+      status: [],
+      /** 完结状态 */
+      statuHandleItems: [
+        {
+          name: '赢单',
+          type: 1,
+          value: '100%',
+          img: require('@/assets/img/check_suc.png')
+        },
+        {
+          name: '输单',
+          type: 2,
+          value: '0%',
+          img: require('@/assets/img/check_fail.png')
+        },
+        {
+          name: '无效',
+          type: 3,
+          value: '0%',
+          img: require('@/assets/img/check_cancel.png')
+        }
+      ],
+      isCreate: false, // 编辑操作
+      contentStyleObj: {
+        height: '100px'
+      },
+      isPushed: false,
+      pushStatus: 1,
+      pushOptions: [{value: 1, label: '初期沟通'}, {value: 2, label: '需求分析'}, {value: 3, label: '方案报价'}, {value: 4, label: '商务谈判'}, {value: 5, label: '成功'}, {value: 6, label: '搁置'}]
+    }
+  },
+  computed: {
+    tabName () {
+      if (this.tabCurrentName === 'followlog') {
+        return 'business-follow'
+      } else if (this.tabCurrentName === 'basicinfo') {
+        return 'c-r-m-base-info'
+      } else if (this.tabCurrentName === 'team') {
+        return 'relative-team'
+      } else if (this.tabCurrentName === 'contract') {
+        return 'relative-contract'
+      } else if (this.tabCurrentName === 'operationlog') {
+        return 'relative-handle'
+      } else if (this.tabCurrentName === 'product') {
+        return 'relative-product'
+      } else if (this.tabCurrentName === 'file') {
+        return 'relative-files'
+      } else if (this.tabCurrentName === 'contacts') {
+        return 'relative-contacts'
+      } else if (this.tabCurrentName === 'offers') {
+        return 'relative-offers'
+      } else if (this.tabCurrentName === 'approval') {
+        return 'relative-approval'
+      } else if (this.tabCurrentName === 'schedule') {
+        return 'relative-schedule'
+      }
+      return ''
+    },
+    tabnames () {
+      let tempsTabs = []
+      // if (this.crm.business && this.crm.business.read) {
+      tempsTabs.push({ label: '基本信息', name: 'basicinfo' })
+      // }
+      tempsTabs.push({ label: '跟进记录', name: 'followlog' })
+      // if (this.crm.contacts && this.crm.contacts.index) {
+      // tempsTabs.push({ label: '联系人', name: 'contacts' })
+      // }
+      tempsTabs.push({ label: '报价', name: 'offers' })
+
+      // if (this.crm.contract && this.crm.contract.index) {
+      tempsTabs.push({ label: '合同', name: 'contract' })
+      // }
+      // if (this.crm.product && this.crm.product.index) {
+      tempsTabs.push({ label: '产品', name: 'product' })
+      tempsTabs.push({ label: '商机流转跟踪', name: 'approval' })
+      // }
+      // tempsTabs.push({ label: '待办事项', name: 'schedule' })
+      // tempsTabs.push({ label: '相关团队', name: 'team' })
+      // tempsTabs.push({ label: '附件', name: 'file' })
+      tempsTabs.push({ label: '操作记录', name: 'operationlog' })
+      return tempsTabs
+    }
+  },
+  created () {
+    this.getHight()
+    this.getDetial()
+    console.log(this.isFollow)
+    if (this.isFollow) {
+      this.tabCurrentName = 'followlog'
+    }
+    window.addEventListener('resize', this.getHight)
+  },
+  mounted () {},
+  destroyed () {
+    window.removeEventListener('resize', this.getHight)
+  },
+  methods: {
+    getHight () {
+      // this.contentStyleObj.height = (window.innerHeight - 600) + 'px'
+    },
+    getDetial () {
+      this.loading = true
+      GetSalesChanceDetail({
+        Id: this.id
+      })
+        .then(res => {
+          this.loading = false
+          this.detailData = res.data.Result
+
+          let statusList = [{statusId: 1, name: '初期沟通'}, {statusId: 2, name: '需求分析'}, {statusId: 3, name: '方案报价'}, {statusId: 4, name: '商务谈判'}, {statusId: 5, name: '商机成功'}, {statusId: 6, name: '商机搁置'}]
+          let statusId = this.detailData.SalesChanceStage
+          this.pushStatus = statusId
+          this.handleBusinessStatus(0, statusId, statusList, '100%')
+
+          this.headDetails[0].value = res.data.Result.CustomerName || '暂无'
+          this.headDetails[1].value = res.data.Result.ExpectedAmount || 0
+          this.headDetails[2].value = res.data.Result.ReportStatus || '暂无'
+          // 负责人
+          this.headDetails[3].value = res.data.Result.OwerUserName || '暂无'
+          this.headDetails[4].value = res.data.Result.CreateTime || '暂无'
+        })
+        .catch(() => {
+          this.loading = false
+        })
+    },
+    pushState () {
+      this.isPushed = true
+    },
+    handleClose () {
+      // this.pushStatus = 1
+      this.isPushed = false
+    },
+    surePush () {
+      console.log(this.pushStatus)
+      let params = {
+        'Id': this.id,
+        'SalesChanceStage': this.pushStatus
+      }
+      ChangeSalesChanceStage(params).then(res => {
+        if (res.data.ErrorCode === 200) {
+          this.$message.success(res.data.Message)
+          this.getDetial()
+        } else {
+          this.$message.error(res.data.Message)
+        }
+      })
+      this.handleClose()
+    },
+    //* * 点击关闭按钮隐藏视图 */
+    hideView () {
+      this.$emit('hide-view')
+    },
+    /** 处理商机状态数据 */
+    handleBusinessStatus (isEnd, statusId, statusList, statusRemark) {
+      this.status = []
+      let info = this.detailData.SalesChanceForwards
+      if (statusList && statusList.length > 0) {
+        let isdoingIndex = -1
+        for (let index = 0; index < statusList.length; index++) {
+          const item = statusList[index]
+          if (item.statusId === statusId) {
+            isdoingIndex = index
+            item['class'] = 'state-suc'
+          } else {
+            item['class'] = isdoingIndex >= 0 ? 'state-undo' : 'state-suc'
+          }
+          if (info && info.length > 0) {
+            for (let j = 0; j < info.length; j++) {
+              if (item.statusId === info[j].SalesChanceStage) {
+                item['CreateTime'] = info[j].CreateTime
+                item['UserName'] = info[j].UserName
+              } else {
+                if (item.statusId === info[j].SalesChanceStage) {
+                  item['CreateTime'] = info[j].CreateTime
+                  item['UserName'] = info[j].UserName
+                }
+              }
+            }
+          }
+          this.status.push(item)
+        }
+        // const overItem = { type: isEnd }
+        if (isEnd === 0) {
+          // overItem.name = '结束'
+          if (isdoingIndex === statusList.length - 1) {
+            this.status[isdoingIndex].class = 'state-suc'
+            // overItem['class'] = 'state-doing'
+          } else {
+            if (this.status.length > 0 && statusId !== 0) {
+              // 有推进状态 才会有下一阶段
+              this.status[isdoingIndex + 1].class = 'state-doing'
+              this.status[isdoingIndex + 1]['isPushing'] = true
+            }
+            // overItem['class'] = 'state-undo'
+          }
+        }
+        // this.status.push(overItem)
+        this.status = [...this.status]
+      }
+    },
+    /** 操作状态改变 */
+    handleStatuChange (item, index) {
+      if (this.detailData.isEnd !== 0) {
+        // 非完结状态下 可推进
+        return
+      }
+      if (!item.isdoing) {
+        let message = '确定进入' + item.name + '阶段'
+        this.$confirm(message, '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+          .then(() => {
+            this.loading = true
+            // crmBusinessAdvance({
+            //   businessId: this.id,
+            //   statusId: item.statusId
+            // })
+            //   .then(res => {
+            //     this.loading = false
+            //     this.$message.success('操作成功')
+            //     this.getDetial()
+            //   })
+            //   .catch(() => {
+            //     this.loading = false
+            //   })
+          })
+          .catch(() => {
+            this.$message({
+              type: 'info',
+              message: '已取消操作'
+            })
+          })
+      }
+    },
+    /** 完结状态结果 */
+    handleStatuResult (item, index) {
+      if (this.detailData.isEnd !== 0) {
+        // 非完结状态下 可推进
+        return
+      }
+      /** 输单 和 无效 */
+      if (item.type === 2 || item.type === 3) {
+        let message = '请填写' + item.name + '原因:'
+        let title = item.name + '原因'
+        this.$prompt(message, title, {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消'
+        })
+          .then(({ value }) => {
+            this.loading = true
+            // crmBusinessAdvance({
+            //   businessId: this.id,
+            //   statusId: item.statusId,
+            //   isEnd: item.type,
+            //   statusRemark: value
+            // })
+            //   .then(res => {
+            //     this.loading = false
+            //     this.$message.success('操作成功')
+            //     this.getDetial()
+            //   })
+            //   .catch(() => {
+            //     this.loading = false
+            //   })
+          })
+          .catch(() => {
+            this.$message({
+              type: 'info',
+              message: '取消输入'
+            })
+          })
+      } else {
+        let message = '确定将当前商机设为' + item.name + '吗?'
+        this.$confirm(message, '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+          .then(() => {
+            this.loading = true
+            // crmBusinessAdvance({
+            //   businessId: this.id,
+            //   statusId: item.statusId,
+            //   isEnd: item.type
+            // })
+            //   .then(res => {
+            //     this.loading = false
+            //     this.$message.success('操作成功')
+            //     this.getDetial()
+            //   })
+            //   .catch(() => {
+            //     this.loading = false
+            //   })
+          })
+          .catch(() => {
+            this.$message({
+              type: 'info',
+              message: '已取消操作'
+            })
+          })
+      }
+    },
+    editSaveSuccess () {
+      this.$emit('handle', { type: 'save-success' })
+      this.getDetial()
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../styles/crmdetail.scss';
+.busi-line {
+  position: absolute;
+  bottom: 0;
+  left: 17px;
+  right: 17px;
+  height: 1px;
+  background-color: #e6e6e6;
+}
+
+.busi-state {
+  position: relative;
+  padding-left: 20px;
+  overflow-x: auto;
+  overflow-y: hidden;
+  padding-bottom: 80px;
+  a {
+    flex-shrink: 0;
+  }
+}
+
+.busi-state-item {
+  padding: 10px 35px;
+  margin: 5px 0;
+  position: relative;
+  margin-right: 20px;
+  font-size: 14px;
+  font-weight: 500;
+  color: #333333;
+  width: 148px;
+  .state-circle {
+    width: 30px;
+    height: 30px;
+    background-size: 100% 100%;
+    background: url('../../../assets/img/step_wait.png') no-repeat;
+    top: 42px;
+    left: 42%;
+    position: absolute;
+    z-index: -1;
+  }
+  .state-line{
+    width:174px;
+    height: 2px;
+    background: #F1F1F1;
+    position: absolute;
+    top: 50px;
+    left: 65px;
+    z-index: -2;
+  }
+  .state-info{
+    position: absolute;
+    top: 72px;
+    left: 0;
+    text-align: center;
+  }
+  .state-name{
+    margin-left: 10px;
+  }
+}
+
+.state-undo {
+  .state-circle {
+    background: url('../../../assets/img/step_wait.png') no-repeat;
+  }
+  .state-line {
+    background: #F1F1F1;
+  }
+}
+
+.state-doing {
+  .state-circle {
+    background: url('../../../assets/img/step_wait.png') no-repeat;
+  }
+  .state-line {
+    background: #F1F1F1;
+  }
+}
+
+.state-suc {
+  .state-circle {
+    background: url('../../../assets/img/step_success.png') no-repeat;
+  }
+  .state-line {
+    background: #4D88FF;
+  }
+}
+
+.state-fail {
+  .state-circle {
+    background: url('../../../assets/img/step_wait.png') no-repeat;
+  }
+  .state-line {
+    background: red;
+  }
+}
+
+.state-invalid {
+  .state-circle {
+    background: url('../../../assets/img/step_wait.png') no-repeat;
+  }
+  .state-line {
+    background: #F1F1F1;
+  }
+}
+
+/** 状态操作布局 */
+.state-handel-cont {
+  font-size: 13px;
+  color: #333;
+  .state-handel-item {
+    padding: 10px 0;
+    cursor: pointer;
+    .state-handel-item-img {
+      width: 16px;
+      height: 16px;
+      border-radius: 8px;
+      margin-right: 8px;
+      flex-shrink: 0;
+      display: block;
+    }
+    .state-handel-item-name {
+      flex: 1;
+    }
+    .state-handel-item-value {
+      flex-shrink: 0;
+    }
+  }
+  .state-handel-item:hover {
+    background-color: #f7f8fa;
+  }
+}
+.closePushBtn{
+  width: 58px;
+  height: 32px;
+  background: #FFFFFF;
+  border-radius: 3px;
+  border: 1px solid #999999;
+  font-size: 12px;
+  font-weight: 400;
+  color: #333333;
+  &:hover{
+    border-color:#4D88FF;
+    color: #4D88FF;
+  }
+  &:active{
+    border-color:#4D88FF;
+    color: #4D88FF;
+  }
+}
+.surePushBtn{
+  width: 58px;
+  height: 32px;
+  background: #4D88FF;
+  border-radius: 3px;
+  font-weight: 400;
+  color: #FFFFFF;
+}
+</style>
diff --git a/src/views/clients/business/BusinessIndex.vue b/src/views/clients/business/BusinessIndex.vue
new file mode 100644
index 0000000..9178649
--- /dev/null
+++ b/src/views/clients/business/BusinessIndex.vue
@@ -0,0 +1,483 @@
+<template>
+  <div class='customer'>
+    <c-r-m-list-head
+        ref="listHead"
+        title="商机管理"
+        main-title="客户管理" />
+
+    <c-r-m-table-head
+      ref="crmTableHead"
+      :crm-type="crmType"
+      :fieldList='fieldList'
+      @exportFile="exportFile"
+      @importFile='importFile'
+      @filter="handleFilter"
+      @handle="handleHandle"
+      @on-handle="listHeadHandle"
+      @scene="handleScene"
+      @queryList='queryList'/>
+
+    <el-card class="el-card">
+      <el-table
+        v-loading="loading"
+        id="crm-table"
+        :data="list"
+        :height="tableHeight"
+        :cell-style="cellStyle"
+        class="n-table--border"
+        border
+        highlight-current-row
+        style="width: 100%; z-index: 0;"
+        @row-click="handleRowClick"
+        @sort-change="sortChange"
+        @header-dragend="handleHeaderDragend"
+        @selection-change="handleSelectionChange">
+        <el-table-column
+          show-overflow-tooltip
+          type="selection"
+          :selectable="selectable"
+          align="center"
+          width="55"/>
+        <el-table-column
+          v-for="(item, index) in fieldList"
+          :key="index"
+          :fixed="index==0"
+          :prop="item.field"
+          :label="item.value"
+          :width="item.width"
+          :formatter="fieldFormatter"
+          sortable="custom"
+          show-overflow-tooltip>
+          <template
+            slot="header"
+            slot-scope="scope">
+            <div class="table-head-name">
+              {{ scope.column.label }}
+              <c-r-m-table-filter
+                :show="scope.column.label==='项目属性'||scope.column.label==='提交'||scope.column.label==='审批'"
+                :tableType="scope.column.label"
+                @queryList="queryList">
+                </c-r-m-table-filter>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="BusinessStatusString" label="上报状态">
+          <template
+            slot="header"
+            slot-scope="scope">
+            <div class="table-head-name">{{ scope.column.label }}</div>
+          </template>
+          <template slot-scope="scope">
+            <el-tooltip class="item" effect="dark" :content="scope.row.BusinessStatusReason?scope.row.BusinessStatusReason:scope.row.BusinessStatusString" placement="top">
+              <span >{{scope.row.BusinessStatusString}}</span>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+        <el-table-column
+          prop="operation"
+          width="150">
+          <template
+            slot="header"
+            slot-scope="scope">
+            <div class="table-head-name">操作</div>
+          </template>
+          <template slot-scope="scope">
+          <el-button type="text" size="small" :disabled="!scope.row.IsCanEdit"  @click='editList(scope.row)'>编辑 |</el-button>
+          <el-button type="text" size="small" :disabled="!scope.row.IsCanDelete"  @click='deleteSingleModule(scope.row.Id)'>删除 |</el-button>
+          <el-button type="text" size="small"  @click='goFollow(scope.row.Id)'>跟进</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="p-contianer" v-show='total>0'>
+        <el-pagination
+          :current-page="currentPage"
+          :page-sizes="pageSizes"
+          :page-size.sync="pageSize"
+          :total="total"
+          class="p-bar"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"/>
+      </div>
+
+    </el-card>
+
+    <!-- 编辑页面 -->
+    <c-r-m-create-view
+      v-if="isCreate"
+      :action="{type: 'update', id: editData.Id, data: editData}"
+      :crm-type="crmType"
+      @save-success="listHeadHandle"
+      @hiden-view="hiddenView"/>
+    <c-r-m-import
+      :show="showCRMImport"
+      :crm-type="crmType"
+      @close="showCRMImport=false"
+      @queryList='queryList'/>
+    <c-r-m-export
+      :show="showCRMExport"
+      :crm-type="crmType"
+      :search="search"
+      :filter-obj="filterObj"
+      :head-obj="headObj"
+      :is-seas="false"
+      :export-params="exportParams"
+      @close="showCRMExport=false"
+      @queryList='queryList'/>
+    <!-- 相关详情页面 -->
+    <c-r-m-all-detail
+      :key='timer'
+      :visible.sync="showDview"
+      :crm-type="rowType"
+      :id="rowID"
+      :isFollow="isFollow"
+      class="d-view"
+      @handle="handleHandle"/>
+    <fields-set
+      :crm-type="crmType"
+      :dialog-visible.sync="showFieldSet"
+      @set-success="setSave"/>
+  </div>
+</template>
+
+<script>
+import table from '../mixins/table'
+import CRMCreateView from '../components/CRMCreateView'
+import CRMImport from '../components/CRMImport'
+import CRMExport from '../components/CRMExport'
+import CRMAllDetail from '@/views/clients/components/CRMAllDetail'
+import CRMTableFilter from '../components/CRMTableFilter'
+import { DeleteSalesChance } from '@/api/customermanagement/business'
+
+export default {
+  /** 客户管理 的 商机列表 */
+  name: 'BusinessIndex',
+  components: {
+    CRMAllDetail,
+    CRMCreateView,
+    CRMImport,
+    CRMExport,
+    CRMTableFilter
+  },
+  filters: {
+  },
+  mixins: [table],
+  computed: {
+  },
+  data () {
+    return {
+      timer: '',
+      choosedScene: '2',
+      fieldList: [{ field: 'ChanceNumber', value: '编号' },
+        { field: 'ChanceName', value: '商机名称', width: '150' },
+        { field: 'CustomerName', value: '客户名称', width: '150' },
+        { field: 'ContacterName', value: '联系人' },
+        { field: 'ProjectProperty', value: '项目属性' },
+        { field: 'ChanceRequestTypeString', value: '商机类型' },
+        { field: 'SalesChanceStage', value: '销售阶段' },
+        { field: 'UploadStatusName', value: '提交' },
+        { field: 'ReportStatusName', value: '审批' },
+        { field: 'TrackStatus', value: '报备' },
+        // { field: 'BusinessStatusString', value: '上报状态' },
+        { field: 'SubmitTimeString', value: '上报时间' },
+        { field: 'InvalidTimeString', value: '过期时间' },
+        { field: 'ExpectedDate', value: '预期成交日期' },
+        { field: 'ExpectedAmount', value: '商机金额/元' },
+        { field: 'CreateUserName', value: '创建人' },
+        { field: 'OwerName', value: '销售负责人' }
+      ],
+      isDialogVisible: false, // 是创建
+      isCreate: false,
+      // 导入
+      showCRMImport: false,
+      // 导出
+      showCRMExport: false,
+      // 导出选中参数
+      exportParams: {},
+      crmType: 'business',
+      loading: false,
+      addLoading: false,
+      popSearch: '',
+      isFollow: false
+    }
+  },
+  mounted () {
+  },
+  methods: {
+    hiddenView () {
+      this.isCreate = false
+      this.getList()
+    },
+    // 选择文件
+    selectFile () {
+      document.getElementById('importInputFile').click()
+    },
+    // 获取左边padding
+    getPaddingLeft (item, index) {
+      if (item.showblock && item.showblock === true) {
+        return '25px'
+      }
+      return item.styleIndex % 2 === 0 ? '0' : '25px'
+    },
+    // 获取右边padding
+    getPaddingRight (item, index) {
+      if (item.showblock && item.showblock === true) {
+        return '0'
+      }
+
+      return item.styleIndex % 2 === 0 ? '25px' : '0'
+    },
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      if (
+        column.property === 'ChanceName' ||
+        column.property === 'CustomerName'
+      ) {
+        return { color: '#4D88FF', cursor: 'pointer' }
+      } else if (column.property === 'ReportStatusName') {
+        if (row[column.property] === '审批中') {
+          return { color: '#FF8800' }
+        } else if (row[column.property] === '通过') {
+          return { color: '#2DB300' }
+        } else if (row[column.property] === '驳回') {
+          return { color: '#FF4D4D' }
+        } else {
+          return { color: '#333' }
+        }
+      } else if (column.property === 'TrackStatus') {
+        if (row[column.property]) {
+          if (row['IsAutoPassed'] === true) {
+            return { color: '#2DB300' }
+          } else {
+            return { color: '#FF4D4D' }
+          }
+        } else {
+          return { color: '#333' }
+        }
+      } else if (column.property === 'BusinessStatusString') {
+        if (row[column.property] === '待上报') {
+          return { color: '#FF8800' }
+        } else if (row[column.property] === '已上报') {
+          return { color: '#2DB300' }
+        } else if (row[column.property] === '已拒绝') {
+          return { color: '#FF4D4D' }
+        } else {
+          return { color: '#333' }
+        }
+      } else {
+        return ''
+      }
+    },
+    selectable (row, index) {
+      if (row.IsCanDelete) {
+        return true
+      } else {
+        return false
+      }
+    },
+    goFollow (id) {
+      this.rowID = id
+      this.isFollow = true
+      this.rowType = 'business'
+      this.showDview = true
+      this.timer = new Date().getTime()
+      this.$forceUpdate()
+    },
+    deleteSingleModule (id) {
+      this.$confirm('确定删除?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          DeleteSalesChance([{'Id': id}]).then(res => {
+            if (res.data.ErrorCode === 200) {
+              this.$message.success(res.data.Message)
+              this.getList()
+            } else {
+              this.$message.error(res.data.Message)
+            }
+          })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    },
+    exportFile () {
+      this.showCRMExport = true
+    },
+    importFile () {
+      this.showCRMImport = true
+    },
+    queryList (data) {
+      this.headObj = data
+      this.getList(data)
+    },
+    /** 筛选操作 */
+    handleFilter (data) {
+      console.log(data)
+      this.filterObj = data
+      var offsetHei = document.documentElement.clientHeight
+      var removeHeight = Object.keys(this.filterObj).length > 0 ? 310 : 240
+      this.tableHeight = offsetHei - removeHeight
+      this.currentPage = 1
+      this.getList()
+    }
+
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../styles/table.scss';
+#importInputFile {
+  display: none;
+}
+.customer{
+  // .xr-btn--orange{
+  //   background-color: #ff6a00;
+  //   border-color: #ff6a00;
+  // }
+  .customerName{
+    cursor:pointer;
+    // color: #ff6a00
+  }
+}
+.container {
+  position: relative;
+}
+
+.header {
+  height: 40px;
+  padding: 0 10px;
+  flex-shrink: 0;
+  .name {
+    font-size: 13px;
+    padding: 0 10px;
+    color: #333;
+  }
+  .detail {
+    font-size: 12px;
+    padding: 0 10px;
+    color: #aaaaaa;
+    border-left: 1px solid #aaaaaa;
+  }
+  .close {
+    position: absolute;
+    width: 40px;
+    height: 40px;
+    top: 0;
+    right: 10px;
+    padding: 10px;
+  }
+}
+.content{
+  .cropper-box{
+    display:flex;
+    flex-direction: row;
+    align-items: center;
+    padding: 0 20px;
+    .searchTitle{
+      font-size: 14px;
+      width: 124px;
+      color: #333;
+    }
+    .searchInput{
+      margin-right: 20px;
+    }
+  }
+}
+.p-contianer .p-bar{
+  margin: 5px 0 0 14px;
+}
+</style>
+<style lang="scss">
+.customer{
+  /deep/.el-input .el-input-group__append{
+    // background-color: #ff7d00;
+    // border-color: #ff7d00;
+    // color: #fff;
+  }
+}
+/* 新建和编辑 */
+.new-dialog-title {
+  padding-left: 10px;
+  margin-bottom: 3px;
+  border-left: 2px solid #4D88FF;
+}
+.new-busDialog-form {
+  height: 47vh;
+  overflow-y: auto;
+  padding: 20px;
+  display: flex;
+  flex-wrap: wrap;
+}
+.new-busDialog-form /deep/ .el-form-item {
+  // width: 50%;
+  margin: 0;
+  padding-bottom: 10px;
+}
+.new-busDialog-form /deep/ .el-form-item .el-form-item__label {
+  line-height: normal;
+  font-size: 13px;
+  color: #333333;
+  position: relative;
+  padding-bottom: 8px;
+}
+.new-busDialog-form /deep/ .crm-create-item.el-form-item .el-form-item__content {
+  width: 70%;
+}
+.new-busDialog-form /deep/ .crm-create-block-item.el-form-item .el-form-item__content {
+  width: 90%;
+}
+.new-busDialog-form /deep/ .crm-create-block-item.el-form-item .el-form-item__label{
+  width: 10% !important;
+}
+.doubleSelect{
+  display: flex;
+  flex-direction: row;
+  width: 100%;
+  .leftSelect{
+    margin-right: 10px;
+  }
+}
+.radioList{
+  display: flex;
+  flex-direction: row;
+  flex-wrap: wrap;
+  .el-radio{
+    flex: 0 0 40%;
+    line-height: 24px;
+    .el-radio__label{
+      color: #666;
+      font-size: 16px;
+      margin-bottom: 12px;
+    }
+  }
+}
+.crm-create-item {
+  flex: 0 0 45%;
+  flex-shrink: 0;
+  // overflow: hidden;
+  padding-bottom: 10px;
+}
+
+// 占用一整行
+.crm-create-block-item {
+  flex: 0 0 100%;
+  flex-shrink: 0;
+  padding-bottom: 10px;
+}
+.nav-dialog-div {
+  margin-bottom: 20px;
+}
+.nav-dialog-div /deep/ .el-input {
+  width: auto;
+}
+.el-table /deep/ .el-button+.el-button{
+  margin-left: 3px;
+}
+</style>
diff --git a/src/views/clients/business/components/BusinessFollow.vue b/src/views/clients/business/components/BusinessFollow.vue
new file mode 100644
index 0000000..e1a43c3
--- /dev/null
+++ b/src/views/clients/business/components/BusinessFollow.vue
@@ -0,0 +1,208 @@
+<template>
+  <div class="f-container">
+    <div v-loading="sendLoading">
+      <mix-add
+        ref="mixadd"
+        :crm-type="crmType"
+        :id="id"
+        :detail="detail"
+        :show-relative-business="true"
+        :show-relative-contacts="true"
+        @mixadd-info="submitInfo"/>
+    </div>
+    <div class="log-cont">
+      <!--<flexbox>
+        <flexbox
+          v-for="(item, index) in logTypes"
+          :key="index"
+          style="width: auto;"
+          @click.native="logTabsClick(item,index)">
+          <div
+            :style="{ color: logType==item.type ? '#F18C70' : '#777'}"
+            class="log-tabs-item">{{ item.name }}</div>
+          <div
+            v-if="logTypes.length -1 !== index"
+            class="log-tabs-line"/>
+        </flexbox>
+      </flexbox>-->
+      <keep-alive>
+        <component
+          :is="componentsName"
+          :id="id"
+          :crm-type="crmType"/>
+      </keep-alive>
+    </div>
+  </div>
+</template>
+
+<script>
+import MixAdd from '../../components/MixAdd'
+import RecordLog from '../../components/followLog/RecordLog' // 跟进记录
+import JournalLog from '../../components/followLog/JournalLog' // 日志列表
+import ExamineLog from '../../components/followLog/ExamineLog' // 审批列表
+import TaskLog from '../../components/followLog/TaskLog' // 任务日志列表
+import ScheduleLog from '../../components/followLog/ScheduleLog' // 日程日志列表
+import FollowRecordTable from '../../components/followLog/components/FollowRecordTable' // 跟进记录
+import { AddFollowRecord, MakeFollowRecordCompleted } from '@/api/customermanagement/customerManage'
+// import followLogType from '@/views/clients/mixins/followLogType'
+
+export default {
+  /** 客户管理 的 商机详情 的 跟进记录 */
+  name: 'BusinessFollow',
+  components: {
+    MixAdd,
+    RecordLog,
+    JournalLog,
+    ExamineLog,
+    TaskLog,
+    ScheduleLog,
+    FollowRecordTable
+  },
+  // mixins: [followLogType],
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    detail: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    /** 是公海 默认是客户 */
+    isSeas: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    return {
+      sendLoading: false,
+      logType: 'record'
+    }
+  },
+  computed: {
+    logTypes () {
+      // if (this.oa) {
+      return [
+        { type: 'record', name: '跟进记录' }
+        // { type: 'log', name: '日志' },
+        // { type: 'examine', name: '审批' },
+        // { type: 'task', name: '任务' },
+        // { type: 'schedule', name: '日程' }
+      ]
+      // } else {
+      //   return [{ type: 'record', name: '跟进记录' }]
+      // }
+    },
+
+    componentsName () {
+      // if (this.logType === 'record') {
+      return 'FollowRecordTable'
+      // } else if (this.logType === 'log') {
+      //   return 'JournalLog'
+      // } else if (this.logType === 'examine') {
+      //   return 'ExamineLog'
+      // } else if (this.logType === 'task') {
+      //   return 'TaskLog'
+      // } else if (this.logType === 'schedule') {
+      //   return 'ScheduleLog'
+      // }
+      // return ''
+    }
+  },
+  mounted () {
+  },
+  activated: function () {},
+  deactivated: function () {},
+  methods: {
+    /** 发布 时候的类型选择 */
+    logTabsClick (item, index) {
+      this.logType = item.type
+    },
+    /** 告诉mixad 返回数据 */
+    // sendInfo () {
+    //   this.$refs.mixadd.$emit('submit-info')
+    // },
+    /** 快捷添加框内 返回的数据用于上传 */
+    submitInfo (data) {
+      if (data.isEvent && !data.nextTime) {
+        this.$message.error('请选择下次联系时间')
+        return
+      } else if (!data.content) {
+        this.$message.error('请输入跟进内容')
+        return
+      }
+      let params = {
+        'Id': '',
+        'FollowType': 1,
+        'FollowWay': data.wayTypeId,
+        'Content': data.content,
+        'Title': '',
+        'SourceId': this.detail.CustomerId,
+        'FollowTime': data.nextTime || '',
+        'IsCompleted': true,
+        'CustomerContacterId': data.contacts,
+        'SalesChanceId': this.id
+      }
+      if (data.files || data.images) {
+        // 1代表附件 2代表图片
+        console.log(data)
+        params['Files'] = []
+        if (data.files && data.files.length > 0) {
+          for (let i in data.files) {
+            let list1 = {
+              'Id': '',
+              'DocumentName': data.files[i].name,
+              'DocumentFileName': data.files[i].path,
+              'FileType': 1
+            }
+            params['Files'].push(list1)
+          }
+        }
+        if (data.images && data.images.length > 0) {
+          let list2 = {
+            'Id': '',
+            'DocumentName': data.images[0].name,
+            'DocumentFileName': data.images[0].path,
+            'FileType': 2
+          }
+          params['Files'].push(list2)
+        }
+      }
+      console.log(params)
+      this.sendLoading = true
+      if (data.isEvent) {
+        MakeFollowRecordCompleted({'Id': this.id}).then(res => {
+          this.$message.success('完成跟进')
+        })
+      }
+      AddFollowRecord(params)
+        .then(res => {
+          if (res.data.ErrorCode === 200) {
+            this.sendLoading = false
+            this.$message.success('发布成功')
+            // 重置页面
+            this.$refs.mixadd.resetInfo()
+            // 刷新数据
+            this.$bus.emit('follow-log-refresh', { type: 'follow-record-table' })
+          } else {
+            this.sendLoading = false
+            this.$message.error(res.data.Message)
+          }
+        })
+        .catch(() => {
+          this.sendLoading = false
+        })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../../styles/followlog.scss';
+</style>
diff --git a/src/views/clients/businessChances/BusinessChancesDetail.vue b/src/views/clients/businessChances/BusinessChancesDetail.vue
new file mode 100644
index 0000000..c30aef7
--- /dev/null
+++ b/src/views/clients/businessChances/BusinessChancesDetail.vue
@@ -0,0 +1,694 @@
+<template>
+  <slide-view
+    v-empty="!canShowDetail"
+    :listener-ids="listenerIDs"
+    :no-listener-ids="noListenerIDs"
+    :no-listener-class="noListenerClass"
+    :body-style="{padding: 0, height: '100%'}"
+    xs-empty-icon="nopermission"
+    xs-empty-text="暂无权限"
+    @side-close="hideView">
+    <flexbox
+      v-loading="loading"
+      v-if="canShowDetail"
+      direction="column"
+      align="stretch"
+      class="d-container">
+      <c-r-m-detail-head
+        :detail="detailData"
+        :head-details="headDetails"
+        :id="id"
+        crm-type="business"
+        @handle="detailHeadHandle"
+        @close="hideView">
+        <!--<div class="busi-line"/>-->
+      </c-r-m-detail-head>
+
+      <div class="tabs" style="margin-bottom:24px;">
+        <el-tabs
+          v-model="tabCurrentName"
+          @tab-click="handleClick">
+          <el-tab-pane
+            v-for="(item, index) in tabnames"
+            :key="index"
+            :label="item.label"
+            :name="item.name"/>
+        </el-tabs>
+      </div>
+
+      <!--<div
+        style="padding:10px 50px;margin-bottom:24px;">
+        <flexbox
+          class="busi-state">
+          <a
+            v-for="(item, index) in status"
+            :key="index">
+              <div
+                v-if="status.length -1 !=index"
+                slot="reference"
+                :class="item.class"
+                class="busi-state-item"
+                @click="handleStatuChange(item, index)">
+                {{ item.name }}
+                <div class="state-circle"/>
+                <div class="state-line"/>
+                <div class='state-info'>
+                  <el-button type="primary" @click="pushState" v-if="item.isPushing" style='margin-left:36px;'>推进</el-button>
+                  <div v-if="item.class === 'state-suc'" class='state-name'>{{item.UserName}}</div>
+                  <div v-if="item.class === 'state-suc'" class='state-name'>{{item.CreateTime}}</div>
+                </div>
+              </div>
+              <div
+                v-if="status.length -1 ==index"
+                :class="item.class"
+                class="busi-state-item"
+                style="margin-left:8px;">
+                <i
+                  :class="item.overIcon"
+                  style="margin-right:8px;"/>
+                {{ item.name }}
+                <div class="state-circle"/>
+              </div>
+          </a>
+        </flexbox>
+      </div>
+      <el-dialog
+        title="推进"
+        :visible.sync="isPushed"
+        width="20%"
+        append-to-body
+        :before-close="handleClose">
+        <div class='pushBody'>
+          <i class="el-icon-warning" style="color: #e6a23c;"></i>
+          <span>确定推进商机到</span>
+          <el-select v-model="pushStatus" placeholder="请选择">
+            <el-option
+              v-for="item in pushOptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value">
+            </el-option>
+          </el-select>
+          <span>阶段</span>
+        </div>
+        <span slot="footer" class="dialog-footer">
+          <el-button @click="handleClose" class='closePushBtn'>取 消</el-button>
+          <el-button type="primary" @click="surePush" class='surePushBtn'>确 定</el-button>
+        </span>
+      </el-dialog>
+      <div style="width:100%; height:8px; background: #F5F6FA;margin-bottom:48px;"></div>-->
+      <div
+        id="follow-log-content"
+        class="t-loading-content"
+        :style="'height:' + contentStyleObj.height">
+        <keep-alive>
+          <component
+            :is="tabName"
+            :detail="detailData"
+            :id="id"
+            crm-type="businessChances"/>
+        </keep-alive>
+      </div>
+    </flexbox>
+    <c-r-m-create-view
+      v-if="isCreate"
+      :action="{type: 'update', id: id, batchId: detailData.batchId}"
+      crm-type="businessChances"
+      @save-success="editSaveSuccess"
+      @hiden-view="isCreate=false"/>
+  </slide-view>
+</template>
+
+<script>
+import {
+  GetSalesChanceDetail,
+  ChangeSalesChanceStage
+} from '@/api/customermanagement/business'
+
+import SlideView from '@/components/SlideView'
+import CRMDetailHead from '../components/CRMDetailHead'
+import BusinessFollow from './components/BusinessFollow' // 跟进记录
+import CRMBaseInfo from '../components/CRMBaseInfo' // 商机基本信息
+import RelativeContract from '../components/RelativeContract' // 相关合同
+import RelativeContacts from '../components/RelativeContacts' // 相关联系人
+import RelativeHandle from '../components/RelativeHandle' // 相关操作
+import RelativeTeam from '../components/RelativeTeam' // 相关团队
+import RelativeProduct from '../components/RelativeProduct' // 相关团队
+import RelativeFiles from '../components/RelativeFiles' // 相关附件
+import RelativeOffers from '../components/RelativeOffers' // 相关报价
+import RelativeSchedule from '../components/RelativeSchedule' // 相关待办事项
+import CRMCreateView from '../components/CRMCreateView' // 新建页面
+import RelativeApproval from '../components/RelativeApproval' // 相关商机流转跟踪记录
+
+import detail from '../mixins/detail'
+
+export default {
+  /** 客户管理 的 商机详情 */
+  name: 'BusinessChancesDetail',
+  components: {
+    SlideView,
+    CRMDetailHead,
+    BusinessFollow,
+    CRMBaseInfo,
+    RelativeContract,
+    RelativeContacts,
+    RelativeHandle,
+    RelativeTeam,
+    RelativeProduct,
+    RelativeFiles,
+    CRMCreateView,
+    RelativeOffers,
+    RelativeSchedule,
+    RelativeApproval
+  },
+  mixins: [detail],
+  props: {
+    // 详情信息id
+    id: [String, Number],
+    // 监听的dom 进行隐藏详情
+    listenerIDs: {
+      type: Array,
+      default: () => {
+        return ['crm-main-container']
+      }
+    },
+    isFollow: {
+      type: Boolean,
+      default: false
+    },
+    // 不监听
+    noListenerIDs: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    noListenerClass: {
+      type: Array,
+      default: () => {
+        return ['el-table__body']
+      }
+    }
+  },
+  data () {
+    return {
+      loading: false, // 展示加载loading
+      crmType: 'businessChances',
+      detailData: {}, // read 详情
+      headDetails: [
+        { title: '客户名称', value: '' },
+        { title: '预计成交金额(元)', value: '' },
+        { title: '商机状态', value: '' },
+        { title: '负责人', value: '' },
+        { title: '创建时间', value: '' }
+      ],
+      tabCurrentName: 'basicinfo',
+      /** 商机状态数据 */
+      status: [],
+      /** 完结状态 */
+      statuHandleItems: [
+        {
+          name: '赢单',
+          type: 1,
+          value: '100%',
+          img: require('@/assets/img/check_suc.png')
+        },
+        {
+          name: '输单',
+          type: 2,
+          value: '0%',
+          img: require('@/assets/img/check_fail.png')
+        },
+        {
+          name: '无效',
+          type: 3,
+          value: '0%',
+          img: require('@/assets/img/check_cancel.png')
+        }
+      ],
+      isCreate: false, // 编辑操作
+      contentStyleObj: {
+        height: '100px'
+      },
+      isPushed: false,
+      pushStatus: 1,
+      pushOptions: [{value: 1, label: '初期沟通'}, {value: 2, label: '需求分析'}, {value: 3, label: '方案报价'}, {value: 4, label: '商务谈判'}, {value: 5, label: '成功'}, {value: 6, label: '搁置'}]
+    }
+  },
+  computed: {
+    tabName () {
+      if (this.tabCurrentName === 'followlog') {
+        return 'business-follow'
+      } else if (this.tabCurrentName === 'basicinfo') {
+        return 'c-r-m-base-info'
+      } else if (this.tabCurrentName === 'team') {
+        return 'relative-team'
+      } else if (this.tabCurrentName === 'contract') {
+        return 'relative-contract'
+      } else if (this.tabCurrentName === 'operationlog') {
+        return 'relative-handle'
+      } else if (this.tabCurrentName === 'product') {
+        return 'relative-product'
+      } else if (this.tabCurrentName === 'file') {
+        return 'relative-files'
+      } else if (this.tabCurrentName === 'contacts') {
+        return 'relative-contacts'
+      } else if (this.tabCurrentName === 'offers') {
+        return 'relative-offers'
+      } else if (this.tabCurrentName === 'approval') {
+        return 'relative-approval'
+      } else if (this.tabCurrentName === 'schedule') {
+        return 'relative-schedule'
+      }
+      return ''
+    },
+    tabnames () {
+      let tempsTabs = []
+      // if (this.crm.business && this.crm.business.read) {
+      tempsTabs.push({ label: '基本信息', name: 'basicinfo' })
+      // }
+      tempsTabs.push({ label: '跟进记录', name: 'followlog' })
+      // if (this.crm.contacts && this.crm.contacts.index) {
+      // tempsTabs.push({ label: '联系人', name: 'contacts' })
+      // }
+      tempsTabs.push({ label: '报价', name: 'offers' })
+
+      // if (this.crm.contract && this.crm.contract.index) {
+      tempsTabs.push({ label: '合同', name: 'contract' })
+      // }
+      // if (this.crm.product && this.crm.product.index) {
+      tempsTabs.push({ label: '产品', name: 'product' })
+      tempsTabs.push({ label: '商机流转跟踪', name: 'approval' })
+      // }
+      // tempsTabs.push({ label: '待办事项', name: 'schedule' })
+      // tempsTabs.push({ label: '相关团队', name: 'team' })
+      // tempsTabs.push({ label: '附件', name: 'file' })
+      tempsTabs.push({ label: '操作记录', name: 'operationlog' })
+      return tempsTabs
+    }
+  },
+  created () {
+    this.getHight()
+    this.getDetial()
+    console.log(this.isFollow)
+    if (this.isFollow) {
+      this.tabCurrentName = 'followlog'
+    }
+    window.addEventListener('resize', this.getHight)
+  },
+  mounted () {},
+  destroyed () {
+    window.removeEventListener('resize', this.getHight)
+  },
+  methods: {
+    getHight () {
+      // this.contentStyleObj.height = (window.innerHeight - 600) + 'px'
+    },
+    getDetial () {
+      this.loading = true
+      GetSalesChanceDetail({
+        Id: this.id
+      })
+        .then(res => {
+          this.loading = false
+          this.detailData = res.data.Result
+
+          let statusList = [{statusId: 1, name: '初期沟通'}, {statusId: 2, name: '需求分析'}, {statusId: 3, name: '方案报价'}, {statusId: 4, name: '商务谈判'}, {statusId: 5, name: '商机成功'}, {statusId: 6, name: '商机搁置'}]
+          let statusId = this.detailData.SalesChanceStage
+          this.pushStatus = statusId
+          this.handleBusinessStatus(0, statusId, statusList, '100%')
+
+          this.headDetails[0].value = res.data.Result.CustomerName || '暂无'
+          this.headDetails[1].value = res.data.Result.ExpectedAmount || 0
+          this.headDetails[2].value = res.data.Result.ReportStatus || '暂无'
+          // 负责人
+          this.headDetails[3].value = res.data.Result.OwerUserName || '暂无'
+          this.headDetails[4].value = res.data.Result.CreateTime || '暂无'
+        })
+        .catch(() => {
+          this.loading = false
+        })
+    },
+    pushState () {
+      this.isPushed = true
+    },
+    handleClose () {
+      // this.pushStatus = 1
+      this.isPushed = false
+    },
+    surePush () {
+      console.log(this.pushStatus)
+      let params = {
+        'Id': this.id,
+        'SalesChanceStage': this.pushStatus
+      }
+      ChangeSalesChanceStage(params).then(res => {
+        if (res.data.ErrorCode === 200) {
+          this.$message.success(res.data.Message)
+          this.getDetial()
+        } else {
+          this.$message.error(res.data.Message)
+        }
+      })
+      this.handleClose()
+    },
+    //* * 点击关闭按钮隐藏视图 */
+    hideView () {
+      this.$emit('hide-view')
+    },
+    /** 处理商机状态数据 */
+    handleBusinessStatus (isEnd, statusId, statusList, statusRemark) {
+      this.status = []
+      let info = this.detailData.SalesChanceForwards
+      if (statusList && statusList.length > 0) {
+        let isdoingIndex = -1
+        for (let index = 0; index < statusList.length; index++) {
+          const item = statusList[index]
+          if (item.statusId === statusId) {
+            isdoingIndex = index
+            item['class'] = 'state-suc'
+          } else {
+            item['class'] = isdoingIndex >= 0 ? 'state-undo' : 'state-suc'
+          }
+          if (info && info.length > 0) {
+            for (let j = 0; j < info.length; j++) {
+              if (item.statusId === info[j].SalesChanceStage) {
+                item['CreateTime'] = info[j].CreateTime
+                item['UserName'] = info[j].UserName
+              } else {
+                if (item.statusId === info[j].SalesChanceStage) {
+                  item['CreateTime'] = info[j].CreateTime
+                  item['UserName'] = info[j].UserName
+                }
+              }
+            }
+          }
+          this.status.push(item)
+        }
+
+        const overItem = { type: isEnd }
+        if (isEnd === 0) {
+          overItem.name = '结束'
+          if (isdoingIndex === statusList.length - 1) {
+            overItem['class'] = 'state-doing'
+          } else {
+            if (this.status.length > 0 && statusId !== 0) {
+              // 有推进状态 才会有下一阶段
+              this.status[isdoingIndex + 1].class = 'state-doing'
+              this.status[isdoingIndex + 1]['isPushing'] = true
+            }
+            overItem['class'] = 'state-undo'
+          }
+        } else if (isEnd === 1) {
+          overItem.name = '赢单'
+          overItem.title = '赢单' // 详情标题 和 内容
+          overItem.detail = '赢单率100%'
+          overItem['overIcon'] = ['el-icon-check', 'el-icon--right']
+          overItem['class'] = 'state-suc'
+        } else if (isEnd === 2) {
+          overItem.name = '输单'
+          overItem.title = '赢单率0%'
+          overItem.detail = statusRemark
+          overItem['overIcon'] = ['el-icon-circle-close', 'el-icon--right']
+          overItem['class'] = 'state-fail'
+        } else if (isEnd === 3) {
+          overItem.name = '无效'
+          overItem.title = '赢单率0%'
+          overItem.detail = statusRemark
+          overItem['overIcon'] = ['el-icon-remove-outline', 'el-icon--right']
+          overItem['class'] = 'state-invalid'
+        }
+        this.status.push(overItem)
+      }
+    },
+    /** 操作状态改变 */
+    handleStatuChange (item, index) {
+      if (this.detailData.isEnd !== 0) {
+        // 非完结状态下 可推进
+        return
+      }
+      if (!item.isdoing) {
+        let message = '确定进入' + item.name + '阶段'
+        this.$confirm(message, '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+          .then(() => {
+            this.loading = true
+            // crmBusinessAdvance({
+            //   businessId: this.id,
+            //   statusId: item.statusId
+            // })
+            //   .then(res => {
+            //     this.loading = false
+            //     this.$message.success('操作成功')
+            //     this.getDetial()
+            //   })
+            //   .catch(() => {
+            //     this.loading = false
+            //   })
+          })
+          .catch(() => {
+            this.$message({
+              type: 'info',
+              message: '已取消操作'
+            })
+          })
+      }
+    },
+    /** 完结状态结果 */
+    handleStatuResult (item, index) {
+      if (this.detailData.isEnd !== 0) {
+        // 非完结状态下 可推进
+        return
+      }
+      /** 输单 和 无效 */
+      if (item.type === 2 || item.type === 3) {
+        let message = '请填写' + item.name + '原因:'
+        let title = item.name + '原因'
+        this.$prompt(message, title, {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消'
+        })
+          .then(({ value }) => {
+            this.loading = true
+            // crmBusinessAdvance({
+            //   businessId: this.id,
+            //   statusId: item.statusId,
+            //   isEnd: item.type,
+            //   statusRemark: value
+            // })
+            //   .then(res => {
+            //     this.loading = false
+            //     this.$message.success('操作成功')
+            //     this.getDetial()
+            //   })
+            //   .catch(() => {
+            //     this.loading = false
+            //   })
+          })
+          .catch(() => {
+            this.$message({
+              type: 'info',
+              message: '取消输入'
+            })
+          })
+      } else {
+        let message = '确定将当前商机设为' + item.name + '吗?'
+        this.$confirm(message, '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+          .then(() => {
+            this.loading = true
+            // crmBusinessAdvance({
+            //   businessId: this.id,
+            //   statusId: item.statusId,
+            //   isEnd: item.type
+            // })
+            //   .then(res => {
+            //     this.loading = false
+            //     this.$message.success('操作成功')
+            //     this.getDetial()
+            //   })
+            //   .catch(() => {
+            //     this.loading = false
+            //   })
+          })
+          .catch(() => {
+            this.$message({
+              type: 'info',
+              message: '已取消操作'
+            })
+          })
+      }
+    },
+    editSaveSuccess () {
+      this.$emit('handle', { type: 'save-success' })
+      this.getDetial()
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../styles/crmdetail.scss';
+.busi-line {
+  position: absolute;
+  bottom: 0;
+  left: 17px;
+  right: 17px;
+  height: 1px;
+  background-color: #e6e6e6;
+}
+
+.busi-state {
+  position: relative;
+  padding-left: 20px;
+  overflow-x: auto;
+  overflow-y: hidden;
+  padding-bottom: 80px;
+  a {
+    flex-shrink: 0;
+  }
+}
+
+.busi-state-item {
+  padding: 10px 35px;
+  margin: 5px 0;
+  position: relative;
+  margin-right: 20px;
+  font-size: 14px;
+  font-weight: 500;
+  color: #333333;
+  width: 126px;
+  .state-circle {
+    width: 30px;
+    height: 30px;
+    background-size: 100% 100%;
+    background: url('../../../assets/img/step_wait.png') no-repeat;
+    top: 42px;
+    left: 42%;
+    position: absolute;
+    z-index: -1;
+  }
+  .state-line{
+    width:160px;
+    height: 2px;
+    background: #F1F1F1;
+    position: absolute;
+    top: 50px;
+    left: 65px;
+    z-index: -2;
+  }
+  .state-info{
+    position: absolute;
+    top: 72px;
+    left: 0;
+    text-align: center;
+  }
+  .state-name{
+    margin-left: 10px;
+  }
+}
+
+.state-undo {
+  .state-circle {
+    background: url('../../../assets/img/step_wait.png') no-repeat;
+  }
+  .state-line {
+    background: #F1F1F1;
+  }
+}
+
+.state-doing {
+  .state-circle {
+    background: url('../../../assets/img/step_wait.png') no-repeat;
+  }
+  .state-line {
+    background: #F1F1F1;
+  }
+}
+
+.state-suc {
+  .state-circle {
+    background: url('../../../assets/img/step_success.png') no-repeat;
+  }
+  .state-line {
+    background: #4D88FF;
+  }
+}
+
+.state-fail {
+  .state-circle {
+    background: url('../../../assets/img/step_wait.png') no-repeat;
+  }
+  .state-line {
+    background: red;
+  }
+}
+
+.state-invalid {
+  .state-circle {
+    background: url('../../../assets/img/step_wait.png') no-repeat;
+  }
+  .state-line {
+    background: #F1F1F1;
+  }
+}
+
+/** 状态操作布局 */
+.state-handel-cont {
+  font-size: 13px;
+  color: #333;
+  .state-handel-item {
+    padding: 10px 0;
+    cursor: pointer;
+    .state-handel-item-img {
+      width: 16px;
+      height: 16px;
+      border-radius: 8px;
+      margin-right: 8px;
+      flex-shrink: 0;
+      display: block;
+    }
+    .state-handel-item-name {
+      flex: 1;
+    }
+    .state-handel-item-value {
+      flex-shrink: 0;
+    }
+  }
+  .state-handel-item:hover {
+    background-color: #f7f8fa;
+  }
+}
+.closePushBtn{
+  width: 58px;
+  height: 32px;
+  background: #FFFFFF;
+  border-radius: 3px;
+  border: 1px solid #999999;
+  font-size: 12px;
+  font-weight: 400;
+  color: #333333;
+  &:hover{
+    border-color:#4D88FF;
+    color: #4D88FF;
+  }
+  &:active{
+    border-color:#4D88FF;
+    color: #4D88FF;
+  }
+}
+.surePushBtn{
+  width: 58px;
+  height: 32px;
+  background: #4D88FF;
+  border-radius: 3px;
+  font-weight: 400;
+  color: #FFFFFF;
+}
+</style>
diff --git a/src/views/clients/businessChances/BusinessChancesIndex.vue b/src/views/clients/businessChances/BusinessChancesIndex.vue
new file mode 100644
index 0000000..cd580d2
--- /dev/null
+++ b/src/views/clients/businessChances/BusinessChancesIndex.vue
@@ -0,0 +1,557 @@
+<template>
+  <div class='customer'>
+    <c-r-m-list-head
+        ref="listHead"
+        title="商机列表"
+        main-title="商务管理" />
+
+    <c-r-m-table-head
+      ref="crmTableHead"
+      :crm-type="crmType"
+      :fieldList='fieldList'
+      @exportFile="exportFile"
+      @importFile='importFile'
+      @filter="handleFilter"
+      @handle="handleHandle"
+      @on-handle="listHeadHandle"
+      @scene="handleScene"
+      @queryList='queryList'/>
+
+    <el-card class="el-card">
+      <el-table
+        v-loading="loading"
+        id="crm-table"
+        :data="list"
+        :height="tableHeight"
+        :cell-style="cellStyle"
+        class="n-table--border"
+        border
+        highlight-current-row
+        style="width: 100%; z-index: 0;"
+        @row-click="handleRowClick"
+        @sort-change="sortChange"
+        @header-dragend="handleHeaderDragend"
+        @selection-change="handleSelectionChange">
+        <!--<el-table-column
+          show-overflow-tooltip
+          type="selection"
+          align="center"
+          width="55"/>-->
+        <el-table-column
+          v-for="(item, index) in fieldList"
+          :key="index"
+          :fixed="index==0"
+          :prop="item.field"
+          :label="item.value"
+          :width="item.width"
+          :formatter="fieldFormatter"
+          sortable="custom"
+          show-overflow-tooltip>
+          <template
+            slot="header"
+            slot-scope="scope">
+            <div class="table-head-name">
+              {{ scope.column.label }}
+              <c-r-m-table-filter
+                :show="scope.column.label==='项目属性'||scope.column.label==='提交'||scope.column.label==='审批'"
+                :tableType="scope.column.label"
+                @queryList="queryList">
+                </c-r-m-table-filter>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="BusinessStatusString" label="上报状态">
+          <template
+            slot="header"
+            slot-scope="scope">
+            <div class="table-head-name">{{ scope.column.label }}</div>
+          </template>
+          <template slot-scope="scope">
+            <el-tooltip class="item" effect="dark" :content="scope.row.BusinessStatusReason?scope.row.BusinessStatusReason:scope.row.BusinessStatusString" placement="top">
+              <span >{{scope.row.BusinessStatusString}}</span>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+        <el-table-column
+          prop="operation"
+          width="150">
+          <template
+            slot="header"
+            slot-scope="scope">
+            <div class="table-head-name">操作</div>
+          </template>
+          <template slot-scope="scope">
+          <el-button type="text" size="small" :disabled="!scope.row.IsCanEdit"  @click='editList(scope.row)'>编辑<span v-if="scope.row.IsCanSubmitToAuto"> | </span></el-button>
+            <el-button type="text" v-if="scope.row.IsCanSubmitToAuto" size="small"  @click='getCommit(scope.row)'>上报</el-button>
+            <!-- v-if="scope.row.ReportStatus === 2&&scope.row.BusinessStatus===0"<el-button type="text" size="small"  @click='deleteSingleModule(scope.row.Id)'>删除</el-button>
+            <el-button type="text" size="small"  @click='goFollow(scope.row.Id)'>跟进</el-button>-->
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="p-contianer" v-show='total>0'>
+        <el-pagination
+          :current-page="currentPage"
+          :page-sizes="pageSizes"
+          :page-size.sync="pageSize"
+          :total="total"
+          class="p-bar"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"/>
+      </div>
+
+    </el-card>
+
+    <!-- 编辑页面 -->
+    <c-r-m-create-view
+      v-if="isCreate"
+      :action="{type: 'update', id: editData.Id, data: editData}"
+      crm-type="business"
+      @save-success="listHeadHandle"
+      @hiden-view="isCreate=false"/>
+    <c-r-m-import
+      :show="showCRMImport"
+      :crm-type="crmType"
+      @close="showCRMImport=false"
+      @queryList='queryList'/>
+    <c-r-m-export
+      :show="showCRMExport"
+      :crm-type="crmType"
+      :search="search"
+      :filter-obj="filterObj"
+      :is-seas="false"
+      :export-params="exportParams"
+      @close="showCRMExport=false"
+      @queryList='queryList'/>
+    <!-- 相关详情页面 -->
+    <c-r-m-all-detail
+      :key='timer'
+      :visible.sync="showDview"
+      :crm-type="rowType"
+      :id="rowID"
+      :isFollow="isFollow"
+      class="d-view"
+      @handle="handleHandle"/>
+    <fields-set
+      :crm-type="crmType"
+      :dialog-visible.sync="showFieldSet"
+      @set-success="setSave"/>
+
+     <!--保存并申报 -->
+      <el-dialog
+        title="提交申报"
+        :visible.sync="isCommited"
+        width="24%"
+        append-to-body
+        :before-close="handleClose">
+        <div class='pushBody'>
+          <div class='hintSelect'>
+            <span>是否将商机上报到欧特克?</span>
+            <el-select v-model="pushStatus" placeholder="请选择">
+              <el-option key="1" label="是" value="1">
+              </el-option>
+              <el-option key="2" label="否" value="2">
+              </el-option>
+            </el-select>
+          </div>
+          <div class='hintContent' v-if="pushStatus==='2'">
+            <el-input placeholder="请输入拒绝原因" type="textarea" v-model="pushContent"  class='areaInput'>
+            </el-input>
+          </div>
+        </div>
+        <span slot="footer" class="dialog-footer">
+          <el-button @click="handleClose" class='closePushBtn'>取 消</el-button>
+          <el-button type="primary" @click="confirmClick(false)" class='surePushBtn'>提交</el-button>
+        </span>
+      </el-dialog>
+  </div>
+</template>
+
+<script>
+import table from '../mixins/table'
+import CRMCreateView from '../components/CRMCreateView'
+import CRMImport from '../components/CRMImport'
+import CRMExport from '../components/CRMExport'
+import CRMAllDetail from '@/views/clients/components/CRMAllDetail'
+import CRMTableFilter from '../components/CRMTableFilter'
+import { DeleteSalesChance, SubmitSalesChance } from '@/api/customermanagement/business'
+
+export default {
+  /** 客户管理 的 商机列表 */
+  name: 'BusinessChancesIndex',
+  components: {
+    CRMAllDetail,
+    CRMCreateView,
+    CRMImport,
+    CRMExport,
+    CRMTableFilter
+  },
+  filters: {
+  },
+  mixins: [table],
+  computed: {
+  },
+  data () {
+    return {
+      timer: '',
+      choosedScene: '2',
+      fieldList: [{ field: 'ChanceNumber', value: '编号' },
+        { field: 'ChanceName', value: '商机名称', width: '150' },
+        { field: 'CustomerName', value: '客户名称', width: '150' },
+        { field: 'ContacterName', value: '联系人' },
+        // { field: 'ProjectProperty', value: '项目属性' },
+        { field: 'ChanceRequestTypeString', value: '商机类型' },
+        { field: 'SalesChanceStage', value: '销售阶段' },
+        { field: 'UploadStatusName', value: '提交' },
+        { field: 'ReportStatusName', value: '审批' },
+        { field: 'TrackStatus', value: '报备' },
+        { field: 'AutoSalesChanceId', value: '欧特克商机编号' },
+        { field: 'SubmitTimeString', value: '上报时间' },
+        // { field: 'BusinessStatusString', value: '上报状态' },
+        { field: 'ApprovalTimeString', value: '确认时间' },
+        { field: 'InvalidTimeString', value: '过期时间' },
+        { field: 'CreateUserName', value: '创建人' },
+        // { field: 'ExpectedDate', value: '预期成交日期' },
+        // { field: 'ExpectedAmount', value: '商机金额/元' },
+        { field: 'OwerName', value: '销售负责人' }
+      ],
+      isDialogVisible: false, // 是创建
+      isCreate: false,
+      // 导入
+      showCRMImport: false,
+      // 导出
+      showCRMExport: false,
+      // 导出选中参数
+      exportParams: {},
+      crmType: 'businessChances',
+      loading: false,
+      addLoading: false,
+      popSearch: '',
+      isFollow: false,
+      isCommited: false,
+      pushStatus: '1',
+      pushContent: '',
+      commitRow: []
+    }
+  },
+  mounted () {
+  },
+  methods: {
+    // 选择文件
+    selectFile () {
+      document.getElementById('importInputFile').click()
+    },
+    // 获取左边padding
+    getPaddingLeft (item, index) {
+      if (item.showblock && item.showblock === true) {
+        return '25px'
+      }
+      return item.styleIndex % 2 === 0 ? '0' : '25px'
+    },
+    // 获取右边padding
+    getPaddingRight (item, index) {
+      if (item.showblock && item.showblock === true) {
+        return '0'
+      }
+
+      return item.styleIndex % 2 === 0 ? '25px' : '0'
+    },
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      if (
+        column.property === 'ChanceName' ||
+        column.property === 'CustomerName'
+      ) {
+        return { color: '#4D88FF', cursor: 'pointer' }
+      } else if (column.property === 'ReportStatusName') {
+        if (row[column.property] === '审批中') {
+          return { color: '#FF8800' }
+        } else if (row[column.property] === '通过') {
+          return { color: '#2DB300' }
+        } else if (row[column.property] === '驳回') {
+          return { color: '#FF4D4D' }
+        } else {
+          return { color: '#333' }
+        }
+      } else if (column.property === 'TrackStatus') {
+        if (row[column.property]) {
+          if (row['IsAutoPassed'] === true) {
+            return { color: '#2DB300' }
+          } else {
+            return { color: '#FF4D4D' }
+          }
+        } else {
+          return { color: '#333' }
+        }
+      } else if (column.property === 'BusinessStatusString') {
+        if (row[column.property] === '待上报') {
+          return { color: '#FF8800' }
+        } else if (row[column.property] === '已上报') {
+          return { color: '#2DB300' }
+        } else if (row[column.property] === '已拒绝') {
+          return { color: '#FF4D4D' }
+        } else {
+          return { color: '#333' }
+        }
+      } else {
+        return ''
+      }
+    },
+    getCommit (row) {
+      console.log(row)
+      this.isCommited = true
+      this.commitRow = row
+    },
+    handleClose () {
+      this.isCommited = false
+      this.pushStatus = '1'
+      this.pushContent = ''
+    },
+    // 确定选择
+    confirmClick () {
+      this.isCommited = true
+      let params = {
+        'SalesChanceId': this.commitRow.Id,
+        'BusinessStatus': JSON.parse(this.pushStatus),
+        'BusinessStatusReason': this.pushContent
+      }
+      SubmitSalesChance(params).then(res => {
+        if (res.data.ErrorCode === 200) {
+          this.$message.success(res.data.Message)
+          this.isCommited = false
+        } else {
+          this.$message.error(res.data.Message)
+        }
+      })
+        .catch(() => {
+          // this.$message({
+          //   type: 'info',
+          //   message: '已取消上报'
+          // })
+        })
+    },
+    goFollow (id) {
+      this.rowID = id
+      this.isFollow = true
+      this.rowType = 'business'
+      this.showDview = true
+      this.timer = new Date().getTime()
+      this.$forceUpdate()
+    },
+    deleteSingleModule (id) {
+      this.$confirm('确定删除?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          DeleteSalesChance([{'Id': id}]).then(res => {
+            if (res.data.ErrorCode === 200) {
+              this.$message.success(res.data.Message)
+              this.getList()
+            } else {
+              this.$message.error(res.data.Message)
+            }
+          })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    },
+    exportFile () {
+      this.showCRMExport = true
+    },
+    importFile () {
+      this.showCRMImport = true
+    },
+    queryList (data) {
+      this.getList(data)
+    },
+    /** 筛选操作 */
+    handleFilter (data) {
+      console.log(data)
+      this.filterObj = data
+      var offsetHei = document.documentElement.clientHeight
+      var removeHeight = Object.keys(this.filterObj).length > 0 ? 310 : 240
+      this.tableHeight = offsetHei - removeHeight
+      this.currentPage = 1
+      this.getList()
+    }
+
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../styles/table.scss';
+#importInputFile {
+  display: none;
+}
+.customer{
+  // .xr-btn--orange{
+  //   background-color: #ff6a00;
+  //   border-color: #ff6a00;
+  // }
+  .customerName{
+    cursor:pointer;
+    // color: #ff6a00
+  }
+}
+.container {
+  position: relative;
+}
+
+.header {
+  height: 40px;
+  padding: 0 10px;
+  flex-shrink: 0;
+  .name {
+    font-size: 13px;
+    padding: 0 10px;
+    color: #333;
+  }
+  .detail {
+    font-size: 12px;
+    padding: 0 10px;
+    color: #aaaaaa;
+    border-left: 1px solid #aaaaaa;
+  }
+  .close {
+    position: absolute;
+    width: 40px;
+    height: 40px;
+    top: 0;
+    right: 10px;
+    padding: 10px;
+  }
+}
+.content{
+  .cropper-box{
+    display:flex;
+    flex-direction: row;
+    align-items: center;
+    padding: 0 20px;
+    .searchTitle{
+      font-size: 14px;
+      width: 124px;
+      color: #333;
+    }
+    .searchInput{
+      margin-right: 20px;
+    }
+  }
+}
+.p-contianer .p-bar{
+  margin: 5px 0 0 14px;
+}
+</style>
+<style lang="scss">
+.customer{
+  /deep/.el-input .el-input-group__append{
+    // background-color: #ff7d00;
+    // border-color: #ff7d00;
+    // color: #fff;
+  }
+}
+/* 新建和编辑 */
+.new-dialog-title {
+  padding-left: 10px;
+  margin-bottom: 3px;
+  border-left: 2px solid #4D88FF;
+}
+.new-busDialog-form {
+  height: 47vh;
+  overflow-y: auto;
+  padding: 20px;
+  display: flex;
+  flex-wrap: wrap;
+}
+.new-busDialog-form /deep/ .el-form-item {
+  // width: 50%;
+  margin: 0;
+  padding-bottom: 10px;
+}
+.new-busDialog-form /deep/ .el-form-item .el-form-item__label {
+  line-height: normal;
+  font-size: 13px;
+  color: #333333;
+  position: relative;
+  padding-bottom: 8px;
+}
+.new-busDialog-form /deep/ .crm-create-item.el-form-item .el-form-item__content {
+  width: 70%;
+}
+.new-busDialog-form /deep/ .crm-create-block-item.el-form-item .el-form-item__content {
+  width: 90%;
+}
+.new-busDialog-form /deep/ .crm-create-block-item.el-form-item .el-form-item__label{
+  width: 10% !important;
+}
+.doubleSelect{
+  display: flex;
+  flex-direction: row;
+  width: 100%;
+  .leftSelect{
+    margin-right: 10px;
+  }
+}
+.radioList{
+  display: flex;
+  flex-direction: row;
+  flex-wrap: wrap;
+  .el-radio{
+    flex: 0 0 40%;
+    line-height: 24px;
+    .el-radio__label{
+      color: #666;
+      font-size: 16px;
+      margin-bottom: 12px;
+    }
+  }
+}
+.crm-create-item {
+  flex: 0 0 45%;
+  flex-shrink: 0;
+  // overflow: hidden;
+  padding-bottom: 10px;
+}
+
+// 占用一整行
+.crm-create-block-item {
+  flex: 0 0 100%;
+  flex-shrink: 0;
+  padding-bottom: 10px;
+}
+.nav-dialog-div {
+  margin-bottom: 20px;
+}
+.nav-dialog-div /deep/ .el-input {
+  width: auto;
+}
+.el-table /deep/ .el-button+.el-button{
+  margin-left: 3px;
+}
+.areaInput.el-textarea /deep/ .el-textarea__inner{
+  &:hover{
+    border-color: #4D88FF !important;
+  }
+}
+.pushBody{
+  margin: 0 60px;
+  .hintWord{
+    margin-top: 10px;
+  }
+  .hintSelect{
+    margin-top: 20px;
+    .el-select{
+      width: 78px;
+    }
+  }
+  .hintContent {
+     margin-top: 20px;
+  }
+}
+</style>
diff --git a/src/views/clients/businessChances/components/BusinessFollow.vue b/src/views/clients/businessChances/components/BusinessFollow.vue
new file mode 100644
index 0000000..c6dc862
--- /dev/null
+++ b/src/views/clients/businessChances/components/BusinessFollow.vue
@@ -0,0 +1,208 @@
+<template>
+  <div class="f-container">
+    <!--<div v-loading="sendLoading">
+      <mix-add
+        ref="mixadd"
+        :crm-type="crmType"
+        :id="id"
+        :detail="detail"
+        :show-relative-business="true"
+        :show-relative-contacts="true"
+        @mixadd-info="submitInfo"/>
+    </div>-->
+    <div class="log-cont">
+      <!--<flexbox>
+        <flexbox
+          v-for="(item, index) in logTypes"
+          :key="index"
+          style="width: auto;"
+          @click.native="logTabsClick(item,index)">
+          <div
+            :style="{ color: logType==item.type ? '#F18C70' : '#777'}"
+            class="log-tabs-item">{{ item.name }}</div>
+          <div
+            v-if="logTypes.length -1 !== index"
+            class="log-tabs-line"/>
+        </flexbox>
+      </flexbox>-->
+      <keep-alive>
+        <component
+          :is="componentsName"
+          :id="id"
+          :crm-type="crmType"/>
+      </keep-alive>
+    </div>
+  </div>
+</template>
+
+<script>
+import MixAdd from '../../components/MixAdd'
+import RecordLog from '../../components/followLog/RecordLog' // 跟进记录
+import JournalLog from '../../components/followLog/JournalLog' // 日志列表
+import ExamineLog from '../../components/followLog/ExamineLog' // 审批列表
+import TaskLog from '../../components/followLog/TaskLog' // 任务日志列表
+import ScheduleLog from '../../components/followLog/ScheduleLog' // 日程日志列表
+import FollowRecordTable from '../../components/followLog/components/FollowRecordTable' // 跟进记录
+import { AddFollowRecord, MakeFollowRecordCompleted } from '@/api/customermanagement/customerManage'
+// import followLogType from '@/views/clients/mixins/followLogType'
+
+export default {
+  /** 客户管理 的 商机详情 的 跟进记录 */
+  name: 'BusinessFollow',
+  components: {
+    MixAdd,
+    RecordLog,
+    JournalLog,
+    ExamineLog,
+    TaskLog,
+    ScheduleLog,
+    FollowRecordTable
+  },
+  // mixins: [followLogType],
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    detail: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    /** 是公海 默认是客户 */
+    isSeas: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    return {
+      sendLoading: false,
+      logType: 'record'
+    }
+  },
+  computed: {
+    logTypes () {
+      // if (this.oa) {
+      return [
+        { type: 'record', name: '跟进记录' }
+        // { type: 'log', name: '日志' },
+        // { type: 'examine', name: '审批' },
+        // { type: 'task', name: '任务' },
+        // { type: 'schedule', name: '日程' }
+      ]
+      // } else {
+      //   return [{ type: 'record', name: '跟进记录' }]
+      // }
+    },
+
+    componentsName () {
+      // if (this.logType === 'record') {
+      return 'FollowRecordTable'
+      // } else if (this.logType === 'log') {
+      //   return 'JournalLog'
+      // } else if (this.logType === 'examine') {
+      //   return 'ExamineLog'
+      // } else if (this.logType === 'task') {
+      //   return 'TaskLog'
+      // } else if (this.logType === 'schedule') {
+      //   return 'ScheduleLog'
+      // }
+      // return ''
+    }
+  },
+  mounted () {
+  },
+  activated: function () {},
+  deactivated: function () {},
+  methods: {
+    /** 发布 时候的类型选择 */
+    logTabsClick (item, index) {
+      this.logType = item.type
+    },
+    /** 告诉mixad 返回数据 */
+    // sendInfo () {
+    //   this.$refs.mixadd.$emit('submit-info')
+    // },
+    /** 快捷添加框内 返回的数据用于上传 */
+    submitInfo (data) {
+      if (data.isEvent && !data.nextTime) {
+        this.$message.error('请选择下次联系时间')
+        return
+      } else if (!data.content) {
+        this.$message.error('请输入跟进内容')
+        return
+      }
+      let params = {
+        'Id': '',
+        'FollowType': 1,
+        'FollowWay': data.wayTypeId,
+        'Content': data.content,
+        'Title': '',
+        'SourceId': this.detail.CustomerId,
+        'FollowTime': data.nextTime || '',
+        'IsCompleted': true,
+        'CustomerContacterId': data.contacts,
+        'SalesChanceId': this.id
+      }
+      if (data.files || data.images) {
+        // 1代表附件 2代表图片
+        console.log(data)
+        params['Files'] = []
+        if (data.files && data.files.length > 0) {
+          for (let i in data.files) {
+            let list1 = {
+              'Id': '',
+              'DocumentName': data.files[i].name,
+              'DocumentFileName': data.files[i].path,
+              'FileType': 1
+            }
+            params['Files'].push(list1)
+          }
+        }
+        if (data.images && data.images.length > 0) {
+          let list2 = {
+            'Id': '',
+            'DocumentName': data.images[0].name,
+            'DocumentFileName': data.images[0].path,
+            'FileType': 2
+          }
+          params['Files'].push(list2)
+        }
+      }
+      console.log(params)
+      this.sendLoading = true
+      if (data.isEvent) {
+        MakeFollowRecordCompleted({'Id': this.id}).then(res => {
+          this.$message.success('完成跟进')
+        })
+      }
+      AddFollowRecord(params)
+        .then(res => {
+          if (res.data.ErrorCode === 200) {
+            this.sendLoading = false
+            this.$message.success('发布成功')
+            // 重置页面
+            this.$refs.mixadd.resetInfo()
+            // 刷新数据
+            this.$bus.emit('follow-log-refresh', { type: 'follow-record-table' })
+          } else {
+            this.sendLoading = false
+            this.$message.error(res.data.Message)
+          }
+        })
+        .catch(() => {
+          this.sendLoading = false
+        })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../../styles/followlog.scss';
+</style>
diff --git a/src/views/clients/businessContracts/BusinessContractsDetail.vue b/src/views/clients/businessContracts/BusinessContractsDetail.vue
new file mode 100644
index 0000000..4458eae
--- /dev/null
+++ b/src/views/clients/businessContracts/BusinessContractsDetail.vue
@@ -0,0 +1,217 @@
+<template>
+  <slide-view
+    v-empty="!canShowDetail"
+    :listener-ids="listenerIDs"
+    :no-listener-ids="noListenerIDs"
+    :no-listener-class="noListenerClass"
+    :body-style="{padding: 0, height: '100%'}"
+    xs-empty-icon="nopermission"
+    xs-empty-text="暂无权限"
+    @side-close="hideView">
+    <flexbox
+      v-loading="loading"
+      v-if="canShowDetail"
+      direction="column"
+      align="stretch"
+      class="d-container">
+      <c-r-m-detail-head
+        :detail="detailData"
+        :head-details="headDetails"
+        :id="id"
+        crm-type="contract"
+        @handle="detailHeadHandle"
+        @close="hideView"/>
+      <div class="examine-info">
+        <examine-info
+          :id="id"
+          :record-id="detailData.examineRecordId"
+          :owner-user-id="detailData.ownerUserId"
+          class="examine-info-border"
+          examine-type="crm_contract"/>
+      </div>
+      <div class="tabs">
+        <el-tabs
+          v-model="tabCurrentName"
+          @tab-click="handleClick">
+          <el-tab-pane
+            v-for="(item, index) in tabnames"
+            :key="index"
+            :label="item.label"
+            :name="item.name"/>
+        </el-tabs>
+      </div>
+      <div
+        id="follow-log-content"
+        class="t-loading-content">
+        <keep-alive>
+          <component
+            :is="tabName"
+            :detail="detailData"
+            :id="id"
+            crm-type="contract"/>
+        </keep-alive>
+      </div>
+    </flexbox>
+    <c-r-m-create-view
+      v-if="isCreate"
+      :action="{type: 'update', id: id, batchId: detailData.batchId}"
+      crm-type="contract"
+      @save-success="editSaveSuccess"
+      @hiden-view="isCreate=false"/>
+  </slide-view>
+</template>
+
+<script>
+// import { crmContractRead } from '@/api/customermanagement/contract'
+
+import SlideView from '@/components/SlideView'
+import CRMDetailHead from '../components/CRMDetailHead'
+import ContractFollow from './components/ContractFollow' // 跟进记录
+import CRMBaseInfo from '../components/CRMBaseInfo' // 商机基本信息
+import RelativeHandle from '../components/RelativeHandle' // 相关操作
+import RelativeTeam from '../components/RelativeTeam' // 相关团队
+import RelativeProduct from '../components/RelativeProduct' // 相关团队
+import RelativeReturnMoney from '../components/RelativeReturnMoney' // 相关回款
+import RelativeFiles from '../components/RelativeFiles' // 相关附件
+import ExamineInfo from '@/components/Examine/ExamineInfo'
+
+import CRMCreateView from '../components/CRMCreateView' // 新建页面
+
+import detail from '../mixins/detail'
+
+export default {
+  /** 客户管理 的 合同详情 */
+  name: 'BusinessContractsDetail',
+  components: {
+    SlideView,
+    CRMDetailHead,
+    ContractFollow,
+    CRMBaseInfo,
+    RelativeHandle,
+    RelativeTeam,
+    RelativeProduct,
+    RelativeReturnMoney,
+    RelativeFiles,
+    ExamineInfo,
+    CRMCreateView
+  },
+  mixins: [detail],
+  props: {
+    // 详情信息id
+    id: [String, Number],
+    // 监听的dom 进行隐藏详情
+    listenerIDs: {
+      type: Array,
+      default: () => {
+        return ['crm-main-container']
+      }
+    },
+    // 不监听
+    noListenerIDs: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    noListenerClass: {
+      type: Array,
+      default: () => {
+        return ['el-table__body']
+      }
+    }
+  },
+  data () {
+    return {
+      loading: false, // 展示加载loading
+      crmType: 'contract',
+      detailData: {}, // read 详情
+      headDetails: [
+        { title: '合同编号', value: '' },
+        { title: '客户名称', value: '' },
+        { title: '合同金额(元)', value: '' },
+        { title: '签约时间', value: '' },
+        { title: '回款金额(元)', value: '' },
+        { title: '负责人', value: '' }
+      ],
+      tabCurrentName: 'basicinfo',
+      isCreate: false // 编辑操作
+    }
+  },
+  computed: {
+    tabName () {
+      if (this.tabCurrentName === 'followlog') {
+        return 'contract-follow'
+      } else if (this.tabCurrentName === 'basicinfo') {
+        return 'c-r-m-base-info'
+      } else if (this.tabCurrentName === 'team') {
+        return 'relative-team'
+      } else if (this.tabCurrentName === 'contract') {
+        return 'relative-contract'
+      } else if (this.tabCurrentName === 'operationlog') {
+        return 'relative-handle'
+      } else if (this.tabCurrentName === 'product') {
+        return 'relative-product'
+      } else if (this.tabCurrentName === 'returnedmoney') {
+        return 'relative-return-money'
+      } else if (this.tabCurrentName === 'file') {
+        return 'relative-files'
+      }
+      return ''
+    },
+    tabnames () {
+      var tempsTabs = []
+      tempsTabs.push({ label: '跟进记录', name: 'followlog' })
+      if (this.crm.contract && this.crm.contract.read) {
+        tempsTabs.push({ label: '基本信息', name: 'basicinfo' })
+      }
+      if (this.crm.product && this.crm.product.index) {
+        tempsTabs.push({ label: '产品', name: 'product' })
+      }
+      if (this.crm.receivables && this.crm.receivables.index) {
+        tempsTabs.push({ label: '回款信息', name: 'returnedmoney' })
+      }
+      tempsTabs.push({ label: '相关团队', name: 'team' })
+      tempsTabs.push({ label: '附件', name: 'file' })
+      tempsTabs.push({ label: '操作记录', name: 'operationlog' })
+      return tempsTabs
+    }
+  },
+  mounted () {},
+  methods: {
+    getDetial () {
+      this.loading = true
+      // crmContractRead({
+      //   contractId: this.id
+      // })
+      //   .then(res => {
+      //     this.loading = false
+      //     this.detailData = res.data // 创建回款计划的时候使用
+
+      //     this.headDetails[0].value = res.data.num
+      //     this.headDetails[1].value = res.data.customerName
+      //     this.headDetails[2].value = this.moneyFormat(res.data.money)
+      //     this.headDetails[3].value = res.data.orderDate
+      //     this.headDetails[4].value = this.moneyFormat(res.data.receivablesMoney)
+      //     this.headDetails[5].value = res.data.ownerUserName
+      //   })
+      //   .catch(() => {
+      //     this.loading = false
+      //   })
+    },
+    //* * 点击关闭按钮隐藏视图 */
+    hideView () {
+      this.$emit('hide-view')
+    },
+    //* * tab标签点击 */
+    handleClick (tab, event) {},
+    editSaveSuccess () {
+      this.$emit('handle', { type: 'save-success' })
+      this.getDetial()
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../styles/crmdetail.scss';
+</style>
diff --git a/src/views/clients/businessContracts/BusinessContractsIndex.vue b/src/views/clients/businessContracts/BusinessContractsIndex.vue
new file mode 100644
index 0000000..7690fab
--- /dev/null
+++ b/src/views/clients/businessContracts/BusinessContractsIndex.vue
@@ -0,0 +1,264 @@
+<template>
+  <div>
+    <c-r-m-list-head
+      ref="listHead"
+      title="合同处理列表"
+      main-title="商务管理"/>
+      <c-r-m-table-head
+        ref="crmTableHead"
+        :crm-type="crmType"
+        :fieldList='fieldList'
+        @filter="handleFilter"
+        @handle="handleHandle"
+        @on-handle="listHeadHandle"
+        @scene="handleScene"
+        @queryList='queryList'/>
+      <el-card class="el-card">
+        <el-table
+          v-loading="loading"
+          id="crm-table"
+          :data="list"
+          :height="tableHeight"
+          :cell-style="cellStyle"
+          class="n-table--border"
+          border
+          highlight-current-row
+          style="width: 100%"
+          @row-click="handleRowClick"
+          @sort-change="sortChange"
+          @header-dragend="handleHeaderDragend"
+          @selection-change="handleSelectionChange">
+          <!--<el-table-column
+            show-overflow-tooltip
+            type="selection"
+            align="left"
+            width="55"/>-->
+          <el-table-column
+            v-for="(item, index) in fieldList"
+            :key="index"
+            :prop="item.field"
+            :label="item.value"
+            :width="item.width"
+            :formatter="fieldFormatter"
+            sortable="custom"
+            show-overflow-tooltip>
+            <template
+              slot="header"
+              slot-scope="scope">
+              <div class="table-head-name">
+                  {{ scope.column.label }}
+                  <c-r-m-table-filter
+                    :show="scope.column.label==='合同类型'"
+                    :tableType="scope.column.label"
+                    @queryList="queryList">
+                  </c-r-m-table-filter>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column prop="BeforeSealFile" label="盖章前合同">
+            <template
+              slot="header"
+              slot-scope="scope">
+              <div class="table-head-name">{{ scope.column.label }}</div>
+            </template>
+            <template slot-scope="scope">
+              <span>{{scope.row.BeforeSealFile===''?'--':'点击下载'}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="SealFile" label="盖章后合同">
+            <template
+              slot="header"
+              slot-scope="scope">
+              <div class="table-head-name">{{ scope.column.label }}</div>
+            </template>
+            <template slot-scope="scope">
+              <span>{{scope.row.SealFile===''?'--':'点击下载'}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column
+            prop="operation"
+            width="150">
+            <template
+              slot="header"
+              slot-scope="scope">
+              <div class="table-head-name">操作</div>
+            </template>
+            <template slot-scope="scope">
+            <el-button type="text" size="small"  @click='editList(scope.row)'>上传盖章合同</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="p-contianer"  v-show='total>0'>
+          <el-pagination
+            :current-page="currentPage"
+            :page-sizes="pageSizes"
+            :page-size.sync="pageSize"
+            :total="total"
+            class="p-bar"
+            layout="total, sizes, prev, pager, next, jumper"
+            @size-change="handleSizeChange"
+            @current-change="handleCurrentChange"/>
+        </div>
+      </el-card>
+    <el-dialog title="上传盖章合同" :visible.sync="isCreate" :modal-append-to-body="false" width="30%">
+      <c-r-m-create-file-view
+        v-if="isCreate"
+        :id="rowID"
+        :action="createActionInfo"
+        crm-type="sealContract"
+        @save-success="createSaveSuccess"
+        @hiden-view="isCreate=false"/>
+    </el-dialog>
+    <!-- 相关详情页面 -->
+    <c-r-m-all-detail
+      :visible.sync="showDview"
+      :crm-type="rowType"
+      :id="rowID"
+      class="d-view"
+      @handle="handleHandle"/>
+    <fields-set
+      :crm-type="crmType"
+      :dialog-visible.sync="showFieldSet"
+      @set-success="setSave"/>
+  </div>
+</template>
+
+<script>
+import CRMAllDetail from '@/views/clients/components/CRMAllDetail'
+import table from '../mixins/table'
+import CRMTableFilter from '../components/CRMTableFilter'
+import CRMCreateFileView from '@/views/clients/components/CRMCreateFileView'
+import { DeleteAgreenment } from '@/api/customermanagement/contract'
+
+export default {
+  /** 客户管理 的 合同列表 */
+  name: 'BusinessContractsIndex',
+  components: {
+    CRMAllDetail,
+    CRMTableFilter,
+    CRMCreateFileView
+  },
+  mixins: [table],
+  data () {
+    return {
+      crmType: 'businessContract',
+      isCreate: false,
+      // 创建的相关信息
+      createActionInfo: { type: 'update', crmType: this.crmType, data: {} },
+      fieldList: [],
+      moneyData: null // 合同列表金额
+    }
+  },
+  computed: {
+    moneyPageData () {
+      // 未勾选展示合同总金额信息
+      if (this.selectionList.length === 0 && this.moneyData) {
+        return this.moneyData
+      } else {
+        let contractMoney = 0.0
+        let receivedMoney = 0.0
+        for (let index = 0; index < this.selectionList.length; index++) {
+          const element = this.selectionList[index]
+          // 2 审核通过的合同
+          if (element.checkStatus === 1) {
+            contractMoney += parseFloat(element.money)
+            receivedMoney += parseFloat(element.receivedMoney)
+          }
+        }
+        return {
+          contractMoney: contractMoney.toFixed(2),
+          receivedMoney: receivedMoney.toFixed(2)
+        }
+      }
+    }
+  },
+  mounted () {
+    this.getFieldList()
+  },
+  methods: {
+    getFieldList () {
+      this.fieldList.push(
+        { field: 'AgreeNumber', value: '合同编号' },
+        { field: 'AgreeName', value: '合同名称' },
+        { field: 'Comment', value: '合同备注' },
+        { field: 'CustomerName', value: '客户名称' },
+        { field: 'SalesChanceName', value: '商机名称' },
+        { field: 'AuditStatus', value: '是否审核', width: '100' },
+        { field: 'AuditUserName', value: '审核人' },
+        { field: 'SealTypeString', value: '合同类型' },
+        { field: 'IsSeal', value: '是否盖章', width: '100' },
+        { field: 'SealUserName', value: '盖章上传人' },
+        { field: 'CreateTime', value: '创建时间' },
+        { field: 'ExpressNumber', value: '快递单号' },
+        { field: 'ExpressComment', value: '快递备注信息' }
+        // { field: 'BeforeSealFile', value: '盖章前合同' },
+        // { field: 'SealFile', value: '盖章后合同' }
+      )
+    },
+    queryList (data) {
+      this.getList(data)
+    },
+    /** 编辑 */
+    editList (row) {
+      console.log(row)
+      this.createActionInfo.data = row
+      this.isCreate = true
+    },
+    deleteModule (id) {
+      this.$confirm('确定删除?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          DeleteAgreenment([{'Id': id}]).then(res => {
+            if (res.data.ErrorCode === 200) {
+              this.$message.success(res.data.Message)
+              this.getList()
+            } else {
+              this.$message.error(res.data.Message)
+            }
+          })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    },
+    createSaveSuccess () {
+      this.getList()
+      this.isCreate = false
+    },
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      if (column.property === 'BeforeSealFile' || column.property === 'SealFile' || column.property === 'SalesChanceName' ||
+        column.property === 'CustomerName') {
+        return { color: '#4D88FF', cursor: 'pointer' }
+      } else if (column.property === 'AuditStatus') {
+        if (row[column.property] === '审批中') {
+          return { color: '#FF8800' }
+        } else if (row[column.property] === '通过') {
+          return { color: '#2DB300' }
+        } else if (row[column.property] === '驳回') {
+          return { color: '#FF4D4D' }
+        }
+      } else {
+        return { textAlign: 'left' }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../styles/table.scss';
+.money-bar {
+  color: #99a9bf;
+  line-height: 44px !important;
+  position: absolute;
+  left: 20px;
+  top: 0;
+}
+</style>
diff --git a/src/views/clients/businessContracts/components/ContractFollow.vue b/src/views/clients/businessContracts/components/ContractFollow.vue
new file mode 100644
index 0000000..bf3cfa4
--- /dev/null
+++ b/src/views/clients/businessContracts/components/ContractFollow.vue
@@ -0,0 +1,197 @@
+<template>
+  <div class="f-container">
+    <div v-loading="sendLoading" v-show="crmType === 'business'">
+      <mix-add
+        ref="mixadd"
+        :crm-type="crmType"
+        :id="id"
+        @mixadd-info="submitInfo"/>
+      <flexbox class="se-section">
+        <div class="se-name">记录类型</div>
+        <el-dropdown
+          style="margin-right: 20px;"
+          trigger="click"
+          @command="handleTypeDrop">
+          <flexbox class="se-select">
+            <div class="se-select-name">{{ followType ? followType : '请选择' }}</div>
+            <i
+              class="el-icon-arrow-down el-icon--right"
+              style="color:#ccc;"/>
+          </flexbox>
+          <el-dropdown-menu slot="dropdown">
+            <el-dropdown-item
+              v-for="(item, index) in followTypes"
+              :key="index"
+              :command="item.type">{{ item.name }}</el-dropdown-item>
+          </el-dropdown-menu>
+        </el-dropdown>
+        <div class="se-name">下次联系时间</div>
+        <el-date-picker
+          v-model="nextTime"
+          :default-value="new Date"
+          :editable="false"
+          class="se-datepicker"
+          type="datetime"
+          placeholder="选择日期"
+          value-format="yyyy-MM-dd HH:mm:ss"/>
+        <el-checkbox
+          v-if="showOAPermission"
+          v-model="isEvent">添加到日程提醒</el-checkbox>
+        <el-button
+          class="se-send"
+          type="primary"
+          @click.native="sendInfo">发布</el-button>
+      </flexbox>
+    </div>
+    <div class="log-cont">
+      <flexbox style="border-bottom: 1px solid #E6E6E6;">
+        <flexbox
+          v-for="(item, index) in logTypes"
+          :key="index"
+          style="width: auto;"
+          @click.native="logTabsClick(item,index)">
+          <div
+            :style="{ color: logType==item.type ? '#F18C70' : '#777'}"
+            class="log-tabs-item">{{ item.name }}</div>
+          <div
+            v-if="logTypes.length -1 !== index"
+            class="log-tabs-line"/>
+        </flexbox>
+      </flexbox>
+      <keep-alive>
+        <component
+          :is="componentsName"
+          :id="id"
+          :crm-type="crmType"/>
+      </keep-alive>
+    </div>
+  </div>
+</template>
+
+<script>
+import MixAdd from '../../components/MixAdd'
+import RecordLog from '../../components/followLog/RecordLog' // 跟进记录
+import JournalLog from '../../components/followLog/JournalLog' // 日志列表
+import ExamineLog from '../../components/followLog/ExamineLog' // 审批列表
+import TaskLog from '../../components/followLog/TaskLog' // 任务日志列表
+import ScheduleLog from '../../components/followLog/ScheduleLog' // 日程日志列表
+// import { crmContractRecordSave } from '@/api/customermanagement/contract'
+import followLogType from '@/views/clients/mixins/followLogType'
+
+export default {
+  /** 客户管理 的 合同详情 的 跟进记录 */
+  name: 'ContractFollow',
+  components: {
+    MixAdd,
+    RecordLog,
+    JournalLog,
+    ExamineLog,
+    TaskLog,
+    ScheduleLog
+  },
+  mixins: [followLogType],
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      sendLoading: false,
+      /** 下次联系时间 */
+      nextTime: '',
+      /** 是否添加日程提醒 */
+      isEvent: false,
+      logType: 'record'
+    }
+  },
+  computed: {
+    logTypes () {
+      if (this.oa) {
+        return [
+          { type: 'record', name: '跟进记录' },
+          { type: 'log', name: '日志' },
+          { type: 'examine', name: '审批' },
+          { type: 'task', name: '任务' },
+          { type: 'schedule', name: '日程' }
+        ]
+      } else {
+        return [{ type: 'record', name: '跟进记录' }]
+      }
+    },
+
+    componentsName () {
+      if (this.logType === 'record') {
+        return 'RecordLog'
+      } else if (this.logType === 'log') {
+        return 'JournalLog'
+      } else if (this.logType === 'examine') {
+        return 'ExamineLog'
+      } else if (this.logType === 'task') {
+        return 'TaskLog'
+      } else if (this.logType === 'schedule') {
+        return 'ScheduleLog'
+      }
+      return ''
+    }
+  },
+  mounted () {},
+  activated: function () {},
+  deactivated: function () {},
+  methods: {
+    /** 发布 时候的类型选择 */
+    handleTypeDrop (command) {
+      this.followType = command
+    },
+    logTabsClick (item, index) {
+      this.logType = item.type
+    },
+    /** 告诉mixad 返回数据 */
+    sendInfo () {
+      this.$refs.mixadd.$emit('submit-info')
+    },
+    /** 快捷添加框内 返回的数据用于上传 */
+    submitInfo (data) {
+      if (this.isEvent && !this.nextTime) {
+        this.$message.error('请选择下次联系时间')
+        return
+      } else if (!data.content) {
+        this.$message.error('请输入跟进内容')
+        return
+      }
+
+      var params = {}
+      params.typesId = this.id
+      params.content = data.content
+      params.category = this.followType
+      params.batchId = data.batchId
+      params.isEvent = this.isEvent ? 1 : 0
+      params.nextTime = this.nextTime || ''
+
+      this.sendLoading = true
+      // crmContractRecordSave(params)
+      //   .then(res => {
+      //     this.sendLoading = false
+      //     this.$message.success('发布成功')
+      //     // 重置页面
+      //     this.$refs.mixadd.resetInfo()
+      //     this.isEvent = false
+      //     this.nextTime = ''
+      //     // 刷新数据
+      //     this.$bus.emit('follow-log-refresh', { type: 'record-log' })
+      //   })
+      //   .catch(() => {
+      //     this.sendLoading = false
+      //   })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../../styles/followlog.scss';
+</style>
diff --git a/src/views/clients/businessCustomer/BusinessCustomerDetail.vue b/src/views/clients/businessCustomer/BusinessCustomerDetail.vue
new file mode 100644
index 0000000..b509b34
--- /dev/null
+++ b/src/views/clients/businessCustomer/BusinessCustomerDetail.vue
@@ -0,0 +1,271 @@
+<template>
+  <slide-view
+    v-empty="!canShowDetail"
+    :listener-ids="listenerIDs"
+    :no-listener-ids="noListenerIDs"
+    :no-listener-class="noListenerClass"
+    :body-style="{padding: 0, height: '100%'}"
+    xs-empty-icon="nopermission"
+    xs-empty-text="暂无权限"
+    @side-close="hideView">
+    <flexbox
+      v-loading="loading"
+      v-if="canShowDetail"
+      direction="column"
+      align="stretch"
+      class="d-container">
+      <c-r-m-detail-head
+        :is-seas="isSeasDetail"
+        :detail="detailData"
+        :head-details="headDetails"
+        :id="id"
+        crm-type="customer"
+        @handle="detailHeadHandle"
+        @close="hideView"/>
+      <div class="tabs">
+        <el-tabs
+          v-model="tabCurrentName"
+          @tab-click="handleClick">
+          <el-tab-pane
+            v-for="(item, index) in tabnames"
+            :key="index"
+            :label="item.label"
+            :name="item.name"/>
+        </el-tabs>
+      </div>
+      <div
+        id="follow-log-content"
+        class="t-loading-content"
+        :style="'height:' + contentStyleObj.height">
+        <keep-alive>
+          <component
+            class="scroll-item"
+            :is="tabName"
+            :detail="detailData"
+            :id="id"
+            :is-seas="isSeasDetail"
+            crm-type="businessCustomer"/>
+        </keep-alive>
+      </div>
+    </flexbox>
+    <c-r-m-create-view
+      v-if="isCreate"
+      :action="{type: 'update', id: id, batchId: detailData.batchId}"
+      crm-type="customer"
+      @save-success="editSaveSuccess"
+      @hiden-view="isCreate=false"/>
+  </slide-view>
+</template>
+
+<script>
+import { GetCustomerDetail } from '@/api/customermanagement/customerManage'
+
+import SlideView from '@/components/SlideView'
+import CRMDetailHead from '../components/CRMDetailHead'
+import CustomerFollow from './components/CustomerFollow' // 跟进记录
+import CRMBaseInfo from '../components/CRMBaseInfo' // 基本信息
+import RelativeContacts from '../components/RelativeContacts' // 相关联系人
+import RelativeBusiness from '../components/RelativeBusiness' // 相关商机
+import RelativeContract from '../components/RelativeContract' // 相关合同
+import RelativeReturnMoney from '../components/RelativeReturnMoney' // 相关回款
+import RelativeFiles from '../components/RelativeFiles' // 相关附件
+import RelativeHandle from '../components/RelativeHandle' // 相关操作
+import RelativeTeam from '../components/RelativeTeam' // 相关团队
+
+import CRMCreateView from '../components/CRMCreateView' // 新建页面
+
+import detail from '../mixins/detail'
+
+export default {
+  /** 客户管理 的 客户详情 */
+  name: 'BusinessCustomerDetail',
+  components: {
+    SlideView,
+    CustomerFollow,
+    CRMDetailHead,
+    CRMBaseInfo,
+    RelativeContacts,
+    RelativeBusiness,
+    RelativeContract,
+    RelativeReturnMoney,
+    RelativeFiles,
+    RelativeHandle,
+    RelativeTeam,
+    CRMCreateView
+  },
+  mixins: [detail],
+  props: {
+    // 详情信息id
+    id: [String, Number],
+    // 监听的dom 进行隐藏详情
+    listenerIDs: {
+      type: Array,
+      default: () => {
+        return ['crm-main-container']
+      }
+    },
+    // 不监听
+    noListenerIDs: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    noListenerClass: {
+      type: Array,
+      default: () => {
+        return ['el-table__body']
+      }
+    }
+  },
+  data () {
+    return {
+      loading: false, // 展示加载loading
+      crmType: 'businessCustomer',
+      detailData: {}, // read 详情
+      headDetails: [
+        { title: '客户状态', value: '' },
+        { title: '负责人', value: '' },
+        { title: '更新时间', value: '' }
+      ],
+      tabCurrentName: 'basicinfo',
+      isCreate: false, // 编辑操作
+      contentStyleObj: {
+        height: '100px'
+      }
+    }
+  },
+  computed: {
+    tabName () {
+      if (this.tabCurrentName === 'followlog') {
+        return 'customer-follow'
+      } else if (this.tabCurrentName === 'basicinfo') {
+        return 'c-r-m-base-info'
+      } else if (this.tabCurrentName === 'contacts') {
+        return 'relative-contacts'
+      } else if (this.tabCurrentName === 'team') {
+        return 'relative-team'
+      } else if (this.tabCurrentName === 'business') {
+        return 'relative-business'
+      } else if (this.tabCurrentName === 'contract') {
+        return 'relative-contract'
+      } else if (this.tabCurrentName === 'returnedmoney') {
+        return 'relative-return-money'
+      } else if (this.tabCurrentName === 'file') {
+        return 'relative-files'
+      } else if (this.tabCurrentName === 'operationlog') {
+        return 'relative-handle'
+      }
+      return ''
+    },
+    tabnames () {
+      var tempsTabs = []
+      // if (this.crm.customer && this.crm.customer.read) {
+      tempsTabs.push({ label: '基本信息', name: 'basicinfo' })
+      // }
+      tempsTabs.push({ label: '联系人', name: 'contacts' })
+      tempsTabs.push({ label: '商机', name: 'business' })
+
+      tempsTabs.push({ label: '跟进记录', name: 'followlog' })
+
+      // if (this.crm.contacts && this.crm.contacts.index) {
+      // }
+      // tempsTabs.push({ label: '相关团队', name: 'team' })
+      // if (this.crm.business && this.crm.business.index) {
+      // }
+      // if (this.crm.contract && this.crm.contract.index) {
+      tempsTabs.push({ label: '合同', name: 'contract' })
+      // }
+      // if (this.crm.receivables && this.crm.receivables.index) {
+      tempsTabs.push({ label: '回款信息', name: 'returnedmoney' })
+      // }
+      // tempsTabs.push({ label: '附件', name: 'file' })
+      tempsTabs.push({ label: '操作记录', name: 'operationlog' })
+      return tempsTabs
+    },
+    /**
+     * isSeas 是从公海模块传入的 配合详情is_pool字段确定
+     */
+    isSeasDetail () {
+      // if (this.detailData && this.detailData.hasOwnProperty('isPool')) {
+      //   return this.detailData.isPool === 1
+      // }
+      // return this.isSeas
+      return false
+    }
+  },
+  created () {
+    this.getHight()
+    window.addEventListener('resize', this.getHight)
+  },
+  mounted () {},
+  destroyed () {
+    window.removeEventListener('resize', this.getHight)
+  },
+  methods: {
+    getHight () {
+      // this.contentStyleObj.height = (window.innerHeight - 600) + 'px'
+    },
+    getDetial () {
+      this.loading = true
+      console.log(this.id)
+      GetCustomerDetail({
+        Id: this.id
+      })
+        .then(res => {
+          console.log(res.data)
+          this.loading = false
+          this.detailData = res.data.Result
+          // 负责人
+          // this.headDetails[0].value = res.data.Result.客户级别
+          switch (res.data.Result.CustomerStatus) {
+            case 0:
+              this.headDetails[0].value = '暂无'
+              break
+            case 1:
+              this.headDetails[0].value = '潜在客户'
+              break
+            case 2:
+              this.headDetails[0].value = '高意向潜在客户'
+              break
+            case 3:
+              this.headDetails[0].value = '试用客户'
+              break
+            case 4:
+              this.headDetails[0].value = '成交客户'
+              break
+            case 5:
+              this.headDetails[0].value = '失败关闭'
+              break
+            case 6:
+              this.headDetails[0].value = '销售线索'
+              break
+            case 7:
+              this.headDetails[0].value = '在谈客户'
+              break
+            case 8:
+              this.headDetails[0].value = '在谈休眠客户'
+              break
+          }
+          this.headDetails[1].value = res.data.Result.SaleName || '暂无'
+          this.headDetails[2].value = res.data.Result.NextFollowTime
+        })
+        .catch(() => {
+          this.loading = false
+        })
+    },
+    //* * 点击关闭按钮隐藏视图 */
+    hideView () {
+      this.$emit('hide-view')
+    },
+    editSaveSuccess () {
+      this.$emit('handle', { type: 'save-success' })
+      this.getDetial()
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../styles/crmdetail.scss';
+</style>
diff --git a/src/views/clients/businessCustomer/BusinessCustomerManage.vue b/src/views/clients/businessCustomer/BusinessCustomerManage.vue
new file mode 100644
index 0000000..da1ee48
--- /dev/null
+++ b/src/views/clients/businessCustomer/BusinessCustomerManage.vue
@@ -0,0 +1,561 @@
+<template>
+  <div class='customer'>
+    <c-r-m-list-head
+      ref="listHead"
+      title="客户列表"
+      main-title="商务管理" />
+
+    <c-r-m-table-head
+      ref="crmTableHead"
+      :crm-type="crmType"
+      :fieldList='fieldList'
+      @exportFile="exportFile"
+      @importFile='importFile'
+      @filter="handleFilter"
+      @handle="handleHandle"
+      @on-handle="listHeadHandle"
+      @scene="handleScene"
+      @queryList='queryList'/>
+
+    <el-card class="el-card">
+      <el-table
+        v-loading="loading"
+        id="crm-table"
+        :data="list"
+        :height="tableHeight"
+        :cell-style="cellStyle"
+        class="n-table--border"
+        border
+        highlight-current-row
+        style="width: 100%; z-index:0;"
+        @row-click="handleRowClick"
+        @sort-change="sortChange"
+        @header-dragend="handleHeaderDragend"
+        @selection-change="handleSelectionChange">
+        <!--<el-table-column
+          show-overflow-tooltip
+          type="selection"
+          align="center"/>-->
+        <el-table-column
+          v-for="(item, index) in fieldList"
+          :key="index"
+          :prop="item.field"
+          :label="item.value"
+          :width="item.width"
+          :formatter="fieldFormatter"
+          sortable="custom"
+          show-overflow-tooltip>
+          <template
+            slot="header"
+            slot-scope="scope">
+            <div class="table-head-name">
+              {{ scope.column.label }}
+              <c-r-m-table-filter
+              :show="scope.column.label==='企业性质' || scope.column.label==='行业细分'"
+              :tableType="scope.column.label"
+              @queryList="queryList">
+              </c-r-m-table-filter>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          prop="operation">
+          <template
+            slot="header"
+            slot-scope="scope">
+            <div class="table-head-name">操作</div>
+          </template>
+          <template slot-scope="scope">
+            <el-button type="text" size="small"  @click='editList(scope.row)'>编辑</el-button>
+              <!--<el-button type="text" size="small"  @click='deleteCustomer(scope.row.Id)'>删除</el-button>-->
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="p-contianer" v-show='total>0'>
+        <el-pagination
+          :current-page="currentPage"
+          :page-sizes="pageSizes"
+          :page-size.sync="pageSize"
+          :total="total"
+          class="p-bar"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"/>
+      </div>
+    </el-card>
+
+    <c-r-m-import
+      :show="showCRMImport"
+      :crm-type="crmType"
+      @close="showCRMImport=false"
+      @queryList='queryList'/>
+    <c-r-m-export
+      :show="showCRMExport"
+      :crm-type="crmType"
+      :search="search"
+      :filter-obj="filterObj"
+      :is-seas="false"
+      :export-params="exportParams"
+      @close="showCRMExport=false"
+      @queryList='queryList'/>
+    <!-- 相关详情页面 -->
+    <c-r-m-all-detail
+      :key='timer'
+      :visible.sync="showDview"
+      :crm-type="rowType"
+      :id="rowID"
+      class="d-view"
+      @handle="handleHandle"/>
+      <!-- 编辑页面 -->
+    <c-r-m-create-view
+      v-if="isCreate"
+      :action="{type: 'update', id: editData.Id, data: editData}"
+      crm-type="customer"
+      @save-success="listHeadHandle"
+      @hiden-view="isCreate=false"/>
+    <fields-set
+      :crm-type="crmType"
+      :dialog-visible.sync="showFieldSet"
+      @set-success="setSave"/>
+  </div>
+</template>
+
+<script>
+import table from '../mixins/table'
+import CreateView from '@/components/CreateView'
+import CreateSections from '@/components/CreateSections'
+import CRMCreateView from '../components/CRMCreateView'
+import CRMImport from '../components/CRMImport'
+import CRMExport from '../components/CRMExport'
+import CRMTableFilter from '../components/CRMTableFilter'
+import CRMAllDetail from '@/views/clients/components/CRMAllDetail'
+import BusinessCheck from './components/BusinessCheck' // 相关商机
+import { DeleteCustomer } from '@/api/customermanagement/customerManage'
+// import moment from 'moment'
+// import { getDateFromTimestamp } from '@/utils'
+import {
+  XhCustomerAddress
+} from '@/components/CreateCom'
+export default {
+  name: 'BusinessCustomerManage',
+  components: {
+    CRMAllDetail,
+    CRMCreateView,
+    BusinessCheck,
+    CRMImport,
+    CRMExport,
+    XhCustomerAddress,
+    CreateView,
+    CreateSections,
+    CRMTableFilter
+  },
+  filters: {
+    /** 根据type 找到组件 */
+    typeToComponentName (formType) {
+      if (formType === 'map_address') {
+        return 'XhCustomerAddress'
+      }
+    }
+  },
+  mixins: [table],
+  computed: {
+    followList: function () {
+      return [
+        { field: 'CustomerName', value: '客户名称', showblock: false },
+        { field: 'ChanceName', value: '关联商机', showblock: false },
+        { field: 'SalesChanceStage', value: '销售进度', showblock: false, type: 'select' },
+        { field: 'NextFollowTime', value: '下次联系时间', showblock: false, type: 'datetime' },
+        { field: 'RealName', value: '联系人姓名', showblock: false },
+        { field: 'ContacterMobile', value: '联系方式', showblock: false, type: 'select' },
+        { field: 'Command', value: '描述', showblock: false, type: 'textarea' }
+      ]
+    }
+  },
+  data () {
+    return {
+      timer: '',
+      fieldList: [
+        { field: 'CustomerNumber', value: '客户编号' },
+        { field: 'CustomerName', value: '客户名称' },
+        { field: 'Contacter', value: '联系人' },
+        { field: 'ContactMobile', value: '手机号' },
+        { field: 'OfficePhone', value: '座机号' },
+        { field: 'CompanyType', value: '企业性质' },
+        { field: 'ProvinceCode', value: '所属地区' },
+        { field: 'FirmSize', value: '设计人员数' },
+        { field: 'Industry', value: '行业细分' },
+        { field: 'Address', value: '通信地址' },
+        { field: 'PostNumber', value: '邮政编码' },
+        { field: 'SaleName', value: '销售负责人' },
+        // { field: 'Comment', value: '备注' }
+        { field: 'CreateUserName', value: '创建人' }
+      ],
+      formInline: {},
+      optionsList: {
+        SalesChanceStage: {
+          field: 'SalesChanceStage',
+          list: ['初期沟通', '需求分析', '方案报价', '商务谈判', '成功', '成功', '搁置']
+        },
+        ContacterMobile: {
+          field: 'ContacterMobile',
+          list: ['电话', '微信', '信息', '其他']
+        }
+      },
+      // 导入
+      showCRMImport: false,
+      // 导出
+      showCRMExport: false,
+      // 导出选中参数
+      exportParams: {},
+      crmType: 'businessCustomer',
+      loading: false,
+      addLoading: false,
+      rightsList: [],
+      radioInput: '',
+      otherInput: '',
+      isOtherOpt: false,
+      // 跟进弹窗
+      isFollowDialog: false,
+      followLoading: false,
+      followFormRules: {
+        CustomerName: [
+          { required: true, message: '联系人不能为空', trigger: 'blur' }
+        ]
+      },
+      followForm: {}
+    }
+  },
+  mounted () {
+  },
+  methods: {
+    // 获取左边padding
+    getPaddingLeft (item, index) {
+      if (item.showblock && item.showblock === true) {
+        return '25px'
+      }
+      return item.styleIndex % 2 === 0 ? '0' : '25px'
+    },
+    // 获取左边padding
+    getPaddingRight (item, index) {
+      if (item.showblock && item.showblock === true) {
+        return '0'
+      }
+
+      return item.styleIndex % 2 === 0 ? '25px' : '0'
+    },
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      if (
+        column.property === 'CustomerName' ||
+        column.property === 'businessCheck'
+      ) {
+        return { color: '#4D88FF', cursor: 'pointer' }
+      } else {
+        return ''
+      }
+    },
+    // ----delete
+    deleteCustomer (id) {
+      this.$confirm('确定删除?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          DeleteCustomer([{'Id': id}]).then(res => {
+            if (res.data.ErrorCode === 200) {
+              this.$message.success(res.data.Message)
+              this.getList()
+            } else {
+              this.$message.error(res.data.Message)
+            }
+          })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    },
+    /**
+     * 新建客户同时新建联系人
+     */
+    relativeBusinessClick (data) {
+      this.rowID = data.businessId
+      this.rowType = 'business'
+      this.showDview = true
+    },
+    // 商机信息查看
+    businessCheckClick (e, scope) {
+      if (scope.row.businessCount === 0) {
+        return
+      }
+      this.$set(scope.row, 'show', !scope.row.show)
+      // const popoverEl = e.target.parentNode
+      // popoverEl.__vue__.showPopper = !scope.row.show
+    },
+    businessClose (e, scope) {
+      // const popoverEl = e.parentNode
+      // popoverEl.__vue__.showPopper = false
+      this.$set(scope.row, 'show', false)
+    },
+    exportFile () {
+      this.showCRMExport = true
+    },
+    importFile () {
+      this.showCRMImport = true
+    },
+    queryList (data) {
+      console.log(data)
+      this.getList(data)
+    }
+
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../styles/table.scss';
+.crm-create-container {
+  position: relative;
+  height: 100%;
+}
+
+.crm-create-flex {
+  position: relative;
+  overflow-x: hidden;
+  overflow-y: auto;
+  flex: 1;
+}
+
+.crm-create-header {
+  height: 40px;
+  margin-bottom: 20px;
+  padding: 0 10px;
+  flex-shrink: 0;
+  display: flex;
+  .close {
+    display: block;
+    // width: 15px;
+    // height: 15px;
+    margin-right: -10px;
+    padding: 10px;
+    cursor: pointer;
+  }
+}
+
+.crm-create-body {
+  flex: 1;
+  // overflow-x: hidden;
+  // overflow-y: auto;
+  max-height: 500px;
+}
+
+/** 将其改变为flex布局 */
+.crm-create-box {
+  display: flex;
+  flex-wrap: wrap;
+  padding: 0 10px;
+}
+
+.crm-create-item {
+  flex: 0 0 45%;
+  flex-shrink: 0;
+  // overflow: hidden;
+  padding-bottom: 30px;
+}
+
+// 占用一整行
+.crm-create-block-item {
+  flex: 0 0 100%;
+  flex-shrink: 0;
+  padding-bottom: 10px;
+}
+
+.el-form-item /deep/ .el-form-item__label {
+  // line-height: 32px;
+  font-size: 13px;
+  color: #333333;
+  position: relative;
+  padding-left: 8px;
+  padding-bottom: 0;
+}
+
+.el-form /deep/ .el-form-item {
+  margin-bottom: 0px;
+}
+
+.el-form /deep/ .el-form-item.is-required .el-form-item__label:before {
+  content: '*';
+  color: #f56c6c;
+  margin-right: 4px;
+  position: absolute;
+  left: 0;
+  top: 8px;
+}
+
+.handle-bar {
+  position: relative;
+  .handle-button {
+    float: right;
+    margin-top: 5px;
+    margin-right: 20px;
+  }
+}
+
+.el-button + .el-button {
+  margin-left: 0;
+}
+.container{
+  position: relative;
+  .popover-foot{
+    position: relative;
+    left: 38%;
+    width: 100%;
+    margin-bottom: 30px;
+  }
+}
+.content {
+  position: relative;
+  padding: 32px 40px;
+  display: flex;
+  flex-direction: column;
+  margin-bottom: 40px;
+  height: 355px;
+  overflow: hidden;
+  overflow-y: auto;
+  border-bottom: 1px solid #f1f1f1;
+  .content-wrap{
+    width: 100%;
+  }
+  .otherOpt{
+    margin-bottom: 15px;
+    width: 100%;
+  }
+  p{
+    margin-bottom: 36px;
+    font-size: 14px;
+    font-weight: 550;
+    color: #333;
+
+  }
+  .con-group{
+    margin-bottom: 28px;
+  }
+  .content-wrap /deep/.el-radio-group .el-radio{
+    margin-right: 64px;
+    margin-bottom: 12px;
+  }
+  .content-wrap /deep/.el-radio-group .el-radio .el-radio__label{
+    font-weight: 400;
+    color: #666666;
+    font-size: 14px;
+  }
+}
+.header {
+  padding: 16px 30px;
+  flex-shrink: 0;
+  border-bottom: 1px solid #F1F1F1;
+  .name {
+    font-size: 13px;
+    padding: 0 10px;
+    color: #333;
+  }
+  .detail {
+    font-size: 12px;
+    padding: 0 10px;
+    color: #aaaaaa;
+    border-left: 1px solid #aaaaaa;
+  }
+  .close {
+    position: absolute;
+    width: 40px;
+    height: 40px;
+    top: 5px;
+    right: 10px;
+    padding: 10px;
+  }
+}
+.customer{
+  // .xr-btn--orange{
+  //   background-color: #ff6a00;
+  //   border-color: #ff6a00;
+  // }
+  .customerName{
+    cursor:pointer;
+    // color: #ff6a00
+  }
+}
+</style>
+<style lang="scss">
+.customer{
+  /deep/.el-input .el-input-group__append{
+    // background-color: #ff7d00;
+    // border-color: #ff7d00;
+    // color: #fff;
+  }
+}
+/* 新建和编辑 */
+.new-dialog-title {
+  padding-left: 10px;
+  margin-bottom: 3px;
+  border-left: 2px solid #4D88FF;
+}
+.user-dialog{
+  height: 20vh;
+}
+.base-dialog{
+  height: 35vh;
+}
+.followDialog{
+  height: 35vh;
+}
+.new-cusDialog-form {
+  overflow-y: auto;
+  padding: 20px;
+  display: flex;
+  flex-wrap: wrap;
+}
+
+.new-cusDialog-form /deep/ .el-form-item {
+  // width: 50%;
+  margin: 0;
+  padding-bottom: 10px;
+}
+.new-cusDialog-form /deep/ .el-form-item .el-form-item__label {
+  line-height: normal;
+  font-size: 13px;
+  color: #333333;
+  position: relative;
+  padding-bottom: 8px;
+}
+.new-cusDialog-form /deep/ .crm-create-item.el-form-item .el-form-item__content {
+  width: 70%;
+}
+.new-cusDialog-form /deep/ .crm-create-block-item.el-form-item .el-form-item__content {
+  width: 90%;
+}
+.new-cusDialog-form /deep/ .crm-create-item.el-form-item .el-form-item__content .el-input.is-disabled .el-input__inner{
+  cursor: pointer;
+}
+.crm-create-item {
+  flex: 0 0 45%;
+  flex-shrink: 0;
+  // overflow: hidden;
+  padding-bottom: 10px;
+}
+
+// 占用一整行
+.crm-create-block-item {
+  flex: 0 0 100%;
+  flex-shrink: 0;
+  padding-bottom: 10px;
+}
+.nav-dialog-div {
+  margin-bottom: 20px;
+}
+.nav-dialog-div /deep/ .el-input {
+  width: auto;
+}
+</style>
diff --git a/src/views/clients/businessCustomer/components/BusinessCheck.vue b/src/views/clients/businessCustomer/components/BusinessCheck.vue
new file mode 100644
index 0000000..ee6bd92
--- /dev/null
+++ b/src/views/clients/businessCustomer/components/BusinessCheck.vue
@@ -0,0 +1,170 @@
+<template>
+  <div
+    v-empty="!canShowIndex"
+    class="container"
+    xs-empty-icon="nopermission"
+    xs-empty-text="暂无权限">
+    <flexbox class="header">
+      <div class="name">{{ data.row.customerName }}</div>
+      <div class="detail">商机({{ list.length }})</div>
+      <img
+        class="close"
+        src="@/assets/img/task_close.png"
+        @click="hidenView" >
+    </flexbox>
+    <el-table
+      v-loading="loading"
+      :data="list"
+      :cell-style="cellStyle"
+      :header-cell-style="headerCellStyle"
+      height="250"
+      style="margin-right:3px;"
+      highlight-current-row
+      @row-click="handleRowClick">
+      <el-table-column
+        v-for="(item, index) in fieldList"
+        :key="index"
+        :prop="item.prop"
+        :label="item.label"
+        align="center"
+        header-align="center"
+        show-overflow-tooltip/>
+    </el-table>
+  </div>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+// import { crmCustomerQueryBusiness } from '@/api/customermanagement/customerManage'
+
+export default {
+  /** 客户管理 的 客户列表  相关商机列表 */
+  name: 'BusinessCheck',
+  components: {},
+  props: {
+    show: Boolean,
+    data: {
+      type: Object,
+      default: () => {
+        return {
+          row: {
+            name: ''
+          }
+        }
+      }
+    }
+  },
+  data () {
+    return {
+      loading: false,
+      list: [],
+      fieldList: []
+    }
+  },
+  computed: {
+    ...mapGetters(['crm']),
+    canShowIndex () {
+      // return this.crm.business && this.crm.business.index
+      return 2
+    }
+  },
+  watch: {
+    show: {
+      handler (val) {
+        if (
+          this.canShowIndex &&
+          val &&
+          this.data.row &&
+          this.data.row.businessCount > 0 &&
+          this.list.length === 0
+        ) {
+          this.getDetail()
+        }
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+  mounted () {
+    this.fieldList.push({
+      prop: 'businessName',
+      width: '200',
+      label: '商机名称'
+    })
+    this.fieldList.push({
+      prop: 'money',
+      width: '200',
+      label: '商机金额'
+    })
+    this.fieldList.push({
+      prop: 'customerName',
+      width: '200',
+      label: '客户名称'
+    })
+    this.fieldList.push({ prop: 'typeName', width: '200', label: '商机状态组' })
+    this.fieldList.push({ prop: 'statusName', width: '200', label: '状态' })
+  },
+  methods: {
+    getDetail () {
+      this.loading = true
+      // crmCustomerQueryBusiness({
+      //   pageType: 0,
+      //   customerId: this.data.row.customerId
+      // })
+      //   .then(res => {
+      //     this.loading = false
+      //     this.list = res.data
+      //   })
+      //   .catch(() => {
+      //     this.loading = false
+      //   })
+    },
+    hidenView () {
+      document.querySelector('#app').click()
+      this.$emit('close', this.$el, this.data)
+    },
+    // 当某一行被点击时会触发该事件
+    handleRowClick (row, column, event) {
+      this.$emit('click', row)
+    },
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      return { fontSize: '12px', textAlign: 'center', cursor: 'pointer' }
+    },
+    headerCellStyle ({ row, column, rowIndex, columnIndex }) {
+      return { fontSize: '12px', textAlign: 'center' }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.container {
+  position: relative;
+}
+
+.header {
+  height: 40px;
+  padding: 0 10px;
+  flex-shrink: 0;
+  .name {
+    font-size: 13px;
+    padding: 0 10px;
+    color: #333;
+  }
+  .detail {
+    font-size: 12px;
+    padding: 0 10px;
+    color: #aaaaaa;
+    border-left: 1px solid #aaaaaa;
+  }
+  .close {
+    position: absolute;
+    width: 40px;
+    height: 40px;
+    top: 0;
+    right: 10px;
+    padding: 10px;
+  }
+}
+</style>
diff --git a/src/views/clients/businessCustomer/components/CustomerFollow.vue b/src/views/clients/businessCustomer/components/CustomerFollow.vue
new file mode 100644
index 0000000..a54d3a1
--- /dev/null
+++ b/src/views/clients/businessCustomer/components/CustomerFollow.vue
@@ -0,0 +1,142 @@
+<template>
+  <div class="f-container">
+    <div class="log-cont">
+      <keep-alive>
+        <component
+          :is="componentsName"
+          :id="id"
+          :crm-type="crmType"/>
+      </keep-alive>
+    </div>
+  </div>
+</template>
+
+<script>
+import MixAdd from '../../components/MixAdd'
+import RecordLog from '../../components/followLog/RecordLog' // 跟进记录
+import JournalLog from '../../components/followLog/JournalLog' // 日志列表
+import ExamineLog from '../../components/followLog/ExamineLog' // 审批列表
+import TaskLog from '../../components/followLog/TaskLog' // 任务日志列表
+import ScheduleLog from '../../components/followLog/ScheduleLog' // 日程日志列表
+import FollowRecordTable from '../../components/followLog/components/FollowRecordTable' // 跟进记录
+import { AddFollowRecord, MakeFollowRecordCompleted } from '@/api/customermanagement/customerManage'
+import followLogType from '@/views/clients/mixins/followLogType'
+
+export default {
+  /** 客户管理 的 客户详情 的 跟进记录 */
+  name: 'CustomerFollow',
+  components: {
+    MixAdd,
+    RecordLog,
+    JournalLog,
+    ExamineLog,
+    TaskLog,
+    ScheduleLog,
+    FollowRecordTable
+  },
+  mixins: [followLogType],
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    /** 是公海 默认是客户 */
+    isSeas: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    return {
+      sendLoading: false,
+      logType: 'record'
+    }
+  },
+  computed: {
+    logTypes () {
+      return [
+        { type: 'record', name: '跟进记录' }
+      ]
+    },
+
+    componentsName () {
+      return 'FollowRecordTable'
+    }
+  },
+  watch: {
+    id: function (val) {}
+  },
+  mounted () {},
+  activated: function () {},
+  deactivated: function () {},
+  methods: {
+    /** 发布 时候的类型选择 */
+    logTabsClick (item, index) {
+      this.logType = item.type
+    },
+    /** 告诉mixad 返回数据 */
+    // sendInfo () {
+    //   this.$refs.mixadd.$emit('submit-info')
+    // },
+    /** 快捷添加框内 返回的数据用于上传 */
+    submitInfo (data) {
+      console.log(data)
+      if (data.isEvent && !data.nextTime) {
+        this.$message.error('请选择下次联系时间')
+        return
+      } else if (!data.content) {
+        this.$message.error('请输入跟进内容')
+        return
+      }
+
+      var params = {}
+      params.SourceId = this.id
+      params.Title = data.title
+      params.Content = data.content
+      params.FollowType = data.followTypeId
+      params.FollowWay = data.wayTypeId
+      // var businessIds = data.business.map(function (element, index, array) {
+      //   return element.businessId
+      // })
+      // var contactsIds = data.contacts.map(function (element, index, array) {
+      //   return element.contactsId
+      // })
+
+      // params.batchId = data.batchId
+      // params.businessIds = businessIds.join(',')
+      // params.contactsIds = contactsIds.join(',')
+
+      params.IsCompleted = data.isEvent
+      params.FollowTime = data.nextTime || ''
+
+      this.sendLoading = true
+      if (data.isEvent) {
+        MakeFollowRecordCompleted({'Id': this.id}).then(res => {
+          this.$message.success('完成跟进')
+        })
+      }
+      AddFollowRecord(params)
+        .then(res => {
+          this.sendLoading = false
+          this.$message.success('发布成功')
+          // 重置页面
+          this.$refs.mixadd.resetInfo()
+          // this.isEvent = false
+          // this.nextTime = ''
+          // 刷新数据
+          this.$bus.emit('follow-log-refresh', { type: 'follow-record-table' })
+        })
+        .catch(() => {
+          this.sendLoading = false
+        })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../../styles/followlog.scss';
+</style>
diff --git a/src/views/clients/clue/ClueDetail.vue b/src/views/clients/clue/ClueDetail.vue
new file mode 100644
index 0000000..03acfa2
--- /dev/null
+++ b/src/views/clients/clue/ClueDetail.vue
@@ -0,0 +1,181 @@
+<template>
+  <slide-view
+    v-empty="!canShowDetail"
+    :listener-ids="listenerIDs"
+    :no-listener-ids="noListenerIDs"
+    :no-listener-class="noListenerClass"
+    :body-style="{padding: 0, height: '100%'}"
+    xs-empty-icon="nopermission"
+    xs-empty-text="暂无权限"
+    @side-close="hideView">
+    <flexbox
+      v-loading="loading"
+      v-if="canShowDetail"
+      direction="column"
+      align="stretch"
+      class="d-container">
+      <c-r-m-detail-head
+        :detail="detailData"
+        :head-details="headDetails"
+        :id="id"
+        crm-type="leads"
+        @handle="detailHeadHandle"
+        @close="hideView"/>
+      <div class="tabs">
+        <el-tabs
+          v-model="tabCurrentName"
+          @tab-click="handleClick">
+          <el-tab-pane
+            v-for="(item, index) in tabnames"
+            :key="index"
+            :label="item.label"
+            :name="item.name"/>
+        </el-tabs>
+      </div>
+      <div
+        id="follow-log-content"
+        class="t-loading-content">
+        <keep-alive>
+          <component
+            :is="tabName"
+            :detail="detailData"
+            :id="id"
+            crm-type="leads"/>
+        </keep-alive>
+      </div>
+    </flexbox>
+    <c-r-m-create-view
+      v-if="isCreate"
+      :action="{type: 'update', id: id, batchId: detailData.batchId}"
+      crm-type="leads"
+      @save-success="editSaveSuccess"
+      @hiden-view="isCreate=false"/>
+  </slide-view>
+</template>
+
+<script>
+// import { crmLeadsRead } from '@/api/customermanagement/clue'
+
+import SlideView from '@/components/SlideView'
+import CRMDetailHead from '../components/CRMDetailHead'
+import ClueFollow from './components/ClueFollow' // 跟进记录
+import CRMBaseInfo from '../components/CRMBaseInfo' // 线索基本信息
+import RelativeFiles from '../components/RelativeFiles' // 相关附件
+import RelativeHandle from '../components/RelativeHandle' // 相关操作
+
+import CRMCreateView from '../components/CRMCreateView' // 新建页面
+
+import detail from '../mixins/detail'
+
+export default {
+  /** 线索管理 的 线索详情 */
+  name: 'ClueDetail',
+  components: {
+    SlideView,
+    CRMDetailHead,
+    ClueFollow,
+    CRMBaseInfo,
+    RelativeFiles,
+    RelativeHandle,
+    CRMCreateView
+  },
+  mixins: [detail],
+  props: {
+    // 详情信息id
+    id: [String, Number],
+    // 监听的dom 进行隐藏详情
+    listenerIDs: {
+      type: Array,
+      default: () => {
+        return ['crm-main-container']
+      }
+    },
+    // 不监听
+    noListenerIDs: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    noListenerClass: {
+      type: Array,
+      default: () => {
+        return ['el-table__body']
+      }
+    }
+  },
+  data () {
+    return {
+      loading: false, // 展示加载loading
+      crmType: 'leads',
+      detailData: {}, // read 详情
+      headDetails: [
+        { title: '姓名', value: '' },
+        { title: '线索来源', value: '' },
+        { title: '手机', value: '' },
+        { title: '负责人', value: '' },
+        { title: '创建时间', value: '' }
+      ],
+      tabnames: [
+        { label: '跟进记录', name: 'followlog' },
+        { label: '基本信息', name: 'basicinfo' },
+        { label: '附件', name: 'file' },
+        { label: '操作记录', name: 'operationlog' }
+      ],
+      tabCurrentName: 'basicinfo',
+      isCreate: false // 编辑操作
+    }
+  },
+  computed: {
+    tabName () {
+      if (this.tabCurrentName === 'followlog') {
+        return 'clue-follow'
+      } else if (this.tabCurrentName === 'basicinfo') {
+        return 'c-r-m-base-info'
+      } else if (this.tabCurrentName === 'file') {
+        return 'relative-files'
+      } else if (this.tabCurrentName === 'operationlog') {
+        return 'relative-handle'
+      }
+      return ''
+    }
+  },
+  mounted () {},
+  methods: {
+    getDetial () {
+      this.loading = true
+      // crmLeadsRead({
+      //   leadsId: this.id
+      // })
+      //   .then(res => {
+      //     this.detailData = res.data
+
+      //     this.headDetails[0].value = res.data.name
+      //     this.headDetails[1].value = res.data.线索来源
+      //     this.headDetails[2].value = res.data.mobile
+      //     // 负责人
+      //     this.headDetails[3].value = res.data.ownerUserName
+      //     this.headDetails[4].value = res.data.createTime
+      //     this.loading = false
+      //   })
+      //   .catch(() => {
+      //     this.loading = false
+      //   })
+    },
+    //* * 点击关闭按钮隐藏视图 */
+    hideView () {
+      this.$emit('hide-view')
+    },
+    //* * tab标签点击 */
+    handleClick (tab, event) {},
+    editSaveSuccess () {
+      this.$emit('handle', { type: 'save-success' })
+      this.getDetial()
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../styles/crmdetail.scss';
+</style>
diff --git a/src/views/clients/clue/ClueIndex.vue b/src/views/clients/clue/ClueIndex.vue
new file mode 100644
index 0000000..a3bbebe
--- /dev/null
+++ b/src/views/clients/clue/ClueIndex.vue
@@ -0,0 +1,131 @@
+<template>
+  <div>
+    <c-r-m-list-head
+      :search.sync="search"
+      :crm-type="crmType"
+      title="线索管理"
+      placeholder="请输入线索名称/手机/电话"
+      main-title="新建线索"
+      @on-handle="listHeadHandle"
+      @on-search="crmSearch"
+      @on-export="exportInfos"/>
+    <div
+      v-empty="!crm.leads.index"
+      xs-empty-icon="nopermission"
+      xs-empty-text="暂无权限"
+      class="crm-container">
+      <c-r-m-table-head
+        ref="crmTableHead"
+        :crm-type="crmType"
+        @filter="handleFilter"
+        @exportData="exportData"
+        @handle="handleHandle"
+        @scene="handleScene"/>
+      <el-table
+        v-loading="loading"
+        id="crm-table"
+        :data="list"
+        :height="tableHeight"
+        :cell-style="cellStyle"
+        class="n-table--border"
+        border
+        highlight-current-row
+        style="width: 100%"
+        @row-click="handleRowClick"
+        @sort-change="sortChange"
+        @header-dragend="handleHeaderDragend"
+        @selection-change="handleSelectionChange">
+        <el-table-column
+          show-overflow-tooltip
+          type="selection"
+          align="center"
+          width="55"/>
+        <el-table-column
+          v-for="(item, index) in fieldList"
+          :key="index"
+          :fixed="index==0"
+          :prop="item.prop"
+          :label="item.label"
+          :width="item.width"
+          :formatter="fieldFormatter"
+          sortable="custom"
+          show-overflow-tooltip>
+          <template
+            slot="header"
+            slot-scope="scope">
+            <div class="table-head-name">{{ scope.column.label }}</div>
+          </template>
+        </el-table-column>
+        <el-table-column/>
+        <el-table-column
+          fixed="right"
+          width="36">
+          <template
+            slot="header"
+            slot-scope="slot">
+            <img
+              src="@/assets/img/t_set.png"
+              class="table-set"
+              @click="handleTableSet" >
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="p-contianer">
+        <el-pagination
+          :current-page="currentPage"
+          :page-sizes="pageSizes"
+          :page-size.sync="pageSize"
+          :total="total"
+          class="p-bar"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"/>
+      </div>
+    </div>
+    <clue-detail
+      v-if="showDview"
+      :id="rowID"
+      class="d-view"
+      @handle="handleHandle"
+      @hide-view="showDview=false"/>
+    <fields-set
+      :crm-type="crmType"
+      :dialog-visible.sync="showFieldSet"
+      @set-success="setSave"/>
+  </div>
+</template>
+
+<script>
+import ClueDetail from './ClueDetail'
+import table from '../mixins/table'
+
+export default {
+  /** 客户管理 的 线索列表 */
+  name: 'ClueIndex',
+  components: {
+    ClueDetail
+  },
+  mixins: [table],
+  data () {
+    return {
+      crmType: 'leads'
+    }
+  },
+  computed: {},
+  mounted () {},
+  methods: {
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      if (column.property === 'leadsName') {
+        return { color: '#4D88FF', cursor: 'pointer' }
+      } else {
+        return ''
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../styles/table.scss';
+</style>
diff --git a/src/views/clients/clue/components/ClueFollow.vue b/src/views/clients/clue/components/ClueFollow.vue
new file mode 100644
index 0000000..6a58941
--- /dev/null
+++ b/src/views/clients/clue/components/ClueFollow.vue
@@ -0,0 +1,169 @@
+<template>
+  <div class="f-container">
+    <div v-loading="sendLoading">
+      <mix-add
+        ref="mixadd"
+        :crm-type="crmType"
+        :id="id"
+        @mixadd-info="submitInfo"/>
+      <flexbox class="se-section">
+        <div class="se-name">记录类型</div>
+        <el-dropdown
+          style="margin-right: 20px;"
+          trigger="click"
+          @command="handleTypeDrop">
+          <flexbox class="se-select">
+            <div class="se-select-name">{{ followType ? followType : '请选择' }}</div>
+            <i
+              class="el-icon-arrow-down el-icon--right"
+              style="color:#ccc;"/>
+          </flexbox>
+          <el-dropdown-menu slot="dropdown">
+            <el-dropdown-item
+              v-for="(item, index) in followTypes"
+              :key="index"
+              :command="item.type">{{ item.name }}</el-dropdown-item>
+          </el-dropdown-menu>
+        </el-dropdown>
+        <div class="se-name">下次联系时间</div>
+        <el-date-picker
+          v-model="nextTime"
+          :default-value="new Date"
+          :editable="false"
+          class="se-datepicker"
+          type="datetime"
+          placeholder="选择日期"
+          value-format="yyyy-MM-dd HH:mm:ss"/>
+        <el-checkbox
+          v-if="showOAPermission"
+          v-model="isEvent">添加到日程提醒</el-checkbox>
+        <el-button
+          class="se-send"
+          type="primary"
+          @click.native="sendInfo">发布</el-button>
+      </flexbox>
+    </div>
+    <div class="log-cont">
+      <flexbox
+        v-if="logTypes.length > 0"
+        style="border-bottom: 1px solid #E6E6E6;">
+        <flexbox
+          v-for="(item, index) in logTypes"
+          :key="index"
+          style="width: auto;"
+          @click.native="logTabsClick(item,index)">
+          <div
+            :style="{ color: logType==item.type ? '#F18C70' : '#777'}"
+            class="log-tabs-item">{{ item.name }}</div>
+          <div
+            v-if="logTypes.length -1 != index"
+            class="log-tabs-line"/>
+        </flexbox>
+      </flexbox>
+      <component
+        :is="componentsName"
+        :id="id"
+        :crm-type="crmType"/>
+    </div>
+  </div>
+</template>
+
+<script>
+import MixAdd from '../../components/MixAdd'
+import RecordLog from '../../components/followLog/RecordLog' // 跟进记录
+// import { crmLeadsRecordSave } from '@/api/customermanagement/clue'
+import followLogType from '@/views/clients/mixins/followLogType'
+
+export default {
+  /** 线索管理 的 线索详情 的 跟进记录 */
+  name: 'ClueFollow',
+  components: {
+    MixAdd,
+    RecordLog
+  },
+  mixins: [followLogType],
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      sendLoading: false,
+      /** 下次联系时间 */
+      nextTime: '',
+      /** 是否添加日程提醒 */
+      isEvent: false,
+      logType: 'record',
+      logTypes: []
+    }
+  },
+  computed: {
+    componentsName () {
+      if (this.logType === 'record') {
+        return 'RecordLog'
+      }
+      return ''
+    }
+  },
+  watch: {},
+  mounted () {},
+  activated: function () {},
+  deactivated: function () {},
+  methods: {
+    /** 发布 时候的类型选择 */
+    handleTypeDrop (command) {
+      this.followType = command
+    },
+    logTabsClick (item, index) {
+      this.logType = item.type
+    },
+    /** 告诉mixad 返回数据 */
+    sendInfo () {
+      this.$refs.mixadd.$emit('submit-info')
+    },
+    /** 快捷添加框内 返回的数据用于上传 */
+    submitInfo (data) {
+      if (this.isEvent && !this.nextTime) {
+        this.$message.error('请选择下次联系时间')
+        return
+      } else if (!data.content) {
+        this.$message.error('请输入跟进内容')
+        return
+      }
+
+      var params = {}
+      params.typesId = this.id
+      params.content = data.content
+      params.category = this.followType
+      params.batchId = data.batchId
+      params.isEvent = this.isEvent ? 1 : 0
+      params.nextTime = this.nextTime || ''
+
+      this.sendLoading = true
+      // crmLeadsRecordSave(params)
+      //   .then(res => {
+      //     this.sendLoading = false
+      //     this.$message.success('发布成功')
+      //     // 重置页面
+      //     this.$refs.mixadd.resetInfo()
+      //     this.isEvent = false
+      //     this.nextTime = ''
+      //     // 刷新数据
+      //     this.$bus.emit('follow-log-refresh', { type: 'record-log' })
+      //   })
+      //   .catch(() => {
+      //     this.sendLoading = false
+      //   })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../../styles/followlog.scss';
+</style>
diff --git a/src/views/clients/components/CRMAllDetail.vue b/src/views/clients/components/CRMAllDetail.vue
new file mode 100644
index 0000000..3a334c5
--- /dev/null
+++ b/src/views/clients/components/CRMAllDetail.vue
@@ -0,0 +1,179 @@
+<template>
+  <div class="main" v-if="visible">
+    <div class="bgColor" @click.self="hiddenView"></div>
+    <div class="content">
+       <component
+        v-if="id&&visible"
+        :is="tabName"
+        :crm-type="crmType"
+        :id="id"
+        :isFollow="isFollow"
+        :listener-ids="listenerIDs"
+        :no-listener-ids="noListenerIDs"
+        class="d-view"
+        @handle="detailHandle"
+        @hide-view="hiddenView"/>
+    </div>
+  </div>
+</template>
+
+<script type="text/javascript">
+import { getMaxIndex } from '@/utils/index'
+import ClueDetail from '../clue/ClueDetail'
+import CustomerDetail from '../customer/CustomerDetail'
+import ContactsDetail from '../contacts/ContactsDetail'
+import BusinessDetail from '../business/BusinessDetail'
+import BusinessCustomerDetail from '../businessCustomer/BusinessCustomerDetail'
+import BusinessChancesDetail from '../businessChances/BusinessChancesDetail'
+// import ContractDetail from '../contract/ContractDetail'
+// import ProductDetail from '../product/ProductDetail'
+// import MoneyDetail from '../money/MoneyDetail'
+
+export default {
+  name: 'CRMAllDetail', // 详情
+  components: {
+    ClueDetail,
+    CustomerDetail,
+    ContactsDetail,
+    BusinessDetail,
+    BusinessCustomerDetail,
+    BusinessChancesDetail
+    // ContractDetail,
+    // ProductDetail,
+    // MoneyDetail
+  },
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    visible: {
+      type: Boolean,
+      default: false
+    },
+    // 监听的dom 进行隐藏详情
+    listenerIDs: {
+      type: Array,
+      default: () => {
+        return ['crm-main-container']
+      }
+    },
+    isFollow: {
+      type: Boolean,
+      default: false
+    },
+    // 不监听
+    noListenerIDs: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    noListenerClass: {
+      type: Array,
+      default: () => {
+        return ['el-table__body']
+      }
+    }
+  },
+  data () {
+    return {
+      // tabName: '' // 组件名
+    }
+  },
+  computed: {
+    tabName: function () {
+      let name = ''
+      if (this.crmType === 'leads') {
+        name = 'clue-detail'
+      } else if (this.crmType === 'customer') {
+        name = 'customer-detail'
+      } else if (this.crmType === 'contacts') {
+        name = 'contacts-detail'
+      } else if (this.crmType === 'business') {
+        name = 'business-detail'
+      } else if (this.crmType === 'contract') {
+        name = 'contract-detail'
+      } else if (this.crmType === 'product') {
+        name = 'product-detail'
+      } else if (this.crmType === 'receivables') {
+        name = 'money-detail'
+      } else if (this.crmType === 'businessCustomer') {
+        name = 'business-customer-detail'
+      } else if (this.crmType === 'businessChances') {
+        name = 'business-chances-detail'
+      }
+      return name
+    }
+  },
+  watch: {
+  },
+  mounted () {
+    console.log(this.crmType, this.visible, this.id)
+    if (this.visible) {
+      document.body.appendChild(this.$el)
+      this.$el.style.zIndex = getMaxIndex()
+    }
+  },
+  destroyed () {
+    // remove DOM node after destroy
+    if (this.$el && this.$el.parentNode) {
+      this.$el.parentNode.removeChild(this.$el)
+    }
+  },
+  methods: {
+    hiddenView () {
+      this.$emit('update:visible', false)
+    },
+
+    /**
+     * 详情操作
+     */
+    detailHandle (data) {
+      this.$emit('handle', data)
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.full-container {
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  overflow: auto;
+  margin: 0;
+  background-color: rgba(0, 0, 0, 0.3);
+}
+
+.d-view {
+  position: fixed;
+  width: 1200px;
+  top: 0px;
+  // width: 100%;
+  // top: 500px;
+  bottom: 0px;
+  right: 0px;
+  // background: #FFFFFF;
+  box-shadow: 0px -4px 12px 0px rgba(61, 121, 204, 0.2);
+  border-radius: 24px 0px 0px 0px;
+}
+.bgColor {
+  width: 100%;
+  height: 100%;
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  overflow: hidden;
+  outline: 0;
+  filter: alpha(opacity=60);
+  background-color: rgba(51, 51, 51, 0.2);
+  z-index: 100;
+}
+</style>
diff --git a/src/views/clients/components/CRMBaseInfo.vue b/src/views/clients/components/CRMBaseInfo.vue
new file mode 100644
index 0000000..bd1de0a
--- /dev/null
+++ b/src/views/clients/components/CRMBaseInfo.vue
@@ -0,0 +1,481 @@
+<template>
+  <div class="b-cont">
+    <div>
+      <sections
+        class="b-cells"
+        title="基本信息"
+        m-color="#4D88FF"
+        content-height="auto">
+        <flexbox
+          :gutter="0"
+          wrap="wrap"
+          style="padding: 10px 8px 0;">
+          <flexbox-item
+            v-for="(item, index) in fifterList"
+            :span="0.5"
+            :key="index"
+            class="b-cell">
+            <flexbox
+              v-if="item.formType === 'file'"
+              align="stretch"
+              class="b-cell-b">
+              <div class="b-cell-name">{{ item.name }}</div>
+              <div class="b-cell-value">
+                <flexbox
+                  v-for="(file, index) in item.value"
+                  :key="index"
+                  class="f-item">
+                  <img
+                    class="f-img"
+                    src="@/assets/img/relevance_file.png" >
+                  <div class="f-name">{{ file | fileName }}</div>
+                  <el-button
+                    type="text"
+                    @click.native="handleFile('preview', item, index)">预览</el-button>
+                  <el-button
+                    type="text"
+                    @click.native="handleFile('download', file, index)">下载</el-button>
+                </flexbox>
+              </div>
+            </flexbox>
+
+            <flexbox
+              v-else
+              align="stretch"
+              class="b-cell-b">
+              <div class="b-cell-name">{{ item.name }}:</div>
+              <div class="b-cell-value">{{ item.value || '暂无'}}</div>
+            </flexbox>
+          </flexbox-item>
+
+          <!--<flexbox
+            v-if="crmType === 'customer' && address "
+            :gutter="0"
+            wrap="wrap">
+            <flexbox-item
+              :span="0.5"
+              class="b-cell"
+              @click.native="checkMapView(address)">
+              <flexbox
+                class="b-cell-b"
+                align="stretch">
+                <div class="b-cell-name">定位</div>
+                <div
+                  class="b-cell-value"
+                  style="color: #4D88FF;cursor: pointer;">{{ address.value.location }}</div>
+              </flexbox>
+            </flexbox-item>
+            <flexbox-item
+              :span="0.5"
+              class="b-cell">
+              <flexbox
+                class="b-cell-b"
+                align="stretch">
+                <div class="b-cell-name">区域</div>
+                <div class="b-cell-value">{{ address.value.address | addressShow }}</div>
+              </flexbox>
+            </flexbox-item>
+            <flexbox-item
+              :span="0.5"
+              class="b-cell">
+              <flexbox
+                class="b-cell-b"
+                align="stretch">
+                <div class="b-cell-name">详细地址</div>
+                <div class="b-cell-value">{{ address.value.detailAddress }}</div>
+              </flexbox>
+            </flexbox-item>
+          </flexbox>-->
+        </flexbox>
+
+      </sections>
+      <div style='height: 100px;'></div>
+    </div>
+    <map-view
+      v-if="showMapView"
+      :title="mapViewInfo.title"
+      :lat="mapViewInfo.lat"
+      :lng="mapViewInfo.lng"
+      @hidden="showMapView=false"/>
+  </div>
+</template>
+
+<script>
+import loading from '../mixins/loading'
+// import crmTypeModel from '@/views/clients/model/crmTypeModel'
+import Sections from '../components/Sections'
+// import { filedGetInformation } from '@/api/clients/common' moneyFormat
+import { fileSize, downloadFile } from '@/utils'
+import MapView from '@/components/MapView' // 地图详情
+
+export default {
+  /** 客户管理 的 基本信息 */
+  name: 'CRMBaseInfo',
+  components: {
+    Sections,
+    MapView
+  },
+  filters: {
+    addressShow: function (list) {
+      // return list ? list.join(' ') : ''
+      return list.replace(/,/g, ' ')
+    },
+    fileName (file) {
+      const name = file.name && file.name.length > 10 ? (file.name.substring(0, 10) + '...') : file.name
+      return name + '(' + fileSize(file.size) + ')'
+    }
+  },
+  mixins: [loading],
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    detail: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      list: [],
+      fifterList: [],
+      showMapView: false, // 控制展示地图详情
+      mapViewInfo: {}, // 地图详情信息
+      address: {
+        value: {
+          location: '',
+          address: '',
+          detailAddress: ''
+        }
+      }
+    }
+  },
+  computed: {},
+  watch: {
+    detail: function (val) {
+      this.filtersData(val)
+    }
+  },
+  mounted () {
+    this.filtersData(this.detail)
+  },
+  activated: function () {},
+  deactivated: function () {},
+  methods: {
+    /**
+     * 附件查看
+     */
+    handleFile (type, item, index) {
+      if (type === 'preview') {
+        var previewList = item.value.map(element => {
+          element.url = element.filePath
+          return element
+        })
+        this.$bus.emit('preview-image-bus', {
+          index: index,
+          data: previewList
+        })
+      } else if (type === 'download') {
+        downloadFile({ path: item.filePath, name: item.name })
+      }
+    },
+    /**
+     * 查看地图详情
+     */
+    checkMapView (item) {
+      if (item.value && item.value !== '') {
+        this.mapViewInfo = {
+          title: item.address,
+          lat: Number(item.lat),
+          lng: Number(item.lng)
+        }
+        this.showMapView = true
+      }
+    },
+    /** 处理数据 */
+    filtersData (item) {
+      console.log(item, this.crmType)
+      this.fifterList = []
+      switch (item.CompanyType) {
+        case 1:
+          item.CompanyType = '国企'
+          break
+        case 2:
+          item.CompanyType = '外企'
+          break
+        case 3:
+          item.CompanyType = '民营'
+          break
+        case 4:
+          item.CompanyType = '其他'
+          break
+      }
+      switch (item.ReportStatus) {
+        case 0:
+          item.ReportStatus = '--'
+          break
+        case 1:
+          item.ReportStatus = '待提交'
+          break
+        case 2:
+          item.ReportStatus = '已提交'
+          break
+        case 3:
+          item.ReportStatus = '报备成功'
+          break
+        case 4:
+          item.ReportStatus = '报备失败'
+          break
+      }
+      switch (item.SalesChanceStage) {
+        case 0:
+          item.SalesChanceStage = '--'
+          break
+        case 1:
+          item.SalesChanceStage = '初期沟通'
+          break
+        case 2:
+          item.SalesChanceStage = '需求分析'
+          break
+        case 3:
+          item.SalesChanceStage = '方案报价'
+          break
+        case 4:
+          item.SalesChanceStage = '商务谈判'
+          break
+
+        case 5:
+          item.SalesChanceStage = '成功'
+          break
+        case 6:
+          item.SalesChanceStage = '搁置'
+          break
+      }
+      switch (item.UploadStatus) {
+        case 0:
+          item.UploadStatus = '--'
+          break
+        case 1:
+          item.UploadStatus = '待上传'
+          break
+        case 2:
+          item.UploadStatus = '审核中'
+          break
+        case 3:
+          item.UploadStatus = '已上传'
+          break
+      }
+      switch (item.CompanyType) {
+        case 1:
+          item.CompanyType = '国企'
+          break
+        case 2:
+          item.CompanyType = '外企'
+          break
+        case 3:
+          item.CompanyType = '民营'
+          break
+        case 4:
+          item.CompanyType = '其他'
+          break
+      }
+      switch (item.ChancePercent) {
+        case 1:
+          item.ChancePercent = 'Failed: 0%'
+          break
+        case 2:
+          item.ChancePercent = 'pipeline: 10%'
+          break
+        case 3:
+          item.ChancePercent = 'BusinessOpporutnity: 30%'
+          break
+        case 4:
+          item.ChancePercent = 'Upside: 40%'
+          break
+        case 5:
+          item.ChancePercent = 'Forecast: 60%'
+          break
+        case 6:
+          item.ChancePercent = 'LPIOrdered: 80%'
+          break
+      }
+      switch (item.ChanceRequestType) {
+        case 0:
+          item.ChanceRequestType = 'Other'
+          break
+        case 1:
+          item.ChanceRequestType = 'LC'
+          break
+        case 2:
+          item.ChanceRequestType = 'ACAD'
+          break
+        case 3:
+          item.ChanceRequestType = 'AEC'
+          break
+        case 4:
+          item.ChanceRequestType = 'MFG'
+          break
+        case 5:
+          item.ChanceRequestType = 'MNE'
+          break
+      }
+      if (this.crmType === 'customer' || this.crmType === 'businessCustomer') {
+        this.fifterList.push(
+          { value: item.CustomerNumber, name: '客户编号' },
+          { value: item.CustomerName, name: '客户名称' },
+          { value: item.CompanyType, name: '企业性质' },
+          { value: item.SaleName, name: '销售负责人' },
+          { value: item.SalesChanceStage, name: '商机阶段' },
+          { value: item.ProvinceCode, name: '所属地区' },
+          { value: item.NextFollowTimeString, name: '最新跟进时间' },
+          { value: item.Industry, name: '行业细分' },
+          { value: item.FirmSize, name: '设计人员数' },
+          { value: item.Industry, name: '所属行业' },
+          { value: item.Address, name: '通信地址' },
+          { value: item.PostNumber, name: '邮政编码' },
+          { value: item.Comment, name: '备注' }
+        )
+      } else if (this.crmType === 'contacts') {
+        this.fifterList.push(
+          { value: item.RealName, name: '联系人姓名' },
+          { value: item.Sex ? (item.Sex === 1 ? '男' : '女') : '暂无', name: '性别' },
+          { value: item.CustomerName, name: '客户名称' },
+          { value: item.DepartmentName, name: '部门' },
+          { value: item.JobPosition, name: '职务' },
+          // { value: item.BirthDay, name: '生日' },
+          { value: item.IsCustomerDefault ? '是' : '否', name: '是否为默认联系客户' },
+          { value: item.MobilePhone, name: '联系电话' },
+          // { value: item.OfficePhone, name: '办公电话' },
+          { value: item.Email, name: '邮箱' },
+          // { value: item.QQNumber, name: 'QQ' },
+          // { value: item.WeixinNumber, name: '微信号' },
+          { value: item.Comment, name: '备注' },
+          { value: item.OwerName, name: '销售负责人' }
+          // { value: item.DocumentFiles, name: '关联附件' }
+        )
+      } else if (this.crmType === 'business') {
+        this.fifterList.push(
+          { value: item.ChanceName, name: '商机名称' },
+          { value: item.OwerUserName, name: '销售负责人' },
+          { value: item.ChanceNumber, name: '商机编号' },
+          { value: item.ExpectedAmount, name: '商机金额/元' },
+          { value: item.CustomerName, name: '客户名称' },
+          { value: item.ExpectedDate, name: '预期成交日期' },
+          { value: item.SalesChanceStageString, name: '商机阶段' },
+          { value: item.ContacterName, name: '联系人' },
+          { value: item.ChancePercent, name: '成功几率(%)' },
+          { value: item.ProvinceCode + item.CityCode, name: '所属地区' },
+          { value: item.ContacterName, name: '联系人' },
+          { value: item.ContacterMobilePhone, name: '联系人方式' },
+          { value: item.ProjectProperty, name: '项目属性' },
+          { value: item.ChanceRequestTypeString, name: '商机类型' },
+          // { value: item.ReportStatus, name: '报备状态' },
+          // { value: item.UploadStatus, name: '商机上传状态' },
+          { value: item.Comment, name: '说明' },
+          { value: item.CreateTime, name: '创建时间' },
+          { value: item.InvalidTimeString, name: '过期时间' },
+          { value: item.ApprovalTimeString, name: '确认时间' },
+          { value: item.SubmitTimeString, name: '上报时间' },
+          { value: item.BusinessStatusString, name: '上报状态' },
+          { value: item.BusinessStatusReason, name: '上报拒绝理由' },
+          { value: item.CreateUserName, name: '创建人' },
+          { value: item.AutoSalesChanceId, name: '欧特克商机编号' }
+        )
+      } else if (this.crmType === 'businessChances') {
+        this.fifterList.push(
+          { value: item.ChanceName, name: '商机名称' },
+          { value: item.OwerUserName, name: '销售负责人' },
+          { value: item.ChanceNumber, name: '商机编号' },
+          { value: item.ExpectedAmount, name: '商机金额/元' },
+          { value: item.CustomerName, name: '客户名称' },
+          { value: item.ExpectedDate, name: '预期成交日期' },
+          { value: item.SalesChanceStageString, name: '商机阶段' },
+          { value: item.ContacterName, name: '联系人' },
+          { value: item.ChancePercent, name: '成功几率(%)' },
+          { value: item.ProvinceCode + item.CityCode, name: '所属地区' },
+          { value: item.ContacterName, name: '联系人' },
+          { value: item.ContacterMobilePhone, name: '联系人方式' },
+          { value: item.ProjectProperty, name: '项目属性' },
+          { value: item.ChanceRequestTypeString, name: '商机类型' },
+          // { value: item.ReportStatus, name: '报备状态' },
+          // { value: item.UploadStatus, name: '商机上传状态' },
+          { value: item.Comment, name: '说明' },
+          { value: item.CreateTime, name: '创建时间' },
+          { value: item.ApprovalTimeString, name: '确认时间' },
+          { value: item.InvalidTimeString, name: '过期时间' },
+          { value: item.SubmitTimeString, name: '上报时间' },
+          { value: item.BusinessStatusString, name: '上报状态' },
+          { value: item.BusinessStatusReason, name: '上报拒绝理由' },
+          { value: item.CreateUserName, name: '创建人' },
+          { value: item.AutoSalesChanceId, name: '欧特克商机编号' }
+        )
+      } else {
+        this.fifterList = []
+      }
+      // console.log(this.fifterList)
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.b-cont {
+  position: relative;
+  padding: 0 80px 20px;
+}
+
+.b-cells {
+  margin-top: 25px;
+}
+
+.b-cell {
+  padding: 0 10px;
+  .b-cell-b {
+    width: auto;
+    padding: 8px;
+    .b-cell-name {
+      width: 100px;
+      margin-right: 10px;
+      font-size: 14px;
+      flex-shrink: 0;
+      color: #777;
+    }
+    .b-cell-value {
+      font-size: 13px;
+      color: #333;
+      white-space: pre-wrap;
+      word-wrap: break-word;
+    }
+    .b-cell-foot {
+      flex-shrink: 0;
+      display: block;
+      width: 15px;
+      height: 15px;
+      margin-left: 8px;
+    }
+  }
+}
+
+.f-item {
+  padding: 3px 0;
+  height: 25px;
+  .f-img {
+    position: block;
+    width: 15px;
+    height: 15px;
+    padding: 0 1px;
+    margin-right: 8px;
+  }
+  .f-name {
+    color: #666;
+    font-size: 12px;
+    margin-right: 10px;
+  }
+}
+</style>
diff --git a/src/views/clients/components/CRMCreateFileView.vue b/src/views/clients/components/CRMCreateFileView.vue
new file mode 100644
index 0000000..ab9d968
--- /dev/null
+++ b/src/views/clients/components/CRMCreateFileView.vue
@@ -0,0 +1,696 @@
+<template>
+    <div class="cr-contianer">
+      <el-form
+        ref="dialogRef"
+        :model="formInline"
+        :rules="formRules"
+        label-position="left"
+        label-width="auto"
+        class="crm-create-box">
+        <el-form-item
+          v-for="(item, index) in tableList"
+          :key="index"
+          :prop="item.field"
+          class="crm-create-block-item">
+          <div
+            slot="label"
+            style="display: inline-block;">
+            <div style="margin:5px 0;font-size:16px;word-wrap:break-word;word-break:break-all;">
+              {{ item.value }}:
+            </div>
+          </div>
+          <template v-if="item.type === 'select'">
+            <el-select
+              v-model="formInline[item.field]"
+              filterable
+              placeholder="请选择"
+              style='width: 100%;'
+              @change='getSelectVal(item.field)'>
+              <el-option
+                v-for="optionItem in optionsList[item.field].list"
+                :key="optionItem.value"
+                :label="optionItem.name"
+                :value="optionItem.value"/>
+            </el-select>
+          </template>
+          <template v-else-if="item.type === 'text'">
+            <span class="showText">{{formInline[item.field] || '暂无'}}</span>
+          </template>
+          <el-tooltip effect="light" :disabled='!item.tips' :content="item.tips" placement="right" v-else>
+            <el-input
+              class='disInput'
+              placeholder="请输入"
+              v-model="formInline[item.field]"
+              :disabled="item.disabled"/>
+          </el-tooltip>
+        </el-form-item>
+        <div class="btm" :style="crmType==='contract'?'margin-left: 80px;':'margin-left: 100px;'">
+          <section
+            v-if="files.length > 0"
+            class="file-cont">
+            <flexbox class="f-header">
+              <img
+                class="f-logo"
+                src="@/assets/img/send_file.png">
+              <div class="f-name">附件</div>
+            </flexbox>
+            <div class="f-body">
+              <flexbox
+                v-for="(item, index) in files"
+                :key="index"
+                class="f-item">
+                <img
+                  :src="item.icon"
+                  class="f-img">
+                <div class="f-name">{{ item.name +(item.size?'('+item.size+')':'') }}</div>
+                <!--{{ item.name+'('+item.size+')' }}-->
+                <div
+                  class="close-button"
+                  @click="deleteImgOrFile('file', item, index)">×</div>
+              </flexbox>
+            </div>
+            <!--<div
+              class="img-bar"
+              @click="files=[]">全部删除</div>-->
+          </section>
+          <flexbox
+            class="bar-item"
+            @click="barClick">
+            <input
+              accept="*.*"
+              type="file"
+              class="bar-input"
+              multiple
+              @change="uploadFile">
+            <img
+              src="@/assets/img/update_files.png"
+              class="bar-img">
+            <div class="bar-title">{{ addTitle }}</div>
+          </flexbox>
+          <div class="handle-bar" :style="crmType==='offers'?'margin-left: 42px;':(crmType==='contract'?'margin-left: 58px;':'margin-left: 92px;')">
+            <el-button @click="closeView">取消</el-button>
+            <el-button
+              v-if="crmType === 'sealContract' || crmType === 'sealOffers'"
+              :disabled="isClicked"
+              type="primary"
+              @click="confirmClick(false)">上传</el-button>
+            <el-button
+              v-if="crmType !== 'sealContract' && crmType !== 'sealOffers'"
+              :disabled="isClicked"
+              type="primary"
+              @click="confirmClick(false)">保存</el-button>
+            <el-button
+              v-if="crmType !== 'sealContract' && crmType !== 'sealOffers'"
+              :disabled="isClicked || !isUpload"
+              class="handle-button"
+              type="primary"
+              @click.native="confirmClick(true)">保存并申报</el-button>
+          </div>
+        </div>
+      </el-form>
+      <!--保存并申报 -->
+      <el-dialog
+        title="提交申报"
+        :visible.sync="isCommited"
+        width="24%"
+        append-to-body
+        :before-close="handleClose">
+        <div class='pushBody'>
+          <div class='hintWord'>
+            <i class="el-icon-warning" style="color: #e6a23c;"></i>
+            <span>提交申报后,不能撤回修改。请确保提交信息准确有效!</span>
+          </div>
+          <div class='hintSelect'>
+            <span>审批人:</span>
+            <el-select v-model="pushStatus" placeholder="请选择">
+              <el-option
+                v-for="item in pushOptions"
+                :key="item.UserId"
+                :label="item.Name"
+                :value="item.UserId">
+              </el-option>
+            </el-select>
+          </div>
+        </div>
+        <span slot="footer" class="dialog-footer">
+          <el-button @click="handleClose" class='closePushBtn'>取 消</el-button>
+          <el-button type="primary" @click="confirmClick(false)" class='surePushBtn'>提交</el-button>
+        </span>
+      </el-dialog>
+    </div>
+</template>
+
+<script type="text/javascript">
+// import { objDeepCopy } from '@/utils'
+import { fileSize, getFileTypeIcon, getTypeIcon } from '@/utils/index'
+import { UploadImageAsync, UploadFileAsync, GetAgreementNumber, GetQuotationNumber, GetWxSpUserList, GetQuotationName, GetAgreenmentName } from '@/api/common'
+import { AddAgreement, AgreementToSeal, UpdateAgreement } from '@/api/customermanagement/contract'
+import { AddQuatotationSheet, QuotationSheetToSeal, UpdateQuotationSheet } from '@/api/customermanagement/offer'
+export default {
+  name: 'CRMCreateFileView', // 新建合同 报价
+  components: {
+  },
+  props: {
+    /** 没有值就是全部类型 有值就是当个类型 */
+    id: [String, Number],
+    crmType: {
+      type: String,
+      default: ''
+    },
+    /** true 的时候 发请求 */
+    show: {
+      type: Boolean,
+      default: true
+    },
+    /**
+     * default 默认  condition 固定条件筛选 moduleType 下的
+     * relative: 相关 添加
+     */
+    action: {
+      type: Object,
+      default: () => {
+        return {
+          type: 'default',
+          data: {}
+        }
+      }
+    }
+  },
+  data () {
+    return {
+      formInline: {},
+      formRules: {
+        CustomerId: [
+          { required: true, message: '请选择客户', trigger: 'blur' }
+        ]
+      },
+      optionsList: {
+        SealType: {
+          field: 'SealType',
+          list: [{value: 1, name: '合同章'}, {value: 2, name: '公章'}]
+        }
+      },
+      /** 图片信息 */
+      files: [],
+      saveAndCreate: false,
+      isCommited: false,
+      pushStatus: '',
+      pushOptions: [],
+      isUpload: false,
+      isClicked: false
+    }
+  },
+  computed: {
+    addTitle: function () {
+      if (this.crmType === 'offers' || this.crmType === 'sealOffers') {
+        return '上传报价单'
+      } else if (this.crmType === 'contract' || this.crmType === 'sealContract') {
+        return '上传合同'
+      }
+    },
+    tableList: function () {
+      // if (this.action.type === 'save') {
+      //   this.getId()
+      // }
+      if (this.crmType === 'offers') {
+        return [
+          { field: 'QuotationNumber', value: '编号', disabled: true },
+          { field: 'QuotationName', value: '报价单名称', disabled: true },
+          { field: 'Comment', value: '备注信息' }
+        ]
+      } else if (this.crmType === 'contract') {
+        return [
+          { field: 'AgreementNumber', value: '编号', disabled: true },
+          { field: 'AgreeName', value: '合同名称', disabled: true },
+          { field: 'Comment', value: '合同备注' },
+          { field: 'SealType', value: '合同类型', type: 'select' }
+        ]
+      } else if (this.crmType === 'sealContract') {
+        return [
+          { field: 'CustomerName', value: '客户名称', type: 'text' },
+          { field: 'AgreeName', value: '合同名称', type: 'text' },
+          { field: 'CreateUserName', value: '销售负责人', type: 'text' },
+          { field: 'SealTypeString', value: '合同类型', type: 'text' },
+          { field: 'Comment', value: '备注信息', type: 'text' },
+          { field: 'ExpressComment', value: '快递备注' },
+          { field: 'ExpressNumber', value: '快递单号' }
+        ]
+      } else if (this.crmType === 'sealOffers') {
+        return [
+          { field: 'CustomerName', value: '客户名称', type: 'text' },
+          { field: 'QuotationName', value: '报价单名称', type: 'text' },
+          { field: 'CreateUserName', value: '销售负责人', type: 'text' },
+          { field: 'Comment', value: '备注信息', type: 'text' }
+        ]
+      }
+    }
+  },
+  watch: {
+  },
+  created () {
+
+  },
+  mounted () {
+    this.getUserOpt()
+    this.getField()
+  },
+  methods: {
+    handleClose () {
+      this.pushStatus = ''
+      this.isCommited = false
+    },
+    getId () {
+      this.getName()
+      if (this.crmType === 'contract') {
+        GetAgreementNumber().then(res => {
+          // this.formInline['AgreementNumber'] = res.data.Result
+          this.$set(this.formInline, 'AgreementNumber', res.data.Result)
+        })
+      } else if (this.crmType === 'offers') {
+        GetQuotationNumber().then(res => {
+          this.$set(this.formInline, 'QuotationNumber', res.data.Result)
+          // this.formInline['QuotationNumber'] = res.data.Result
+        })
+      }
+      console.log(this.formInline)
+    },
+    getName () {
+      let params = {
+        salesChanceId: this.id
+      }
+      console.log(this.formInline)
+      if (this.crmType === 'contract') {
+        GetAgreenmentName(params).then(res => {
+          this.$set(this.formInline, 'AgreeName', res.data.Result)
+        })
+      } else if (this.crmType === 'offers') {
+        GetQuotationName(params).then(res => {
+          this.$set(this.formInline, 'QuotationName', res.data.Result)
+        })
+      }
+    },
+    // 获取自定义字段
+    getField () {
+      console.log(this.action)
+      if (this.action.type === 'update') {
+        this.formInline = {...this.action.data}
+        if (this.crmType === 'contract') {
+          // this.isUpload = this.action.data.UploadStatus === 1
+          this.isUpload = this.action.data.IsCanReport
+          this.formInline['AgreementNumber'] = this.action.data.AgreeNumber
+          if (this.action.data.BeforeSealFile) {
+            let list = []
+            list['icon'] = getTypeIcon(this.action.data.BeforeSealFile)
+            list['name'] = this.action.data.BeforeSealFile
+            list['path'] = this.action.data.BeforeSealFile
+            this.files.push(list)
+          } else {
+            this.files = []
+          }
+        } else if (this.crmType === 'offers') {
+          // this.isUpload = this.action.data.UploadStatus === 1
+          this.isUpload = this.action.data.IsCanReport
+          this.formInline['QuotationNumber'] = this.action.data.QuotationNumber
+          if (this.action.data.BeforeSealFile) {
+            let list = []
+            list['icon'] = getTypeIcon(this.action.data.BeforeSealFile)
+            list['name'] = this.action.data.BeforeSealFile
+            list['path'] = this.action.data.BeforeSealFile
+            this.files.push(list)
+          } else {
+            this.files = []
+          }
+        } else if (this.crmType === 'sealContract' || this.crmType === 'sealOffers') {
+          if (this.action.data.SealFile) {
+            let list = []
+            list['icon'] = getTypeIcon(this.action.data.SealFile)
+            list['name'] = this.action.data.SealFile
+            list['path'] = this.action.data.SealFile
+            this.files.push(list)
+          } else {
+            this.files = []
+          }
+        }
+      } else if (this.action.type === 'save') {
+        this.getId()
+      }
+    },
+    getSelectVal (type) {
+      if (type === 'SealType') {
+        console.log(this.formInline['SealType'])
+      }
+    },
+    barClick (item) {},
+    /** 图片选择出发 */
+    uploadFile (event) {
+      var files = event.target.files
+      if (files.length) {
+        for (let index = 0; index < files.length; index++) {
+          const file = files[index]
+          if (
+            file.type.indexOf('image') === -1 &&
+            this.showRelativeType === 'img'
+          ) {
+            this.$message.error('请上传正确的文件类型')
+            return
+          }
+        }
+
+        var type = event.target.accept === 'image/*' ? 'img' : 'file'
+        var firstFile = files[0]
+        this.sendFileRequest(firstFile, type, () => {
+          for (let index = 1; index < files.length; index++) {
+            const file = files[index]
+            this.sendFileRequest(file, type)
+          }
+          event.target.value = ''
+        })
+      }
+    },
+    // 发送请求
+    sendFileRequest (file, type, result) {
+      var params = { file: file, type: type }
+      let request = {
+        'img': UploadImageAsync,
+        'file': UploadFileAsync
+      }[type]
+      request(params)
+        .then(res => {
+          // if (this.batchId === '') {
+          //   this.batchId = res.batchId
+          // }
+          if (res.data.ErrorCode === 200) {
+            let list = []
+            list['size'] = fileSize(file.size)
+            if (type === 'img') {
+              list['name'] = res.data.Message
+              list['path'] = res.data.Result
+              console.log(list)
+              // this.imgFiles.push(list)
+            } else {
+              list['icon'] = getFileTypeIcon(file)
+              list['name'] = res.data.Message
+              list['path'] = res.data.Result
+              this.files.push(list)
+            }
+            this.$message.success('上传成功')
+          } else {
+            this.$message.fail('res.data.Message')
+          }
+
+          if (result) {
+            result()
+          }
+        })
+        .catch(() => {})
+    },
+    deleteImgOrFile (type, item, index) {
+      if (type === 'image') {
+        this.imgFiles.splice(index, 1)
+      } else {
+        this.files.splice(index, 1)
+      }
+      this.$message.success('操作成功')
+    },
+    /** 获取列表请求 */
+    getIndexRequest () {
+      if (this.action.type === 'save') {
+        if (this.crmType === 'contract') {
+          return AddAgreement
+        } else if (this.crmType === 'offers') {
+          return AddQuatotationSheet
+        } else if (this.crmType === 'sealContract') {
+          return AgreementToSeal
+        } else if (this.crmType === 'sealOffers') {
+          return QuotationSheetToSeal
+        }
+      } else if (this.action.type === 'update') {
+        if (this.crmType === 'contract') {
+          return UpdateAgreement
+        } else if (this.crmType === 'offers') {
+          return UpdateQuotationSheet
+        } else if (this.crmType === 'sealContract') {
+          return AgreementToSeal
+        } else if (this.crmType === 'sealOffers') {
+          return QuotationSheetToSeal
+        }
+      }
+    },
+    // 获取审批人员列表
+    getUserOpt () {
+      GetWxSpUserList().then(res => {
+        if (res.data.ErrorCode === 200) {
+          this.pushOptions = res.data.Result
+        }
+      })
+    },
+    // 确定选择
+    confirmClick (saveAndCreate) {
+      this.saveAndCreate = saveAndCreate
+      this.isClicked = true
+      if (saveAndCreate) {
+        this.isCommited = true
+      } else {
+        this.sendQuery()
+      }
+    },
+    sendQuery () {
+      this.formInline['files'] = this.files && this.files.length > 0 ? this.files[0].path : ''
+      console.log(this.formInline)
+      let crmIndexRequest = this.getIndexRequest()
+      let params = {}
+      if (this.action.type === 'save') {
+        if (this.crmType === 'contract') {
+          params = {
+            'AuditUserId': this.pushStatus,
+            'IsSubmitReport': this.isCommited,
+            'AgreementNumber': this.formInline['AgreementNumber'],
+            'SalesChanceId': this.id,
+            'AgreeName': this.formInline['AgreeName'],
+            'Comment': this.formInline['Comment'],
+            'BeforeSealFile': this.formInline['files'],
+            'SealType': this.formInline['SealType'],
+            'QuotationSheetId': ''
+          }
+        } else if (this.crmType === 'offers') {
+          params = {
+            'AuditUserId': this.pushStatus,
+            'IsSubmitReport': this.isCommited,
+            'QuotationNumber': this.formInline['QuotationNumber'],
+            'SalesChanceId': this.id,
+            'QuotationName': this.formInline['QuotationName'],
+            'Comment': this.formInline['Comment'],
+            'BeforeSealFile': this.formInline['files']
+          }
+        } else if (this.crmType === 'sealContract') {
+          params = {
+            'Id': this.action.data.Id,
+            'SealFile': this.formInline['files'],
+            'ExpressComment': this.formInline['ExpressComment'],
+            'ExpressNumber': this.formInline['ExpressNumber']
+          }
+        } else if (this.crmType === 'sealOffers') {
+          params = {
+            'Id': this.action.data.Id,
+            'SealFile': this.formInline['files']
+          }
+        }
+      } else if (this.action.type === 'update') {
+        if (this.crmType === 'contract') {
+          params = {
+            'Id': this.formInline['Id'],
+            'Comment': this.formInline['Comment'],
+            'BeforeSealFile': this.formInline['files'],
+            'SealType': this.formInline['SealType'],
+            'FinalFile': '',
+            'IsSubmitReport': this.isCommited,
+            'AuditUserId': this.pushStatus
+          }
+        } else if (this.crmType === 'offers') {
+          params = {
+            'Id': this.formInline['Id'],
+            'Comment': this.formInline['Comment'],
+            'BeforeSealFile': this.formInline['files'],
+            'IsSubmitReport': this.isCommited,
+            'AuditUserId': this.pushStatus
+          }
+        } else if (this.crmType === 'sealContract') {
+          params = {
+            'Id': this.action.data.Id,
+            'SealFile': this.formInline['files'],
+            'ExpressComment': this.formInline['ExpressComment'],
+            'ExpressNumber': this.formInline['ExpressNumber']
+          }
+          if (this.formInline['ExpressComment'] !== '' && this.formInline['ExpressNumber'] === '') {
+            return this.$message.error('请填写快递单号')
+          } else if (this.formInline['ExpressNumber'] !== '' && this.formInline['ExpressComment'] === '') {
+            return this.$message.error('请填写快递备注')
+          }
+        } else if (this.crmType === 'sealOffers') {
+          params = {
+            'Id': this.action.data.Id,
+            'SealFile': this.formInline['files']
+          }
+        }
+      }
+      crmIndexRequest(params)
+        .then(res => {
+          if (res.data.ErrorCode === 200) {
+            this.$message.success(
+              this.action.type === 'update' ? '编辑成功' : '添加成功'
+            )
+            this.$emit('save-success')
+            this.isClicked = false
+          } else {
+            this.$message.error(res.data.Message)
+            this.isClicked = false
+          }
+        }).catch(() => {
+          this.isClicked = false
+        })
+    },
+    // 关闭操作
+    closeView () {
+      this.$emit('hiden-view')
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.cr-contianer {
+  position: relative;
+  // padding: 50px 0 50px 0;
+}
+/** 将其改变为flex布局 */
+.crm-create-box {
+  display: flex;
+  flex-wrap: wrap;
+  padding: 0 10px;
+}
+.crm-create-block-item {
+  flex: 0 0 90%;
+  flex-shrink: 0;
+  padding-bottom: 10px;
+  margin-bottom: 0;
+}
+.bar-item {
+  width: auto;
+  padding-right: 20px;
+  position: relative;
+  cursor: pointer;
+  left: 10px;
+  .bar-input {
+    position: absolute;
+    top: 0;
+    left: 0;
+    height: 15px;
+    width: 100px;
+    opacity: 0;
+    font-size: 0;
+    cursor: pointer;
+  }
+  .bar-img {
+    display: block;
+    margin-right: 6px;
+  }
+  .bar-title {
+    color: #4D88FF;
+    font-size: 12px;
+  }
+}
+/** 附件  */
+.file-cont {
+  padding: 0 10px;
+  margin: 0 10px 15px;
+  border: 1px dashed #dfdfdf;
+  .f-header {
+    padding: 8px 0 15px;
+    .f-logo {
+      position: block;
+      width: 15px;
+      height: 15px;
+      margin-right: 8px;
+    }
+    .f-name {
+      color: #777;
+      font-size: 12px;
+    }
+  }
+
+  .f-body {
+    .f-item {
+      padding: 3px 0;
+      .f-img {
+        position: block;
+        width: 15px;
+        height: 15px;
+        margin-right: 8px;
+      }
+      .f-name {
+        color: #666;
+        font-size: 12px;
+      }
+    }
+  }
+
+  .img-bar {
+    color: #5a8ae2;
+    font-size: 12px;
+    padding: 5px 0;
+    cursor: pointer;
+  }
+}
+/** 关闭按钮  */
+.close-button {
+  width: 30px;
+  line-height: 16px;
+  cursor: pointer;
+  color: #ccc;
+  height: 16px;
+  font-size: 17px;
+  text-align: center;
+}
+.btm{
+  display: flex;
+  flex-direction: column;
+}
+.handle-bar {
+  display: flex;
+  flex-direction: row;
+  margin-top: 30px;
+  z-index: 2;
+  button {
+    float: right;
+    margin-top: 10px;
+    margin-right: 10px;
+  }
+}
+.pushBody{
+  margin: 0 60px;
+  .hintWord{
+    margin-top: 10px;
+  }
+  .hintSelect{
+    margin-top: 20px;
+    .el-select{
+      width: 224px;
+    }
+  }
+}
+.closePushBtn{
+  margin-right: 16px;
+}
+.showText{
+  color: #333;
+  font-size: 16px;
+  font-weight: 400;
+  display: inline-block;
+  margin: 5px 0px;
+  font-size: 16px;
+  overflow-wrap: break-word;
+  word-break: break-all;
+}
+.disInput.el-input.is-disabled /deep/ .el-input__inner{
+  color: #333 !important;
+}
+</style>
diff --git a/src/views/clients/components/CRMCreateView.vue b/src/views/clients/components/CRMCreateView.vue
new file mode 100644
index 0000000..485c212
--- /dev/null
+++ b/src/views/clients/components/CRMCreateView.vue
@@ -0,0 +1,2201 @@
+<template>
+  <create-view
+    :loading="loading"
+    :body-style="{ height: '100%'}">
+    <flexbox
+      direction="column"
+      align="stretch"
+      class="crm-create-container">
+      <flexbox class="crm-create-header">
+        <div style="flex:1;font-size:18px;color:#333;font-weight: 700;">{{ title }}</div>
+        <img
+          class="close"
+          src="@/assets/img/task_close.png"
+          @click="hidenView" >
+      </flexbox>
+      <div class="crm-create-flex">
+        <create-sections title="基本信息">
+          <flexbox
+            direction="column"
+            align="stretch">
+            <div class="crm-create-body">
+              <el-form
+                ref="dialogRef"
+                :model="formInline"
+                :rules="formRules"
+                label-position="left"
+                label-width="auto"
+                class="crm-create-box">
+                <el-form-item
+                  v-for="(item, index) in tableList"
+                  :key="index"
+                  :prop="item.field"
+                  :class="{ 'crm-create-block-item': item.showblock, 'crm-create-item': !item.showblock }"
+                  :style="{'padding-left': getPaddingLeft(item, index), 'padding-right': getPaddingRight(item, index)}">
+                  <div
+                    slot="label"
+                    style="display: inline-block;">
+                    <div style="margin:5px 0;font-size:16px;word-wrap:break-word;word-break:break-all;">
+                      {{ item.value }}{{item.value?':': ''}}
+                    </div>
+                  </div>
+                  <!-- 员工 和部门 为多选(radio=false)  relation 相关合同商机使用-->
+                    <template v-if="item.type === 'select'">
+                      <el-select
+                        v-model="formInline[item.field]"
+                        filterable
+                        placeholder="请选择"
+                        style='width: 100%;'
+                        @change='getSelectVal(item.field)'>
+                        <el-option
+                          v-for="optionItem in optionsList[item.field].list"
+                          :key="optionItem.value"
+                          :label="optionItem.name"
+                          :value="optionItem.value"/>
+                      </el-select>
+                    </template>
+                    <template v-else-if="item.type === 'selectCheckout'">
+                      <el-select
+                        v-model="formInline[item.field]"
+                        :popper-append-to-body="false"
+                        popper-class="select-popper-class"
+                        filterable
+                        placeholder="请选择">
+                        <el-option
+                          v-for="item in optionsList[item.field].list"
+                          :key="item.Id"
+                          :label="item.DepartmentName"
+                          :value="item.Id"/>
+                      </el-select>
+                    </template>
+                    <template slot-scope="scope" v-else-if="item.type === 'relationInput'">
+                      <el-popover
+                        :offset="250"
+                        placement="right"
+                        popper-class="no-padding-popover"
+                        width="700"
+                        :disabled="action.type === 'update'"
+                        trigger="click">
+                        <div class="pop-container">
+                          <flexbox class="pop-header">
+                            <div class="pop-name">关联客户</div>
+                            <!--<div class="detail"></div>-->
+                            <img
+                              class="pop-close"
+                              src="@/assets/img/task_close.png"
+                              @click="hidenRelationInput" >
+                          </flexbox>
+                          <flexbox class="pop-content">
+                            <div class="pop-cropper-box">
+                              <el-input class='pop-searchInput' v-model='popSearch' placeholder='请输入关键字'>
+                               <template slot="append"><el-button  type="primary" class='pop-searchBtn' @click='getCustomerTable'>查询</el-button></template>
+                              </el-input>
+                            </div>
+                          </flexbox>
+                          <flexbox class="pop-content">
+                            <el-table
+                              class="pop-cropper-table"
+                              v-loading="popLoading"
+                              :data="popData"
+                              :cell-style="popCellStyle"
+                              :header-cell-style="headerCellStyle"
+                              height="250"
+                              style="margin-right:3px;"
+                              highlight-current-row
+                              @row-click="handlePopRowClick">
+                              <el-table-column
+                                v-for="(item, index) in popFieldList"
+                                :key="index"
+                                :prop="item.field"
+                                :label="item.value"
+                                :formatter="fieldFormatter"
+                                align="center"
+                                header-align="center"
+                                show-overflow-tooltip/>
+                            </el-table>
+                          </flexbox>
+                          <div class="p-contianer">
+                            <el-pagination
+                              :current-page="currentPopPage"
+                              :page-sizes="pagePopSizes"
+                              :page-size.sync="pagePopSize"
+                              :total="totalPop"
+                              class="p-bar"
+                              layout="total, sizes, prev, pager, next, jumper"
+                              @size-change="handlePopSizeChange"
+                              @current-change="handlePopCurrentChange"/>
+                          </div>
+                        </div>
+                        <el-input slot="reference" class='relationInput'
+                         placeholder='请点击选择客户'
+                         :disabled='true' v-model="customerChosed"></el-input>
+                      </el-popover>
+                    </template>
+                    <template v-else-if="item.type === 'radio'">
+                      <el-radio-group v-model="formInline[item.field]">
+                        <el-radio :label="1">男</el-radio>
+                        <el-radio :label="2">女</el-radio>
+                      </el-radio-group>
+                    </template>
+                    <template v-else-if="item.type === 'switch'">
+                      <el-switch v-model="formInline[item.field]" @change='getSwitch(item.field)'></el-switch>
+                    </template>
+                    <template v-else-if="item.type === 'inputPopover'">
+                      <el-popover
+                        class='pop'
+                        :disabled="(action.type === 'update'&&crmType === 'customer') ||item.disabled"
+                        :offset="250"
+                        placement="right"
+                        popper-class="no-padding-popover"
+                        width="500"
+                        trigger="click">
+                        <div class="container">
+                            <flexbox class="header">
+                              <div class="name">行业</div>
+                              <!--<div class="detail"></div>-->
+                              <img
+                                class="close"
+                                src="@/assets/img/close.png"
+                                @click="hidenPopoverView" >
+                            </flexbox>
+                            <flexbox class="content">
+                              <div v-for="(item,index) of rightsList" :key="index" class='content-wrap'>
+                                <p>{{rightsList[index].CategoryName || '暂无'}}</p>
+                                <el-radio-group v-model="radioInput" class='con-group' :disabled='isOtherOpt'>
+                                  <el-radio
+                                    v-for="(item, i) in rightsList[index].IndustryData"
+                                    @change="getRadioInput(item, i)"
+                                    :key="item"
+                                    :label="item"
+                                    :value="item">{{item}}</el-radio>
+                                </el-radio-group>
+                              </div>
+                              <!--<div class='otherOpt'>其他:请注明:
+                              <el-input
+                                  v-model="otherInput"
+                                  maxlength="10"
+                                  @blur='blurOtherOpt'
+                                  @focus='getOtherOpt'/>
+                              </div>-->
+                            </flexbox>
+                            <flexbox class="popover-foot">
+                              <el-button @click="hidenPopoverView" style='margin-right:16px;'>取 消</el-button>
+                              <el-button
+                                type="primary"
+                                @click="setIndustry">确 定</el-button>
+                            </flexbox>
+                        </div>
+                        <el-input slot="reference" :class="(action.type === 'update'&&crmType === 'customer')?'cn':'inputPopover'" placeholder='请点击选择行业' :disabled='true' v-model="formInline['radioInput']" ></el-input>
+                      </el-popover>
+
+                    </template>
+                    <template v-else-if="item.type === 'cascaderSingle'">
+                      <el-cascader
+                        ref="salesCas"
+                        placeholder="请选择销售员"
+                        :options="salesManList"
+                        :props="{
+                          children: 'children',
+                          label: 'Name',
+                          value: 'Id'
+                        }"
+                        v-model="salesId"
+                        style="width: 100%;"
+                        @change='getUser'/>
+                    </template>
+                    <template v-else-if="item.type === 'doubleSelect'">
+                      <div class='doubleSelect'>
+                        <el-select
+                            v-model="formInline[item.field]"
+                            filterable
+                            class='leftSelect'
+                            placeholder="请选择"
+                            @change='getSelectVal(item.field)'>
+                            <el-option
+                              v-for="(optionItem, index) in optionsList[item.field].list[0]"
+                              :key="index"
+                              :label="optionItem"
+                              :value="index"/>
+                          </el-select>
+                          <el-select
+                            v-model="formInline[item.field]"
+                            filterable
+                            class='rightSelect'
+                            placeholder="请选择"
+                            @change='getSelectVal(item.field)'>
+                            <el-option
+                              v-for="(optionItem, index) in optionsList[item.field].list[1]"
+                              :key="index"
+                              :label="optionItem"
+                              :value="index"/>
+                          </el-select>
+                      </div>
+                    </template>
+                    <template v-else-if="item.type === 'file'">
+                      <el-input
+                          v-model="file.name"
+                          :disabled="true"
+                          placeholder='请点击选择文件'/>
+                        <el-button
+                          type="primary"
+                          @click="selectFile">选择文件</el-button>
+                    </template>
+                    <template v-else-if="item.type === 'radioList'">
+                      <el-radio-group v-model="formInline[item.field]" class='radioList' @change='getPropertyName'>
+                        <el-radio
+                          v-for="(optionItem, index) in optionsList[item.field].list"
+                          :key="index"
+                          :label="optionItem.PropertyName"
+                          :value="optionItem.PropertyName"></el-radio>
+                      </el-radio-group>
+                    </template>
+                    <template v-else-if="item.type === 'date'">
+                      <el-date-picker
+                        v-model="formInline[item.field]"
+                        style="width: 100%;"
+                        type="date"
+                        value-format="yyyy-MM-dd"
+                        placeholder="选择日期"/>
+                    </template>
+                    <template v-else-if="item.type === 'map_address'">
+                      <flexbox-item style="width: 100%;">
+                        <XhCustomerAddress
+                        :disabled="(action.type === 'update'&&crmType === 'customer') || item.disabled"
+                        :hideArea='true'
+                        :province="formInline[item.field].province"
+                        :city="formInline[item.field].city"
+                        @province="selectProvince"
+                        @city="selectCity">
+                        </XhCustomerAddress>
+                        <!--<v-distpicker
+                          :disabled="(action.type === 'update'&&crmType === 'customer') || item.disabled"
+                          :province="formInline[item.field].province"
+                          :city="formInline[item.field].city"
+                          :area="formInline[item.field].area"
+                          hide-area
+                          @province="selectProvince"
+                          @city="selectCity"/>-->
+                          <!--hide-area-->
+                      </flexbox-item>
+                    </template>
+                    <component
+                      ref='xhProduct'
+                      v-else-if="item.type === 'product'"
+                      :is="item.type | typeToComponentName"
+                      :key="timer"
+                      :isLC='isLC'
+                      :value="formInline[item.field]"
+                      :index="index"
+                      :item="item"
+                      :relation="item.relation"
+                      :radio="false"
+                      :disabled="item.disabled"
+                      :customerId="formInline['CustomerId']"
+                      @value-change="fieldValueChange"/>
+                    <el-input placeholder="注册信息、合作伙伴、竞争对手、以及相关预算等" type="textarea" v-model="formInline[item.field]"  v-else-if="item.type === 'textarea'" class='areaInput'>
+                      </el-input>
+                    <el-input placeholder="请输入" type="number" min='0' max='1000' v-model="formInline[item.field]"  v-else-if="item.type === 'number'">
+                    </el-input>
+                    <el-tooltip effect="light" :disabled='!item.tips' :content="item.tips" placement="right" v-else-if="item.type === 'disInput'">
+                      <el-input
+                        class='disInput'
+                        placeholder="自动生成"
+                        v-model="formInline[item.field]"
+                        :disabled="item.disabled "/>
+                    </el-tooltip>
+                    <el-tooltip effect="light" :disabled='!item.tips' :content="item.tips" placement="right" v-else>
+                      <el-input
+                        placeholder="请输入"
+                        v-model="formInline[item.field]"
+                        :disabled="(action.type === 'update'&&item.field === 'CustomerName') || item.disabled"/>
+                    </el-tooltip>
+                  <!--<component
+                    name='createcom'
+                    :is="item.type | typeToComponentName"
+                    :value="item.value"
+                    :index="index"
+                    :item="item"
+                    :relation="item.relation"
+                    :radio="false"
+                    :disabled="item.disabled"
+                    @value-change="fieldValueChange"/>-->
+                </el-form-item>
+              </el-form>
+            </div>
+          </flexbox>
+        </create-sections>
+        <create-sections title="联系人信息" v-if="crmType === 'customer'">
+          <flexbox
+            direction="column"
+            align="stretch">
+            <div class="crm-create-body">
+              <el-form
+                ref="userDialogRef"
+                label-position="left"
+                label-width="auto"
+                class="crm-create-box"
+                :model="formInline"
+                :rules="dialogUserRules">
+                <el-form-item
+                  v-for="(item, index) in tableUserList"
+                  :label="item.value"
+                  :prop="item.field"
+                  :class="{ 'crm-create-block-item': item.showblock, 'crm-create-item': !item.showblock }"
+                  :style="{'padding-left': getPaddingLeft(item, index), 'padding-right': getPaddingRight(item, index)}"
+                  :key="index">
+                  <div
+                    slot="label"
+                    style="display: inline-block;">
+                    <div style="margin:5px 0;font-size:16px;word-wrap:break-word;word-break:break-all;">
+                      {{ item.value }}:
+                    </div>
+                  </div>
+                  <el-input
+                    v-model="formInline[item.field]"
+                    :disabled="item.disabled "/>
+                </el-form-item>
+              </el-form>
+            </div>
+          </flexbox>
+        </create-sections>
+        <create-sections
+          v-if="showExamine"
+          title="审核信息">
+          <div
+            v-if="examineInfo.examineType===1 || examineInfo.examineType===2"
+            slot="header"
+            class="examine-type">{{ examineInfo.examineType===1 ? '固定审批流' : '授权审批人' }}</div>
+          <create-examine-info
+            ref="examineInfo"
+            :types="'crm_' + crmType"
+            :types-id="action.id"
+            @value-change="examineValueChange"/>
+        </create-sections>
+      </div>
+      <input
+      id="importInputFile"
+      type="file"
+      accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
+      @change="uploadFile">
+      <div class="handle-bar">
+        <el-button
+          class="handle-button"
+          @click.native="hidenView">取消</el-button>
+        <el-button
+          :disabled="isClicked || (crmType === 'customer'&&radioInput === '')||(crmType !== 'customer'&&customerChosed === '')"
+          class="handle-button"
+          type="primary"
+          @click.native="saveField(false)">保存</el-button>
+        <el-button
+          v-show="crmType === 'business'"
+          :disabled="isClicked || crmType !== 'customer'&&customerChosed === ''||isSubmit"
+          class="handle-button"
+          type="primary"
+          @click.native="saveField(true)">保存并申报</el-button>
+        <!--<el-button
+          class="handle-button"
+          type="primary"
+          @click.native="saveField(false)">{{ sureBtnTitle }}</el-button> -->
+      </div>
+      <el-dialog
+        title="提交申报"
+        :visible.sync="isCommited"
+        width="24%"
+        append-to-body
+        class='productTitle'
+        :before-close="handleClose">
+        <div class='pushBody'>
+          <div class='hintWord'>
+            <i class="el-icon-warning" style="color: #e6a23c;"></i>
+            <span>商机提交申报后,不能撤回修改。请确保提交信息准确有效!</span>
+          </div>
+          <div class='hintSelect'>
+            <span>是否跨区:</span>
+            <el-switch v-model="isCrossArea" @change='getCrossArea'></el-switch>
+          </div>
+          <div class='hintSelect' v-if="isUserSelect">
+            <span>审批人:</span>
+            <el-select v-model="pushStatus" placeholder="请选择">
+              <el-option
+                v-for="item in pushOptions"
+                :key="item.UserId"
+                :label="item.Name"
+                :value="item.UserId">
+              </el-option>
+            </el-select>
+          </div>
+        </div>
+        <span slot="footer" class="dialog-footer">
+          <el-button @click="handleClose" class='closePushBtn'>取 消</el-button>
+          <el-button type="primary" @click="saveField(false)" class='surePushBtn'>提交</el-button>
+        </span>
+      </el-dialog>
+    </flexbox>
+  </create-view>
+</template>
+<script type="text/javascript">
+// import crmTypeModel from '@/views/clients/model/crmTypeModel'
+import CreateView from '@/components/CreateView'
+import CreateSections from '@/components/CreateSections'
+import CreateExamineInfo from '@/components/Examine/CreateExamineInfo'
+import VDistpicker from 'v-distpicker'
+import {
+// regexIsCRMNumber,
+// regexIsCRMMoneyNumber,
+// regexIsCRMMobile,
+// regexIsCRMEmail,
+// objDeepCopy
+} from '@/utils'
+import { GetDepartmentUserChildList, GetDepartmentAreaList } from '@/api/systemManagement/departmentManage'
+import {GetCusomterNumber, GetIndustryListChildrenData, GetContacterNumber, GetSalesChanceNumber, GetProjectPropertyData, GetExtendProjectPropertyData, GetSalesChanceName, GetWxSpUserList} from '@/api/common'
+import Lockr from 'lockr'
+// import { isArray } from '@/utils/types'
+
+import {
+  XhInput,
+  XhTextarea,
+  XhSelect,
+  XhMultipleSelect,
+  XhDate,
+  XhDateTime,
+  XhUserCell,
+  XhStructureCell,
+  XhFiles,
+  CrmRelativeCell,
+  XhProuctCate,
+  XhProduct,
+  XhBusinessStatus,
+  XhCustomerAddress,
+  XhReceivablesPlan // 回款计划期数
+} from '@/components/CreateCom'
+
+import { AddCustomer, UpdateCustomer, GetPersonalCustomerPageList, GetCustomerDetail } from '@/api/customermanagement/customerManage'
+import { AddContacter, UpdateContacter, GetContacterDetail } from '@/api/customermanagement/contacts'
+import { AddSalesChance, UpdateSalesChance, GetSalesChanceDetail } from '@/api/customermanagement/business'
+import axios from 'axios'
+
+export default {
+  name: 'CrmCreateView', // 所有新建效果的view
+  components: {
+    CreateView,
+    CreateSections,
+    CreateExamineInfo, // 审核信息
+    XhInput,
+    XhTextarea,
+    XhSelect,
+    XhMultipleSelect,
+    XhDate,
+    XhDateTime,
+    XhUserCell,
+    XhStructureCell,
+    XhFiles,
+    CrmRelativeCell,
+    XhProuctCate,
+    XhProduct,
+    XhBusinessStatus,
+    XhCustomerAddress,
+    XhReceivablesPlan,
+    VDistpicker
+  },
+  filters: {
+    /** 根据type 找到组件 */
+    typeToComponentName (formType) {
+      if (
+        formType === 'text' ||
+        formType === 'number' ||
+        formType === 'floatnumber' ||
+        formType === 'mobile' ||
+        formType === 'email'
+      ) {
+        return 'XhInput'
+      } else if (formType === 'textarea') {
+        return 'XhTextarea'
+      } else if (formType === 'select' || formType === 'business_status') {
+        return 'XhSelect'
+      } else if (formType === 'checkbox') {
+        return 'XhMultipleSelect'
+      } else if (formType === 'date') {
+        return 'XhDate'
+      } else if (formType === 'datetime') {
+        return 'XhDateTime'
+      } else if (formType === 'user') {
+        return 'XhUserCell'
+      } else if (formType === 'structure') {
+        return 'XhStructureCell'
+      } else if (formType === 'file') {
+        return 'XhFiles'
+      } else if (
+        formType === 'contacts' ||
+        formType === 'customer' ||
+        formType === 'contract' ||
+        formType === 'business'
+      ) {
+        return 'CrmRelativeCell'
+      } else if (formType === 'category') {
+        // 产品类别
+        return 'XhProuctCate'
+      } else if (formType === 'business_type') {
+        // 商机类别
+        return 'XhBusinessStatus'
+      } else if (formType === 'product') {
+        return 'XhProduct'
+      } else if (formType === 'map_address') {
+        return 'XhCustomerAddress'
+      } else if (formType === 'receivables_plan') {
+        return 'XhReceivablesPlan'
+      }
+    }
+  },
+  props: {
+    // CRM类型
+    crmType: {
+      type: String,
+      default: ''
+    },
+    /**
+     * save:添加、update:编辑(action_id)、read:详情、index:列表
+     * relative: 相关 添加(目前用于客户等相关添加) 如果有relativeData 直接合并入上传
+     */
+    action: {
+      type: Object,
+      default: () => {
+        return {
+          type: 'save',
+          id: '',
+          data: {} // 编辑所需信息
+        }
+      }
+    }
+  },
+  data () {
+    var validateUsername = (rule, value, callback) => {
+      let isPhone = /^1\d{10}$/
+      let isMob = /^0\d{2,3}-?\d{7,8}$/
+      if (value && value === 'admin') {
+        callback()
+      } else if (isPhone.test(value) || isMob.test(value)) {
+        callback()
+      } else {
+        callback(new Error('目前只支持中国大陆的手机号码或座机号'))
+      }
+    }
+    return {
+      // 标题展示名称
+      title: '',
+      timer: '',
+      loading: false,
+      saveAndCreate: false, // 保存并新建
+      file: { name: '' },
+      // 自定义字段验证规则
+      crmRules: {
+        CustomerName: [
+          { required: true, message: '客户名称不能为空', trigger: 'blur' }
+        ],
+        SaleOwerId: [
+          { required: true, message: '请选择', trigger: 'blur' }
+        ],
+        CompanyType: [
+          { required: true, message: '请选择', trigger: 'blur' }
+        ],
+        FirmSize: [
+          { required: true, message: '请输入客户设计人数', trigger: 'blur' }
+        ],
+        mapAddress: [
+          { required: true, message: '请选择地区', trigger: 'blur' }
+        ],
+        radioInput: [
+          { required: true, message: '请选择行业', trigger: 'blur' }
+        ],
+        Address: [
+          { required: true, message: '请输入通信地址', trigger: 'blur' }
+        ],
+        PostNumber: [
+          { required: true, message: '请输入正确的客户邮编', pattern: /^[0-9]{6}$/, trigger: 'blur' }
+        ]
+      },
+      dialogRules: {
+        RealName: [
+          { required: true, message: '联系人姓名不能为空', trigger: 'blur' }
+        ],
+        CustomerId: [
+          { required: true, message: '客户名称不能为空', type: '', trigger: 'blur' }
+        ],
+        MobilePhone: [
+          { required: true, message: '联系人手机号码不能为空' },
+          {
+            validator: validateUsername,
+            trigger: 'blur'
+          }
+        ],
+        OfficePhone: [
+          { required: false, message: '联系人座机号码不能为空' },
+          {
+            validator: validateUsername,
+            trigger: 'blur'
+          }
+        ],
+        JobPosition: [
+          { required: true, message: '联系人职位不能为空', trigger: 'blur' }
+        ],
+        Email: [
+          {
+            // eslint-disable-next-line no-useless-escape
+            pattern: /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/,
+            message: '请输入正确的邮箱格式',
+            trigger: 'blur',
+            required: true
+          }
+        ]
+      },
+      busDialogRules: {
+        // ChanceNumber: [
+        //   { required: true, message: '商机编号不能为空', trigger: 'blur' }
+        // ],
+        CustomerId: [
+          { required: true, message: '请选择客户', trigger: 'blur' }
+        ],
+        // ContacterName: [
+        //   { required: true, message: '请选择联系人', trigger: 'blur' }
+        // ],
+        // ContacterMobile: [
+        //   { required: true, message: '联系人方式不能为空' },
+        //   {
+        //     validator: validateUsername,
+        //     trigger: 'blur'
+        //   }
+        // ],
+        OwerUserId: [
+          { required: true, message: '请选择负责人', trigger: 'blur' }
+        ],
+        ChanceRequestType: [
+          { required: true, message: '请选择商机类型', trigger: 'blur' }
+        ],
+        ExpectedDate: [
+          { required: true, message: '预计成交日期', trigger: 'blur' }
+        ]
+      },
+      dialogUserRules: {
+        Contacter: [
+          { required: true, message: '联系人不能为空', trigger: 'blur' }
+        ],
+        ContactMobile: [
+          { required: true, message: '联系人手机号码不能为空' },
+          {
+            validator: validateUsername,
+            trigger: 'blur'
+          }
+        ],
+        OfficePhone: [
+          { required: false, message: '联系人座机号码不能为空' },
+          {
+            validator: validateUsername,
+            trigger: 'blur'
+          }
+        ],
+        Email: [
+          {
+            // eslint-disable-next-line no-useless-escape
+            pattern: /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/,
+            message: '请输入正确的邮箱格式',
+            trigger: 'blur',
+            required: true
+          }
+        ],
+        JobPosition: [
+          { required: true, message: '请输入联系人职务' },
+          {
+            trigger: 'blur'
+          }
+        ]
+      },
+      // 自定义字段信息表单
+      crmForm: {
+        crmFields: []
+      },
+      // 审批信息
+      examineInfo: {},
+      formInline: {
+        mapAddress: {
+          province: '',
+          city: ''
+        }
+      },
+      customerChosed: '',
+      otherInput: '',
+      isOtherOpt: false,
+      rightsList: [],
+      salesManList: [],
+      salesId: '',
+      optionsList: {
+        CustomerStatus: {
+          field: 'CustomerStatus',
+          list: ['潜在客户', '高意向潜在客户', '试用客户', '成交客户', '失败关闭', '销售线索', '在谈客户', '在谈休眠客户']
+        },
+        CustomerSource: {
+          field: 'CustomerSource',
+          list: ['电话来访', '公司分配', '客户介绍', '独立开发', '朋友介绍', ' 广告宣传', '市场活动', '合作伙伴', '公开招标', '老客户', '代理商', '400百度', '其他400', '老客户介绍', '代理商客户', '电话陌生拜访', '直接访问', '个人自找', '项目合作', '金蝶商机', '公司电话', '后台注册', '二次销售', '其他']
+        },
+        CustomerType: {
+          field: 'CustomerType',
+          list: ['大客户', '区域客户']
+        },
+        CostomerCategory: {
+          field: 'CostomerCategory',
+          list: ['普通客户', 'VIP客户', '合作伙伴', '竞争对手', '竞争对手客户', '集成商', '代理商', '供应商', '其他']
+        },
+        Industry: {
+          field: 'Industry',
+          list: ['电子', '通讯', '咨询', '教育', '酒店', '保险', '运输', '机械', '零售', '物流', '技术', '餐饮', '服装', '银行', '能源', '工程', '娱乐', '环境', '卫生保健', '食品饮料', '休闲娱乐', '公共事业', '生物技术', '其他行业']
+        },
+        ContacterMobile: {
+          field: 'ContacterMobile',
+          list: ['电话', '微信', '信息', '其他']
+        },
+        DepartmentId: {
+          field: 'DepartmentId',
+          list: ['初期沟通', '需求分析', '方案报价', '商务谈判', '成功', '搁置']
+        },
+        ChanceType: {
+          field: 'ChanceType',
+          list: ['暂无', '新业务', '已有业务来往']
+        },
+        ChanceSource: {
+          field: 'ChanceSource',
+          list: ['电话来访', '公司分配', '客户介绍', '独立开发', '朋友介绍', ' 广告宣传', '市场活动', '合作伙伴', '公开招标', '老客户', '代理商', '400百度', '其他400', '老客户介绍', '代理商客户', '电话陌生拜访', '直接访问', '个人自找', '项目合作', '金蝶商机', '公司电话', '后台注册', '二次销售', '其他']
+        },
+        projectStatus: {
+          field: 'projectStatus',
+          list: ['无', 'LC和商业商机', 'Solution行业商机', '仅提交LC商机']
+        },
+        winChance: {
+          field: 'winChance',
+          list: [{0: '无', 1: 'LC和商业商机', 2: 'Solution行业商机', 3: '仅提交LC商机'}, {0: '无', 1: 'LC和商业商机', 2: 'Solution行业商机', 3: '仅提交LC商机'}]
+        },
+        ProjectProperty: {
+          field: 'projectType',
+          list: ['普通项目', 'LC协作', 'ACAD项目', 'ACAD重点客户', 'AEC项目', 'AEC倍增计划', 'MFG项目', 'MNE项目', '企业信息特例', '特别案例', '区域重点客户']
+        },
+        ExtendProjectProperty: {
+          field: 'ExtendProjectProperty',
+          list: ['LC协作(ACAD)', 'LC协作(AEC)', 'LC协作(MFG)', 'LC协作(MNE)']
+        },
+        LcAgency: {
+          field: 'LcAgency',
+          list: [{value: 0, name: '暂无'}, {value: 1, name: '嘉禾'}, {value: 2, name: '信品'}]
+        },
+        CompanyType: {
+          field: 'CompanyType',
+          list: [{value: 1, name: '国企'}, {value: 2, name: '外企'}, {value: 3, name: '民营'}, {value: 4, name: '其他'}]
+        },
+        SalesChanceStage: {
+          field: 'SalesChanceStage',
+          list: [{value: 1, name: '初期沟通'}, {value: 2, name: '需求分析'}, {value: 3, name: '方案报价'}, {value: 4, name: '商务谈判'}, {value: 5, name: '成功'}, {value: 6, name: '搁置'}]
+        },
+        SalesChanceCustomerType: {
+          field: 'SalesChanceCustomerType',
+          list: [{value: 1, name: '普通客户'}, {value: 2, name: '大客户AEC客户'}, {value: 3, name: '大客户MFG客户'}, {value: 4, name: '大客户MNE客户'}]
+        },
+        ChancePercent: {
+          field: 'ChancePercent',
+          list: [{value: 1, name: 'Failed: 0%'}, {value: 2, name: 'pipeline: 10%'}, {value: 3, name: 'BusinessOpporutnity: 30%'}, {value: 4, name: 'Upside: 40%'}, {value: 5, name: 'Forecast: 60%'}, {value: 6, name: 'LPIOrdered: 80%'}]
+        },
+        ChanceRequestType: {
+          field: 'ChanceRequestType',
+          list: [{value: 1, name: 'LC'}, {value: 2, name: 'ACAD'}, {value: 3, name: 'AEC'}, {value: 4, name: 'MFG'}, {value: 5, name: 'MNE'}]
+        }
+      },
+      // popField
+      popFieldList: [
+        { field: 'CustomerNumber', value: '客户编号', width: '20' },
+        { field: 'CustomerName', value: '客户名称', width: '20' },
+        { field: 'Contacter', value: '联系人', width: '20' },
+        { field: 'ContactMobile', value: '手机号', width: '30' },
+        { field: 'OfficePhone', value: '座机号', width: '30' },
+        // { field: 'CustomerStatus', value: '客户业务状态', width: '30' },
+        // { field: 'CustomerSource', value: '客户来源', width: '20' },
+        // { field: 'CustomerType', value: '客户大类型', width: '20' },
+        // { field: 'CostomerCategory', value: '客户类别', width: '20' },
+        { field: 'Industry', value: '所属行业', width: '20' },
+        { field: 'ProvinceCode', value: '所属地区', width: '20' },
+        // { field: 'Address', value: '通信地址', width: '20' },
+        // { field: 'SaleOwerId', value: '销售员', width: '150' },
+        { field: 'SaleName', value: '销售负责人', width: '20' }
+        // { field: 'CreateTime', value: '创建时间', width: '20' }
+        // { field: 'NextFollowTime', value: '最新跟进时间', width: '150' }
+      ],
+      totalPop: 0,
+      currentPopPage: 1,
+      pagePopSize: 15,
+      pagePopSizes: [10, 30, 60, 100],
+      popSearch: '',
+      popData: [],
+      popLoading: false,
+      editData: {},
+      isLC: false,
+      isSubmit: false,
+      isCommited: false,
+      pushStatus: '',
+      isCrossArea: false,
+      isUserSelect: false,
+      pushOptions: [],
+      radioInput: '',
+      isClicked: false
+    }
+  },
+  computed: {
+    /** 合同 回款 下展示审批人信息 */
+    showExamine () {
+      if (this.crmType === 'contract' || this.crmType === 'receivables') {
+        return true
+      }
+      return false
+    },
+    sureBtnTitle () {
+      if (this.crmType === 'contract' || this.crmType === 'receivables') {
+        return '提交审核'
+      }
+      return '保存'
+    },
+    formRules () {
+      if (this.crmType === 'customer') {
+        return this.crmRules
+      } else if (this.crmType === 'contacts') {
+        return this.dialogRules
+      } else if (this.crmType === 'business') {
+        return this.busDialogRules
+      }
+      return false
+    },
+    tableList: function () {
+      if (this.crmType === 'customer') {
+        return [
+          { field: 'CustomerName', value: '客户名称', showblock: false, tips: '请录入营业执照的名称,不能录入空格、斜杠、逗号、分号、下划线、中杠等特殊符号。只能录入简体中文' },
+          { field: 'SaleOwerId', value: '销售负责人', type: 'cascaderSingle', showblock: false },
+          { field: 'CompanyType', value: '企业性质', type: 'select', showblock: false },
+          { field: 'FirmSize', value: '客户设计人数', type: 'number', showblock: false },
+          { field: 'radioInput', value: '行业细分', type: 'inputPopover', showblock: false },
+          { field: 'PostNumber', value: '邮政编码', showblock: false },
+          { field: 'Address', value: '通信地址', showblock: false },
+          { field: 'Comment', value: '备注', showblock: false, type: 'textarea' },
+          { field: 'mapAddress', value: '所属地区', type: 'map_address', showblock: true }
+        ]
+      } else if (this.crmType === 'contacts') {
+        return [
+          { field: 'RealName', value: '联系人姓名', showblock: false },
+          { field: 'CustomerId', value: '关联客户', type: 'relationInput', showblock: false },
+          { field: 'MobilePhone', value: '手机号', showblock: false },
+          { field: 'OfficePhone', value: '座机号', showblock: false },
+          { field: 'DepartmentName', value: '部门', showblock: false },
+          { field: 'Email', value: '邮箱', showblock: false },
+          { field: 'JobPosition', value: '职务', showblock: false }
+        ]
+      } else if (this.crmType === 'business') {
+        return [
+          { field: 'ChanceNumber', value: '编号', disabled: true, showblock: false },
+          { field: 'SalesChanceCustomerType', value: '客户类型', type: 'select', showblock: false },
+          { field: 'ChanceName', value: '名称', showblock: false, disabled: true, tips: '自动生成规则:“客户名称”+“年月日”+“序号”', type: 'disInput' },
+          { field: 'ExpectedAmount', value: '商机金额/元', type: 'number', showblock: false },
+          { field: 'CustomerId', value: '客户', type: 'relationInput', showblock: false, chosedCusName: '' },
+          { field: 'ChanceRequestType', value: '商机类型', type: 'select', showblock: false },
+          { field: 'SalesChanceStage', value: '销售阶段', type: 'select', showblock: false },
+          { field: 'OwerUserId', value: '销售负责人', type: 'cascaderSingle', showblock: false },
+          { field: 'mapAddress', value: '所属地区', type: 'map_address', showblock: false, disabled: true },
+          { field: 'ChancePercent', value: '成交几率', type: 'select', showblock: false },
+          { field: 'ExpectedDate', value: '预计成交日期', type: 'date', showblock: false },
+          { field: 'Comment', value: '说明', type: 'textarea', showblock: false },
+          // { field: 'PirateNumber', value: '盗版用量', type: 'number', showblock: false },
+          { field: 'ProjectProperty', value: '项目属性', type: 'radioList', showblock: false },
+          { field: 'Products', type: 'product', showblock: true }
+        ]
+      }
+    },
+    tableUserList: function () {
+      if (this.crmType === 'customer') {
+        return [
+          { field: 'Contacter', value: '姓名', showblock: false },
+          { field: 'ContactMobile', value: '手机号', showblock: false },
+          { field: 'OfficePhone', value: '座机号', showblock: false },
+          { field: 'JobPosition', value: '职务', showblock: false },
+          { field: 'Email', value: '邮箱', showblock: false }
+        ]
+      }
+    }
+  },
+  watch: {
+    crmType: function (value) {
+      this.title = this.getTitle()
+      this.crmRules = {}
+      // this.crmForm = {
+      //   crmFields: []
+      // }
+      this.examineInfo = {}
+      // this.getField()
+    },
+    radioInput: function (value) {
+      this.formInline['radioInput'] = value
+    }
+  },
+  mounted () {
+    console.log(this.action)
+    // 商务数据展示
+    let userInfo = Lockr.get('User-Info')
+    if (userInfo.PositionType === 4) {
+      this.optionsList['ChanceRequestType'].list.push({value: 6, name: 'ACAD重点项目'})
+    }
+    console.log(this.optionsList['ChanceRequestType'])
+    // 获取title展示名称
+    document.body.appendChild(this.$el)
+    this.title = this.getTitle()
+    this.getSalesList()
+    this.getField()
+    this.getUserOpt()
+  },
+  destroyed () {
+    // remove DOM node after destroy
+    if (this.$el && this.$el.parentNode) {
+      this.$el.parentNode.removeChild(this.$el)
+    }
+  },
+  methods: {
+    /** 格式化字段 */
+    fieldFormatter (row, column) {
+      // 如果需要格式化
+      return row[column.property] || '--'
+    },
+    // 关联选择样式
+    popCellStyle ({ row, column, rowIndex, columnIndex }) {
+      return { fontSize: '12px', textAlign: 'center', cursor: 'pointer' }
+    },
+    headerCellStyle ({ row, column, rowIndex, columnIndex }) {
+      return { fontSize: '12px', textAlign: 'center' }
+    },
+    handlePopRowClick (row, column, event) {
+      this.formInline['CustomerId'] = row.Id
+      this.customerChosed = row.CustomerName
+      console.log(row)
+      this.hidenRelationInput()
+      if (this.crmType === 'business') {
+        this.getSalesChanceName(row.Id)
+        this.formInline['mapAddress'] = {
+          province: row.ProvinceCode,
+          city: row.CityCode
+        }
+        this.formInline['ProvinceCode'] = row.ProvinceCode
+        this.formInline['CityCode'] = row.CityCode
+      }
+    },
+    handlePopSizeChange (newSize) {
+      this.pagePopSizes = newSize
+      this.getCustomerTable()
+    },
+    handlePopCurrentChange (newPage) {
+      this.currentPopPage = newPage
+      this.getCustomerTable()
+    },
+    // 审批信息值更新
+    examineValueChange (data) {
+      this.examineInfo = data
+    },
+    getCrossArea () {
+      console.log(this.isCrossArea)
+      if (this.isCrossArea) {
+        this.isUserSelect = true
+      } else {
+        this.isUserSelect = false
+        this.pushStatus = ''
+      }
+    },
+    // 获取审批人员列表
+    getUserOpt () {
+      GetWxSpUserList().then(res => {
+        if (res.data.ErrorCode === 200) {
+          this.pushOptions = res.data.Result
+          // this.pushStatus = this.pushOptions[0].UserId
+        }
+      })
+    },
+    // 字段的值更新
+    fieldValueChange (data) {
+      console.log(data)
+      if (data.index === 'CustomerId') {
+        this.formInline['CustomerId'] = data.value
+        this.tableList[3].disabled = false
+        this.tableList[2].chosedCusName = data.name
+        this.timer = new Date().getTime()
+      }
+      if (data.index === 'ContacterId') {
+        this.formInline['ContacterId'] = data.value
+      }
+      if (data.type === 'product') {
+        if (this.isLC) {
+          this.formInline['SalesChancePirates'] = data.data
+        } else {
+          this.formInline['Products'] = data.data
+        }
+      }
+    },
+    // 选择文件
+    selectFile () {
+      document.getElementById('importInputFile').click()
+    },
+    /** 图片选择出发 */
+    uploadFile (event) {
+      let files = event.target.files
+      const file = files[0]
+      this.file = file
+      event.target.value = ''
+      let data = new FormData()
+      data.append('file', file)
+      axios.post('http://192.168.0.107:8081/api/File/UploadFileAsync', data, {
+        headers: {
+          'Content-Type': 'multipart/form-data'
+        }
+      }).then(res => {
+        if (res.data.ErrorCode === 200) {
+          this.formInline['DocumentFiles'] = [{
+            'DocumentFileName': res.data.Message,
+            'DocumentFilePath': res.data.Result
+          }]
+        } else {
+          this.$message.error(res.data.Message)
+        }
+      }).catch(err => {
+        console.log(err)
+      })
+    },
+    // 获取自定义字段
+    getField () {
+      this.loading = true
+      // 进行编辑操作
+      if (this.action.type === 'update') {
+        this.getEditData()
+      // 新增操作
+      } else if (this.action.type === 'save') {
+        this.salesId = Lockr.get('User-Info').Id
+        if (this.crmType === 'customer') {
+          this.formInline['SaleOwerId'] = this.salesId
+        } else if (this.crmType === 'business') {
+          this.formInline['SaleOwerId'] = this.salesId
+          this.formInline = {
+            mapAddress: {
+              province: '',
+              city: ''
+            },
+            SalesChanceCustomerType: 1,
+            SalesChanceStage: 1,
+            OwerUserId: this.salesId
+          }
+        }
+        this.getId()
+      }
+      if (this.crmType === 'contacts' || this.crmType === 'business') {
+        this.getCustomerTable()
+      }
+      this.getAreaList()
+      this.getIndustryList()
+      this.getProjectPropertyData()
+      this.getExtendProjectPropertyData()
+      this.loading = false
+    },
+    getEditData () {
+      let editRequest = this.getUpdataData()
+      let params = {
+        Id: this.action.id
+      }
+      editRequest(params)
+        .then(res => {
+          if (res.data.ErrorCode === 200) {
+            this.editData = res.data.Result
+            if (res.data.Result) {
+              this.formInline = {...this.editData}
+              if (this.crmType === 'customer') {
+              // 客户编辑
+                this.formInline['mapAddress'] = {
+                  province: this.editData.ProvinceCode,
+                  city: this.editData.CityCode
+                }
+                this.formInline['mapAddress'].type = 'map_address'
+                this.salesId = this.formInline['SaleOwerId']
+                this.formInline['radioInput'] = this.formInline['Industry']
+                this.radioInput = this.formInline['Industry']
+              } else if (this.crmType === 'contacts') {
+              // 联系人编辑
+                this.customerChosed = this.editData.CustomerName
+                console.log(this.editData, this.editData.CustomerName)
+              } else if (this.crmType === 'business') {
+              // 商机编辑
+                this.formInline['mapAddress'] = {
+                  province: this.editData.ProvinceCode,
+                  city: this.editData.CityCode
+                }
+                this.formInline['mapAddress'].type = 'map_address'
+
+                this.formInline['SalesChanceStage'] = this.editData.SalesChanceStage && this.editData.SalesChanceStage !== '--' ? JSON.parse(this.editData.SalesChanceStage) : 1
+
+                this.formInline['SalesChanceCustomerType'] = this.editData.SalesChanceCustomerType && this.editData.SalesChanceCustomerType !== '--' ? JSON.parse(this.editData.SalesChanceCustomerType) : 1
+
+                this.formInline['ChanceRequestType'] = this.editData.ChanceRequestType && this.editData.ChanceRequestType !== '--' ? JSON.parse(this.editData.ChanceRequestType) : 1
+                // 入值
+                this.salesId = this.formInline['OwerUserId']
+                this.customerChosed = this.editData.CustomerName
+                if (this.formInline['ProjectProperty'] === 'LC协作') {
+                  this.isLC = true
+                  this.formInline['Products'] = this.editData.SalesChancePirates
+                  this.formInline['LcAgency'] = this.editData.LcAgency === '' || this.editData.LcAgency === '暂无' ? 0 : (this.editData.LcAgency === '嘉禾' ? 1 : 2)
+                  if (this.tableList[13].field !== 'ExtendProjectProperty') {
+                    this.tableList.splice(13, 0, { field: 'ExtendProjectProperty', value: '扩展项目属性', type: 'radioList', showblock: false })
+                    this.tableList.splice(14, 0, { field: 'PirateNumber', value: '盗版用量', type: 'number', showblock: false })
+                    this.tableList.splice(15, 0, { field: 'LcAgency', value: '知识产权代理', type: 'select', showblock: false })
+                  }
+                } else {
+                  this.isLC = false
+                  this.formInline['Products'] = this.editData.Products
+                }
+                if (this.$refs['xhProduct'][0].selectInfos) {
+                  this.$refs['xhProduct'][0].selectInfos(this.formInline['Products'], this.isLC)
+                }
+
+                // this.editData.UploadStatusName === '已提交' ||
+                if (!this.editData.IsCanReport) {
+                  this.isSubmit = true
+                } else {
+                  this.isSubmit = false
+                }
+                console.log(this.formInline)
+              }
+            }
+          } else {
+            this.$message.error(res.data.Message)
+            this.editData = {}
+          }
+        })
+    },
+    getUpdataData () {
+      if (this.action.type === 'update') {
+        if (this.crmType === 'customer') {
+          return GetCustomerDetail
+        } else if (this.crmType === 'contacts') {
+          return GetContacterDetail
+        } else if (this.crmType === 'business') {
+          return GetSalesChanceDetail
+        } else if (this.crmType === 'product') {
+        // return crmProductSave
+        } else if (this.crmType === 'contract') {
+        // return crmContractSave
+        } else if (this.crmType === 'receivables') {
+        // return crmReceivablesSave
+        } else if (this.crmType === 'receivables_plan') {
+        // return crmReceivablesPlanSave
+        }
+      }
+    },
+    // 销售员级联列表
+    getSalesList () {
+      GetDepartmentUserChildList().then(res => {
+        if (res.data.ErrorCode === 200 && res.data.Result !== 0) {
+          let list = res.data.Result
+          let array = this.addLabel(list)
+          this.salesManList = array
+        } else {
+          this.$message.error(res.data.Message)
+          this.loading = false
+        }
+      })
+    },
+    addLabel (arr) {
+      for (let k in arr) {
+        if (arr[k].DepartmentAndUserChildren && arr[k].DepartmentAndUserChildren.length < 1) {
+          // 当后台返回的children为空时,页面会留空白,把空白部分去掉
+          arr[k].children = undefined
+        } else {
+          arr[k].children = arr[k].DepartmentAndUserChildren
+          this.addLabel(arr[k].DepartmentAndUserChildren)
+        }
+      }
+      return arr
+    },
+    getUser (val) {
+      console.log(this.$refs['salesCas'][0].getCheckedNodes()[0].label, val[val.length - 1])
+      this.formInline['SaleOwerId'] = val[val.length - 1]
+      this.formInline['SaleName'] = this.$refs['salesCas'][0].getCheckedNodes()[0].label
+      this.formInline['OwerUserId'] = val[val.length - 1]
+      this.formInline['OwerUserName'] = this.$refs['salesCas'][0].getCheckedNodes()[0].label
+    },
+    /** 区域选择 */
+    selectProvince (value) {
+      console.log(value)
+      this.formInline['mapAddress'].province = value
+      this.formInline['ProvinceCode'] = value
+    },
+    selectCity (value) {
+      this.formInline['mapAddress'].city = value
+      this.formInline['CityCode'] = value
+      console.log(this.formInline['CityCode'])
+    },
+    // select选择
+    getSelectVal (type) {
+      console.log(type)
+      if (type === 'CustomerType') {
+        console.log(this.formInline['CustomerType'])
+        if (this.formInline['CustomerType'] === 1) {
+          console.log(this.tableList)
+          this.tableList.splice(5, 0, { field: 'DepartmentId', value: '所属区域', type: 'selectCheckout' })
+        } else {
+          if (this.tableList[5].field === 'DepartmentId') {
+            this.tableList.splice(5, 1)
+          }
+        }
+      } else if (type === 'ChancePercent') {
+        // this.formInline['ChancePercent'] = this.optionsList['ChancePercent'].list[this.formInline['ChancePercent']]
+        console.log(this.formInline['ChancePercent'])
+      } else if (type === 'SalesChanceStage') {
+        console.log(this.formInline['SalesChanceStage'])
+      } else if (type === 'ChanceRequestType') {
+        if (this.formInline['ChanceRequestType'] === 1) {
+          if (this.tableList[13].field !== 'ExtendProjectProperty') {
+            this.formInline['ProjectProperty'] = 'LC协作'
+            this.tableList.splice(13, 0, { field: 'ExtendProjectProperty', value: '扩展项目属性', type: 'radioList', showblock: false })
+            this.tableList.splice(14, 0, { field: 'PirateNumber', value: '盗版用量', type: 'number', showblock: false })
+            this.tableList.splice(15, 0, { field: 'LcAgency', value: '知识产权代理', type: 'select', showblock: false })
+            this.isLC = true
+            this.$forceUpdate()
+          }
+        } else {
+          if (this.tableList[13].field === 'ExtendProjectProperty') {
+            this.tableList.splice(15, 1)
+            this.tableList.splice(14, 1)
+            this.tableList.splice(13, 1)
+            this.isLC = false
+            this.$forceUpdate()
+          }
+        }
+        console.log(this.formInline['ChanceRequestType'])
+      } else if (type === 'LcAgency') {
+        if (this.formInline['LcAgency'] === 0) {
+          this.formInline['LcAgency'] = '暂无'
+        } else if (this.formInline['LcAgency'] === 1) {
+          this.formInline['LcAgency'] = '嘉禾'
+        } else if (this.formInline['LcAgency'] === 2) {
+          this.formInline['LcAgency'] = '信品'
+        }
+        console.log(this.formInline['LcAgency'])
+      }
+    },
+    getAreaList () {
+      GetDepartmentAreaList().then(res => {
+        if (res.data.Result) {
+          this.optionsList['DepartmentId'].list = res.data.Result
+        } else {
+          this.$message.error(res.data.Message)
+        }
+      })
+    },
+    //  switch 选择
+    getSwitch (type) {
+      console.log(this.formInline[type])
+      for (let i in this.tableList) {
+        if (this.tableList[i].field === 'CustomerAddJobShcedule') {
+          this.tableList[i].disabled = !this.formInline[type]
+        }
+      }
+    },
+    getCustomerTable () {
+      this.popLoading = true
+      let params = {
+        Name: this.popSearch,
+        PageIndex: this.currentPopPage,
+        PageSize: this.pagePopSize
+      }
+      GetPersonalCustomerPageList(params).then(res => {
+        if (res.data.ErrorCode === 200 && res.data.Result !== 0) {
+          this.popData = res.data.Result.List || []
+          this.totalPop = res.data.Result.Count
+          this.popLoading = false
+        } else {
+          this.$message.error(res.data.Message)
+          this.popLoading = false
+        }
+      })
+        .catch(() => {
+          this.popLoading = false
+        })
+    },
+    getId () {
+      if (this.crmType === 'customer') {
+        GetCusomterNumber().then(res => {
+          this.formInline['CustomerNumber'] = res.data.Result
+        })
+      } else if (this.crmType === 'contacts') {
+        GetContacterNumber().then(res => {
+          this.formInline['ContacterNumber'] = res.data.Result
+        })
+      } else if (this.crmType === 'business') {
+        GetSalesChanceNumber().then(res => {
+          this.formInline['ChanceNumber'] = res.data.Result
+        })
+      }
+    },
+    getSalesChanceName (data) {
+      console.log('aaaaaaaaaaaa')
+      let params = {
+        customerId: data
+      }
+      GetSalesChanceName(params).then(res => {
+        this.formInline['ChanceName'] = res.data.Result
+        this.$forceUpdate()
+      })
+    },
+    getProjectPropertyData () {
+      GetProjectPropertyData().then(res => {
+        this.optionsList['ProjectProperty'].list = res.data.Result
+      })
+    },
+    getExtendProjectPropertyData () {
+      GetExtendProjectPropertyData().then(res => {
+        this.optionsList['ExtendProjectProperty'].list = res.data.Result
+      })
+    },
+    getPropertyName () {
+      console.log(this.formInline['ProjectProperty'])
+      if (this.formInline['ProjectProperty'] === 'LC协作') {
+        this.formInline['ChanceRequestType'] = 1
+        if (this.tableList[13].field !== 'ExtendProjectProperty') {
+          this.tableList.splice(13, 0, { field: 'ExtendProjectProperty', value: '扩展项目属性', type: 'radioList', showblock: false })
+          this.tableList.splice(14, 0, { field: 'PirateNumber', value: '盗版用量', type: 'number', showblock: false })
+          this.tableList.splice(15, 0, { field: 'LcAgency', value: '知识产权代理', type: 'select', showblock: false })
+          this.isLC = true
+          this.$forceUpdate()
+        }
+      } else {
+        console.log(this.tableList[13].field)
+        if (this.tableList[13].field === 'ExtendProjectProperty') {
+          this.tableList.splice(15, 1)
+          this.tableList.splice(14, 1)
+          this.tableList.splice(13, 1)
+          this.isLC = false
+          this.$forceUpdate()
+        }
+      }
+    },
+    // ---inputpopover
+    getIndustryList () {
+      GetIndustryListChildrenData().then(res => {
+        this.rightsList = res.data.Result
+      })
+    },
+    hidenPopoverView () {
+      document.querySelector('#app').click()
+      this.formInline['radioInput'] = this.editData.Industry
+      // this.otherInput = ''
+      // this.isOtherOpt = false
+    },
+    getOtherOpt (val) {
+      this.formInline['radioInput'] = ''
+      this.isOtherOpt = true
+    },
+    blurOtherOpt () {
+      if (!this.otherInput) {
+        this.isOtherOpt = false
+      }
+    },
+    getRadioInput (val, index) {
+      console.log('yesssssssssssssssss', val, index, this.radioInput)
+      // this.formInline['radioInput'] = val
+    },
+    setIndustry () {
+      this.formInline['Industry'] = this.formInline['radioInput']
+      document.querySelector('#app').click()
+    },
+    // 根据自定义字段获取自定义字段规则
+    getcrmRulesAndModel (list) {
+    },
+    /**
+     * 获取关联项的值 和 关联信息
+     */
+    getParamsValueAndRelativeInfo (params, item, list) {
+      console.log(params)
+      if (this.action.type === 'relative') {
+        const relativeData = this.editData[item.formType]
+        if (item.formType === 'receivables_plan') {
+          params['value'] = ''
+        } else {
+          params['value'] = relativeData ? [relativeData] : []
+        }
+      } else {
+        if (item.formType === 'receivables_plan') {
+          params['value'] = item.value || ''
+        } else {
+          params['value'] = item.value || []
+        }
+      }
+      if (this.action.type === 'relative' || this.action.type === 'update') {
+        // 回款计划 需要合同信息
+        if (item.formType === 'receivables_plan') {
+          const contractItem = this.getItemRelatveInfo(item, list, 'contract')
+          if (contractItem) {
+            contractItem['moduleType'] = 'contract'
+            params['relation'] = contractItem
+          }
+          // 商机合同 需要客户信息
+        } else if (item.formType === 'business' || item.formType === 'contract') {
+          const customerItem = this.getItemRelatveInfo(item, list, 'customer')
+          if (item.formType === 'business' && customerItem) {
+            customerItem['moduleType'] = 'customer'
+            params['relation'] = customerItem
+          } else if (item.formType === 'contract' && customerItem) {
+            customerItem['moduleType'] = 'customer'
+            customerItem['params'] = { checkStatus: 1 }
+            params['relation'] = customerItem
+          }
+        }
+      }
+    },
+    /**
+     * 获取相关联item
+     */
+    getItemRelatveInfo (item, list, fromType) {
+      let crmItem = null
+      if (this.action.type === 'relative') {
+        crmItem = this.editData[fromType]
+      } else {
+        const crmObj = list.find(listItem => {
+          return listItem.formType === fromType
+        })
+        if (crmObj && crmObj.value && crmObj.value.length > 0) {
+          crmItem = crmObj.value[0]
+        }
+      }
+      return crmItem
+    },
+    /**
+     * 获取关联项是否可操作
+     */
+    getItemDisabledFromItem (item) {
+      // 相关添加
+      if (this.action.type === 'relative') {
+        const relativeDisInfos = {
+          business: {
+            customer: { customer: true },
+            contacts: { customer: true }
+          },
+          contacts: {
+            customer: { customer: true },
+            business: { customer: true }
+          },
+          contract: {
+            customer: { customer: true },
+            business: { customer: true, business: true }
+          },
+          receivables_plan: {
+            contract: { customer: true, contract: true },
+            customer: { customer: true }
+          },
+          receivables: {
+            contract: { customer: true, contract: true },
+            customer: { customer: true }
+          }
+        }
+        // 添加类型
+        const crmTypeDisInfos = relativeDisInfos[this.crmType]
+        if (crmTypeDisInfos) {
+          // 在哪个类型下添加
+          const relativeTypeDisInfos = crmTypeDisInfos[this.action.crmType]
+          if (relativeTypeDisInfos) {
+            // 包含的字段值
+            return relativeTypeDisInfos[item.formType] || false
+          }
+        }
+        return false
+      } else if (this.action.type !== 'update') {
+        // 新建
+        if (this.crmType === 'contract' && item.formType === 'business') {
+          return true
+          // 回款下 新建 合同 和 回款计划 默认不能操作
+        } else if (this.crmType === 'receivables') {
+          if (item.formType === 'contract') {
+            return true
+          } else if (item.formType === 'receivables_plan') {
+            return true
+          }
+        }
+      }
+      return false
+    },
+    /**
+     * item 当行数据源
+     */
+    // 保存数据
+    saveField (saveAndCreate, isDraft = false) {
+      console.log(saveAndCreate)
+      this.saveAndCreate = saveAndCreate
+      console.log(this.formInline)
+      if (this.crmType === 'business') {
+        if (this.isCrossArea && this.pushStatus === '') {
+          this.$message.error('请选择跨区审批人员!')
+          return
+        }
+        if (this.formInline['ProjectProperty'] === 'LC协作' && !this.formInline['SalesChancePirates']) {
+          this.$message.error('请选择产品!')
+          return
+        }
+        if (this.formInline['ProjectProperty'] !== 'LC协作' && !this.formInline['Products']) {
+          this.$message.error('请选择产品!')
+          return
+        }
+        if (this.formInline['ProjectProperty'] === 'LC协作' && this.formInline['SalesChancePirates'].length === 0) {
+          this.$message.error('请选择产品!')
+          return
+        }
+        if (this.formInline['ProjectProperty'] !== 'LC协作' && this.formInline['Products'].length === 0) {
+          this.$message.error('请选择产品!')
+          return
+        }
+      }
+      this.$refs.dialogRef.validate(valid => {
+        if (valid) {
+          if (this.crmType === 'customer') {
+            this.$refs.userDialogRef.validate(valid => {
+              if (valid) {
+                this.formInline['CompanyType'] = Number(this.formInline['CompanyType'])
+                this.formInline['FirmSize'] = Number(this.formInline['FirmSize'])
+                let {mapAddress, radioInput, OwerUserId, OwerUserName, ...data} = this.formInline
+                this.submiteParams(data)
+              } else {
+                return false
+              }
+            })
+          } else if (this.crmType === 'contacts') {
+            // let {customerChosed, ...data} = this.formInline
+            this.submiteParams(this.formInline)
+          } else if (this.crmType === 'business') {
+            this.formInline['SalesChanceCustomerType'] = this.formInline['SalesChanceCustomerType'] ? JSON.parse(this.formInline['SalesChanceCustomerType']) : 1
+            this.formInline['SalesChanceStage'] = this.formInline['SalesChanceStage'] ? JSON.parse(this.formInline['SalesChanceStage']) : 1
+            this.formInline['PirateNumber'] = this.formInline['PirateNumber'] ? Number(this.formInline['PirateNumber']) : 0
+            // 知识产权代理
+            if (this.formInline['LcAgency'] === 0 || this.formInline['LcAgency'] === '暂无') {
+              this.formInline['LcAgency'] = ''
+            } else if (this.formInline['LcAgency'] === 1) {
+              this.formInline['LcAgency'] = '嘉禾'
+            } else if (this.formInline['LcAgency'] === 2) {
+              this.formInline['LcAgency'] = '信品'
+            }
+            this.formInline['ExpectedAmount'] = this.formInline['ExpectedAmount'] ? Number(this.formInline['ExpectedAmount']) : 0
+            this.formInline['ChanceRequestType'] = this.formInline['ChanceRequestType'] ? JSON.parse(this.formInline['ChanceRequestType']) : 1
+            // 是否申报
+            this.formInline['IsSubmitReport'] = this.isCommited
+            // 是否跨区
+            this.formInline['IsTransRegional'] = this.isCrossArea
+            // 跨区审批人
+            this.formInline['AuditUserId'] = this.pushStatus
+            // 销售id
+            // this.formInline['OwerUserId'] = this.formInline['SaleOwerId']
+            // this.formInline['OwerUserName'] = this.formInline['SaleName']
+            if (this.formInline['ProjectProperty'] === 'LC协作') {
+              // 去掉多余的入参
+              let {mapAddress, Products, SaleOwerId, SaleName, ...data} = this.formInline
+              this.submiteParams(data)
+            } else {
+              // 去掉多余的入参
+              let {mapAddress, SalesChancePirates, SaleOwerId, SaleName, ...data} = this.formInline
+              console.log(data)
+              this.submiteParams(data)
+            }
+          }
+        } else {
+          return false
+        }
+      })
+    },
+    /** 上传 */
+    submiteParams (params) {
+      this.loading = true
+      this.isClicked = true
+      console.log(params)
+      if (this.saveAndCreate) {
+        this.isCommited = true
+        // this.$confirm('确定保存并申报吗?(申报后无法撤回)', '提示', {
+        //   confirmButtonText: '确定',
+        //   cancelButtonText: '取消',
+        //   type: 'warning'
+        // })
+        //   .then(() => {
+        //     this.sendQuery(params)
+        //   })
+        //   .catch(() => {
+        //     this.loading = false
+        //     this.$message({
+        //       type: 'info',
+        //       message: '已取消保存并申报'
+        //     })
+        //   })
+      } else {
+        this.sendQuery(params)
+      }
+    },
+    surePush () {
+
+    },
+    sendQuery (params) {
+      let crmRequest = this.getSubmiteRequest()
+      crmRequest(params).then(res => {
+        if (res.data.ErrorCode === 200) {
+          this.hidenView()
+          this.$message.success(
+            this.action.type === 'update' ? '编辑成功' : '添加成功'
+          )
+          // 回到保存成功
+          this.$emit('save-success', {
+            type: this.crmType,
+            data: res.data || {},
+            saveAndCreate: this.saveAndCreate
+          })
+        } else {
+          this.$message.error(res.data.Message)
+          this.formInline['PirateNumber'] = 0
+        }
+        this.loading = false
+        this.handleClose()
+      })
+        .catch(() => {
+          this.loading = false
+          this.handleClose()
+        })
+    },
+    handleClose () {
+      this.isCommited = false
+      this.loading = false
+      this.isClicked = false
+      this.isSubmit = false
+      this.pushStatus = ''
+      this.isCrossArea = false
+    },
+    /** 获取上传url */
+    getSubmiteRequest () {
+      if (this.action.type === 'update') {
+        if (this.crmType === 'leads') {
+        // return crmLeadsSave
+        } else if (this.crmType === 'customer') {
+          return UpdateCustomer
+        } else if (this.crmType === 'contacts') {
+          return UpdateContacter
+        } else if (this.crmType === 'business') {
+          return UpdateSalesChance
+        } else if (this.crmType === 'product') {
+        // return crmProductSave
+        } else if (this.crmType === 'contract') {
+        // return crmContractSave
+        } else if (this.crmType === 'receivables') {
+        // return crmReceivablesSave
+        } else if (this.crmType === 'receivables_plan') {
+        // return crmReceivablesPlanSave
+        }
+      } else if (this.action.type === 'save') {
+        if (this.crmType === 'leads') {
+        // return crmLeadsSave
+        } else if (this.crmType === 'customer') {
+          return AddCustomer
+        } else if (this.crmType === 'contacts') {
+          return AddContacter
+        } else if (this.crmType === 'business') {
+          return AddSalesChance
+        } else if (this.crmType === 'product') {
+        // return crmProductSave
+        } else if (this.crmType === 'contract') {
+        // return crmContractSave
+        } else if (this.crmType === 'receivables') {
+        // return crmReceivablesSave
+        } else if (this.crmType === 'receivables_plan') {
+        // return crmReceivablesPlanSave
+        }
+      }
+    },
+    /** 拼接上传传输 */
+    getSubmiteParams (array) {
+      console.log(array)
+      let params = {}
+      for (let index = 0; index < array.length; index++) {
+        const element = array[index]
+        params[element.key] = element.value
+        if (element.key === 'mapAddress') {
+          params.address = element.value.address.join(',')
+          delete params['mapAddress']
+        } else if (element.key === 'CompanyType') {
+          params['CompanyType'] = JSON.parse(params['CompanyType'])
+        } else if (element.key === 'FirmSize') {
+          params['FirmSize'] = JSON.parse(params['FirmSize'])
+        }
+        // if (element.key === 'product') {
+        //   this.getProductParams(params, element)
+        // } else if (element.key === 'map_address') {
+        //   this.getCustomerAddressParams(params.entity, element)
+        // } else if (element.data.fieldType === 1) {
+        //   params.entity[element.key] = this.getRealParams(element) || ''
+        // } else {
+        //   element.data.value = this.getRealParams(element)
+
+        //   params.field.push(element.data)
+        // }
+      }
+      console.log(params)
+      return params
+    },
+    getProductParams (params, element) {
+      if (element.value) {
+        params['product'] = element.value.product ? element.value.product : []
+        params.entity['totalPrice'] = element.value.totalPrice
+          ? element.value.totalPrice
+          : 0
+        params.entity['discountRate'] = element.value.discountRate
+          ? element.value.discountRate
+          : 0
+      } else {
+        params['product'] = []
+        params.entity['totalPrice'] = ''
+        params.entity['discountRate'] = ''
+      }
+    },
+    // 获取客户位置参数
+    getCustomerAddressParams (params, element) {
+      params['address'] = element.value.address
+        ? element.value.address.join(',')
+        : ''
+      params['detailAddress'] = element.value.detailAddress
+      params['location'] = element.value.location
+      params['lng'] = element.value.lng
+      params['lat'] = element.value.lat
+    },
+    // 关联客户 联系人等数据要特殊处理
+    getRealParams (element) {
+      if (
+        element.key === 'customer_id' ||
+        element.key === 'contacts_id' ||
+        element.key === 'business_id' ||
+        element.key === 'leads_id' ||
+        element.key === 'contract_id'
+      ) {
+        if (element.value && element.value.length) {
+          const key = element.key.replace('_id', 'Id')
+          return element.value[0][key]
+        } else {
+          return ''
+        }
+      } else if (
+        element.type === 'user' ||
+        element.type === 'structure'
+      ) {
+        return element.value
+          .map(function (item, index, array) {
+            return element.type === 'user' ? item.userId : item.id
+          })
+          .join(',')
+      } else if (element.type === 'file') {
+        if (element.value && element.value.length > 0) {
+          return element.value[0].batchId
+        }
+        return ''
+      } else if (element.key === 'category_id') {
+        if (element.value && element.value.length > 0) {
+          return element.value[element.value.length - 1]
+        }
+        return ''
+      } else if (element.type === 'checkbox') {
+        if (element.value && element.value.length > 0) {
+          return element.value.join(',')
+        }
+        return ''
+      }
+
+      return element.value
+    },
+    hidenView () {
+      this.$emit('hiden-view')
+    },
+    hidenRelationInput () {
+      this.popSearch = ''
+      document.querySelector('#app').click()
+      this.$emit('close', this.$el, this.data)
+    },
+    // 根据类型获取标题展示名称
+    getTitle () {
+      if (this.crmType === 'leads') {
+        return this.action.type === 'update' ? '编辑线索' : '新建线索'
+      } else if (this.crmType === 'customer') {
+        return this.action.type === 'update' ? '编辑客户' : '新建客户'
+      } else if (this.crmType === 'contacts') {
+        return this.action.type === 'update' ? '编辑联系人' : '新建联系人'
+      } else if (this.crmType === 'business') {
+        return this.action.type === 'update' ? '编辑商机' : '新建商机'
+      } else if (this.crmType === 'product') {
+        return this.action.type === 'update' ? '编辑产品' : '新建产品'
+      } else if (this.crmType === 'contract') {
+        return this.action.type === 'update' ? '编辑合同' : '新建合同'
+      } else if (this.crmType === 'receivables') {
+        return this.action.type === 'update' ? '编辑回款' : '新建回款'
+      } else if (this.crmType === 'receivables_plan') {
+        return this.action.type === 'update' ? '编辑回款计划' : '新建回款计划'
+      }
+    },
+    // 获取左边padding
+    getPaddingLeft (item, index) {
+      if (item.showblock && item.showblock === true) {
+        return '0'
+      }
+      return item.styleIndex % 2 === 0 ? '0' : '25px'
+    },
+    // 获取左边padding
+    getPaddingRight (item, index) {
+      if (item.showblock && item.showblock === true) {
+        return '0'
+      }
+
+      return item.styleIndex % 2 === 0 ? '25px' : '0'
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+@import '../styles/table.scss';
+#importInputFile {
+  display: none;
+}
+.crm-create-container {
+  position: relative;
+  height: 100%;
+}
+
+.crm-create-flex {
+  position: relative;
+  overflow-x: hidden;
+  overflow-y: auto;
+  flex: 1;
+}
+
+.crm-create-header {
+  height: 40px;
+  margin-bottom: 20px;
+  padding: 0 10px;
+  flex-shrink: 0;
+  display: flex;
+  .close {
+    display: block;
+    width: 45px;
+    height: 45px;
+    margin-right: -10px;
+    padding: 10px;
+    cursor: pointer;
+  }
+}
+
+.crm-create-body {
+  flex: 1;
+  // overflow-x: hidden;
+  // overflow-y: auto;
+  max-height: 500px;
+}
+
+/** 将其改变为flex布局 */
+.crm-create-box {
+  display: flex;
+  flex-wrap: wrap;
+  padding: 0 10px;
+}
+
+.crm-create-item {
+  flex: 0 0 45%;
+  flex-shrink: 0;
+  // overflow: hidden;
+  padding-bottom: 30px;
+}
+
+// 占用一整行
+.crm-create-block-item {
+  flex: 0 0 100%;
+  flex-shrink: 0;
+  padding-bottom: 10px;
+  padding-left: 25px !important;
+}
+
+.el-form-item /deep/ .el-form-item__label {
+  line-height: 32px;
+  font-size: 13px;
+  color: #333333;
+  position: relative;
+  padding-left: 8px;
+  padding-bottom: 0;
+}
+
+.el-form /deep/ .el-form-item {
+  margin-bottom: 0px;
+}
+
+.el-form /deep/ .el-form-item.is-required .el-form-item__label:before {
+  content: '*';
+  color: #f56c6c;
+  margin-right: 4px;
+  position: absolute;
+  left: 0;
+  top: 8px;
+}
+
+.handle-bar {
+  position: relative;
+  margin: 0 auto;
+  .handle-button {
+    // float: right;
+    margin-top: 5px;
+    margin-right: 20px;
+  }
+}
+
+.el-button + .el-button {
+  margin-left: 0;
+}
+
+// 审核信息 里的审核类型
+.examine-type {
+  font-size: 12px;
+  color: white;
+  background-color: #fd715a;
+  padding: 0 8px;
+  margin-left: 5px;
+  height: 16px;
+  line-height: 16px;
+  border-radius: 8px;
+  transform: scale(0.8, 0.8);
+}
+
+.container{
+  position: relative;
+  .popover-foot{
+    position: relative;
+    left: 38%;
+    width: 100%;
+    margin-bottom: 30px;
+  }
+}
+.content {
+  position: relative;
+  padding: 32px 40px;
+  display: flex;
+  flex-direction: column;
+  margin-bottom: 40px;
+  height: 355px;
+  overflow: hidden;
+  overflow-y: auto;
+  border-bottom: 1px solid #f1f1f1;
+  .content-wrap{
+    width: 100%;
+  }
+  .otherOpt{
+    margin-bottom: 15px;
+    width: 100%;
+  }
+  p{
+    margin-bottom: 36px;
+    font-size: 14px;
+    font-weight: 550;
+    color: #333;
+
+  }
+  .con-group{
+    margin-bottom: 28px;
+  }
+  .content-wrap /deep/.el-radio-group .el-radio{
+    margin-right: 64px;
+    margin-bottom: 12px;
+  }
+  .content-wrap /deep/.el-radio-group .el-radio .el-radio__label{
+    font-weight: 400;
+    color: #666666;
+    font-size: 14px;
+  }
+}
+.header {
+  padding: 16px 30px;
+  flex-shrink: 0;
+  border-bottom: 1px solid #F1F1F1;
+  .name {
+    font-size: 13px;
+    padding: 0 10px;
+    color: #333;
+  }
+  .detail {
+    font-size: 12px;
+    padding: 0 10px;
+    color: #aaaaaa;
+    border-left: 1px solid #aaaaaa;
+  }
+  .close {
+    position: absolute;
+    width: 40px;
+    height: 40px;
+    top: 5px;
+    right: 10px;
+    padding: 10px;
+  }
+}
+.pop-container {
+  position: relative;
+}
+
+.pop-header {
+  padding: 16px 30px;
+  flex-shrink: 0;
+  border-bottom: 1px solid #F1F1F1;
+  margin-bottom: 13px;
+  .pop-name {
+    font-size: 16px;
+    font-weight: 550;
+    padding: 0 10px;
+    color: #333;
+  }
+  .pop-detail {
+    font-size: 12px;
+    padding: 0 10px;
+    color: #aaaaaa;
+    border-left: 1px solid #aaaaaa;
+  }
+  .pop-close {
+    position: absolute;
+    top: 16px;
+    right: 10px;
+    width: 25px;
+    height: 25px;
+  }
+}
+.pop-content{
+  padding: 0 30px;
+  .pop-cropper-box{
+    display:flex;
+    flex-direction: row;
+    align-items: center;
+    margin-bottom: 30px;
+    .pop-searchTitle{
+      font-size: 14px;
+      width: 124px;
+      color: #333;
+    }
+    .pop-searchInput{
+      margin-right: 20px;
+    }
+  }
+}
+.p-contianer{
+  margin: 30px 0;
+  .p-bar{
+    margin: 5px 0 0 14px;
+  }
+}
+.distpicker-address-wrapper{
+  display: flex;
+}
+.distpicker-address-wrapper /deep/ label{
+  margin-right: 10px;
+}
+.distpicker-address-wrapper /deep/ select {
+  color: #333;
+  height: 36px; /*no*/
+  font-size: 14px; /*no*/
+  border-radius: 4px;
+  border: 1px solid #D9D9D9;
+  padding: 2px; /*no*/
+  &:disabled{
+    color: #333;
+    background-color: #F7FAFF;
+    border-color: #D9D9D9;
+    opacity: 1;
+    cursor: not-allowed;
+    appearance: none;
+  }
+}
+.el-input /deep/ .el-input__inner {
+  // padding: 0 8px;
+  height: 36px;
+  line-height: 36px;
+  font-size: 14px;
+}
+.el-input /deep/ .el-input-group__append{
+  background-color: #4D88FF;
+  color: #fff;
+  height: 36px;
+  line-height: 36px;
+}
+.el-input.is-disabled /deep/ .el-input__inner{
+  background-color: #F7FAFF !important;
+  border-color: #D9D9D9 !important;
+  color: #333 !important;
+  cursor:pointer;
+}
+.relationInput.el-input.is-disabled /deep/ .el-input__inner{
+  background-color: #fff !important;
+  border-color: #D9D9D9 !important;
+  color: #333 !important;
+  cursor:pointer;
+  &:hover{
+    border-color: #4D88FF !important;
+  }
+}
+.areaInput.el-textarea /deep/ .el-textarea__inner{
+  &:hover{
+    border-color: #4D88FF !important;
+  }
+}
+.cn.el-input.is-disabled /deep/ .el-input__inner{
+  cursor: not-allowed;
+}
+.inputPopover.el-input.is-disabled /deep/ .el-input__inner{
+  background-color: #fff !important;
+  border-color: #D9D9D9 !important;
+  color: #333 !important;
+  cursor:pointer;
+}
+.disInput.el-input.is-disabled /deep/ .el-input__inner{
+  background-color: #F7FAFF !important;
+  border-color: #D9D9D9 !important;
+  color: #333 !important;
+  cursor: not-allowed;
+}
+// .el-date-editor /deep/ .el-input__prefix{
+//   right: -230px;
+// }
+.doubleSelect{
+  display: flex;
+  flex-direction: row;
+  width: 100%;
+  .leftSelect{
+    margin-right: 10px;
+  }
+}
+.radioList{
+  display: flex;
+  flex-direction: row;
+  flex-wrap: wrap;
+  .el-radio{
+    flex: 0 0 40%;
+    line-height: 24px;
+    .el-radio__label{
+      color: #666;
+      font-size: 16px;
+      margin-bottom: 12px;
+    }
+  }
+}
+.pushBody{
+  margin: 0 60px;
+  .hintWord{
+    margin-top: 10px;
+  }
+  .hintSelect{
+    margin-top: 20px;
+    .el-select{
+      width: 224px;
+    }
+  }
+}
+.closePushBtn{
+  margin-right: 16px;
+}
+.productTitle /deep/ .el-dialog__headerbtn .el-dialog__close{
+  font-size: 24px;
+}
+</style>
diff --git a/src/views/clients/components/CRMDetailHead.vue b/src/views/clients/components/CRMDetailHead.vue
new file mode 100644
index 0000000..0b43bd4
--- /dev/null
+++ b/src/views/clients/components/CRMDetailHead.vue
@@ -0,0 +1,596 @@
+<template>
+  <div style="position: relative;">
+    <flexbox class="t-section">
+      <!--<img
+        :src="crmIcon"
+        class="t-img" >
+      <div class="t-name">{{titleName}}:{{ name }}</div>-->
+      <div class="t-name">{{ name }}</div>
+      <!--<el-button
+        v-if="showCancel"
+        class="head-handle-button"
+        type="primary"
+        @click.native="handleTypeClick('discard')">作废</el-button>
+      <el-button
+        v-if="showTransfer"
+        class="head-handle-button"
+        type="primary"
+        @click.native="handleTypeClick('transfer')">转移</el-button>
+      <el-button
+        v-if="showEdit"
+        class="head-handle-button"
+        type="primary"
+        @click.native="handleTypeClick('edit')">编辑</el-button>
+      <el-dropdown
+        trigger="click"
+        @command="handleTypeClick">
+        <flexbox class="t-more">
+          <div>更多</div>
+          <i
+            class="el-icon-arrow-down el-icon--right"
+            style="color:#ccc;"/>
+        </flexbox>
+        <el-dropdown-menu slot="dropdown">
+          <el-dropdown-item
+            v-for="(item, index) in moreTypes"
+            v-if="whetherTypeShowByPermision(item.type)"
+            :key="index"
+            :command="item.type">{{ item.name }}</el-dropdown-item>
+        </el-dropdown-menu>
+      </el-dropdown>-->
+      <img
+        class="t-close"
+        src="@/assets/img/close.png"
+        @click="hideView" >
+    </flexbox>
+    <!--<flexbox
+      class="h-section"
+      align="stretch">
+      <flexbox-item
+        v-for="(item, index) in headDetails"
+        :key="index"
+        class="h-item"
+        span="200">
+        <div class="h-title">{{ item.title }}</div>
+        <div class="h-value text-one-line" >{{ item.value }}</div>
+      </flexbox-item>
+    </flexbox>-->
+    <slot/>
+    <transfer-handle
+      :crm-type="crmType"
+      :selection-list="[detail]"
+      :dialog-visible.sync="transferDialogShow"
+      @handle="handleCallBack"/>
+    <alloc-handle
+      :crm-type="crmType"
+      :selection-list="[detail]"
+      :dialog-visible.sync="allocDialogShow"
+      @handle="handleCallBack"/>
+    <deal-status-handle
+      :crm-type="crmType"
+      :selection-list="[detail]"
+      :visible.sync="dealStatusShow"
+      @handle="handleCallBack"/>
+  </div>
+</template>
+<script type="text/javascript">
+import { mapGetters } from 'vuex'
+// import {
+//   crmLeadsTransform,
+//   crmLeadsDelete
+// } from '@/api/clients/clue'
+// import {
+//   crmCustomerLock,
+//   crmCustomerPutInPool,
+//   crmCustomerDelete,
+//   crmCustomerReceive
+// } from '@/api/customermanagement/customerManage'
+// import { crmContactsDelete } from '@/api/clients/contacts'
+// import { crmBusinessDelete } from '@/api/clients/business'
+// import { crmContractDelete, CrmContractContractDiscard } from '@/api/clients/contract'
+// import { crmReceivablesDelete } from '@/api/clients/money'
+// import { crmProductStatus } from '@/api/clients/product'
+import TransferHandle from './selectionHandle/TransferHandle' // 转移
+import AllocHandle from './selectionHandle/AllocHandle' // 公海分配操作
+import DealStatusHandle from './selectionHandle/DealStatusHandle' // 客户状态修改操作
+
+export default {
+  name: 'CRMDetailHead',
+  components: {
+    TransferHandle,
+    AllocHandle,
+    DealStatusHandle
+  },
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    // 辅助 使用
+    isSeas: {
+      type: Boolean,
+      default: false
+    },
+    /** 联系人人下 新建商机 需要联系人里的客户信息  合同下需要客户和商机信息 */
+    detail: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    headDetails: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    }
+  },
+  data () {
+    return {
+      moreTypes: [], // 更多操作
+      transferDialogShow: false, // 转移操作
+      allocDialogShow: false, // 公海分配操作提示框
+      dealStatusShow: false // 成交状态修改框
+    }
+  },
+  computed: {
+    ...mapGetters(['crm', 'CRMConfig']),
+    crmIcon () {
+      if (this.crmType === 'customer') {
+        return require('@/assets/img/customer_detail.png')
+      } else if (this.crmType === 'leads') {
+        return require('@/assets/img/clue_detail.png')
+      } else if (this.crmType === 'business') {
+        return require('@/assets/img/business_detail.png')
+      } else if (this.crmType === 'contacts') {
+        return require('@/assets/img/contacts_detail.png')
+      } else if (this.crmType === 'contract') {
+        return require('@/assets/img/contract_detail.png')
+      } else if (this.crmType === 'receivables') {
+        return require('@/assets/img/money_detail.png')
+      } else if (this.crmType === 'product') {
+        return require('@/assets/img/product_detail.png')
+      }
+      return ''
+    },
+    name () {
+      if (this.crmType === 'receivables') {
+        return this.detail.number
+      } else if (this.crmType === 'customer') {
+        return this.detail.CustomerName
+      } else if (this.crmType === 'business') {
+        return this.detail.ChanceName
+      } else if (this.crmType === 'contacts') {
+        return this.detail.RealName
+      }
+      return this.detail.Name
+    },
+    titleName () {
+      if (this.crmType === 'contacts') {
+        return '联系人名称'
+      } else if (this.crmType === 'customer') {
+        return '客户名称'
+      } else if (this.crmType === 'business') {
+        return '商机名称'
+      }
+      return '名称'
+    },
+    // 展示转移
+    showTransfer () {
+      if (
+        this.crmType === 'receivables' ||
+        this.crmType === 'product' ||
+        this.isSeas
+      ) {
+        return false
+      }
+      // return this.crm[this.crmType].transfer
+      return true
+    },
+    showEdit () {
+      // return this.isSeas ? false : this.crm[this.crmType].update
+      return !this.isSeas
+    },
+    // 展示作废
+    showCancel () {
+      if (this.crmType === 'contract') {
+        if (this.crm.contract.discard) {
+          if (this.detail.checkStatus === 1) {
+            return true
+          }
+          return false
+        }
+        return false
+      }
+      return false
+    }
+  },
+  watch: {
+    isSeas () {
+      this.moreTypes = this.getSelectionHandleItemsInfo()
+    }
+  },
+  mounted () {
+    console.log(this.detail)
+    this.moreTypes = this.getSelectionHandleItemsInfo()
+  },
+  methods: {
+    /** 更多操作 */
+    handleTypeClick (type) {
+      if (type === 'edit') {
+        // 编辑
+        this.$emit('handle', { type: 'edit' })
+      } else if (type === 'transfer') {
+        // 转移
+        this.transferDialogShow = true
+      } else if (
+        type === 'transform' ||
+        type === 'put_seas' ||
+        type === 'delete' ||
+        type === 'lock' ||
+        type === 'unlock' ||
+        type === 'start' ||
+        type === 'disable' ||
+        type === 'get' ||
+        type === 'discard'
+      ) {
+        var message = ''
+        if (type === 'transform') {
+          message = '确定将这些线索转换为客户吗?'
+        } else if (type === 'put_seas') {
+          message = '确定转移到公海吗?'
+        } else if (type === 'delete') {
+          message = '确定要删除这些数据吗?'
+        } else if (type === 'lock') {
+          message = '确定要锁定这些客户吗?锁定后将不会掉入公海。'
+        } else if (type === 'unlock') {
+          message = '确定要解锁这些客户吗?'
+        } else if (type === 'start') {
+          message = '确定要上架这些产品吗?'
+        } else if (type === 'disable') {
+          message = '确定要下架这些产品吗?'
+        } else if (type === 'get') {
+          message = '确定要领取该客户吗?'
+        } else if (type === 'discard') {
+          message = '确定要作废此合同吗?'
+          if (this.detail.receivablesCount) {
+            message = '合同下有相关回款,确定要作废吗?'
+          }
+        }
+        this.$confirm(message, '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+          .then(() => {
+            this.confirmHandle(type)
+          })
+          .catch(() => {
+            this.$message({
+              type: 'info',
+              message: '已取消操作'
+            })
+          })
+      } else if (type === 'alloc') {
+        // 公海分配操作
+        this.allocDialogShow = true
+      } else if (type === 'deal_status') {
+        // 客户成交状态操作
+        this.dealStatusShow = true
+      }
+    },
+    confirmHandle (type) {
+      if (type === 'lock' || type === 'unlock') {
+        // crmCustomerLock({
+        //   isLock: type === 'lock' ? '1' : '0', // 1锁0不锁
+        //   ids: this.id
+        // })
+        //   .then(res => {
+        //     this.$message({
+        //       type: 'success',
+        //       message: '操作成功'
+        //     })
+        //     this.$emit('handle', { type: type })
+        //   })
+        //   .catch(() => {})
+      } else if (type === 'put_seas') {
+        // crmCustomerPutInPool({
+        //   ids: this.id
+        // })
+        //   .then(res => {
+        //     this.$message({
+        //       type: 'success',
+        //       message: '操作成功'
+        //     })
+        //     this.$emit('handle', { type: type })
+        //   })
+        //   .catch(() => {})
+      } else if (type === 'transform') {
+        // crmLeadsTransform({
+        //   leadsIds: this.id
+        // })
+        //   .then(res => {
+        //     this.$message({
+        //       type: 'success',
+        //       message: '转化成功'
+        //     })
+        //     this.$emit('handle', { type: type })
+        //   })
+        //   .catch(() => {})
+      } else if (type === 'discard') {
+        // CrmContractContractDiscard({
+        //   contractId: this.id
+        // }).then(res => {
+        //   this.$message.success('合同作废成功')
+        //   this.$emit('handle', { type })
+        // }).catch(() => {})
+      } else if (type === 'start' || type === 'disable') {
+        // crmProductStatus({
+        //   ids: this.id,
+        //   status: type === 'start' ? '1' : '0'
+        // })
+        //   .then(res => {
+        //     this.$message({
+        //       type: 'success',
+        //       message: '操作成功'
+        //     })
+        //     this.$emit('handle', { type: type })
+        //   })
+        //   .catch(() => {})
+      } else if (type === 'delete') {
+        const request = {
+          // leads: crmLeadsDelete,
+          // customer: crmCustomerDelete,
+          // contacts: crmContactsDelete,
+          // business: crmBusinessDelete,
+          // contract: crmContractDelete,
+          // receivables: crmReceivablesDelete
+        }[this.crmType]
+        request({
+          [this.crmType + 'Ids']: this.id
+        })
+          .then(res => {
+            this.$message({
+              type: 'success',
+              message: '删除成功'
+            })
+            this.$emit('handle', { type: type })
+          })
+          .catch(() => {})
+      } else if (type === 'get') {
+        // 领取
+        // crmCustomerReceive({
+        //   ids: this.id
+        // })
+        //   .then(res => {
+        //     this.$message({
+        //       type: 'success',
+        //       message: '操作成功'
+        //     })
+        //     this.$emit('handle', { type: type })
+        //   })
+        //   .catch(() => {})
+      }
+    },
+    hideView () {
+      this.$emit('close')
+    },
+    // 子组件 回调的 结果
+    handleCallBack (data) {
+      this.$emit('handle', { type: data.type })
+    },
+
+    /** 更多操作 */
+    /** 获取展示items */
+    getSelectionHandleItemsInfo () {
+      const handleInfos = {
+        transfer: {
+          name: '转移',
+          type: 'transfer',
+          icon: require('@/assets/img/selection_transfer.png')
+        },
+        transform: {
+          name: '转化为客户',
+          type: 'transform',
+          icon: require('@/assets/img/selection_convert_customer.png')
+        },
+        delete: {
+          name: '删除',
+          type: 'delete',
+          icon: require('@/assets/img/selection_delete.png')
+        },
+        put_seas: {
+          name: '放入公海',
+          type: 'put_seas',
+          icon: require('@/assets/img/selection_putseas.png')
+        },
+        lock: {
+          name: '锁定',
+          type: 'lock',
+          icon: require('@/assets/img/selection_lock.png')
+        },
+        unlock: {
+          name: '解锁',
+          type: 'unlock',
+          icon: require('@/assets/img/selection_unlock.png')
+        },
+        alloc: {
+          name: '分配',
+          type: 'alloc',
+          icon: require('@/assets/img/selection_alloc.png')
+        },
+        get: {
+          name: '领取',
+          type: 'get',
+          icon: require('@/assets/img/selection_get.png')
+        },
+        start: {
+          name: '上架',
+          type: 'start',
+          icon: require('@/assets/img/selection_start.png')
+        },
+        disable: {
+          name: '下架',
+          type: 'disable',
+          icon: require('@/assets/img/selection_disable.png')
+        },
+        deal_status: {
+          name: '更改成交状态',
+          type: 'deal_status',
+          icon: require('@/assets/img/selection_deal_status.png')
+        }
+      }
+      if (this.crmType === 'leads') {
+        return this.forSelectionHandleItems(handleInfos, [
+          'transform',
+          'delete'
+        ])
+      } else if (this.crmType === 'customer') {
+        if (this.isSeas) {
+          return this.forSelectionHandleItems(handleInfos, [
+            'alloc',
+            'get',
+            'delete'
+          ])
+        } else {
+          return this.forSelectionHandleItems(handleInfos, [
+            // 'put_seas',
+            'deal_status',
+            'lock',
+            'unlock',
+            'delete'
+          ])
+        }
+      } else if (this.crmType === 'contacts') {
+        return this.forSelectionHandleItems(handleInfos, ['delete'])
+      } else if (this.crmType === 'business') {
+        return this.forSelectionHandleItems(handleInfos, ['delete'])
+      } else if (this.crmType === 'contract') {
+        return this.forSelectionHandleItems(handleInfos, ['delete'])
+      } else if (this.crmType === 'receivables') {
+        return this.forSelectionHandleItems(handleInfos, ['delete'])
+      } else if (this.crmType === 'product') {
+        return this.forSelectionHandleItems(handleInfos, ['start', 'disable'])
+      }
+    },
+    forSelectionHandleItems (handleInfos, array) {
+      var tempsHandles = []
+      for (let index = 0; index < array.length; index++) {
+        tempsHandles.push(handleInfos[array[index]])
+      }
+      return tempsHandles
+    },
+    // 判断是否展示
+    whetherTypeShowByPermision: function (type) {
+      console.log(type)
+      // if (type === 'transfer') {
+      //   return this.crm[this.crmType].transfer
+      // } else if (type === 'transform') {
+      //   return this.crm[this.crmType].transform
+      // } else if (type === 'export') {
+      //   if (this.isSeas) {
+      //     return this.crm.pool.excelexport
+      //   }
+      //   return this.crm[this.crmType].excelexport
+      // } else if (type === 'delete') {
+      //   if (this.crmType === 'contract') {
+      //     if (this.detail.checkStatus === 6) {
+      //       if (this.detail.isAdmin === 1) {
+      //         return true
+      //       }
+      //       return false
+      //     } else {
+      //       // this.crm[this.crmType].delete
+      //     }
+      //   }
+      //   return this.crm[this.crmType].delete
+      // } else if (type === 'put_seas') {
+      //   // 放入公海(客户)
+      //   return this.crm[this.crmType].putinpool
+      // } else if (type === 'lock' || type === 'unlock') {
+      //   // 锁定解锁(客户)
+      //   return this.crm[this.crmType].lock && this.CRMConfig.customerConfig === 1
+      // } else if (type === 'add_user' || type === 'delete_user') {
+      //   // 添加 移除团队成员
+      //   return this.crm[this.crmType].teamsave
+      // } else if (type === 'alloc') {
+      //   // 分配(公海)
+      //   return this.crm.pool.distribute
+      // } else if (type === 'get') {
+      //   // 领取(公海)
+      //   return this.crm.pool.receive
+      // } else if (type === 'start' || type === 'disable') {
+      //   // 上架 下架(产品)
+      //   return this.crm[this.crmType].status
+      // } else if (type === 'deal_status') {
+      //   // 客户状态修改
+      //   return this.crm[this.crmType].dealStatus
+      // }
+
+      return true
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+.t-section {
+  position: relative;
+  padding: 24px 40px;
+  min-height: 60px;
+  .t-img {
+    display: block;
+    width: 35px;
+    height: 35px;
+    margin-right: 10px;
+  }
+  .t-name {
+    flex: 1;
+    font-size: 18px; /*no*/
+    font-weight: 550;
+    color: #333333;
+  }
+  .t-more {
+    border: 1px solid #dcdfe6;
+    font-size: 12px;
+    color: #606266;
+    padding: 0 10px 0 12px;
+    border-radius: 2px;
+    font-weight: 500;
+    height: 25px;
+    cursor: pointer;
+  }
+  .t-close {
+    display: block;
+    width: 50px;
+    height: 50px;
+    margin-left: 20px;
+    padding: 10px;
+    cursor: pointer;
+  }
+}
+
+.h-section {
+  position: relative;
+  padding: 10px 0;
+  min-height: 58px;
+  .h-item {
+    .h-title {
+      font-size: 12px;
+      color: #777;
+    }
+    .h-value {
+      min-height: 14px;
+      margin-top: 8px;
+      font-size: 13px;
+      color: #333333;
+    }
+  }
+}
+.head-handle-button {
+  padding: 5px 15px;
+  margin-right: 10px;
+}
+</style>
diff --git a/src/views/clients/components/CRMExport.vue b/src/views/clients/components/CRMExport.vue
new file mode 100644
index 0000000..add542a
--- /dev/null
+++ b/src/views/clients/components/CRMExport.vue
@@ -0,0 +1,340 @@
+<template>
+  <el-dialog
+    :visible.sync="showDialog"
+    :title="'导出'+crmTypeName"
+    :append-to-body="true"
+    :close-on-click-modal="false"
+    :before-close="beforeClose"
+    :close-on-press-escape="false"
+    width="550px"
+    @close="closeView"
+  >
+    <div class="dialog-body">
+      <p
+        v-if="error"
+        class="error"
+        v-text="error" />
+      <p
+        v-if="done"
+        class="done">
+        <i class="el-icon-success"/>
+        导出已完成
+      </p>
+      <p
+        v-else-if="cancel"
+        class="cancel">
+        <i class="el-icon-warning"/>
+        导出已取消
+      </p>
+      <div v-else>
+        <i class="el-icon-loading" />
+        导出中...
+        {{ progress }}
+      </div>
+    </div>
+    <span slot="footer" class="dialog-footer" />
+  </el-dialog>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+import {
+  OutputCustomerToExcel,
+  OutputContacterToExcel,
+  OutputSalesChanceToExcel,
+  OutputOtherSalesChanceToExcel,
+  DownloadSubscriptions
+} from '@/api/common'
+
+export default {
+  name: 'CRMExport', // 文件导出
+  components: {},
+
+  props: {
+    show: {
+      type: Boolean,
+      default: false
+    },
+    // CRM类型
+    crmType: {
+      type: String,
+      default: ''
+    },
+    /** 是公海 */
+    isSeas: {
+      type: Boolean,
+      default: false
+    },
+    // 搜索条件
+    search: {
+      type: String,
+      default: ''
+    },
+    // 场景
+    scene_id: {
+      type: [Number, String],
+      default: ''
+    },
+    // 高级搜索
+    filterObj: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    // 顶部搜索
+    headObj: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    exportParams: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  data () {
+    return {
+      showDialog: false,
+      progress: '',
+      error: '',
+      // 导出已完成
+      done: false,
+      // 取消导出
+      cancel: false,
+      // 队列标识
+      exportQueueIndex: '',
+      // 临时数据
+      tempData: {
+        temp_file: ''
+      },
+      // 排序
+      sortData: {}
+    }
+  },
+  computed: {
+    ...mapGetters(['userInfo']),
+    crmTypeName () {
+      return (
+        {
+          customer: '客户',
+          leads: '线索',
+          contacts: '联系人',
+          product: '产品'
+        }[this.crmType] || ''
+      )
+    }
+  },
+  watch: {
+    show (val) {
+      console.log(val)
+      this.showDialog = val
+      if (val) {
+        this.cancel = false
+        this.exportInfos()
+        // window.onbeforeunload = (event) => {
+        //   this.exportInfos({
+        //     page: -1,
+        //     temp_file: this.tempData.temp_file
+        //   })
+        //   return event
+        // }
+      } else {
+        window.onbeforeunload = null
+      }
+    }
+  },
+  mounted () {
+    this.$bus.off('getSortData')
+    this.$bus.on('getSortData', (sortData) => {
+      this.sortData = sortData
+    })
+  },
+  methods: {
+    // 关闭操作
+    closeView () {
+      this.error = ''
+      this.done = false
+      this.exportQueueIndex = ''
+      this.progress = ''
+      this.$emit('close')
+      this.$emit('queryList')
+    },
+    // 点叉
+    beforeClose (done) {
+      if (this.error || this.done) {
+        done()
+        return
+      }
+      this.$confirm('此操作将终止导出, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          this.cancel = true
+          done()
+        })
+        .catch(() => {
+        })
+    },
+    // 导出操作
+    exportInfos (data = {}) {
+      console.log(this.headObj)
+      let params
+      if (this.crmType === 'customer') {
+        params = {
+          'PageIndex': 1,
+          'PageSize': 999,
+          'SelectOwnedType': this.headObj && this.headObj.list ? this.headObj.list.customer : 0,
+          'BrachUserId': this.headObj && this.headObj.list ? this.headObj.list.BrachUserId : '',
+          'Name': this.headObj && this.headObj.list ? this.headObj.list.user : '',
+          'CreateStartTime': '',
+          'CreateEndTime': '',
+          'StartFollowTime': '',
+          'EndFolowTime': ''
+        }
+      } else if (this.crmType === 'contacts') {
+        params = {
+          'PageIndex': 1,
+          'PageSize': 999,
+          'SelectOwnedType': this.headObj && this.headObj.list ? this.headObj.list.customer : 0,
+          'BrachUserId': this.headObj && this.headObj.list ? this.headObj.list.BrachUserId : '',
+          'Name': this.headObj && this.headObj.list ? this.headObj.list.user : ''
+        }
+      } else if (this.crmType === 'business') {
+        params = {
+          'PageIndex': 1,
+          'PageSize': 999,
+          'SalesChanceStage': this.headObj && this.headObj.list ? this.headObj.list.businessType : '',
+          'SelectOwnedType': this.headObj && this.headObj.list ? this.headObj.list.customer : 0,
+          'BrachUserId': this.headObj && this.headObj.list ? this.headObj.list.BrachUserId : '',
+          'Name': this.headObj && this.headObj.list ? this.headObj.list.user : '',
+          'SalesChanceType': this.headObj && this.headObj.list ? this.headObj.list.businessType : '',
+          'ProvinceCode': this.headObj && this.headObj.list ? this.headObj.list.area : ''
+        }
+      } else if (this.crmType === 'businessChances') {
+        params = {
+          'PageIndex': 1,
+          'PageSize': 999,
+          'SalesChanceStage': this.headObj && this.headObj.list ? this.headObj.list.businessType : '',
+          'SelectOwnedType': this.headObj && this.headObj.list ? this.headObj.list.customer : 0,
+          'BrachUserId': this.headObj && this.headObj.list ? this.headObj.list.BrachUserId : '',
+          'Name': this.headObj && this.headObj.list ? this.headObj.list.user : '',
+          'SalesChanceType': this.headObj && this.headObj.list ? this.headObj.list.businessType : '',
+          'ProvinceCode': this.headObj && this.headObj.list ? this.headObj.list.area : '',
+          'CreateStartTime': '',
+          'CreateEndTime': '',
+          'ProjectProperty': '',
+          'UploadStatusName': '',
+          'ReportStatusName': ''
+        }
+      } else if (this.crmType === 'subscriptions') {
+        params = {
+          'taskId': this.headObj ? this.headObj.taskId : ''
+        }
+      }
+      let month = new Date().getMonth() + 1
+      let timer = new Date().getFullYear() + '-' + month + '-' + new Date().getDate()
+      let request
+      request = {
+        customer: OutputCustomerToExcel,
+        contacts: OutputContacterToExcel,
+        business: OutputSalesChanceToExcel,
+        businessChances: OutputOtherSalesChanceToExcel,
+        subscriptions: DownloadSubscriptions
+      }[this.crmType]
+      console.log(request)
+      request(params)
+        .then(res => {
+          this.exportQueueIndex = ''
+          this.done = true
+          var blob
+          if (res.data === 'subscriptions') {
+            blob = new Blob([res.data], {
+              type: 'application/octet-stream;charset=utf-8'
+            })
+          } else {
+            blob = new Blob([res.data], {
+              type: 'application/vnd.ms-excel;charset=utf-8'
+            })
+          }
+          // var blob = new Blob([res.data], {
+          //   type: 'application/json'
+          // })
+          var downloadElement = document.createElement('a')
+          var href = window.URL.createObjectURL(blob) // 创建下载的链接
+          downloadElement.href = href
+          // downloadElement.download =
+          //     decodeURI(
+          //       res.headers['content-disposition'].split('filename=')[1]
+          //     ) || '' // 下载后文件名
+          if (this.crmType === 'customer') {
+            downloadElement.download = `客户列表` + timer + `.xlsx`
+          } else if (this.crmType === 'business') {
+            downloadElement.download = `商机列表` + timer + `.xlsx`
+          } else if (this.crmType === 'contacts') {
+            downloadElement.download = `客户联系人列表` + timer + `.xlsx`
+          } else if (this.crmType === 'subscriptions') {
+            downloadElement.download = `订阅列表` + timer + `.zip`
+          } else {
+            downloadElement.download = `列表` + timer + `.xlsx`
+          }
+          document.body.appendChild(downloadElement)
+          downloadElement.click() // 点击下载
+          document.body.removeChild(downloadElement) // 下载完成移除元素
+          window.URL.revokeObjectURL(href) // 释放掉blob对象
+          // }
+        })
+        .catch(() => {
+        })
+    }
+  }
+}
+</script>
+
+<style scoped lang="less">
+
+.dialog-body {
+  height: 150px;
+  text-align: center;
+  padding-top: 40px;
+  color: #659DED;
+  .el-icon-loading {
+    margin-bottom: 10px;
+    display: block;
+  }
+  p.error {
+    color: #E6A23C;
+  }
+  p.done {
+    color: #67C23A;
+    .el-icon-success {
+      font-size: 30px;
+      display: block;
+    }
+  }
+}
+
+.cancel {
+  color: #E6A23C;
+  .el-icon-warning {
+    font-size: 30px;
+    display: block;
+  }
+}
+
+.el-dialog__wrapper {
+  /deep/ .el-icon-loading {
+    font-size: 30px;
+  }
+
+  /deep/ .el-loading-text {
+    font-size: 18px;
+    margin-top: 10px;
+  }
+}
+</style>
diff --git a/src/views/clients/components/CRMFullScreenDetail.vue b/src/views/clients/components/CRMFullScreenDetail.vue
new file mode 100644
index 0000000..08da530
--- /dev/null
+++ b/src/views/clients/components/CRMFullScreenDetail.vue
@@ -0,0 +1,161 @@
+<template>
+  <div
+    v-show="visible"
+    class="full-container">
+    <component
+      v-if="id&&showDetail"
+      :is="tabName"
+      :crm-type="crmType"
+      :id="id"
+      class="d-view"
+      @handle="detailHandle"
+      @hide-view="hiddenView"/>
+  </div>
+</template>
+
+<script type="text/javascript">
+import { getMaxIndex } from '@/utils/index'
+import ClueDetail from '../clue/ClueDetail'
+import CustomerDetail from '../customer/CustomerDetail'
+import ContactsDetail from '../contacts/ContactsDetail'
+import BusinessDetail from '../business/BusinessDetail'
+import BusinessCustomerDetail from '../businessCustomer/BusinessCustomerDetail'
+import BusinessChancesDetail from '../businessChances/BusinessChancesDetail'
+// import ContractDetail from '../contract/ContractDetail'
+// import ProductDetail from '../product/ProductDetail'
+// import MoneyDetail from '../money/MoneyDetail'
+// import ExamineDetail from '@/views/OAManagement/examine/components/examineDetail'
+
+export default {
+  name: 'CRMFullScreenDetail', // 客户管理下 重要提醒 回款计划提醒
+  components: {
+    ClueDetail,
+    CustomerDetail,
+    ContactsDetail,
+    BusinessDetail,
+    BusinessCustomerDetail,
+    BusinessChancesDetail
+    // ContractDetail,
+    // ProductDetail,
+    // MoneyDetail,
+    // ExamineDetail
+  },
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    visible: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    return {
+      showDetail: false
+    }
+  },
+  computed: {
+    tabName () {
+      if (this.crmType === 'leads') {
+        return 'clue-detail'
+      } else if (this.crmType === 'customer') {
+        return 'customer-detail'
+      } else if (this.crmType === 'contacts') {
+        return 'contacts-detail'
+      } else if (this.crmType === 'business') {
+        return 'business-detail'
+      } else if (this.crmType === 'contract') {
+        return 'contract-detail'
+      } else if (this.crmType === 'product') {
+        return 'product-detail'
+      } else if (this.crmType === 'receivables') {
+        return 'money-detail'
+      } else if (this.crmType === 'examine') {
+        return 'examine-detail'
+      } else if (this.crmType === 'businessCustomer') {
+        return 'business-customer-detail'
+      } else if (this.crmType === 'businessChances') {
+        return 'business-chances-detail'
+      }
+      return ''
+    }
+  },
+  watch: {
+    visible (val) {
+      this.showDetail = val
+      if (val) {
+        document.body.appendChild(this.$el)
+        this.$el.addEventListener('click', this.handleDocumentClick, false)
+        this.$el.style.zIndex = getMaxIndex()
+      }
+    },
+    showDetail (val) {
+      if (!val) {
+        setTimeout(() => {
+          this.$emit('update:visible', false)
+        }, 350)
+      }
+    }
+  },
+  mounted () {
+    if (this.visible) {
+      document.body.appendChild(this.$el)
+      this.$el.addEventListener('click', this.handleDocumentClick, false)
+      this.$el.style.zIndex = getMaxIndex()
+    }
+  },
+
+  beforeDestroy () {
+    // remove DOM node after destroy
+    if (this.$el && this.$el.parentNode) {
+      this.$el.parentNode.removeChild(this.$el)
+      this.$el.removeEventListener('click', this.handleDocumentClick, false)
+    }
+  },
+  methods: {
+    hiddenView () {
+      this.showDetail = false
+    },
+    handleDocumentClick (e) {
+      e.stopPropagation()
+      if (this.$el === e.target) {
+        this.showDetail = false
+      }
+    },
+
+    /**
+     * 详情操作
+     */
+    detailHandle (data) {
+      if (data.type === 'alloc' || data.type === 'get' || data.type === 'transfer' || data.type === 'transform' || data.type === 'delete' || data.type === 'put_seas') {
+        this.showDetail = false
+      }
+      this.$emit('handle', data)
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.full-container {
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  overflow: auto;
+  margin: 0;
+  background-color: rgba(0, 0, 0, 0.3);
+}
+
+.d-view {
+  position: fixed;
+  width: 1000px;
+  top: 0px;
+  bottom: 0px;
+  right: 0px;
+}
+</style>
diff --git a/src/views/clients/components/CRMImport.vue b/src/views/clients/components/CRMImport.vue
new file mode 100644
index 0000000..6b20ff8
--- /dev/null
+++ b/src/views/clients/components/CRMImport.vue
@@ -0,0 +1,804 @@
+<template>
+  <el-dialog
+    :visible="show"
+    :title="'导入'+crmTypeName"
+    :append-to-body="true"
+    :close-on-click-modal="false"
+    width="600px"
+    class='importDialog'
+    @close="closeView">
+    <div class="dialog-body">
+       <el-steps
+        :active="stepsActive"
+        align-center>
+        <el-step
+          v-for="(item, index) in stepList"
+          :key="index"
+          :title="item.title"
+          :status="item.status">
+          <i class="icon-stepicon" slot="icon"></i>
+        </el-step>
+      </el-steps>
+
+      <div v-if="stepsActive === 1" class="step-section">
+        <div class="sections">
+          <div class="sections__title"><span class='singleNum'>①</span> 请按照数据模板的格式准备要导入的数据<span
+            class="download"
+            @click="download">下载模板</span></div>
+          <!--<div class="sections__tips">导入文件请勿超过2MB(约10,000条数据)</div>-->
+        </div>
+        <div class="sections">
+          <div class="sections__title"><span class='singleNum'>②</span> 请选择数据重复时的处理方式<span class='rules'>查重规则:<span class='rulesName'>{{ fieldUniqueInfo }}</span></span></div>
+          <!--<div class="sections__tips">查重规则为:添加{{ crmTypeName }}时所需填写的所有唯一字段,当前设置唯一字段为:{{ fieldUniqueInfo }}</div> -->
+          <div class="content">
+            <el-select
+              v-model="config"
+              placeholder="请选择">
+              <el-option
+                v-for="(item, index) in [{name: '覆盖系统原有数据',value: 1},{name: '跳过',value: 2}]"
+                :key="index"
+                :label="item.name"
+                :value="item.value"/>
+            </el-select>
+          </div>
+        </div>
+        <div class="sections">
+          <div class="sections__title"><span class='singleNum'>③</span> 请选择需要导入的文件</div>
+          <div class="content">
+            <flexbox class="file-select">
+              <el-input
+                v-model="file.name"
+                :disabled="true"/>
+              <el-button
+                type="primary"
+                @click="selectFile">选择文件</el-button>
+            </flexbox>
+          </div>
+        </div>
+        <!--<div class="sections">
+          <div class="sections__title">四、请选择负责人({{ crmType === 'customer' ? '如不选择,导入的客户将进入公海' : '必选' }})</div>
+          <div class="content">
+            <div class="user-cell">
+              <xh-user-cell
+                :value="user"
+                @value-change="userSelect"/>
+            </div>
+          </div>
+        </div>-->
+      </div>
+
+      <div
+        v-loading="loading"
+        v-else-if="stepsActive === 2"
+        element-loading-text="正在导入数据"
+        element-loading-spinner="el-icon-loading"
+        class="step-section" />
+
+      <div
+        v-loading="loading"
+        v-else-if="stepsActive === 3"
+        class="step-section">
+        <div class="result-info">
+          <i class="wk wk-success result-info__icon" />
+          <p class="result-info__des">数据导入完成</p>
+          <p class="result-info__detail">导入总数据<span class="result-info__detail--all">{{ resultData.ImportCount }}</span>条,导入成功<span class="result-info__detail--suc">{{ resultData.SuccessCount }}</span>条,导入失败<span class="result-info__detail--err">{{ resultData.ErrorCount }}</span>条</p>
+          <!--<el-button
+            v-if="resultData && resultData.ErrorCount > 0"
+            class="result-info__btn--err"
+            type="text"
+            @click="downloadErrData">下载错误数据</el-button> -->
+        </div>
+      </div>
+
+      <input
+        id="importInputFile"
+        type="file"
+        accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
+        @change="uploadFile">
+    </div>
+    <span
+      slot="footer"
+      class="dialog-footer">
+      <el-popover
+        v-model="historyPopoverShow"
+        placement="top"
+        width="800"
+        popper-class="no-padding-popover"
+        trigger="click">
+        <!-- <c-r-m-import-history
+          :show="historyPopoverShow"
+          :crm-type="crmType"
+          @close="historyPopoverShow = false" />
+        <el-button
+          slot="reference"
+          class="history-btn"
+          type="text">查看历史导入记录</el-button> -->
+      </el-popover>
+
+      <el-button
+        :class="{ 'is-hidden': !showCancel }"
+        @click="closeView">取消</el-button>
+      <el-button
+        v-if="sureTitle"
+        type="primary"
+        @click="sureClick">{{ sureTitle }}</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+import {
+  ImportCustomerExcel,
+  ImportContacterExcel,
+  ImportSalesChanceExcel,
+  DownloadCustomerExcelModel,
+  DownloadContacgerExcelModel,
+  DownloadSalesChanceExcelModel
+} from '@/api/common'
+// import {
+//   crmCustomerExcelImport,
+//   crmCustomerDownloadExcelAPI
+// } from '@/api/customermanagement/customerManage'
+// import {
+//   crmLeadsExcelImport,
+//   crmLeadsDownloadExcelAPI
+// } from '@/api/clients/clue'
+// import {
+//   crmContactsExcelImport,
+//   crmContactsDownloadExcelAPI
+// } from '@/api/clients/contacts'
+// import {
+//   crmProductExcelImport,
+//   crmProductDownloadExcelAPI
+// } from '@/api/clients/product'
+
+import { XhUserCell } from '@/components/CreateCom'
+// import CRMImportHistory from './CRMImportHistory'
+
+// import { mapGetters } from 'vuex'
+// import crmTypeModel from '@/views/clients/model/crmTypeModel'
+// import { downloadExcelWithResData } from '@/utils/index'
+
+export default {
+  name: 'CRMImport', // 文件导入
+  components: {
+    XhUserCell
+  },
+  props: {
+    show: {
+      type: Boolean,
+      default: false
+    },
+    // CRM类型
+    crmType: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      loading: false,
+      fieldList: [],
+      config: 1, // 1 覆盖,2跳过
+      file: { name: '' },
+      user: [],
+
+      stepsActive: 1,
+      stepList: [
+        {
+          title: '上传文件',
+          status: 'wait'
+        },
+        {
+          title: '导入数据',
+          status: 'wait'
+        },
+        {
+          title: '导入完成',
+          status: 'wait'
+        }
+      ],
+      resultData: null,
+      processData: {
+        count: 0,
+        status: ''
+      },
+      messageId: null,
+      intervalTimer: null,
+
+      historyPopoverShow: false
+    }
+  },
+  computed: {
+    // ...mapGetters(['userInfo']),
+
+    crmTypeName () {
+      return (
+        {
+          customer: '客户',
+          leads: '线索',
+          contacts: '联系人',
+          product: '产品'
+        }[this.crmType] || ''
+      )
+    },
+
+    sureTitle () {
+      return {
+        1: '导入',
+        2: '',
+        3: ''
+      }[this.stepsActive]
+    },
+
+    showCancel () {
+      return this.stepsActive !== 2
+    },
+
+    fieldUniqueInfo () {
+      return (
+        {
+          customer: '客户名称',
+          contacts: '联系人',
+          business: '商机名称'
+        }[this.crmType] || '无'
+      )
+    }
+  },
+  watch: {
+    show: function (val) {
+      if (val) {
+        if (this.stepsActive === 1) {
+          // if (this.userInfo) {
+          //   this.user = [this.userInfo]
+          // }
+        }
+
+        this.getField()
+      } else {
+        if (this.stepsActive === 3) {
+          this.resetData()
+        }
+
+        this.fieldList = []
+      }
+    },
+
+    stepsActive () {
+      this.$emit('status', {
+        1: 'wait',
+        2: 'process',
+        3: 'finish'
+      }[this.stepsActive])
+    }
+
+    // file() {
+    //   this.getFirstStepStatus()
+    // },
+
+    // user() {
+    //   this.getFirstStepStatus()
+    // }
+
+  },
+  mounted () {
+  },
+  methods: {
+    sureClick () {
+      if (this.stepsActive === 1) {
+        if (this.stepList[0].status === 'finish') {
+          this.stepList[1].status = 'process'
+          this.stepsActive = 2
+          this.firstUpdateFile(res => {
+            // this.messageId = res.data.Message
+            console.log(res)
+            if (res === false) {
+              this.secondQueryNum(res)
+            } else {
+              this.secondQueryNum(res.data.Result)
+            }
+
+            this.intervalTimer = setInterval(() => {
+              if (this.processData.status === 'end') {
+                clearInterval(this.intervalTimer)
+                this.intervalTimer = null
+                if (res === false) {
+                  this.thirdQueryResult(res)
+                } else {
+                  this.thirdQueryResult(res.data.Result)
+                }
+              } else {
+                this.secondQueryNum()
+              }
+            }, 2000)
+          })
+        } else {
+          if (!this.file.name) {
+            this.$message.error('请选择导入文件')
+          }
+          // else if (
+          //   this.crmType !== 'customer' &&
+          //   (!this.user || this.user.length === 0)
+          // ) {
+          //   this.$message.error('请选择负责人')
+          // }
+        }
+      } else {
+        this.closeView()
+      }
+    },
+
+    /**
+     * 第一步上传
+     */
+    firstUpdateFile (result) {
+      var params = {}
+      params.excelImportType = this.config
+      params.file = this.file
+      console.log(params)
+      // params.ownerUserId = this.user.length > 0 ? this.user[0].userId : ''
+      var request = {
+        customer: ImportCustomerExcel,
+        // leads: crmLeadsExcelImport,
+        contacts: ImportContacterExcel,
+        business: ImportSalesChanceExcel
+      }[this.crmType]
+      this.loading = true
+      request(params)
+        .then(res => {
+          if (res.data.ErrorCode === 500) {
+            if (result) {
+              result(false)
+            }
+            this.loading = false
+          } else {
+            if (result) {
+              result(res)
+            }
+          }
+        })
+        .catch(() => {
+          if (result) {
+            result(false)
+          }
+          this.loading = false
+        })
+    },
+
+    /**
+     * 第二步查询数量
+     */
+    secondQueryNum (res) {
+      if (!res) {
+        this.processData.status = 'end'
+      } else {
+        this.processData.status = 'end'
+        this.processData.count = res.CoverCount
+      }
+      // crmQueryImportNumAPI({ messageId: this.messageId })
+      //   .then(res => {
+      //     if (res.data === null) {
+      //       this.processData.status = 'end'
+      //     } else {
+      //       this.processData.status = ''
+      //       this.processData.count = res.data
+      //     }
+      //   })
+      //   .catch(() => {
+      //     // this.processData.status = 'err'
+      //   })
+    },
+
+    /**
+     * 第三部 查询结果
+     */
+    thirdQueryResult (res) {
+      this.loading = false
+      this.stepList[1].status = 'finish'
+      this.stepsActive = 3
+      this.$emit('status', 'finish')
+      if (!res) {
+        this.stepList[2].status = 'error'
+        this.resultData = [{'ImportCount': '0', 'SuccessCount': '0', 'ErrorCount': '0'}]
+      } else {
+        this.resultData = res
+        if (res.ErrorCount && res.ErrorCount > 0) {
+          this.stepList[2].status = 'error'
+        } else {
+          this.stepList[2].status = 'finish'
+        }
+      }
+
+      // crmQueryImportInfoAPI({ messageId: this.messageId })
+      //   .then(res => {
+      //     this.loading = false
+      //     this.stepList[1].status = 'finish'
+      //     this.stepsActive = 3
+      //     this.$emit('status', 'finish')
+      //     if (res) {
+      //       this.resultData = res
+      //       if (res.errSize > 0) {
+      //         this.stepList[2].status = 'error'
+      //       } else {
+      //         this.stepList[2].status = 'finish'
+      //       }
+      //     }
+      //   })
+      //   .catch(() => {})
+    },
+
+    /**
+     * 下载错误模板
+     */
+    downloadErrData () {
+      this.loading = true
+      // crmDownImportErrorAPI({ messageId: this.messageId })
+      //   .then(res => {
+      //     downloadExcelWithResData(res)
+      //     this.loading = false
+      //   })
+      //   .catch(() => {
+      //     this.loading = false
+      //   })
+    },
+
+    // 下载模板操作
+    download () {
+      let timer = new Date().getFullYear() + '-' + new Date().getMonth() + '-' + new Date().getDate()
+      const request = {
+        customer: DownloadCustomerExcelModel,
+        // leads: crmLeadsDownloadExcelAPI,
+        contacts: DownloadContacgerExcelModel,
+        business: DownloadSalesChanceExcelModel
+      }[this.crmType]
+      request()
+        .then(res => {
+          var blob = new Blob([res.data], {
+            type: 'application/vnd.ms-excel;charset=utf-8'
+          })
+          var downloadElement = document.createElement('a')
+          var href = window.URL.createObjectURL(blob) // 创建下载的链接
+          downloadElement.href = href
+          // downloadElement.download =
+          //   decodeURI(
+          //     res.headers['content-disposition'].split('filename=')[1]
+          //   ) || '' // 下载后文件名
+          downloadElement.download = this.crmType === 'customer' ? `客户导入模板` + timer + `.xlsx` : `客户联系人导入模板` + timer + `.xlsx`
+          document.body.appendChild(downloadElement)
+          downloadElement.click() // 点击下载
+          document.body.removeChild(downloadElement) // 下载完成移除元素
+          window.URL.revokeObjectURL(href) // 释放掉blob对象
+        })
+        .catch(() => {})
+    },
+    // 选择文件
+    selectFile () {
+      document.getElementById('importInputFile').click()
+    },
+    /** 图片选择出发 */
+    uploadFile (event) {
+      var files = event.target.files
+      const file = files[0]
+      console.log(file)
+      this.file = file
+      event.target.value = ''
+
+      // 阶段一状态
+      this.getFirstStepStatus()
+    },
+    // 用户选择
+    userSelect (data) {
+      if (data.value && data.value.length > 0) {
+        this.user = data.value
+      } else {
+        this.user = []
+      }
+
+      // 阶段一状态
+      this.getFirstStepStatus()
+    },
+
+    getFirstStepStatus () {
+      console.log(this.file)
+      // 阶段一状态
+      const hasFile = this.file && this.file.size
+      // const hasUser = this.user && this.user.length > 0
+
+      if (this.crmType === 'customer') {
+        this.stepList[0].status = hasFile ? 'finish' : 'wait'
+      } else {
+        this.stepList[0].status = hasFile ? 'finish' : 'wait'
+      }
+    },
+
+    // 关闭操作
+    closeView () {
+      this.$emit('update:show', false)
+      this.$emit('close', this.stepsActive === 3 ? 'finish' : '')
+      this.$emit('queryList')
+    },
+
+    /**
+     * 重置页面数据
+     */
+    resetData () {
+      this.config = 1
+      this.file = { name: '' }
+      this.user = []
+
+      this.stepsActive = 1
+      this.stepList = [
+        {
+          title: '上传文件',
+          status: 'wait'
+        },
+        {
+          title: '导入数据',
+          status: 'wait'
+        },
+        {
+          title: '导入完成',
+          status: 'wait'
+        }
+      ]
+      this.resultData = null
+      this.processData = {
+        count: 0,
+        status: ''
+      }
+      this.messageId = null
+    },
+
+    /**
+     * 获取验证字段
+     */
+    getField () {
+      // var params = {
+      //   label: crmTypeModel[this.crmType]
+      // }
+
+      // filedGetField(params)
+      //   .then(res => {
+      //     this.fieldList = res.data
+      //   })
+      //   .catch(() => {
+      //   })
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.importDialog{
+  /deep/ .el-dialog__title{
+    font-size: 18px;
+    font-weight: 500;
+    color: #333333;
+  }
+  /deep/ .el-dialog__headerbtn .el-dialog__close{
+    font-size: 18px;
+  }
+  /deep/ .el-dialog__footer{
+    text-align: center;
+  }
+}
+.el-steps {
+  margin-bottom: 15px;
+
+  /deep/ .el-step__title {
+    font-size: 14px;
+  }
+
+  /deep/ .el-step.is-simple .el-step__arrow::before,
+  /deep/ .el-step.is-simple .el-step__arrow::after {
+    height: 10px;
+    width: 2px;
+  }
+
+  /deep/ .el-step.is-simple .el-step__arrow::after {
+    transform: rotate(45deg) translateY(3px);
+  }
+  /deep/ .el-step.is-simple .el-step__arrow::before {
+    transform: rotate(-45deg) translateY(-2px);
+  }
+}
+
+.step-section {
+  min-height: 300px;
+
+  /deep/ .el-loading-spinner {
+    top: 45%;
+    .el-icon-loading {
+      font-size: 40px;
+      color: #999;
+    }
+
+    .el-loading-text {
+      color: #333;
+    }
+  }
+}
+
+.sections {
+  font-size: 14px;
+  color: #333;
+  font-weight: 400;
+  margin-bottom: 40px;
+  .singleNum{
+    font-size: 16px;
+    font-weight: 500;
+    color: #4D88FF;
+    margin-right:8px;
+  }
+  &__title {
+    font-weight: 600;
+  }
+
+  &__tips {
+    padding-left: 30px;
+    margin: 8px 0 15px;
+    color: #999;
+    font-size: 12px;
+    line-height: 1.4;
+  }
+  .rules{
+    margin-left: 40px;
+    .rulesName{
+      color: #FF8A04;
+    }
+  }
+  .download {
+    display: inline-block;
+    cursor: pointer;
+    width: 78px;
+    height: 24px;
+    background: #FFFFFF;
+    border-radius: 4px;
+    border: 1px solid #4D88FF;
+    font-size: 12px;
+    font-weight: 400;
+    color: #4D88FF;
+    text-align: center;
+    line-height: 24px;
+    margin-left: 40px;
+  }
+
+}
+
+.sections__tips + .content {
+  padding-top: 0;
+}
+
+.content {
+  padding: 10px 10px 10px 30px;
+  .el-select {
+    width: 320px;
+    height: 36px;
+    /deep/ .el-input--suffix .el-input__inner{
+      height: 36px;
+    }
+  }
+  .user-cell {
+    width: 400px;
+  }
+}
+
+#importInputFile {
+  display: none;
+}
+
+.file-select {
+  .el-input {
+    width: 400px;
+  }
+  button {
+    margin-left: 20px;
+    width: 78px;
+    height: 32px;
+    background: #4D88FF;
+    border-radius: 3px;
+  }
+}
+
+.is-hidden {
+  visibility: hidden;
+}
+
+.history-btn {
+  float: left;
+  margin-left: 15px;
+}
+
+// 结果信息
+.result-info {
+  text-align: center;
+  padding-top: 80px;
+
+  &__icon {
+    font-size: 40px;
+    color: #ff6a00;
+  }
+
+  &__des {
+    margin-top: 15px;
+    color: #333;
+    font-size: 14px;
+  }
+
+  &__detail {
+    margin-top: 15px;
+    font-size: 12px;
+    color: #666;
+    &--all {
+      color: #333;
+      font-weight: 600;
+    }
+
+    &--suc {
+      color: #ff6a00;
+      font-weight: 600;
+    }
+
+    &--err {
+      color: #f94e4e;
+      font-weight: 600;
+    }
+  }
+
+  &__btn--err {
+    margin-top: 10px;
+  }
+}
+.icon-stepicon{
+  width: 20px;
+  height: 20px;
+  background-size: 100% 100%;
+  background: url('../../../assets/img/step_wait.png') no-repeat;
+}
+/deep/ .el-steps{
+  // width: 80%;
+  .el-step.is-horizontal .el-step__line{
+    top: 40%;
+    left: 94px;
+    height: 1px;
+    // right: 48px;
+  }
+  .el-step__icon.is-text{
+    border: 0;
+  }
+  .el-step__head.is-process{
+    border-color: #dedede;
+  }
+  .el-step__head.is-finish{
+    border-color: #285edf;
+  }
+  .el-step__title.is-process{
+    color: #dedede;
+  }
+  .el-step__title.is-finish{
+    color: #285edf;
+  }
+  .el-step__title.is-success{
+    color: #4D88FF;
+  }
+  .el-step__icon{
+    width:20px;
+    height:20px;
+  }
+  .is-finish .icon-stepicon{
+    width: 20px;
+    height: 20px;
+    background-size: 100% 100%;
+    background-image: url("../../../assets/img/step_success.png");
+  }
+  .is-success .el-step__icon-inner{
+    width: 20px;
+    height: 20px;
+    background-size: 100% 100%;
+    background-image: url("../../../assets/img/step_success.png");
+  }
+  .is-success .el-icon-check:before{
+    content:''
+  }
+}
+</style>
diff --git a/src/views/clients/components/CRMListHead.vue b/src/views/clients/components/CRMListHead.vue
new file mode 100644
index 0000000..7e3975d
--- /dev/null
+++ b/src/views/clients/components/CRMListHead.vue
@@ -0,0 +1,74 @@
+<template>
+  <div class="c-container">
+   <el-breadcrumb separator="/" class="el-breadcrumb titleIcon">
+      <!--<el-breadcrumb-item :to="{ path: '/welcome' }">首页</el-breadcrumb-item> -->
+      <span class='seperate'></span>
+      <el-breadcrumb-item>{{ mainTitle }}</el-breadcrumb-item>
+      <el-breadcrumb-item class='blueTitle'>{{ title }}</el-breadcrumb-item>
+    </el-breadcrumb>
+  </div>
+</template>
+
+<script type="text/javascript">
+export default {
+  name: 'CRMListHead', // 面包屑
+  props: {
+    title: {
+      type: String,
+      default: ''
+    },
+    mainTitle: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return { }
+  },
+  mounted () {
+  },
+  methods: {
+  }
+}
+</script>
+<style lang="less" scoped>
+.c-container {
+  position: relative;
+  z-index: 100;
+  // margin-bottom: 16px;
+  .titleIcon{
+    /deep/ .el-breadcrumb__inner{
+      font-weight: 400;
+      color: #666666;
+      font-size: 14px;
+    }
+    .blueTitle{
+      /deep/ .el-breadcrumb__inner{
+        color: #4D88FF;
+      }
+    }
+  }
+  .seperate{
+    width: 2px;
+    height: 16px;
+    background: #4D88FF;
+    border-radius: 10px;
+    display: inline-block;
+    float: left;
+    margin-right: 6px;
+  }
+  .title {
+    float: left;
+    padding: 0 20px;
+    font-size: 18px;
+    line-height: 60px;
+  }
+  .sc-container {
+    width: 300px;
+    margin: -18px 0 0 -150px;
+    position: absolute;
+    left: 50%;
+    top: 50%;
+  }
+}
+</style>
diff --git a/src/views/clients/components/CRMTableFilter.vue b/src/views/clients/components/CRMTableFilter.vue
new file mode 100644
index 0000000..f11d091
--- /dev/null
+++ b/src/views/clients/components/CRMTableFilter.vue
@@ -0,0 +1,221 @@
+<template>
+  <el-popover placement="bottom" width="200" trigger="manual" v-model="visible" @show="showPopover">
+    <el-select
+      v-if="tableType === '企业性质' || tableType === '项目属性' ||tableType === '提交' || tableType === '审批' || tableType === '合同类型'"
+      v-model="value"
+      filterable
+      placeholder="请选择"
+      style='width: 100%;'
+      @change='getSelect'>
+      <el-option
+        v-for="(optionItem, index) in optionsList"
+        :key="index"
+        :label="optionItem"
+        :value="optionItem"/>
+    </el-select>
+    <el-cascader
+      v-if="tableType === '行业细分'"
+      ref="salesCas"
+      :show-all-levels="false"
+      placeholder="请选择行业细分"
+      :options="optionsList"
+      :props="{
+        children: 'children',
+        label: 'Name',
+        value: 'Name'
+      }"
+      v-model="casVal"
+      style="width: 100%;"
+      @change='getCas'/>
+      <el-select
+        v-if="tableType === '商机类型'"
+        v-model="busType"
+        filterable
+        placeholder="请选择"
+        style='width: 100%;'
+        @change='getSelect'>
+        <el-option
+          v-for="(optionItem, index) in optionsList"
+          :key="index"
+          :label="optionItem"
+          :value="optionItem"/>
+      </el-select>
+    <!--<el-input
+      placeholder="请输入内容"
+      v-model="value"
+      clearable
+      @keyup.enter.native="confirm"
+      ref="sInput"
+    >
+    </el-input>-->
+    <div class='filterBtn'>
+      <el-button size="mini" @click="resetData">取消</el-button>
+      <el-button type="primary" size="mini" @click="confirm" style="margin-top:5px">确认</el-button>
+    </div>
+    <div slot="reference" style="margin-left:8px" @click.stop="popClick" v-clickoutside="closeOver" v-show="show">
+      <img class="table-filter" src='../../../assets/img/tablefilter.png'/>
+    </div>
+  </el-popover>
+</template>
+
+<script>
+import { GetIndustryListChildrenData } from '@/api/common'
+import Lockr from 'lockr'
+export default {
+  name: 'CRMTableFilter',
+  data () {
+    return {
+      value: '',
+      casVal: '',
+      busType: '',
+      visible: false,
+      iconColor: false,
+      optionsList: []
+    }
+  },
+  props: {
+    show: {
+      type: Boolean,
+      default: false
+    },
+    tableType: {
+      type: String,
+      default: ''
+    },
+    type: {
+      type: String,
+      default: ''
+    },
+    defaultValue: {
+      type: String,
+      default: ''
+    },
+    options: {
+      type: Array,
+      default: function () {
+        return []
+      }
+    },
+    defaultProps: {
+      type: Object,
+      default: function () {
+        return {
+          label: 'label',
+          value: 'value'
+        }
+      }
+    }
+  },
+  watch: {
+    defaultValue (newVal, oldVal) {
+      const self = this
+      self.value = newVal
+    }
+
+  },
+  mounted () {
+    this.getList()
+    Lockr.set('comType', '')
+    Lockr.set('casType', '')
+  },
+  methods: {
+    showPopover () {
+      this.$nextTick(() => {
+        // this.$refs.sInput.focus()
+      })
+    },
+    getSelect () {
+      console.log(this.value)
+      Lockr.set('comType', this.value)
+    },
+    getCas () {
+      Lockr.set('casType', this.casVal[1])
+    },
+    getList () {
+      if (this.tableType === '企业性质') {
+        this.optionsList = ['国企', '外企', '民营', '其他']
+      } else if (this.tableType === '行业细分') {
+        this.getIndustryList()
+      } else if (this.tableType === '项目属性') {
+        this.optionsList = ['普通项目', 'LC协作', 'ACAD项目', 'ACAD重点客户', 'AEC项目', 'AEC倍增计划', 'MFG项目', 'MNE项目', '企业信息特例', '特别案例', '区域重点客户', '知识产权代理']
+      } else if (this.tableType === '商机类型') {
+        this.optionsList = ['Other', 'LC', 'ACAD', 'AEC', 'MFG', 'MNE']
+      } else if (this.tableType === '提交') {
+        this.optionsList = ['待提交', '已提交']
+      } else if (this.tableType === '审批') {
+        this.optionsList = ['审批中', '通过', '驳回']
+      } else if (this.tableType === '合同类型') {
+        this.optionsList = ['合同章', '公章']
+      }
+    },
+    getIndustryList () {
+      GetIndustryListChildrenData().then(res => {
+        if (res.data.ErrorCode === 200) {
+          let list = res.data.Result
+          let array = this.addLabel(list)
+          console.log(array)
+          this.optionsList = array
+        } else {
+          return []
+        }
+      })
+    },
+    addLabel (arr) {
+      for (let k in arr) {
+        arr[k].Name = arr[k].CategoryName || '无类名'
+        if (arr[k].IndustryData && arr[k].IndustryData.length < 1) {
+          // 当后台返回的children为空时,页面会留空白,把空白部分去掉
+          arr[k].children = undefined
+        } else {
+          arr[k].children = []
+          for (let i in arr[k].IndustryData) {
+            arr[k].children.push({Name: arr[k].IndustryData[i]})
+          }
+        }
+      }
+      return arr
+    },
+    resetData () {
+      this.value = ''
+      this.casVal = ''
+      this.visible = false
+      this.iconColor = false
+      Lockr.set('comType', '')
+      Lockr.set('casType', '')
+      this.$emit('queryList')
+    },
+    closeOver () {
+      this.visible = false
+    },
+    popClick (e) {
+      // e.stopPropagation()
+      this.visible = !this.visible
+    },
+    confirm () {
+      this.visible = false
+      this.iconColor = true
+      if (this.value || this.casVal) {
+        this.$emit('queryList', { value: this.value, busType: this.busType, casVal: this.casVal[1], tableType: this.tableType })
+      }
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.table-filter{
+  width: 20px; /*no*/
+  height: 20px; /*no*/
+  margin-top: 1px;
+}
+.filterBtn{
+  float: right;
+  margin-top:12px;
+  .el-button{
+    width: 40px;
+    height: 20px;
+    font-size: 12px;
+    line-height: 7px;
+    padding: 2px;
+  }
+}
+</style>
diff --git a/src/views/clients/components/CRMTableHead.vue b/src/views/clients/components/CRMTableHead.vue
new file mode 100644
index 0000000..0d8594b
--- /dev/null
+++ b/src/views/clients/components/CRMTableHead.vue
@@ -0,0 +1,636 @@
+<template>
+  <div class='filterBox'>
+    <flexbox
+      class="th-container">
+      <el-row :gutter="24"  class="create-form-inline">
+        <el-col :xs="{span: 5}" :sm="{span: 5}" :md="{span: 5}" :lg="{span: 4}" :xl="{span: 4}">
+          <Xh-inputSelect ref='inputSelect' :arrayList="arrayList" :isProduct="false" @getName="getName" :crm-type="crmType" />
+        </el-col>
+        <el-col :xs="{span: 5}" :sm="{span: 5}" :md="{span: 5}" :lg="{span: 4}" :xl="{span: 4}" v-if="crmType === 'sealContract' || crmType === 'sealOffers' || crmType === 'businessChances' || crmType === 'businessContract' || crmType === 'businessCustomer'" style='display: flex;'>
+          <div class='filter-label'>范围:</div>
+          <el-cascader
+            ref="salesCas"
+            placeholder="请选择"
+            :options="salesManList"
+            :props="{
+              children: 'children',
+              label: 'Name',
+              value: 'Id',
+              checkStrictly: true
+            }"
+            v-model="salesId"
+            style="width: 100%;"
+            @change='getUser'/>
+        </el-col>
+        <el-col :xs="{span: 5}" :sm="{span: 5}" :md="{span: 5}" :lg="{span: 5}" :xl="{span: 4}" v-if="crmType !== 'business'&&crmType !== 'sealContract' && crmType !== 'sealOffers'&& crmType !== 'businessChances'&& crmType !== 'businessCustomer'&& crmType !== 'businessContract'" style='display: flex;'>
+          <div class='filter-label'>范围:</div>
+          <el-cascader
+            ref="workerCas"
+            placeholder="我负责的客户"
+            :options="checkList"
+            :props="{
+              children: 'children',
+              label: 'label',
+              value: 'value',
+              checkStrictly: true
+            }"
+            v-model="formInline.customer"
+            style="width: 100%;"
+            @change='getWorker'/>
+        </el-col>
+        <el-col :xs="{span: 5}" :sm="{span: 5}" :md="{span: 5}" :lg="{span: 5}" :xl="{span: 4}" v-if="crmType === 'business'" style='display: flex;'>
+          <div class='filter-label'>范围:</div>
+          <el-cascader
+            ref="workerCas"
+            placeholder="我负责的客户"
+            :options="checkList"
+            :props="{
+              children: 'children',
+              label: 'label',
+              value: 'value',
+              checkStrictly: true
+            }"
+            v-model="formInline.customer"
+            style="width: 100%;"
+            @change='getWorker'/>
+          <!--<el-select v-model="formInline.customer" placeholder="我负责的客户">
+            <el-option
+            v-for="item in checkList"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"/>
+          </el-select>-->
+        </el-col>
+        <el-col :xs="{span: 5}" :sm="{span: 5}" :md="{span: 5}" :lg="{span: 5}" :xl="{span: 4}"  v-if="crmType === 'business'" style='display: flex;'>
+          <div class='filter-label'>阶段:</div>
+          <el-select v-model="formInline.businessType" placeholder="全部">
+            <el-option
+            v-for="item in businessList"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"/>
+          </el-select>
+        </el-col>
+        <el-col :xs="{span: 5}" :sm="{span: 5}" :md="{span: 5}" :lg="{span: 5}" :xl="{span: 4}" style='display: flex;' v-if="crmType !== 'offers' && crmType !== 'contract'&& crmType !== 'businessContract'&&crmType !== 'sealContract' && crmType !== 'sealOffers'">
+          <div class='filter-label'>区域:</div>
+          <el-select v-model="selectArea" placeholder="请选择">
+            <el-option
+            v-for="item in areaList"
+            :key="item.ID"
+            :label="item.ProvinceName"
+            :value="item.ProvinceName"/>
+          </el-select>
+        </el-col>
+        <el-col :xs="{span: 4}" :sm="{span: 4}" :md="{span: 4}" :lg="{span: 4}" :xl="{span: 4}">
+          <el-button type="primary" @click="onSubmit('query')">查询</el-button>
+          <el-button @click="onSubmit('reset')">重置</el-button>
+        </el-col>
+      </el-row>
+    </flexbox>
+    <flexbox
+      v-if="crmType === 'business' || crmType === 'customer'|| crmType === 'contacts'|| crmType ==='businessChances' || crmType === 'businessCustomer' || selectionList.length>0"
+      class="operation-bar">
+      <el-button
+        v-if="crmType === 'business' || crmType === 'customer'|| crmType === 'contacts'|| crmType === 'businessCustomer'|| crmType === 'businessChances'"
+        type="primary"
+        class="createBtn"
+        @click="createClick">+ {{newTitle}}</el-button>
+        <div class='operationBtn' @click="importFile"  v-if="crmType ==='customer'||crmType ==='contacts' "><img src='../../../assets/aside/import.png'/>导入</div>
+        <div class='operationBtn' @click="exportFile"  v-if="crmType ==='customer'||crmType ==='contacts'||crmType ==='business'||crmType ==='businessChances' "><img src='../../../assets/aside/export.png'/>导出</div>
+        <div class='operationBtn' @click="showDuplicateCheck = true" v-if="crmType ==='customer'|| crmType === 'businessCustomer'"><img src='../../../assets/aside/check.png'/>查重</div>
+        <!--<div class='operationBtn' @click="showDelivery" v-if="crmType ==='contacts'"><img src='../../../assets/aside/dilivery.png'/>分配</div>
+        <div
+        class="operationBtn"
+        @click="showFilterClick">高级筛选</div>-->
+        <div class='operationBtn' @click="handleDelete" v-if='selectionList.length>0'><img src='../../../assets/aside/delete.png' />删除</div>
+        <filter-form
+          :field-list="fieldList"
+          :dialog-visible.sync="showFilter"
+          :obj="filterObj"
+          :crm-type="crmType"
+          :is-seas="isSeas"
+          @filter="handleFilter"/>
+    </flexbox>
+
+    <scene-set
+      :dialog-visible.sync="showSceneSet"
+      :crm-type="crmType"
+      @save-success="updateSceneList"/>
+
+    <scene-create
+      :field-list="fieldList"
+      :crm-type="crmType"
+      :dialog-visible.sync="showSceneCreate"
+      :obj="sceneFilterObj"
+      @saveSuccess="updateSceneList"/>
+
+    <c-r-m-create-view
+      v-if="isCreate"
+      :crm-type="createCRMType"
+      :action="createActionInfo"
+      @save-success="createSaveSuccess"
+      @hiden-view="hideView"/>
+
+    <duplicate-check
+    v-if="showDuplicateCheck"
+    :crm-type="crmType"
+    @hiden-view="showDuplicateCheck=false"/>
+  </div>
+</template>
+
+<script type="text/javascript">
+import { mapGetters } from 'vuex'
+// import crmTypeModel from '@/views/clients/model/crmTypeModel'
+import { DeleteCustomer } from '@/api/customermanagement/customerManage'
+import { DeleteContacter } from '@/api/customermanagement/contacts'
+import { DeleteSalesChance } from '@/api/customermanagement/business'
+import { DeleteQuotationSheet } from '@/api/customermanagement/offer'
+
+import filterForm from './filterForm'
+import filterContent from './filterForm/filterContent'
+import SceneList from './sceneForm/SceneList' // 场景
+import SceneSet from './sceneForm/SceneSet' // 场景设置
+import SceneCreate from './sceneForm/SceneCreate'
+import {XhInputSelect} from '@/components/CreateCom'
+import DuplicateCheck from '../components/duplicateCheck'
+import CRMCreateView from './CRMCreateView'
+import { GetProvincesList } from '@/api/common'
+import { GetSalesDepartmentUserChildList, GetCurrentBranches } from '@/api/systemManagement/departmentManage'
+
+export default {
+  name: 'CRMTableHead', // 客户管理下 重要提醒 回款计划提醒
+  components: {
+    filterForm,
+    filterContent,
+    SceneList,
+    SceneCreate,
+    SceneSet,
+    XhInputSelect,
+    DuplicateCheck,
+    CRMCreateView
+  },
+  props: {
+    title: {
+      type: String,
+      default: ''
+    },
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    // 辅助 使用 公海没有场景
+    isSeas: {
+      type: Boolean,
+      default: false
+    },
+    fieldList: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    }
+  },
+  data () {
+    return {
+      formInline: {
+        user: '',
+        customer: '0',
+        businessType: '',
+        area: '',
+        userType: ''
+      },
+      selectArea: '',
+      checkList: [{value: '0', label: '全部', children: undefined},
+        {value: '1', label: '我的', children: undefined},
+        {value: '2', label: '我的下属', children: []}],
+      businessList: [{value: '1', label: '初期沟通'},
+        {value: '2', label: '需求分析'},
+        {value: '3', label: '方案报价'},
+        {value: '4', label: '商务谈判'},
+        {value: '5', label: '成功'},
+        {value: '6', label: '搁置'}],
+      areaList: [],
+      sceneType: null,
+      showScene: false, // 场景操作
+      showFilter: false, // 控制筛选框
+      // fieldList: [],
+      filterObj: { form: [] }, // 筛选确定数据
+
+      sceneData: { id: '', bydata: '', name: '' },
+      showSceneSet: false, // 展示场景设置
+      showSceneCreate: false, // 展示场景添加
+      sceneFilterObj: { form: [] }, // 筛选确定数据
+
+      /** 勾选操作数据 */
+      selectionList: [],
+      transferDialogShow: false,
+      teamsDialogShow: false, // 团队操作提示框
+      teamsTitle: '', // 团队操作标题名
+      allocDialogShow: false, // 公海分配操作提示框
+      dealStatusShow: false, // 成交状态修改框
+      arrayList: [],
+      inputSelectData: '', // 接收子组件的值
+      // 展示查重
+      showDuplicateCheck: false,
+      // 创建的相关信息
+      createActionInfo: { type: 'save' },
+      createCRMType: '',
+      isCreate: false, // 是创建
+      salesManList: [],
+      salesId: ''
+    }
+  },
+  computed: {
+    ...mapGetters(['crm', 'CRMConfig']),
+    newTitle: function () {
+      if (this.crmType === 'customer' || this.crmType === 'businessCustomer') {
+        return '新增客户'
+      } else if (this.crmType === 'contacts') {
+        return '新增联系人'
+      } else if (this.crmType === 'business' || this.crmType === 'businessChances') {
+        return '新增商机'
+      }
+    }
+  },
+  watch: {},
+  mounted () {
+    this.getProvince()
+    this.getSalesList()
+    this.getCheckList()
+  },
+  methods: {
+    getProvince () {
+      GetProvincesList().then(res => {
+        console.log(res)
+        this.areaList = res.data.Result || []
+        this.areaList.unshift({ID: 0, ProvinceID: '0', ProvinceName: '全部'})
+        // this.formInline.area = res.data.Result ? res.data.Result[0].ProvinceName : ''
+        this.selectArea = res.data.Result ? res.data.Result[0].ProvinceName : ''
+      })
+    },
+    getName (data) {
+      console.log('this is data of input-select: ', data)
+      this.formInline.user = data.name
+      // this.inputSelectData = data
+    },
+    // 销售员级联列表
+    getSalesList () {
+      GetSalesDepartmentUserChildList().then(res => {
+        if (res.data.ErrorCode === 200 && res.data.Result !== 0) {
+          let list = res.data.Result
+          let array = this.addLabel(list)
+          this.salesManList = array
+        } else {
+          this.$message.error(res.data.Message)
+          this.loading = false
+        }
+      })
+    },
+    // 下属级联
+    getCheckList () {
+      GetCurrentBranches().then(res => {
+        if (res.data.ErrorCode === 200 && res.data.Result !== 0) {
+          let list = res.data.Result
+          let arr = []
+          for (let i in list) {
+            let newObj = {}
+            newObj['value'] = list[i].UserId
+            newObj['label'] = list[i].RealName
+            arr.push(newObj)
+          }
+          this.checkList[2].children = arr
+          console.log('yesssssssssss', arr, this.checkList)
+        } else {
+          this.$message.error(res.data.Message)
+          this.loading = false
+        }
+      })
+    },
+    getWorker (val) {
+      let checkNodes = this.$refs['workerCas'].getCheckedNodes()[0].data
+      // 判断是否进入children级联选项
+      if (this.$refs['workerCas'].getCheckedNodes()[0].pathNodes.length > 1) {
+        if (val[val.length - 1] !== '') {
+          this.formInline['BrachUserId'] = val[val.length - 1]
+          this.formInline['customer'] = 2
+        } else {
+          this.formInline['BrachUserId'] = ''
+          this.formInline['customer'] = 2
+        }
+      } else {
+        if (checkNodes['value'] === '2') {
+          this.formInline['BrachUserId'] = ''
+          this.formInline['customer'] = 2
+        } else {
+          this.formInline['BrachUserId'] = ''
+          this.formInline['customer'] = val[val.length - 1]
+        }
+      }
+    },
+    addLabel (arr) {
+      for (let k in arr) {
+        if (arr[k].DepartmentAndUserChildren && arr[k].DepartmentAndUserChildren.length < 1) {
+          // 当后台返回的children为空时,页面会留空白,把空白部分去掉
+          arr[k].children = undefined
+        } else {
+          arr[k].children = arr[k].DepartmentAndUserChildren
+          this.addLabel(arr[k].DepartmentAndUserChildren)
+        }
+      }
+      return arr
+    },
+    getUser (val) {
+      console.log(this.salesId, this.$refs['salesCas'].getCheckedNodes()[0].data['DepartmentUserType'], this.$refs['salesCas'].getCheckedNodes()[0].label, val[val.length - 1])
+      this.formInline['customer'] = val[val.length - 1]
+      this.formInline['userType'] = this.$refs['salesCas'].getCheckedNodes()[0].data['DepartmentUserType']
+    },
+    onSubmit (val) {
+      console.log(val)
+      if (val === 'query') {
+        if (this.selectArea === '全部') {
+          this.formInline.area = ''
+        } else {
+          this.formInline.area = this.selectArea
+        }
+        this.$emit('queryList', {'list': this.formInline})
+      } else if (val === 'reset') {
+        this.formInline = {
+          user: '',
+          customer: '0',
+          area: '',
+          userType: ''
+        }
+        this.salesId = '0'
+        this.selectArea = '全部'
+        this.$emit('queryList', {'list': this.formInline})
+        this.$refs.inputSelect.resetInput()
+      }
+    },
+    createClick () {
+      if (this.crmType === 'businessCustomer') {
+        this.createCRMType = 'customer'
+      } else if (this.crmType === 'businessChances') {
+        this.createCRMType = 'business'
+      } else {
+        this.createCRMType = this.crmType
+      }
+      this.createActionInfo = { type: 'save' }
+      this.isCreate = !this.isCreate
+    },
+    // 创建数据页面 保存成功
+    createSaveSuccess (data) {
+      this.$emit('on-handle', { type: 'save-success' })
+    },
+    exportFile () {
+      this.$emit('exportFile', true)
+    },
+    importFile () {
+      this.$emit('importFile', true)
+    },
+    showDelivery () {
+
+    },
+    hideView () {
+      this.isCreate = false
+    },
+    /** 发布 时候的类型选择 */
+    handleTypeDrop (command) {
+      this.sceneType = command
+    },
+    /** 展示高级筛选 */
+    showFilterClick () {
+      this.getFilterFieldInfo()
+    },
+    checkRepeat () {
+
+    },
+    showDelete () {
+
+    },
+    // 获取高级筛选字段数据
+    getFilterFieldInfo () {
+      // this.fieldList = []
+      console.log(this.fieldList)
+      this.showFilter = true
+    },
+    handleFilter (form) {
+      console.log(form)
+      this.filterObj = form
+      this.showFilter = false
+      // if (form.saveChecked) {
+      // crmSceneSave({
+      //   type: crmTypeModel[this.crmType],
+      //   isDefault: form.saveDefault ? 1 : 0,
+      //   name: form.saveName,
+      //   data: JSON.stringify(form.obj)
+      // })
+      //   .then(res => {
+      //     this.updateSceneList()
+      //   })
+      //   .catch(() => {})
+      // }
+      this.$emit('filter', form.obj)
+    },
+    // 删除
+    handleDeleteField (data) {
+      console.log(data)
+      this.filterObj = data.obj
+      this.$emit('filter', this.filterObj.obj)
+    },
+    // 场景操作
+    /** 选择了场景 */
+    sceneSelect (data) {
+      this.sceneData = data
+      this.$emit('scene', data)
+    },
+    sceneHandle (data) {
+      if (data.type === 'set') {
+        this.showSceneSet = true
+      } else if (data.type === 'add') {
+        // filterIndexfields({
+        //   label: crmTypeModel[this.crmType]
+        // })
+        //   .then(res => {
+        //     this.fieldList = res.data
+        //     this.showSceneCreate = true
+        //   })
+        //   .catch(() => {})
+      }
+    },
+    /**  创建保存成功 */
+    updateSceneList () {
+      this.$refs.sceneList.getSceneList()
+    },
+    /** 勾选后的表头操作 */
+    headSelectionChange (array) {
+      this.selectionList = array
+    },
+    handleDelete () {
+      let ids = []
+      for (let i in this.selectionList) {
+        ids.push({'Id': this.selectionList[i].Id})
+      }
+      console.log(ids)
+      let request = {
+        customer: DeleteCustomer,
+        contacts: DeleteContacter,
+        business: DeleteSalesChance,
+        offers: DeleteQuotationSheet
+      }[this.crmType]
+      this.$confirm('确定删除?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          request(ids).then(res => {
+            if (res.data.ErrorCode === 200) {
+              this.$message.success(res.data.Message)
+              this.$emit('queryList')
+            } else {
+              this.$message.error(res.data.Message)
+            }
+          })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    },
+    forSelectionHandleItems (handleInfos, array) {
+      var tempsHandles = []
+      for (let index = 0; index < array.length; index++) {
+        tempsHandles.push(handleInfos[array[index]])
+      }
+      return tempsHandles
+    },
+    // 子组件 回调的 结果
+    handleCallBack (data) {
+      this.$emit('handle', { type: data.type })
+    },
+    // 获取默认场景名字
+    getDefaultSceneName () {
+      if (this.crmType === 'leads') {
+        return '全部线索'
+      } else if (this.crmType === 'customer') {
+        return '全部客户'
+      } else if (this.crmType === 'contacts') {
+        return '全部联系人'
+      } else if (this.crmType === 'business') {
+        return '全部商机'
+      } else if (this.crmType === 'contract') {
+        return '全部合同'
+      } else if (this.crmType === 'receivables') {
+        return '全部回款'
+      } else if (this.crmType === 'product') {
+        return '全部产品'
+      }
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+.filterBox{
+  width: 100%;
+  // height: 136px;
+  background: #FFFFFF;
+  margin-bottom:10px;
+  padding:24px 20px;
+}
+.th-container {
+  font-size: 13px;
+  // height: 50px;
+  // margin-bottom: 20px;
+}
+
+.create-form-inline{
+  width: 100%;
+  /deep/.el-form-item{
+    margin-right: 60px;
+  }
+}
+.filter-label{
+  // width: 70px; /*no*/
+  min-width: 40px;/*no*/
+  line-height: 35px;
+  font-weight: 400;
+  color: #333333;
+  font-size: 12px;
+}
+/** 场景和筛选 */
+.condition_title {
+  cursor: pointer;
+}
+.condition_title:hover {
+  // color: #4D88FF;//
+}
+
+.m-arrow {
+  margin: 0 8px;
+}
+.c-filtrate {
+  margin: 0 10px 0 30px;
+  width: 12px;
+}
+
+.operation-bar{
+  margin-top: 20px;
+  .createBtn{
+    // width: 117px;
+    height: 36px;
+    background: #FF8800 !important;
+    border-radius: 4px;
+    border: 1px solid #FF8800 !important;
+    margin-right: 40px;
+    padding: 0 20px;
+  }
+  .operationBtn{
+    color: #333;
+    font-size: 14px;
+    display: flex;
+    align-items: center;
+    margin-right:40px;
+    cursor:pointer;
+    &:hover{
+      color: #4D88FF;
+    }
+    img{
+      width: 20px;
+      height: 20px;
+      margin-right: 8px;
+    }
+  }
+  .operBtn{
+    width: 117px;
+    height: 36px;
+    border-radius: 4px;
+    margin-right: 40px;
+  }
+}
+
+.selection-items-box {
+  overflow-x: auto;
+  overflow-y: hidden;
+  .selection-item {
+    width: auto;
+    padding: 15px;
+    flex-shrink: 0;
+    .selection-item-icon {
+      display: block;
+      margin-right: 5px;
+      width: 15px;
+      height: 15px;
+    }
+    .selection-item-name {
+      cursor: pointer;
+      color: #777;
+    }
+    .selection-item-name:hover {
+      // color: @xr-color-primary;//
+    }
+  }
+}
+</style>
diff --git a/src/views/clients/components/MixAdd.vue b/src/views/clients/components/MixAdd.vue
new file mode 100644
index 0000000..4b4b6ab
--- /dev/null
+++ b/src/views/clients/components/MixAdd.vue
@@ -0,0 +1,819 @@
+<template>
+  <div class='max-container'>
+    <!--<div class='i-types' v-if='!isEdit'>
+        <div class='type-button ' :class="typeBtn===0?'isType':''" @click='getType(0)'>写跟进</div>
+        <div class='type-button ' :class="typeBtn===1?'isType':''" @click='getType(1)'>创建商机</div>
+        <div class='type-button ' :class="typeBtn===2?'isType':''" @click='getType(2)'>创建报价单</div>
+        <div class='type-button ' :class="typeBtn===3?'isType':''" @click='getType(3)'>创建合同</div>
+        <div class='type-button ' :class="typeBtn===4?'isType':''" @click='getType(4)'>创建订单</div>
+    </div> -->
+    <div class="mix-container">
+      <flexbox class="se-section"  v-if='isOpen'>
+        <!--<el-dropdown
+          style="margin-right: 20px;"
+          trigger="click"
+          @command="handleTypeDrop">
+          <flexbox class="se-select">
+            <div class="se-select-name">{{ followType ? followType : '跟进类别' }}</div>
+            <i
+              class="el-icon-arrow-down el-icon--right"
+              style="color:#ccc;"/>
+          </flexbox>
+          <el-dropdown-menu slot="dropdown">
+            <el-dropdown-item
+              v-for="(item, index) in followTypes"
+              :key="index"
+              :command="item.type">{{ item.name }}</el-dropdown-item>
+          </el-dropdown-menu>
+        </el-dropdown>-->
+        <el-dropdown
+          style="margin-right: 20px;"
+          trigger="click"
+          @command="handleTypeDropContact">
+          <flexbox class="se-select">
+            <div class="se-select-name">{{ contactType ? contactType : '联系人' }}</div>
+            <i
+              class="el-icon-arrow-down el-icon--right"
+              style="color:#ccc;"/>
+          </flexbox>
+          <el-dropdown-menu slot="dropdown">
+            <el-dropdown-item
+              v-for="(item, index) in contactTypes"
+              :key="index"
+              :command="item.type">{{ item.name }}</el-dropdown-item>
+          </el-dropdown-menu>
+        </el-dropdown>
+        <el-dropdown
+          style="margin-right: 20px;"
+          trigger="click"
+          @command="handleTypeDropWay">
+          <flexbox class="se-select">
+            <div class="se-select-name">{{ wayType ? wayType : '跟进方式' }}</div>
+            <i
+              class="el-icon-arrow-down el-icon--right"
+              style="color:#ccc;"/>
+          </flexbox>
+          <el-dropdown-menu slot="dropdown">
+            <el-dropdown-item
+              v-for="(item, index) in wayTypes"
+              :key="index"
+              :command="item.type">{{ item.name }}</el-dropdown-item>
+          </el-dropdown-menu>
+        </el-dropdown>
+        <!--<div class="se-name">下次联系时间</div> -->
+        <el-date-picker
+          v-model="nextTime"
+          :default-value="new Date"
+          :editable="false"
+          class="se-datepicker"
+          type="date"
+          placeholder="当前联系时间"
+          :picker-options="pickerOptions"
+          value-format="yyyy-MM-dd"/>
+        <!--<el-checkbox
+          v-if="showOAPermission"
+          v-model="isEvent">是否完成跟进</el-checkbox>-->
+      </flexbox>
+      <div class="i-cont">
+        <!--<el-input
+          ref="text"
+          v-model="title"
+          type="text"
+          clearable
+          resize="none"
+          placeholder="请输入标题"/> -->
+        <el-input
+          ref="textarea"
+          v-model="content"
+          :autosize="inputAutosize"
+          type="textarea"
+          clearable
+          resize="none"
+          placeholder="请输入内容"
+          :class="!isOpen?'singleInput':''"
+          @focus="inputFocus"/>
+      </div>
+      <section
+        v-if="imgFiles.length > 0"
+        class="img-cont">
+        <flexbox wrap="wrap">
+          <div
+            v-for="(item, index) in imgFiles"
+            :key="index"
+            :style="{ 'background-image': 'url('+ headUrl + item.path +')' }"
+            class="img-item"
+            @mouseover="mouseImgOver(item, index)"
+            @mouseleave="mouseImgLeave(item, index)">
+            <div
+              v-if="item.showDelete"
+              class="img-delete"
+              @click="deleteImgOrFile('image', item, index)">×</div>
+          </div>
+          <div class="img-item-add">
+            <input
+              type="file"
+              class="img-item-iput"
+              accept="image/*"
+              multiple
+              @change="uploadFile">
+          </div>
+        </flexbox>
+        <div
+          class="img-bar"
+          @click="deleteAllImg">全部删除</div>
+      </section>
+      <section
+        v-if="files.length > 0"
+        class="file-cont">
+        <flexbox class="f-header">
+          <img
+            class="f-logo"
+            src="@/assets/img/send_file.png">
+          <div class="f-name">附件</div>
+        </flexbox>
+        <div class="f-body">
+          <flexbox
+            v-for="(item, index) in files"
+            :key="index"
+            class="f-item">
+            <img
+              :src="item.icon"
+              class="f-img">
+            <div class="f-name">{{ item.name +'('+item.size+')' }}</div>
+            <!--{{ item.name+'('+item.size+')' }}-->
+            <div
+              class="close-button"
+              @click="deleteImgOrFile('file', item, index)">×</div>
+          </flexbox>
+        </div>
+        <div
+          class="img-bar"
+          @click="files=[]">全部删除</div>
+      </section>
+      <section
+        v-if="business.length > 0"
+        class="c-cont">
+        <flexbox class="c-header">
+          <img
+            class="c-logo"
+            src="@/assets/img/send_business.png">
+          <div class="c-name">商机</div>
+        </flexbox>
+        <div class="c-body">
+          <flexbox wrap="wrap">
+            <flexbox
+              v-for="(item, index) in business"
+              :key="index"
+              class="c-item">
+              <div class="c-item-name">{{ item.businessName }}</div>
+              <div
+                class="c-item-close"
+                @click="business.splice(index, 1)">×</div>
+            </flexbox>
+          </flexbox>
+        </div>
+      </section>
+      <section
+        v-if="contacts.length > 0"
+        class="c-cont">
+        <flexbox class="c-header">
+          <img
+            class="c-logo"
+            src="@/assets/img/send_contacts.png">
+          <div class="c-name">联系人</div>
+        </flexbox>
+        <div class="c-body">
+          <flexbox wrap="wrap">
+            <flexbox
+              v-for="(item, index) in contacts"
+              :key="index"
+              class="c-item">
+              <div class="c-item-name">{{ item.name }}</div>
+              <div
+                class="c-item-close"
+                @click="contacts.splice(index, 1)">×</div>
+            </flexbox>
+          </flexbox>
+        </div>
+      </section>
+      <flexbox class="bar-cont" v-if='isOpen'>
+        <template v-for="(item, index) in barItems">
+          <flexbox
+            v-if="item.type=='img'||item.type=='file'"
+            :key="index"
+            class="bar-item"
+            @click.native="barClick(item)">
+            <input
+              :accept="item.data"
+              type="file"
+              class="bar-input"
+              multiple
+              @change="uploadFile">
+            <img
+              :src="item.img"
+              class="bar-img">
+            <div class="bar-title">{{ item.title }}</div>
+          </flexbox>
+        </template>
+        <el-button
+          class="se-collect"
+          @click.native="inputBlur">收起</el-button>
+        <el-button
+          class="se-send"
+          type="primary"
+          @click.native="sendInfo">发布</el-button>
+      </flexbox>
+    </div>
+  </div>
+</template>
+
+<script>
+import { fileSize, getFileTypeIcon } from '@/utils/index'
+import { UploadImageAsync, UploadFileAsync } from '@/api/common'
+import CrmRelative from '@/components/CreateCom/CrmRelative'
+import followLogType from '@/views/clients/mixins/followLogType'
+import { ResouceUrl } from '@/utils/baseconfig'
+export default {
+  /** 跟进记录 下的 添加 有添加框的都需要 */
+  name: 'MixAdd',
+  components: {
+    CrmRelative
+  },
+  mixins: [followLogType],
+  props: {
+    /** 展示相关商机关联 */
+    showRelativeBusiness: {
+      type: Boolean,
+      default: false
+    },
+    /** 跟进记录编辑 */
+    isEdit: {
+      type: Boolean,
+      default: false
+    },
+    /** 展示相关商机关联 */
+    showRelativeContacts: {
+      type: Boolean,
+      default: false
+    },
+    /** 模块ID */
+    id: [String, Number],
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    detail: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  data () {
+    return {
+      /** 输入法 */
+      title: '',
+      content: '',
+      inputAutosize: { minRows: 1, maxRows: 10 }, // 默认1 聚焦是 变成10
+      isOpen: false,
+      /** 快捷添加 */
+      barItems: [
+        {
+          img: require('@/assets/img/send_img.png'),
+          title: '图片',
+          type: 'img',
+          data: 'image/*'
+        },
+        {
+          img: require('@/assets/img/send_file.png'),
+          title: '附件',
+          type: 'file',
+          data: '*.*'
+        }
+      ],
+      /** 图片信息 */
+      imgFiles: [],
+      /** 图片信息 */
+      files: [],
+      /** 关联商机信息 */
+      business: [],
+      /** 关联联系人信息 */
+      contacts: [],
+      /** 展示关联弹窗 */
+      showRelativeType: '',
+      batchId: '', // 批次ID
+      typeBtn: 0,
+      /** 下次联系时间 */
+      nextTime: '',
+      /** 是否添加日程提醒 */
+      isEvent: false,
+      wayTypeId: 0,
+      followTypeId: 0,
+      contactTypeId: '',
+      pickerOptions: {
+        // disabledDate (time) {
+        //   return time.getTime() < Date.now()
+        // }
+      }
+    }
+  },
+  watch: {
+    detail: function (val) {
+      if (val && this.crmType === 'business') {
+        this.getContact()
+      }
+    }
+  },
+  computed: {},
+  mounted () {
+    this.headUrl = ResouceUrl
+    /** 控制展示关联商机 和 联系人 */
+    if (this.showRelativeBusiness) {
+      this.barItems.push({
+        img: require('@/assets/img/send_business.png'),
+        title: '关联商机',
+        type: 'business',
+        show: false
+      })
+    }
+
+    // if (this.showRelativeContacts) {
+    //   this.barItems.push({
+    //     img: require('@/assets/img/send_contacts.png'),
+    //     title: '关联联系人',
+    //     type: 'contacts',
+    //     show: false
+    //   })
+    // }
+    /** 父组件通知子组件提交数据 */
+    /** 将拼接好的数据回调父组件 this.$refs.child.$emit('submit-info');  调用 */
+    // this.$on('submit-info', function () {
+    //   this.$emit('mixadd-info', {
+    //     title: this.title,
+    //     content: this.content,
+    //     files: this.files,
+    //     images: this.imgFiles,
+    //     business: this.business,
+    //     contacts: this.contacts,
+    //     batchId: this.batchId
+    //   })
+    // })
+  },
+
+  beforeDestroy () {
+    this.$off('submit-info')
+  },
+  methods: {
+    getType (type) {
+      this.typeBtn = type
+    },
+    /** 发布 时候的类型选择 */
+    handleTypeDrop (command) {
+      this.followType = this.followTypes[command].name
+      this.followTypeId = command
+    },
+    handleTypeDropWay (command) {
+      this.wayType = this.wayTypes[command - 1].name
+      this.wayTypeId = command
+    },
+    handleTypeDropContact (command) {
+      this.contactType = this.contactTypes.filter(item => item.type === command)[0].name
+      this.contactTypeId = command
+    },
+    close () {
+      this.$refs.popover[0].doClose()
+      this.resetInfo()
+    },
+    sendInfo () {
+      console.log(this.files, this.contactTypeId)
+      this.$emit('mixadd-info', {
+        content: this.content,
+        files: this.files,
+        images: this.imgFiles,
+        // files: [this.imgFiles, this.files],
+        contacts: this.contactTypeId,
+        // batchId: this.batchId,
+        followTypeId: this.followTypeId,
+        wayTypeId: this.wayTypeId,
+        // isEvent: this.isEvent,
+        nextTime: this.nextTime
+        // followType: this.followType
+      })
+      this.resetInfo()
+    },
+    resetInfo () {
+      /** 输入法 */
+      this.title = ''
+      this.content = ''
+      /** 图片信息 */
+      this.imgFiles = []
+      /** 图片信息 */
+      this.files = []
+      /** 关联商机信息 */
+      this.business = []
+      /** 关联联系人信息 */
+      this.contactType = this.contactTypes[0].name
+      this.contactTypeId = this.contactTypes[0].type
+      this.wayType = this.wayTypes[0].name
+      this.wayTypeId = this.wayTypes[0].type
+      this.contacts = []
+      /** 展示关联弹窗 */
+      this.showRelativeType = ''
+      this.batchId = ''
+    },
+    /** 快捷添加按钮 */
+    checkRelativeInfos (data) {
+      if (this.showRelativeType === 'business') {
+        this.business = data.data
+      } else if (this.showRelativeType === 'contacts') {
+        this.contacts = data.data
+      }
+    },
+    barClick (item) {
+      this.showRelativeType = item.type
+      if (item.type === 'business') {
+        item.show = true
+      } else if (item.type === 'contacts') {
+        item.show = true
+      }
+    },
+    /** 图片选择出发 */
+    uploadFile (event) {
+      var files = event.target.files
+      if (files.length) {
+        for (let index = 0; index < files.length; index++) {
+          const file = files[index]
+          if (
+            file.type.indexOf('image') === -1 &&
+            this.showRelativeType === 'img'
+          ) {
+            this.$message.error('请上传正确的文件类型')
+            return
+          }
+        }
+
+        var type = event.target.accept === 'image/*' ? 'img' : 'file'
+        var firstFile = files[0]
+        this.sendFileRequest(firstFile, type, () => {
+          for (let index = 1; index < files.length; index++) {
+            const file = files[index]
+            this.sendFileRequest(file, type)
+          }
+          event.target.value = ''
+        })
+      }
+    },
+    // 发送请求
+    sendFileRequest (file, type, result) {
+      var params = { file: file, type: type }
+      if (this.batchId) {
+        params.batchId = this.batchId
+      }
+      let request = {
+        'img': UploadImageAsync,
+        'file': UploadFileAsync
+      }[type]
+      request(params)
+        .then(res => {
+          // if (this.batchId === '') {
+          //   this.batchId = res.batchId
+          // }
+          if (res.data.ErrorCode === 200) {
+            let list = []
+            list['size'] = fileSize(file.size)
+            if (type === 'img') {
+              list['name'] = res.data.Message
+              list['path'] = res.data.Result
+              console.log(list)
+              this.imgFiles.push(list)
+            } else {
+              list['icon'] = getFileTypeIcon(file)
+              list['name'] = res.data.Message
+              list['path'] = res.data.Result
+              this.files.push(list)
+            }
+            this.$message.success('上传成功')
+          } else {
+            this.$message.fail('res.data.Message')
+          }
+
+          if (result) {
+            result()
+          }
+        })
+        .catch(() => {})
+    },
+    /** 删除全部图片 */
+    deleteAllImg () {
+      this.imgFiles = []
+    },
+    deleteImgOrFile (type, item, index) {
+      if (type === 'image') {
+        this.imgFiles.splice(index, 1)
+      } else {
+        this.files.splice(index, 1)
+      }
+      this.$message.success('操作成功')
+      // crmFileDelete({
+      //   id: item.fileId
+      // })
+      //   .then(res => {
+      //     if (type === 'image') {
+      //       this.imgFiles.splice(index, 1)
+      //     } else {
+      //       this.files.splice(index, 1)
+      //     }
+      //     this.$message.success('操作成功')
+      //   })
+      //   .catch(() => {})
+    },
+    /** 鼠标移入和移除 图片区域 */
+    mouseImgOver (item, index) {
+      item.showDelete = true
+      this.$set(this.imgFiles, index, item)
+    },
+    mouseImgLeave (item, index) {
+      item.showDelete = false
+      this.$set(this.imgFiles, index, item)
+    },
+    inputFocus () {
+      this.isOpen = true
+      this.inputAutosize = { minRows: 8, maxRows: 12 }
+      this.$nextTick(() => {
+        this.$refs.textarea.resizeTextarea()
+      })
+    },
+    inputBlur () {
+      this.isOpen = false
+      this.inputAutosize = { minRows: 1, maxRows: 10 }
+      this.$nextTick(() => {
+        this.$refs.textarea.resizeTextarea()
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../styles/followlog.scss';
+.max-container{
+  .i-types{
+    display: flex;
+    flex-direction: row;
+    margin-bottom: 20px;
+    .type-button{
+      cursor: pointer;
+      height: 28px;
+      background: #EBF1FF;
+      border-radius: 3px;
+      padding: 4px 8px 4px 24px;
+      font-size: 14px;
+      color: #666;
+      margin-right: 24px;
+      background-image: url('../../../assets/img/button_add_black.png');
+      background-repeat: no-repeat;
+      background-size: 11px 11px;
+      background-position: 8px 8px;
+    }
+    .isType{
+      cursor: pointer;
+      background: #4D88FF;
+      color: #FFFFFF;
+      background-image: url('../../../assets/img/button_add_white.png');
+      background-repeat: no-repeat;
+      background-size: 11px 11px;
+      background-position: 8px 8px;
+    }
+  }
+
+  .mix-container {
+    position: relative;
+    // width: 1000px;
+    border-radius: 4px;
+    border: 1px solid #D9D9D9;
+    .i-cont {
+      padding: 0 12px;
+    }
+  }
+}
+.singleInput /deep/ .el-textarea__inner {
+    min-height: 36px !important;
+    height: 36px !important;
+    line-height: 36px !important;
+  }
+
+.i-cont /deep/ .el-textarea__inner {
+  border: none;
+  padding: 0;
+}
+/** 图片  */
+.img-cont {
+  padding: 0 10px;
+  margin-bottom: 15px;
+  .img-item {
+    width: 98px;
+    height: 98px;
+    border: 1px solid #ccc;
+    display: inline-block;
+    margin: 0 4px 4px 0;
+    background-size: contain;
+    background-repeat: no-repeat;
+    background-position: center;
+    position: relative;
+    .img-delete {
+      position: absolute;
+      cursor: pointer;
+      top: 0;
+      right: 0;
+      width: 20px;
+      height: 20px;
+      line-height: 20px;
+      text-align: center;
+      font-size: 17px;
+      background-color: #666;
+      color: white;
+    }
+  }
+  .img-item-add {
+    width: 98px;
+    height: 98px;
+    line-height: 98px;
+    font-size: 60px;
+    color: #ccc;
+    text-align: center;
+    margin: 0 4px 4px 0;
+    cursor: pointer;
+    display: inline-block;
+    border-width: 1px;
+    border-style: dashed;
+    border-color: #ddd;
+    position: relative;
+    font-weight: 100;
+    .img-item-iput {
+      position: absolute;
+      top: 0;
+      right: 0;
+      height: 98px;
+      width: 98px;
+      opacity: 0;
+      cursor: pointer;
+    }
+  }
+  .img-item-add:before {
+    width: 2px;
+    height: 39.5px;
+    content: ' ';
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    background-color: #2888e4;
+  }
+  .img-item-add:after {
+    width: 39.5px;
+    height: 2px;
+    content: ' ';
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    background-color: #2888e4;
+  }
+  .img-bar {
+    color: #5a8ae2;
+    font-size: 12px;
+    padding: 5px 0;
+    cursor: pointer;
+  }
+}
+/** 附件  */
+.file-cont {
+  padding: 0 10px;
+  margin: 0 10px 15px;
+  border: 1px dashed #dfdfdf;
+  .f-header {
+    padding: 8px 0 15px;
+    .f-logo {
+      position: block;
+      width: 15px;
+      height: 15px;
+      margin-right: 8px;
+    }
+    .f-name {
+      color: #777;
+      font-size: 12px;
+    }
+  }
+
+  .f-body {
+    .f-item {
+      padding: 3px 0;
+      height: 25px;
+      .f-img {
+        position: block;
+        width: 15px;
+        height: 15px;
+        margin-right: 8px;
+      }
+      .f-name {
+        color: #666;
+        font-size: 12px;
+      }
+    }
+  }
+
+  .img-bar {
+    color: #5a8ae2;
+    font-size: 12px;
+    padding: 5px 0;
+    cursor: pointer;
+  }
+}
+/** CRM  */
+.c-cont {
+  padding: 0 10px;
+  margin: 0 10px 15px;
+  border: 1px dashed #dfdfdf;
+  .c-header {
+    padding: 8px 0 15px;
+    .c-logo {
+      position: block;
+      width: 15px;
+      height: 15px;
+      margin-right: 8px;
+    }
+    .c-name {
+      color: #777;
+      font-size: 12px;
+    }
+  }
+
+  .c-body {
+    margin-bottom: 10px;
+    .c-item {
+      height: 24px;
+      border-radius: 12px;
+      padding: 0 8px;
+      margin: 0 5px 5px 0;
+      background-color: #3487e2;
+      color: white;
+      width: auto;
+      .c-item-name {
+        font-size: 12px;
+      }
+      .c-item-close {
+        padding-left: 5px;
+        font-size: 17px;
+      }
+    }
+  }
+}
+/** 底部bar  */
+.bar-cont {
+  // background-color: #f9f9f9;
+  padding: 24px;
+  .bar-item {
+    width: auto;
+    padding-right: 20px;
+    position: relative;
+    cursor: pointer;
+    .bar-input {
+      position: absolute;
+      top: 0;
+      right: 0;
+      height: 10px;
+      width: 68px;
+      opacity: 0;
+      font-size: 0;
+      cursor: pointer;
+    }
+    .bar-img {
+      display: block;
+      margin-right: 8px;
+      &:hover{
+      }
+    }
+    .bar-title {
+      color: #999;
+      font-size: 12px;
+      &:hover{
+        color: #333;
+      }
+    }
+  }
+}
+/** 关闭按钮  */
+.close-button {
+  width: 30px;
+  line-height: 16px;
+  cursor: pointer;
+  color: #ccc;
+  height: 16px;
+  font-size: 17px;
+  text-align: center;
+}
+// .el-date-editor /deep/ .el-input__prefix{
+//   right: -165px;
+// }
+</style>
diff --git a/src/views/clients/components/RelativeApproval.vue b/src/views/clients/components/RelativeApproval.vue
new file mode 100644
index 0000000..2c6f963
--- /dev/null
+++ b/src/views/clients/components/RelativeApproval.vue
@@ -0,0 +1,239 @@
+<template>
+  <div
+    v-empty="nopermission"
+    class="rc-cont"
+    xs-empty-icon="nopermission"
+    xs-empty-text="暂无权限">
+    <el-table
+      :data="list"
+      :height="tableHeight"
+      :header-cell-style="headerRowStyle"
+      :cell-style="cellStyle"
+      style="width: 100%;border: 1px solid #E6E6E6;"
+      @row-click="handleRowClick">
+      <el-table-column
+        v-for="(item, index) in fieldList"
+        :key="index"
+        :prop="item.prop"
+        :formatter="fieldFormatter"
+        :label="item.label"
+        show-overflow-tooltip>
+        <template
+          slot="header"
+          slot-scope="scope">
+          <div class="table-head-name">{{ scope.column.label }}</div>
+        </template>
+       </el-table-column>
+    </el-table>
+    <div class="p-contianer" v-show='total>0'>
+        <el-pagination
+          :current-page="currentPage"
+          :page-sizes="pageSizes"
+          :page-size.sync="pageSize"
+          :total="total"
+          class="p-bar"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"/>
+      </div>
+
+    <c-r-m-full-screen-detail
+      :visible.sync="showFullDetail"
+      :id="contractId"
+      crm-type="contract"/>
+    <c-r-m-create-view
+      v-if="isCreate"
+      :action="createActionInfo"
+      crm-type="contract"
+      @save-success="createSaveSuccess"
+      @hiden-view="isCreate=false"/>
+  </div>
+</template>
+
+<script type="text/javascript">
+import loading from '../mixins/loading'
+import CRMCreateView from './CRMCreateView'
+import { GetCustomerOrderList } from '@/api/customermanagement/customerManage'
+import { GetAutoSalesChanceLogList } from '@/api/customermanagement/business'
+// import { moneyFormat } from '@/utils'
+
+export default {
+  name: 'RelativeApproval', // 相关商机流转跟踪记录  可能再很多地方展示 放到客户管理目录下
+  components: {
+    CRMFullScreenDetail: () => import('./CRMFullScreenDetail.vue'),
+    CRMCreateView
+  },
+  mixins: [loading],
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    /** 是公海 默认是客户 */
+    isSeas: {
+      type: Boolean,
+      default: false
+    },
+    /** 联系人人下 新建商机 需要联系人里的客户信息  合同下需要客户和商机信息 */
+    detail: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  data () {
+    return {
+      nopermission: false,
+      list: [],
+      fieldList: [],
+      tableHeight: '400px',
+      showFullDetail: false,
+      isCreate: false, // 控制新建
+      contractId: '', // 查看全屏联系人详情的 ID
+      // 创建的相关信息
+      createActionInfo: { type: 'relative', crmType: this.crmType, data: {} },
+      total: 0,
+      currentPage: 1,
+      pageSize: 10,
+      pageSizes: [10, 30, 60, 100]
+    }
+  },
+  computed: {},
+  watch: {
+    id: function (val) {
+      this.list = []
+      this.getDetail()
+    }
+  },
+  mounted () {
+    this.getDetail()
+  },
+  activated: function () {},
+  deactivated: function () {},
+  methods: {
+    handleSizeChange (newSize) {
+      this.pageSize = newSize
+      this.getDetail()
+    },
+    handleCurrentChange (newPage) {
+      this.getDetail()
+    },
+    /** 格式化字段 */
+    fieldFormatter (row, column) {
+      // 如果需要格式化
+      return row[column.property] || '--'
+    },
+    getFieldList () {
+      this.fieldList.push(
+        { prop: 'AddTime', label: '商机状态跟踪记录时间' },
+        { prop: 'ExpireTime', label: '商机有效期' },
+        { prop: 'Status', label: '商机审批状态' }
+      )
+    },
+    getDetail () {
+      this.loading = true
+      const request = {
+        customer: GetCustomerOrderList,
+        businessCustomer: GetCustomerOrderList,
+        business: GetAutoSalesChanceLogList,
+        businessChances: GetAutoSalesChanceLogList
+      }[this.crmType]
+      const params = {}
+      params['Id'] = this.id
+      params['PageSize'] = this.pageSize
+      params['PageIndex'] = this.currentPage
+      request(params)
+        .then(res => {
+          if (this.fieldList.length === 0) {
+            this.getFieldList()
+          }
+          this.nopermission = false
+          this.loading = false
+          this.list = res.data.Result.List
+          this.total = res.data.Result.Count
+        })
+        .catch(data => {
+          if (data.code === 102) {
+            this.nopermission = true
+          }
+          this.loading = false
+        })
+    },
+
+    /**
+     * 对应的状态名
+     */
+    getStatusName (status) {
+      if (status === 1) {
+        return '已盖章'
+      } else if (status === 2) {
+        return '未盖章'
+      }
+      return '暂无'
+    },
+    getSealName (type) {
+      if (type === 0) {
+        return '暂无'
+      } else if (type === 1) {
+        return '合同章'
+      } else if (type === 2) {
+        return '公章'
+      }
+      return '暂无'
+    },
+    getAuditStatus (type) {
+      if (type === 1) {
+        return '待审核'
+      } else if (type === 2) {
+        return '审核成功'
+      } else if (type === 3) {
+        return '审核失败'
+      }
+      return '暂无'
+    },
+    getSwitch (type) {
+      console.log(type)
+      if (type === false) {
+        return '否'
+      } else if (type === true) {
+        return '是'
+      }
+      return '暂无'
+    },
+    // 当某一行被点击时会触发该事件
+    handleRowClick (row, column, event) {
+      // this.contractId = row.contractId
+      // this.showFullDetail = true
+    },
+    /** 通过回调控制表头style */
+    headerRowStyle ({ row, column, rowIndex, columnIndex }) {
+      return { textAlign: 'left' }
+    },
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      return { textAlign: 'left' }
+    },
+    /** 新建 */
+    createClick () {
+      /** 客户 和 商机 下新建合同 */
+      if (this.crmType === 'business') {
+        this.createActionInfo.data['customer'] = this.detail
+        this.createActionInfo.data['business'] = this.detail
+      } else if (this.crmType === 'customer') {
+        this.createActionInfo.data['customer'] = this.detail
+      }
+      this.isCreate = true
+    },
+    createSaveSuccess () {
+      this.getDetail()
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+@import '../styles/relativecrm.scss';
+</style>
diff --git a/src/views/clients/components/RelativeBusiness.vue b/src/views/clients/components/RelativeBusiness.vue
new file mode 100644
index 0000000..28e456f
--- /dev/null
+++ b/src/views/clients/components/RelativeBusiness.vue
@@ -0,0 +1,409 @@
+<template>
+  <div
+    v-empty="nopermission"
+    class="rc-cont"
+    xs-empty-icon="nopermission"
+    xs-empty-text="暂无权限">
+    <flexbox
+      v-if="!isSeas"
+      class="rc-head"
+      direction="row-reverse">
+      <!--<el-button
+        class="rc-head-item"
+        type="primary"
+        @click.native="createClick">新建商机</el-button>-->
+      <el-button
+        v-if="canRelation"
+        class="rc-head-item"
+        type="primary"
+        @click.native="unRelevanceHandleClick">解除关联</el-button>
+      <el-popover
+        v-if="canRelation"
+        v-model="showRelativeView"
+        placement="bottom"
+        width="700"
+        popper-class="no-padding-popover"
+        trigger="click"
+        style="margin-right: 20px;">
+        <crm-relative
+          ref="crmrelative"
+          v-model="showRelativeView"
+          :show="showRelativeView"
+          :radio="false"
+          :action="{ type: 'condition', data: { moduleType: 'customer', customerId: customerId } }"
+          :selected-data="{ 'business': list }"
+          crm-type="business"
+          @close="showRelativeView = false"
+          @changeCheckout="checkRelativeInfos"/>
+        <el-button
+          slot="reference"
+          class="rc-head-item"
+          style="margin-right: 0;"
+          type="primary"
+          @click.native="showRelativeView = true">关联</el-button>
+      </el-popover>
+
+    </flexbox>
+    <el-table
+      :data="list"
+      :height="tableHeight"
+      :header-cell-style="headerRowStyle"
+      :cell-style="cellStyle"
+      style="width: 100%;border: 1px solid #E6E6E6;"
+      @row-click="handleRowClick"
+      @selection-change="selectionList = $event">
+      <el-table-column
+        v-if="canRelation && fieldList.length > 0"
+        show-overflow-tooltip
+        type="selection"
+        align="center"/>
+      <el-table-column
+        v-for="(item, index) in fieldList"
+        :key="index"
+        :prop="item.prop"
+        :label="item.label"
+        :formatter="fieldFormatter"
+        show-overflow-tooltip>
+        <template
+          slot="header"
+          slot-scope="scope">
+          <div class="table-head-name">{{ scope.column.label }}</div>
+        </template>
+       </el-table-column>
+    </el-table>
+    <div class="p-contianer" v-show='total>0'>
+        <el-pagination
+          :current-page="currentPage"
+          :page-sizes="pageSizes"
+          :page-size.sync="pageSize"
+          :total="total"
+          class="p-bar"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"/>
+      </div>
+    <!-- 相关详情页面 -->
+    <c-r-m-all-detail
+      :visible.sync="showDview"
+      :crm-type="rowType"
+      :id="rowID"
+      class="d-view"/>
+    <c-r-m-full-screen-detail
+      :visible.sync="showFullDetail"
+      :id="businessId"
+      :crm-type="rowType"/>
+    <c-r-m-create-view
+      v-if="isCreate"
+      :action="createActionInfo"
+      crm-type="business"
+      @save-success="createSaveSuccess"
+      @hiden-view="isCreate=false"/>
+  </div>
+</template>
+
+<script type="text/javascript">
+import loading from '../mixins/loading'
+import CRMCreateView from './CRMCreateView'
+import { GetCustomerSalesChanceList } from '@/api/customermanagement/customerManage'
+// import {
+//   crmContactsQueryBusiness,
+//   crmContactsRelateBusinessAPI,
+//   crmContactsUnrelateBusinessAPI
+// } from '@/api/clients/contacts'
+import CrmRelative from '@/components/CreateCom/CrmRelative'
+
+import { moneyFormat } from '@/utils'
+
+export default {
+  name: 'RelativeBusiness', // 相关联系人商机  可能再很多地方展示 放到客户管理目录下(新建时仅和客户进行关联)
+  components: {
+    CRMFullScreenDetail: () => import('./CRMFullScreenDetail.vue'),
+    CRMCreateView,
+    CrmRelative,
+    CRMAllDetail: () => import('./CRMAllDetail.vue')
+  },
+  mixins: [loading],
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    /** 是公海 默认是客户 */
+    isSeas: {
+      type: Boolean,
+      default: false
+    },
+    /** 联系人人下 新建商机 需要联系人里的客户信息  合同下需要客户和商机信息 */
+    detail: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  data () {
+    return {
+      nopermission: false,
+      list: [],
+      fieldList: [{ prop: 'ChanceNumber', label: '商机编号', width: '100' },
+        { prop: 'ChanceName', label: '商机名称', width: '180' },
+        { prop: 'ChanceRequestTypeString', label: '商机类型' },
+        { prop: 'InvalidTimeString', label: '过期时间' },
+        { prop: 'SalesChanceStage', label: '销售阶段' },
+        { prop: 'ExpectedAmount', label: '商机金额/元' },
+        { prop: 'ExpectedDate', label: '预期成交日期' },
+        { prop: 'OwerName', label: '销售负责人' }],
+      // { prop: 'ProjectProperty', label: '项目属性' },
+      tableHeight: '400px',
+      showFullDetail: false,
+      isCreate: false, // 控制新建
+      businessId: '', // 查看全屏联系人详情的 ID
+      // 创建的相关信息
+      createActionInfo: { type: 'relative', crmType: this.crmType, data: {} },
+      /**
+       * 关联的逻辑
+       */
+      showRelativeView: false, // 控制关联信息视图
+      selectionList: [], // 取消关联勾选的数据
+      total: 0,
+      currentPage: 1,
+      pageSize: 10,
+      pageSizes: [10, 30, 60, 100],
+      /** 控制详情展示 */
+      rowID: '', // 行信息
+      rowType: '', // 详情类型
+      showDview: false
+    }
+  },
+  computed: {
+    // 联系人下客户id获取关联商机
+    customerId () {
+      return this.detail.customerId
+    },
+    // 是否能关联
+    canRelation () {
+      return this.crmType === 'contacts'
+    }
+  },
+  watch: {
+    id: function (val) {
+      this.list = []
+      this.getDetail()
+    }
+  },
+  mounted () {
+    this.getDetail()
+  },
+  activated: function () {},
+  deactivated: function () {},
+  methods: {
+    handleSizeChange (newSize) {
+      // this.queryInfo.pagesize = newSize
+      this.pageSize = newSize
+      this.getDetail()
+    },
+    handleCurrentChange (newPage) {
+      // this.queryInfo.pagenum = newPage
+      this.currentPage = newPage
+      this.getDetail()
+    },
+    /**
+     * 获取字段信息
+     */
+    getFieldList () {
+      this.fieldList.push(
+        { prop: 'ChanceNumber', label: '商机编号', width: '100' },
+        { prop: 'ChanceName', label: '商机名称', width: '180' },
+        { prop: 'ProjectProperty', label: '项目属性' },
+        { prop: 'SalesChanceStage', label: '销售阶段' },
+        { prop: 'ExpectedAmount', label: '商机金额/元' },
+        { prop: 'ExpectedDate', label: '预期成交日期' },
+        { prop: 'OwerName', label: '销售负责人' }
+      )
+    },
+    /** 格式化字段 */
+    fieldFormatter (row, column) {
+      if (column.property === 'Sex') {
+        return { 1: '男', 2: '女' }[row.Sex]
+      } else if (column.property === 'IsCustomerDefault') {
+        return { true: '是', false: '否' }[row.IsCustomerDefault]
+      } else if (column.property === 'CompanyType') {
+        return {0: '暂无', 1: '国企', 2: '外企', 3: '民营', 4: '其他'}[row.CompanyType]
+      } else if (column.property === 'money') {
+        return moneyFormat(row[column.property])
+      } else if (column.property === 'SalesChanceStage') {
+        switch (row[column.property]) {
+          case 0:
+            row[column.property] = '--'
+            break
+          case 1:
+            row[column.property] = '初期沟通'
+            break
+          case 2:
+            row[column.property] = '需求分析'
+            break
+          case 3:
+            row[column.property] = '方案报价'
+            break
+          case 4:
+            row[column.property] = '商务谈判'
+            break
+
+          case 5:
+            row[column.property] = '成功'
+            break
+          case 6:
+            row[column.property] = '搁置'
+            break
+        }
+      }
+      // 如果需要格式化
+      return row[column.property] || '--'
+    },
+    /**
+     * 关联的数据
+     */
+    checkRelativeInfos (data) {
+      if (data.data.length > 0) {
+        const params = { contactsId: this.id }
+        params.businessIds = data.data
+          .map(item => {
+            return item.businessId
+          })
+          .join(',')
+        // crmContactsRelateBusinessAPI(params)
+        //   .then(res => {
+        //     this.getDetail()
+        //     this.$message.success('操作成功')
+        //   })
+        //   .catch(() => {})
+      }
+    },
+
+    /**
+     * 取消关联
+     */
+    unRelevanceHandleClick () {
+      if (this.selectionList.length === 0) {
+        this.$message.error('请先勾选数据')
+      } else {
+        this.$confirm('确认取消关联?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+          .then(() => {
+            const params = { contactsId: this.id }
+            params.businessIds = this.selectionList
+              .map(item => {
+                return item.businessId
+              })
+              .join(',')
+            // crmContactsUnrelateBusinessAPI(params)
+            //   .then(res => {
+            //     this.getDetail()
+            //     this.$message.success('操作成功')
+            //   })
+            //   .catch(() => {})
+          })
+          .catch(() => {
+            this.$message.info('已取消操作')
+          })
+      }
+    },
+    getDetail () {
+      this.loading = true
+      const request = {
+        contacts: GetCustomerSalesChanceList,
+        customer: GetCustomerSalesChanceList,
+        businessCustomer: GetCustomerSalesChanceList
+      }[this.crmType]
+      const params = {}
+      params['Id'] = this.id
+      params['PageSize'] = this.pageSize
+      params['PageIndex'] = this.currentPage
+      request(params)
+        .then(res => {
+          console.log(res)
+          if (this.fieldList.length === 0) {
+            this.getFieldList()
+          }
+          this.nopermission = false
+          this.loading = false
+          this.list = res.data.Result.List
+          this.total = res.data.Result.Count
+        })
+        .catch(data => {
+          if (data.code === 102) {
+            this.nopermission = true
+          }
+          this.loading = false
+        })
+    },
+    // 当某一行被点击时会触发该事件
+    handleRowClick (row, column, event) {
+      if (column.property === 'ChanceName') {
+        if (this.crmType === 'businessCustomer') {
+          this.rowID = row.Id
+          this.businessId = row.Id
+          this.rowType = 'businessChances'
+          this.showFullDetail = true
+        } else if (this.crmType === 'customer') {
+          this.rowID = row.Id
+          this.businessId = row.Id
+          this.rowType = 'business'
+          this.showFullDetail = true
+        }
+        // this.showDview = true
+      }
+    },
+    /** 通过回调控制表头style */
+    headerRowStyle ({ row, column, rowIndex, columnIndex }) {
+      return { textAlign: 'left' }
+    },
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      if (
+        column.property === 'ChanceName'
+      ) {
+        return { color: '#4D88FF', cursor: 'pointer', textAlign: 'center' }
+      } else {
+        return { textAlign: 'left' }
+      }
+    },
+    /** 新建 */
+    createClick () {
+      /** 客户 和 联系人 下可新建商机  */
+      if (this.crmType === 'contacts') {
+        this.createActionInfo.data['customer'] = this.detail
+        this.createActionInfo.relativeData = {
+          contactsId: this.detail.contactsId
+        }
+      } else if (this.crmType === 'customer') {
+        this.createActionInfo.data['customer'] = this.detail
+      }
+      this.isCreate = true
+    },
+
+    /**
+     * 创建成功刷新相关信息
+     */
+    createSaveSuccess () {
+      if (this.canRelation) {
+        this.$refs.crmrelative.refreshList()
+      } else {
+        this.getDetail()
+      }
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+@import '../styles/relativecrm.scss';
+.el-table /deep/ thead th:first-child, thead td {
+  border-right: 1px solid #F7FAFF;
+}
+</style>
diff --git a/src/views/clients/components/RelativeContacts.vue b/src/views/clients/components/RelativeContacts.vue
new file mode 100644
index 0000000..61688a5
--- /dev/null
+++ b/src/views/clients/components/RelativeContacts.vue
@@ -0,0 +1,349 @@
+<template>
+  <div
+    v-empty="nopermission"
+    class="rc-cont"
+    xs-empty-icon="nopermission"
+    xs-empty-text="暂无权限">
+    <flexbox
+      v-if="!isSeas"
+      class="rc-head"
+      direction="row-reverse">
+      <!--<el-button
+        class="rc-head-item"
+        type="primary"
+        @click.native="createClick">新建联系人</el-button>-->
+      <el-button
+        v-if="canRelation"
+        class="rc-head-item"
+        type="primary"
+        @click.native="unRelevanceHandleClick">解除关联</el-button>
+      <el-popover
+        v-if="canRelation"
+        v-model="showRelativeView"
+        placement="bottom"
+        width="700"
+        popper-class="no-padding-popover"
+        trigger="click"
+        style="margin-right: 20px;">
+        <crm-relative
+          ref="crmrelative"
+          v-model="showRelativeView"
+          :show="showRelativeView"
+          :radio="false"
+          :action="{ type: 'condition', data: { moduleType: 'customer', customerId: customerId } }"
+          :selected-data="{ 'contacts': list }"
+          crm-type="contacts"
+          @close="showRelativeView = false"
+          @changeCheckout="checkRelativeInfos"/>
+        <el-button
+          slot="reference"
+          class="rc-head-item"
+          style="margin-right: 0;"
+          type="primary"
+          @click.native="showRelativeView = true">关联</el-button>
+      </el-popover>
+
+    </flexbox>
+    <el-table
+      :data="list"
+      :height="tableHeight"
+      :header-cell-style="headerRowStyle"
+      :cell-style="cellStyle"
+      style="width: 100%;border: 1px solid #E6E6E6;"
+      @row-click="handleRowClick"
+      @selection-change="selectionList = $event">
+      <el-table-column
+        v-if="canRelation && fieldList.length > 0"
+        show-overflow-tooltip
+        type="selection"
+        align="center"
+        width="55"/>
+      <el-table-column
+        v-for="(item, index) in fieldList"
+        :key="index"
+        :prop="item.prop"
+        :formatter="fieldFormatter"
+        :label="item.label"
+        show-overflow-tooltip>
+        <template
+          slot="header"
+          slot-scope="scope">
+          <div class="table-head-name">{{ scope.column.label }}</div>
+        </template>
+       </el-table-column>
+    </el-table>
+    <div class="p-contianer" v-show='total>0'>
+        <el-pagination
+          :current-page="currentPage"
+          :page-sizes="pageSizes"
+          :page-size.sync="pageSize"
+          :total="total"
+          class="p-bar"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"/>
+      </div>
+    <c-r-m-full-screen-detail
+      :visible.sync="showFullDetail"
+      :id="contactsId"
+      crm-type="contacts"/>
+    <c-r-m-create-view
+      v-if="isCreate"
+      :action="createActionInfo"
+      crm-type="contacts"
+      @save-success="createSaveSuccess"
+      @hiden-view="isCreate=false"/>
+  </div>
+</template>
+
+<script type="text/javascript">
+import loading from '../mixins/loading'
+import CRMCreateView from './CRMCreateView'
+import { GetCustomerContacterList } from '@/api/customermanagement/customerManage'
+// import {
+//   crmBusinessQueryContactsAPI,
+//   crmBusinessRelateContactsAPI,
+//   crmBusinessUnrelateContactsAPI
+// } from '@/api/clients/business'
+import CrmRelative from '@/components/CreateCom/CrmRelative'
+
+export default {
+  name: 'RelativeContacts', // 相关联系人列表  可能再很多地方展示 放到客户管理目录下
+  components: {
+    CRMFullScreenDetail: () => import('./CRMFullScreenDetail.vue'),
+    CRMCreateView,
+    CrmRelative
+  },
+  mixins: [loading],
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    /** 是公海 默认是客户 */
+    isSeas: {
+      type: Boolean,
+      default: false
+    },
+    /** 联系人人下 新建商机 需要联系人里的客户信息  合同下需要客户和商机信息 */
+    detail: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  data () {
+    return {
+      nopermission: false,
+      list: [],
+      fieldList: [],
+      tableHeight: '400px',
+      showFullDetail: false,
+      isCreate: false, // 控制新建
+      contactsId: '', // 查看全屏联系人详情的 ID
+      // 创建的相关信息
+      createActionInfo: { type: 'relative', crmType: this.crmType, data: {} },
+      /**
+       * 关联的逻辑
+       */
+      showRelativeView: false, // 控制关联信息视图
+      selectionList: [], // 取消关联勾选的数据
+      total: 0,
+      currentPage: 1,
+      pageSize: 10,
+      pageSizes: [10, 30, 60, 100]
+    }
+  },
+  computed: {
+    // 联系人下客户id获取关联商机
+    customerId () {
+      return this.detail.customerId
+    },
+    // 是否能关联
+    canRelation () {
+      return this.crmType === 'business'
+    }
+  },
+  watch: {
+    id: function (val) {
+      this.list = []
+      this.getDetail()
+    }
+  },
+  mounted () {
+    this.getDetail()
+  },
+  activated: function () {},
+  deactivated: function () {},
+  methods: {
+    handleSizeChange (newSize) {
+      this.pageSize = newSize
+      this.getDetail()
+    },
+    handleCurrentChange (newPage) {
+      this.currentPage = newPage
+      this.getDetail()
+    },
+    /** 格式化字段 */
+    fieldFormatter (row, column) {
+      if (column.property === 'Sex') {
+        return { 1: '男', 2: '女' }[row.Sex]
+      } else if (column.property === 'IsCustomerDefault') {
+        return { true: '是', false: '否' }[row.IsCustomerDefault]
+      } else if (column.property === 'CompanyType') {
+        return {0: '暂无', 1: '国企', 2: '外企', 3: '民营', 4: '其他'}[row.CompanyType]
+      }
+      // 如果需要格式化
+      return row[column.property] || '--'
+    },
+    /**
+     * 关联的数据
+     */
+    checkRelativeInfos (data) {
+      if (data.data.length > 0) {
+        const params = { businessId: this.id }
+        params.contactsIds = data.data
+          .map(item => {
+            return item.contactsId
+          })
+          .join(',')
+        // crmBusinessRelateContactsAPI(params)
+        //   .then(res => {
+        //     this.getDetail()
+        //     this.$message.success('操作成功')
+        //   })
+        //   .catch(() => {})
+      }
+    },
+
+    /**
+     * 取消关联
+     */
+    unRelevanceHandleClick () {
+      if (this.selectionList.length === 0) {
+        this.$message.error('请先勾选数据')
+      } else {
+        this.$confirm('确认取消关联?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+          .then(() => {
+            const params = { businessId: this.id }
+            params.contactsIds = this.selectionList
+              .map(item => {
+                return item.contactsId
+              })
+              .join(',')
+            // crmBusinessUnrelateContactsAPI(params)
+            //   .then(res => {
+            //     this.getDetail()
+            //     this.$message.success('操作成功')
+            //   })
+            //   .catch(() => {})
+          })
+          .catch(() => {
+            this.$message.info('已取消操作')
+          })
+      }
+    },
+
+    /**
+     * 表头数据
+     */
+    getFieldList () {
+      this.fieldList.push(
+        { prop: 'RealName', label: '联系人姓名', width: '100' },
+        { prop: 'DepartmentName', label: '所属部门', width: '50' },
+        { prop: 'JobPosition', label: '职位', width: '80' },
+        { prop: 'MobilePhone', label: '联系电话', width: '120' },
+        { prop: 'OwerUserName', label: '销售负责人', width: '80' },
+        { prop: 'Email', label: '联系人邮箱', width: '80' }
+
+        // { prop: 'ContacterNumber', label: '客户联系人编码', width: '100' },
+        // { prop: 'Sex', label: '性别', width: '150' },
+        // { prop: 'BirthDay', label: '生日', width: '100' },
+        // { prop: 'IsCustomerDefault', label: '是否为默认联系客户', width: '100' },
+        // { prop: 'QQNumber', label: 'QQ', width: '150' },
+        // { prop: 'WeixinNumber', label: '微信号', width: '150' },
+        // { prop: 'CreateTime', label: '创建时间', width: '150' },
+        // { prop: 'OwerUserName', label: '负责人', width: '150' },
+        // { prop: 'DocumentFiles', label: '关联附件', width: '150' }
+      )
+    },
+
+    /**
+     * 获取数据
+     */
+    getDetail () {
+      this.loading = true
+      const request = {
+        customer: GetCustomerContacterList,
+        businessCustomer: GetCustomerContacterList
+        // business: crmBusinessQueryContactsAPI
+      }[this.crmType]
+      const params = {}
+      params['Id'] = this.id
+      params['PageSize'] = this.pageSize
+      params['PageIndex'] = this.currentPage
+      request(params)
+        .then(res => {
+          if (this.fieldList.length === 0) {
+            this.getFieldList()
+          }
+          this.nopermission = false
+          this.loading = false
+          this.list = res.data.Result.List || []
+          this.total = res.data.Result.Count || 0
+          console.log(this.list)
+        })
+        .catch(data => {
+          if (data.code === 102) {
+            this.nopermission = true
+          }
+          this.loading = false
+        })
+    },
+    // 当某一行被点击时会触发该事件
+    handleRowClick (row, column, event) {
+      // this.contactsId = row.contactsId
+      // this.showFullDetail = true
+    },
+    /** 通过回调控制表头style */
+    headerRowStyle ({ row, column, rowIndex, columnIndex }) {
+      return { textAlign: 'left' }
+    },
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      return { textAlign: 'left' }
+    },
+    /** 新建 */
+    createClick () {
+      /** 客户 下新建联系人 */
+      if (this.crmType === 'customer') {
+        this.createActionInfo.data['customer'] = this.detail
+      } else if (this.crmType === 'business') {
+        this.createActionInfo.data['customer'] = this.detail
+        this.createActionInfo.relativeData = {
+          businessId: this.detail.businessId
+        }
+      }
+      this.isCreate = true
+    },
+    createSaveSuccess () {
+      if (this.canRelation) {
+        this.$refs.crmrelative.refreshList()
+      } else {
+        this.getDetail()
+      }
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+@import '../styles/relativecrm.scss';
+</style>
diff --git a/src/views/clients/components/RelativeContract.vue b/src/views/clients/components/RelativeContract.vue
new file mode 100644
index 0000000..bf599d6
--- /dev/null
+++ b/src/views/clients/components/RelativeContract.vue
@@ -0,0 +1,327 @@
+<template>
+  <div
+    v-empty="nopermission"
+    class="rc-cont"
+    xs-empty-icon="nopermission"
+    xs-empty-text="暂无权限">
+    <flexbox
+      v-if="crmType==='business'"
+      class="rc-head"
+      direction="row-reverse">
+      <el-button
+        class="rc-head-item"
+        type="primary"
+        @click.native="createClick">新建合同
+      </el-button>
+    </flexbox>
+    <el-table
+      :data="list"
+      :height="tableHeight"
+      :header-cell-style="headerRowStyle"
+      :cell-style="cellStyle"
+      style="width: 100%;border: 1px solid #E6E6E6;"
+      @row-click="handleRowClick">
+      <el-table-column
+        v-for="(item, index) in fieldList"
+        :key="index"
+        :prop="item.prop"
+        :formatter="fieldFormatter"
+        :label="item.label"
+        show-overflow-tooltip>
+        <template
+          slot="header"
+          slot-scope="scope">
+          <div class="table-head-name">{{ scope.column.label }}</div>
+        </template>
+       </el-table-column>
+       <el-table-column prop="BeforeSealFile" label="盖章前合同">
+            <template
+              slot="header"
+              slot-scope="scope">
+              <div class="table-head-name">{{ scope.column.label }}</div>
+            </template>
+            <template slot-scope="scope">
+              <span>{{scope.row.BeforeSealFile===''?'--':'点击下载'}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="SealFile" label="盖章后合同">
+            <template
+              slot="header"
+              slot-scope="scope">
+              <div class="table-head-name">{{ scope.column.label }}</div>
+            </template>
+            <template slot-scope="scope">
+              <span>{{scope.row.SealFile===''?'--':'点击下载'}}</span>
+            </template>
+          </el-table-column>
+    </el-table>
+    <div class="p-contianer" v-show='total>0'>
+        <el-pagination
+          :current-page="currentPage"
+          :page-sizes="pageSizes"
+          :page-size.sync="pageSize"
+          :total="total"
+          class="p-bar"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"/>
+      </div>
+
+    <c-r-m-full-screen-detail
+      :visible.sync="showFullDetail"
+      :id="contractId"
+      crm-type="contract"/>
+    <el-dialog title="新建合同" :visible.sync="isCreate" :modal-append-to-body="false" width="30%">
+      <c-r-m-create-file-view
+        v-if="isCreate"
+        :id="id"
+        :action="createActionInfo"
+        crm-type="contract"
+        @save-success="createSaveSuccess"
+        @hiden-view="isCreate=false"/>
+    </el-dialog>
+  </div>
+</template>
+
+<script type="text/javascript">
+import loading from '../mixins/loading'
+import CRMCreateFileView from './CRMCreateFileView'
+import { GetCustomerAgreenmentList } from '@/api/customermanagement/customerManage'
+import { GetSalesChanceAgreementList } from '@/api/customermanagement/business'
+import { downloadFile } from '@/utils'
+// import { moneyFormat } from '@/utils'
+
+export default {
+  name: 'RelativeContract', // 相关联系人  可能再很多地方展示 放到客户管理目录下
+  components: {
+    CRMFullScreenDetail: () => import('./CRMFullScreenDetail.vue'),
+    CRMCreateFileView
+  },
+  mixins: [loading],
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    /** 是公海 默认是客户 */
+    isSeas: {
+      type: Boolean,
+      default: false
+    },
+    /** 联系人人下 新建商机 需要联系人里的客户信息  合同下需要客户和商机信息 */
+    detail: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  data () {
+    return {
+      nopermission: false,
+      list: [],
+      fieldList: [],
+      tableHeight: '400px',
+      showFullDetail: false,
+      isCreate: false, // 控制新建
+      contractId: '', // 查看全屏联系人详情的 ID
+      // 创建的相关信息
+      createActionInfo: { type: 'save', crmType: this.crmType, data: {} },
+      total: 0,
+      currentPage: 1,
+      pageSize: 10,
+      pageSizes: [10, 30, 60, 100]
+    }
+  },
+  computed: {},
+  watch: {
+    id: function (val) {
+      this.list = []
+      this.getDetail()
+    }
+  },
+  mounted () {
+    this.getDetail()
+  },
+  activated: function () {},
+  deactivated: function () {},
+  methods: {
+    handleSizeChange (newSize) {
+      this.pageSize = newSize
+      this.getDetail()
+    },
+    handleCurrentChange (newPage) {
+      this.currentPage = newPage
+      this.getDetail()
+    },
+    /** 格式化字段 */
+    fieldFormatter (row, column) {
+      if (column.property === 'Sex') {
+        return { 1: '男', 2: '女' }[row.Sex]
+      } else if (column.property === 'IsCustomerDefault') {
+        return { true: '是', false: '否' }[row.IsCustomerDefault]
+      } else if (column.property === 'CompanyType') {
+        return {0: '暂无', 1: '国企', 2: '外企', 3: '民营', 4: '其他'}[row.CompanyType]
+      } else if (column.property === 'SealStatus') {
+        return this.getStatusName(row.SealStatus)
+      } else if (column.property === 'SealType') {
+        return this.getSealName(row.SealType)
+      } else if (column.property === 'AuditStatus') {
+        return this.getAuditStatus(row.AuditStatus)
+      } else if (column.property === 'IsSeal') {
+        return this.getSwitch(row.IsSeal)
+      }
+      // 如果需要格式化
+      return row[column.property] || '--'
+    },
+    getFieldList () {
+      this.fieldList.push(
+        { prop: 'AgreeName', label: '合同名称' },
+        { prop: 'Comment', label: '合同备注' },
+        { prop: 'AuditStatus', label: '是否审核', width: '100' },
+        { prop: 'AuditUserName', label: '审核人' },
+        { prop: 'SealType', label: '合同类型' },
+        { prop: 'IsSeal', label: '是否盖章', width: '100' },
+        { prop: 'SealUserName', label: '盖章上传人' },
+        { prop: 'CreateTime', label: '创建时间' },
+        { prop: 'ExpressNumber', label: '快递单号' },
+        { prop: 'ExpressComment', label: '快递备注信息' }
+        // { prop: 'BeforeSealFile', label: '盖章前合同' },
+        // { prop: 'SealFile', label: '盖章后合同' }
+      )
+    },
+    getDetail () {
+      this.loading = true
+      const request = {
+        customer: GetCustomerAgreenmentList,
+        businessCustomer: GetCustomerAgreenmentList,
+        business: GetSalesChanceAgreementList,
+        businessChances: GetSalesChanceAgreementList
+      }[this.crmType]
+      const params = {}
+      params['Id'] = this.id
+      params['PageSize'] = this.pageSize
+      params['PageIndex'] = this.currentPage
+      request(params)
+        .then(res => {
+          if (this.fieldList.length === 0) {
+            this.getFieldList()
+          }
+          this.nopermission = false
+          this.loading = false
+          this.list = res.data.Result.List
+          this.total = res.data.Result.Count
+        })
+        .catch(data => {
+          if (data.code === 102) {
+            this.nopermission = true
+          }
+          this.loading = false
+        })
+    },
+
+    /**
+     * 对应的状态名
+     */
+    getStatusName (status) {
+      if (status === 1) {
+        return '已盖章'
+      } else if (status === 2) {
+        return '未盖章'
+      }
+      return '暂无'
+    },
+    getSealName (type) {
+      if (type === 1) {
+        return '合同章'
+      } else if (type === 2) {
+        return '公章'
+      }
+      return '暂无'
+    },
+    getAuditStatus (type) {
+      if (type === 1) {
+        return '审批中'
+      } else if (type === 2) {
+        return '通过'
+      } else if (type === 3) {
+        return '驳回'
+      }
+      return '暂无'
+    },
+    getSwitch (type) {
+      if (type === false) {
+        return '否'
+      } else if (type === true) {
+        return '是'
+      }
+      return '暂无'
+    },
+    // 当某一行被点击时会触发该事件
+    handleRowClick (row, column, event) {
+      if (column.property === 'BeforeSealFile' || column.property === 'SealFile') {
+        if (column.property === 'BeforeSealFile' && row.BeforeSealFile !== '') {
+          this.handleFile(column, row)
+        }
+        if (column.property === 'SealFile' && row.SealFile !== '') {
+          this.handleFile(column, row)
+        }
+      }
+      // else if (column.property === 'ChanceName') {
+      //   this.rowID = row.Id
+      //   this.businessId = row.Id
+      //   this.rowType = 'business'
+      //   this.showFullDetail = true
+      // }
+    },
+    handleFile (column, data) {
+      if (column.property === 'BeforeSealFile') {
+        downloadFile({ path: data.BeforeSealFile, name: data.BeforeSealFile })
+      } else if (column.property === 'SealFile') {
+        downloadFile({ path: data.SealFile, name: data.SealFile })
+      }
+    },
+    /** 通过回调控制表头style */
+    headerRowStyle ({ row, column, rowIndex, columnIndex }) {
+      return { textAlign: 'left' }
+    },
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      if (column.property === 'BeforeSealFile' || column.property === 'SealFile') {
+        return { color: '#4D88FF', cursor: 'pointer' }
+      } else if (column.property === 'AuditStatus') {
+        if (row[column.property] === 1) {
+          return { color: '#FF8800' }
+        } else if (row[column.property] === 2) {
+          return { color: '#2DB300' }
+        } else if (row[column.property] === 3) {
+          return { color: '#FF4D4D' }
+        }
+      } else {
+        return { textAlign: 'left' }
+      }
+    },
+    /** 新建 */
+    createClick () {
+      /** 客户 和 商机 下新建合同 */
+      if (this.crmType === 'business') {
+        this.createActionInfo.data['customer'] = this.detail
+        this.createActionInfo.data['business'] = this.detail
+      } else if (this.crmType === 'customer') {
+        this.createActionInfo.data['customer'] = this.detail
+      }
+      this.isCreate = true
+    },
+    createSaveSuccess () {
+      this.getDetail()
+      this.isCreate = false
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+@import '../styles/relativecrm.scss';
+</style>
diff --git a/src/views/clients/components/RelativeFiles.vue b/src/views/clients/components/RelativeFiles.vue
new file mode 100644
index 0000000..b35d6f9
--- /dev/null
+++ b/src/views/clients/components/RelativeFiles.vue
@@ -0,0 +1,318 @@
+<template>
+  <div class="rc-cont">
+    <flexbox
+      v-if="!isSeas"
+      class="rc-head"
+      direction="row-reverse">
+      <!--<el-button
+        class="rc-head-item"
+        type="primary"
+        @click.native="addFile">上传附件</el-button>-->
+      <input
+        id="file"
+        type="file"
+        class="rc-head-file"
+        accept="*/*"
+        multiple
+        @change="uploadFile">
+    </flexbox>
+    <el-table
+      :data="list"
+      :height="tableHeight"
+      :header-cell-style="headerRowStyle"
+      :cell-style="cellStyle"
+      align="center"
+      header-align="center"
+      style="width: 100%;border: 1px solid #E6E6E6;"
+      @row-click="handleRowClick">
+      <el-table-column
+        v-for="(item, index) in fieldList"
+        :key="index"
+        :prop="item.prop"
+        :label="item.label"
+        :formatter="fieldFormatter"
+        show-overflow-tooltip/>
+      <!--<el-table-column
+        label="操作"
+        width="150">
+        <template slot-scope="scope">
+          <flexbox justify="center">
+            <el-button
+              type="text"
+              @click.native="handleFile('preview', scope)">预览</el-button>
+            <el-button
+              type="text"
+              @click.native="handleFile('edit', scope)">重命名</el-button>
+            <el-button
+              type="text"
+              @click.native="handleFile('delete', scope)">删除</el-button>
+          </flexbox>
+        </template>
+      </el-table-column> -->
+    </el-table>
+    <div class="p-contianer" v-show='total>0'>
+      <el-pagination
+        :current-page="currentPage"
+        :page-sizes="pageSizes"
+        :page-size.sync="pageSize"
+        :total="total"
+        class="p-bar"
+        layout="total, sizes, prev, pager, next, jumper"
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"/>
+    </div>
+    <el-dialog
+      :append-to-body="true"
+      :visible.sync="editDialog"
+      title="编辑"
+      width="30%">
+      <el-form :model="editForm">
+        <el-form-item
+          label="新名称"
+          label-width="100">
+          <el-input
+            v-model="editForm.name"
+            autocomplete="off"/>
+        </el-form-item>
+      </el-form>
+      <div
+        slot="footer"
+        class="dialog-footer">
+        <el-button @click="editDialog = false">取 消</el-button>
+        <el-button
+          type="primary"
+          @click="confirmEdit">确 定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script type="text/javascript">
+import loading from '../mixins/loading'
+import { GetCustomerDocumentFileList } from '@/api/customermanagement/customerManage'
+import { GetSalesDocumentFileList } from '@/api/customermanagement/business'
+import { GetContacterDocumentFileList } from '@/api/customermanagement/contacts'
+// import {
+//   crmFileSave,
+//   crmFileIndex,
+//   crmFileDelete,
+//   crmFileUpdate
+// } from '@/api/common'
+
+export default {
+  name: 'RelativeFiles', // 相关附件  可能再很多地方展示 放到客户管理目录下
+  components: {},
+  mixins: [loading],
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    /** 联系人人下 新建商机 需要联系人里的客户信息  合同下需要客户和商机信息 */
+    detail: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    /** 是公海 默认是客户 */
+    isSeas: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    return {
+      list: [],
+      fieldList: [],
+      tableHeight: '400px',
+      /** 重命名 弹窗 */
+      editDialog: false,
+      /** 编辑信息 */
+      editForm: { name: '', data: {} },
+      total: 0,
+      currentPage: 1,
+      pageSize: 10,
+      pageSizes: [10, 30, 60, 100]
+    }
+  },
+  computed: {},
+  watch: {
+    id: function (val) {
+      this.list = []
+      this.getDetail()
+    }
+  },
+  mounted () {
+    this.fieldList.push(
+      { prop: 'DocumentName', label: '附件名称', width: '300' },
+      { prop: 'Comment', label: '备注', width: '400' },
+      { prop: 'DocumentFileName', label: '文档文件名', width: '400' },
+      { prop: 'FileExtensionName', label: '扩展名', width: '200' },
+      // { prop: 'DocumentType', label: '文档所属业务类型', width: '200' },
+      { prop: 'FileType', label: '文档附件类型', width: '100' },
+      { prop: 'CreateTime', label: '创建时间', width: '200' }
+    )
+
+    this.getDetail()
+  },
+  activated: function () {},
+  deactivated: function () {},
+  methods: {
+    handleSizeChange (newSize) {
+      this.pageSize = newSize
+      this.getDetail()
+    },
+    handleCurrentChange (newPage) {
+      this.currentPage = newPage
+      this.getDetail()
+    },
+    getDetail () {
+      this.loading = true
+      const request = {
+        customer: GetCustomerDocumentFileList,
+        business: GetSalesDocumentFileList,
+        contacts: GetContacterDocumentFileList
+      }[this.crmType]
+      const params = {}
+      params['Id'] = this.id
+      params['PageSize'] = this.pageSize
+      params['PageIndex'] = this.currentPage
+      request(params)
+        .then(res => {
+          this.loading = false
+          this.list = res.data.Result
+          this.total = res.data.Result.length
+        })
+        .catch(() => {
+          this.loading = false
+        })
+    },
+    /** 格式化字段 */
+    fieldFormatter (row, column) {
+      // 如果需要格式化
+      if (column.property === 'FileType') {
+        return this.getStatusName(row.FileType)
+      }
+      return row[column.property] || '--'
+    },
+    getStatusName (status) {
+      if (status === 1) {
+        return '附件'
+      } else if (status === 2) {
+        return '图片'
+      }
+      return '暂无'
+    },
+    addFile () {
+      document.getElementById('file').click()
+    },
+    /** 图片选择出发 */
+    uploadFile (event) {
+      var files = event.target.files
+      for (let index = 0; index < files.length; index++) {
+        const file = files[index]
+        // if (file.type.indexOf('image') !== -1) {
+        var params = {}
+        params.batchId = this.detail.batchId
+        params.file = file
+        // crmFileSave(params)
+        //   .then(res => {
+        //     this.getDetail()
+        //   })
+        //   .catch(() => {})
+        // }
+      }
+
+      event.target.value = ''
+    },
+    // 当某一行被点击时会触发该事件
+    handleRowClick (row, column, event) {},
+    /** 编辑删除cell */
+    handleFile (type, item) {
+      if (type === 'preview') {
+        var previewList = this.list.map(element => {
+          element.url = element.DocumentFileName
+          return element
+        })
+        this.$bus.emit('preview-image-bus', {
+          index: item.$index,
+          data: previewList
+        })
+      } else if (type === 'delete') {
+        this.$confirm('您确定要删除该文件吗?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+          .then(() => {
+            // crmFileDelete({
+            //   id: item.row.fileId
+            // })
+            //   .then(res => {
+            //     this.list.splice(item.$index, 1)
+            //     this.$message.success('操作成功')
+            //   })
+            //   .catch(() => {})
+          })
+          .catch(() => {
+            this.$message({
+              type: 'info',
+              message: '已取消操作'
+            })
+          })
+      } else {
+        this.editForm.data = item
+        this.editForm.name = item.row.name
+        this.editDialog = true
+      }
+    },
+    confirmEdit () {
+      if (this.editForm.name) {
+        // crmFileUpdate({
+        //   fileId: this.editForm.data.row.fileId,
+        //   name: this.editForm.name
+        // })
+        //   .then(res => {
+        //     this.$message.success('编辑成功')
+        //     this.editDialog = false
+        //     var item = this.list[this.editForm.data.$index]
+        //     item.name = this.editForm.name
+        //   })
+        //   .catch(() => {})
+      }
+    },
+    /** 通过回调控制表头style */
+    headerRowStyle ({ row, column, rowIndex, columnIndex }) {
+      return { textAlign: 'left' }
+    },
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      return { textAlign: 'left' }
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+@import '../styles/relativecrm.scss';
+.h-item {
+  font-size: 13px;
+  color: #409eff;
+  margin: 0 5px;
+  cursor: pointer;
+}
+
+.rc-head-file {
+  position: absolute;
+  top: 0;
+  right: 0;
+  height: 98px;
+  width: 98px;
+  opacity: 0;
+  z-index: -1;
+  cursor: pointer;
+}
+</style>
diff --git a/src/views/clients/components/RelativeHandle.vue b/src/views/clients/components/RelativeHandle.vue
new file mode 100644
index 0000000..5d56349
--- /dev/null
+++ b/src/views/clients/components/RelativeHandle.vue
@@ -0,0 +1,161 @@
+<template>
+  <div
+    v-empty="list"
+    class="rc-cont"
+    style="padding-right:250px;min-height:500px;">
+    <flexbox
+      v-for="(item, index) in list"
+      :key="index"
+      class="ha-cont"
+      align="stretch"
+      justify="flex-start">
+      <div class="ha-week">{{ item.CreateTime}}</div>
+      <div class="ha-circle"/>
+      <!--<div class="ha-time">{{ item.CreateTime|filterTimestampToFormatTime('H:mm') }}</div>
+      <div
+        v-photo="item"
+        v-lazy:background-image="$options.filters.filterUserLazyImg(item.img)"
+        class="div-photo ha-img"/>-->
+      <div class="ha-name">{{ item.CreateUserName }}</div>
+      <div class="ha-content">
+        <!--<p
+          v-for="(info, infoIndex) in item.Content"
+          :key="infoIndex">{{ info }}</p>-->
+          <p>{{ item.Content }}</p>
+      </div>
+      <div class="ha-line"/>
+    </flexbox>
+  </div>
+</template>
+
+<script type="text/javascript">
+import loading from '../mixins/loading'
+// import crmTypeModel from '@/views/clients/model/crmTypeModel'
+import { GetCustomerOperationLogList } from '@/api/customermanagement/customerManage'
+import { GetSalesChanceOperationLogList } from '@/api/customermanagement/business'
+import { GetContacterOperationLogList } from '@/api/customermanagement/contacts'
+
+export default {
+  name: 'RelativeHandle', // 相关操作  可能再很多地方展示 放到客户管理目录下
+  components: {},
+  mixins: [loading],
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    /** 联系人人下 新建商机 需要联系人里的客户信息  合同下需要客户和商机信息 */
+    detail: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    /** 是公海 默认是客户 */
+    isSeas: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    return {
+      list: []
+    }
+  },
+  computed: {},
+  watch: {
+    id: function (val) {
+      this.list = []
+      this.getDetail()
+    }
+  },
+  mounted () {
+    this.getDetail()
+  },
+  activated: function () {},
+  deactivated: function () {},
+  methods: {
+    getDetail () {
+      this.loading = true
+      const request = {
+        customer: GetCustomerOperationLogList,
+        businessCustomer: GetCustomerOperationLogList,
+        business: GetSalesChanceOperationLogList,
+        businessChances: GetSalesChanceOperationLogList,
+        contacts: GetContacterOperationLogList
+      }[this.crmType]
+      const params = {}
+      params['Id'] = this.id
+      params['PageSize'] = 10
+      params['PageIndex'] = 1
+      request(params)
+        .then(res => {
+          this.loading = false
+          this.list = res.data.Result.List
+        })
+        .catch(() => {
+          this.loading = false
+        })
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+@import '../styles/relativecrm.scss';
+.ha-cont {
+  font-size: 12px;
+  position: relative;
+  line-height: 20px;
+  min-height: 40px;
+  padding-top: 3px;
+  .ha-week {
+    margin: 0 17px 0 10px;
+    flex-shrink: 0;
+    color: #777;
+    width: 80px;
+  }
+  .ha-time {
+    padding: 0 10px 0 24px;
+    flex-shrink: 0;
+    color: #aaa;
+  }
+  .ha-circle {
+    flex-shrink: 0;
+    width: 18px;
+    height: 18px;
+    border-radius: 9px;
+    background-color: white;
+    border: 5px solid #a5ecd7;
+  }
+  .ha-img {
+    flex-shrink: 0;
+    margin: -3px 10px 0 10px;
+    display: block;
+    width: 30px;
+    height: 30px;
+    border-radius: 15px;
+  }
+  .ha-name {
+    padding: 0 10px;
+    flex-shrink: 0;
+    color: #333;
+  }
+  .ha-content {
+    padding: 0px 10px 10px 10px;
+    flex: 1;
+    color: #333;
+  }
+  .ha-line {
+    position: absolute;
+    z-index: -1;
+    width: 1px;
+    top: 3px;
+    bottom: -3px;
+    left: 115px;
+    background-color: #e6e6e6;
+  }
+}
+</style>
diff --git a/src/views/clients/components/RelativeOffers.vue b/src/views/clients/components/RelativeOffers.vue
new file mode 100644
index 0000000..6c35215
--- /dev/null
+++ b/src/views/clients/components/RelativeOffers.vue
@@ -0,0 +1,324 @@
+<template>
+  <div
+    v-empty="nopermission"
+    class="rc-cont"
+    xs-empty-icon="nopermission"
+    xs-empty-text="暂无权限">
+    <flexbox
+      v-if="crmType==='business'"
+      class="rc-head"
+      direction="row-reverse">
+      <el-button
+        class="rc-head-item"
+        type="primary"
+        @click.native="createClick">新建报价
+      </el-button>
+    </flexbox>
+    <el-table
+      :data="list"
+      :height="tableHeight"
+      :header-cell-style="headerRowStyle"
+      :cell-style="cellStyle"
+      style="width: 100%;border: 1px solid #E6E6E6;"
+      @row-click="handleRowClick">
+      <el-table-column
+        v-for="(item, index) in fieldList"
+        :key="index"
+        :prop="item.prop"
+        :formatter="fieldFormatter"
+        :label="item.label"
+        show-overflow-tooltip>
+        <template
+          slot="header"
+          slot-scope="scope">
+          <div class="table-head-name">{{ scope.column.label }}</div>
+        </template>
+       </el-table-column>
+       <el-table-column prop="BeforeSealFile" label="盖章前文件">
+        <template
+          slot="header"
+          slot-scope="scope">
+          <div class="table-head-name">{{ scope.column.label }}</div>
+        </template>
+        <template slot-scope="scope">
+          <span>{{scope.row.BeforeSealFile===''?'--':'点击下载'}}</span>
+        </template>
+       </el-table-column>
+       <el-table-column prop="SealFile" label="盖章后文件">
+        <template
+          slot="header"
+          slot-scope="scope">
+          <div class="table-head-name">{{ scope.column.label }}</div>
+        </template>
+        <template slot-scope="scope">
+          <span>{{scope.row.SealFile===''?'--':'点击下载'}}</span>
+        </template>
+       </el-table-column>
+    </el-table>
+    <div class="p-contianer" v-show='total>0'>
+        <el-pagination
+          :current-page="currentPage"
+          :page-sizes="pageSizes"
+          :page-size.sync="pageSize"
+          :total="total"
+          class="p-bar"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"/>
+      </div>
+
+    <c-r-m-full-screen-detail
+      :visible.sync="showFullDetail"
+      :id="contractId"
+      crm-type="offers"/>
+    <el-dialog title="新建报价" :visible.sync="isCreate" :modal-append-to-body="false" width="30%">
+      <c-r-m-create-file-view
+        v-if="isCreate"
+        :id="id"
+        :action="createActionInfo"
+        :show="isCreate"
+        crm-type="offers"
+        @save-success="createSaveSuccess"
+        @hiden-view="isCreate=false"/>
+    </el-dialog>
+  </div>
+</template>
+
+<script type="text/javascript">
+import loading from '../mixins/loading'
+import CRMCreateFileView from './CRMCreateFileView'
+import { GetCustomerOrderList } from '@/api/customermanagement/customerManage'
+import { GetSalesChanceQuotationSheetList } from '@/api/customermanagement/business'
+import { downloadFile } from '@/utils'
+// import { moneyFormat } from '@/utils'
+
+export default {
+  name: 'RelativeOffers', // 相关报价  可能再很多地方展示 放到客户管理目录下
+  components: {
+    CRMFullScreenDetail: () => import('./CRMFullScreenDetail.vue'),
+    CRMCreateFileView
+  },
+  mixins: [loading],
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    /** 是公海 默认是客户 */
+    isSeas: {
+      type: Boolean,
+      default: false
+    },
+    /** 联系人人下 新建商机 需要联系人里的客户信息  合同下需要客户和商机信息 */
+    detail: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  data () {
+    return {
+      nopermission: false,
+      list: [],
+      fieldList: [],
+      tableHeight: '400px',
+      showFullDetail: false,
+      isCreate: false, // 控制新建
+      contractId: '', // 查看全屏联系人详情的 ID
+      // 创建的相关信息
+      createActionInfo: { type: 'save', crmType: this.crmType, data: {} },
+      total: 0,
+      currentPage: 1,
+      pageSize: 10,
+      pageSizes: [10, 30, 60, 100]
+    }
+  },
+  computed: {},
+  watch: {
+    id: function (val) {
+      this.list = []
+      this.getDetail()
+    }
+  },
+  mounted () {
+    this.getDetail()
+  },
+  activated: function () {},
+  deactivated: function () {},
+  methods: {
+    handleSizeChange (newSize) {
+      this.pageSize = newSize
+      this.getDetail()
+    },
+    handleCurrentChange (newPage) {
+      this.currentPage = newPage
+      this.getDetail()
+    },
+    /** 格式化字段 */
+    fieldFormatter (row, column) {
+      if (column.property === 'Sex') {
+        return { 1: '男', 2: '女' }[row.Sex]
+      } else if (column.property === 'IsCustomerDefault') {
+        return { true: '是', false: '否' }[row.IsCustomerDefault]
+      } else if (column.property === 'CompanyType') {
+        return {0: '暂无', 1: '国企', 2: '外企', 3: '民营', 4: '其他'}[row.CompanyType]
+      } else if (column.property === 'SealStatus') {
+        return this.getStatusName(row.SealStatus)
+      } else if (column.property === 'SealType') {
+        return this.getSealName(row.SealType)
+      } else if (column.property === 'AuditStatus') {
+        return this.getAuditStatus(row.AuditStatus)
+      } else if (column.property === 'IsSeal') {
+        return this.getSwitch(row.IsSeal)
+      }
+      // 如果需要格式化
+      return row[column.property] || '--'
+    },
+    getFieldList () {
+      this.fieldList.push(
+        { prop: 'QuotationNumber', label: '报价单编码' },
+        { prop: 'QuotationName', label: '报价单名称' },
+        // { prop: 'CustomerName', label: '客户名称' },
+        // { prop: 'SalesChanceName', label: '商机名称' },
+        { prop: 'AuditStatus', label: '是否审批' },
+        { prop: 'AuditUserName', label: '审批人' },
+        { prop: 'IsSeal', label: '是否盖章' },
+        { prop: 'SealUserName', label: '盖章上传人' },
+        { prop: 'CreateTime', label: '创建时间' },
+        { prop: 'Comment', label: '备注' }
+        // { prop: 'BeforeSealFile', label: '盖章前文件' },
+        // { prop: 'SealFile', label: '盖章后文件' }
+      )
+    },
+    getDetail () {
+      this.loading = true
+      const request = {
+        customer: GetCustomerOrderList,
+        businessCustomer: GetCustomerOrderList,
+        business: GetSalesChanceQuotationSheetList,
+        businessChances: GetSalesChanceQuotationSheetList
+      }[this.crmType]
+      const params = {}
+      params['Id'] = this.id
+      params['PageSize'] = this.pageSize
+      params['PageIndex'] = this.currentPage
+      request(params)
+        .then(res => {
+          if (this.fieldList.length === 0) {
+            this.getFieldList()
+          }
+          this.nopermission = false
+          this.loading = false
+          this.list = res.data.Result.List
+          this.total = res.data.Result.Count
+        })
+        .catch(data => {
+          if (data.code === 102) {
+            this.nopermission = true
+          }
+          this.loading = false
+        })
+    },
+
+    /**
+     * 对应的状态名
+     */
+    getStatusName (status) {
+      if (status === 1) {
+        return '已盖章'
+      } else if (status === 2) {
+        return '未盖章'
+      }
+      return '暂无'
+    },
+    getSealName (type) {
+      if (type === 0) {
+        return '暂无'
+      } else if (type === 1) {
+        return '合同章'
+      } else if (type === 2) {
+        return '公章'
+      }
+      return '暂无'
+    },
+    getAuditStatus (type) {
+      if (type === 1) {
+        return '审批中'
+      } else if (type === 2) {
+        return '通过'
+      } else if (type === 3) {
+        return '驳回'
+      }
+      return '暂无'
+    },
+    getSwitch (type) {
+      if (type === false) {
+        return '否'
+      } else if (type === true) {
+        return '是'
+      }
+      return '暂无'
+    },
+    // 当某一行被点击时会触发该事件
+    handleRowClick (row, column, event) {
+      if (column.property === 'BeforeSealFile' || column.property === 'SealFile') {
+        if (column.property === 'BeforeSealFile' && row.BeforeSealFile !== '') {
+          this.handleFile(column, row)
+        }
+        if (column.property === 'SealFile' && row.SealFile !== '') {
+          this.handleFile(column, row)
+        }
+      }
+    },
+    handleFile (column, data) {
+      if (column.property === 'BeforeSealFile') {
+        downloadFile({ path: data.BeforeSealFile, name: data.BeforeSealFile })
+      } else if (column.property === 'SealFile') {
+        downloadFile({ path: data.SealFile, name: data.SealFile })
+      }
+    },
+    /** 通过回调控制表头style */
+    headerRowStyle ({ row, column, rowIndex, columnIndex }) {
+      return { textAlign: 'left' }
+    },
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      if (column.property === 'BeforeSealFile' || column.property === 'SealFile') {
+        return { color: '#4D88FF', cursor: 'pointer' }
+      } else if (column.property === 'AuditStatus') {
+        if (row[column.property] === 1) {
+          return { color: '#FF8800' }
+        } else if (row[column.property] === 2) {
+          return { color: '#2DB300' }
+        } else if (row[column.property] === 3) {
+          return { color: '#FF4D4D' }
+        }
+      } else {
+        return { textAlign: 'left' }
+      }
+    },
+    /** 新建 */
+    createClick () {
+      /** 客户 和 商机 下新建合同 */
+      if (this.crmType === 'business') {
+        this.createActionInfo.data['customer'] = this.detail
+        this.createActionInfo.data['business'] = this.detail
+      } else if (this.crmType === 'customer') {
+        this.createActionInfo.data['customer'] = this.detail
+      }
+      this.isCreate = true
+    },
+    createSaveSuccess () {
+      this.getDetail()
+      this.isCreate = false
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+@import '../styles/relativecrm.scss';
+</style>
diff --git a/src/views/clients/components/RelativeProduct.vue b/src/views/clients/components/RelativeProduct.vue
new file mode 100644
index 0000000..daa9f52
--- /dev/null
+++ b/src/views/clients/components/RelativeProduct.vue
@@ -0,0 +1,391 @@
+<template>
+  <div
+    v-empty="nopermission"
+    class="rc-cont"
+    xs-empty-icon="nopermission"
+    xs-empty-text="暂无权限">
+    <flexbox
+      class="rc-head"
+      direction="row-reverse"/>
+    <el-table
+      :data="productList"
+      :height="tableHeight"
+      :header-cell-style="headerRowStyle"
+      :cell-style="cellStyle"
+      style="width: 100%;border: 1px solid #E6E6E6;"
+      @row-click="handleRowClick">
+      <el-table-column
+        v-for="(item, index) in fieldList"
+        :key="index"
+        :prop="item.prop"
+        :label="item.label"
+        :formatter="fieldFormatter"
+        show-overflow-tooltip>
+        <template
+          slot="header"
+          slot-scope="scope">
+          <div class="table-head-name">{{ scope.column.label }}</div>
+        </template>
+      </el-table-column>
+      <el-table-column prop="Amount" label="使用数量">
+        <template
+          slot="header"
+          slot-scope="scope">
+          <div class="table-head-name">使用数量</div>
+        </template>
+        <template slot-scope="scope">
+            <el-input size="small" type="number" min='0' @keyup.enter.native="getEditData(scope.row)" @keyup.esc.native="cancelEdit(scope.row)" v-show="scope.row.show" v-model="scope.row.Amount" placeholder="请输入内容"></el-input><!--v-focus-->
+            <span v-show="!scope.row.show">{{scope.row.Amount}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="Department" label="使用部门" v-if="isLC">
+        <template
+          slot="header"
+          slot-scope="scope">
+          <div class="table-head-name">使用部门</div>
+        </template>
+       <template slot-scope="scope">
+           <el-input size="small" @keyup.enter.native="getEditData(scope.row)" @keyup.esc.native="cancelEdit(scope.row)" v-show="scope.row.show" v-model="scope.row.Department" placeholder="请输入使用部门"></el-input>
+           <span v-show="!scope.row.show">{{scope.row.Department}}</span>
+       </template>
+      </el-table-column>
+      <el-table-column prop="Comment" label="说明" v-if="isLC">
+        <template
+          slot="header"
+          slot-scope="scope">
+          <div class="table-head-name">说明</div>
+        </template>
+       <template slot-scope="scope">
+           <el-input size="small" @keyup.enter.native="getEditData(scope.row)" @keyup.esc.native="cancelEdit(scope.row)" v-show="scope.row.show" v-model="scope.row.Comment" placeholder="请输入说明"></el-input>
+           <span v-show="!scope.row.show">{{scope.row.Comment}}</span>
+       </template>
+      </el-table-column>
+      <el-table-column label="操作" width="150" v-if="crmType !== 'businessChances'">
+        <template
+          slot="header"
+          slot-scope="scope">
+          <div class="table-head-name">操作</div>
+        </template>
+        <template slot-scope="scope">
+          <el-button type="text" :disabled="!list.IsCanEdit" v-show="!scope.row.show" @click="scope.row.show=true">编辑 |</el-button>
+          <el-button type="text" v-show="scope.row.show" @click="getEditData(scope.row)" style="margin-left:0">保存 |</el-button>
+          <el-button type="text" v-show="scope.row.show" @click="cancelEdit(scope.row)" style="margin-left:0">取消</el-button>
+          <el-button type="text" :disabled="!list.IsCanEdit" v-show="!scope.row.show" @click="removeItem(scope.row)" style="margin-left:0">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+     <div class="p-contianer" v-show='total>0'>
+        <el-pagination
+          :current-page="currentPage"
+          :page-sizes="pageSizes"
+          :page-size.sync="pageSize"
+          :total="total"
+          class="p-bar"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"/>
+      </div>
+    <!--<flexbox class="handle-footer" style="display: none;">
+      <div class="discount-title">整单折扣(%):<span class="discount-title-value">{{ totalInfo.discountRate }}</span></div>
+      <div class="total-info">已选中产品:<span class="info-yellow">{{ productList.length }}</span>&nbsp;种&nbsp;&nbsp;总金额:<span class="info-yellow">{{ totalInfo.money }}</span>&nbsp;元</div>
+    </flexbox>-->
+    <c-r-m-full-screen-detail
+      :visible.sync="showFullDetail"
+      :id="productId"
+      crm-type="product"/>
+  </div>
+</template>
+
+<script type="text/javascript">
+import loading from '../mixins/loading'
+// GetSalesChanceProductList
+import { UpdateSalesChance, GetSalesChanceDetail, DeleteSalesChanceProduct } from '@/api/customermanagement/business'
+// import { crmContractProduct } from '@/api/customermanagement/contract'
+import { moneyFormat } from '@/utils'
+
+export default {
+  name: 'RelativeProduct', // 相关产品  可能再很多地方展示 放到客户管理目录下
+  components: {
+    CRMFullScreenDetail: () => import('./CRMFullScreenDetail.vue')
+  },
+  mixins: [loading],
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    /** 联系人人下 新建商机 需要联系人里的客户信息  合同下需要客户和商机信息 */
+    detail: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    /** 是公海 默认是客户 */
+    isSeas: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    return {
+      nopermission: false,
+      list: [],
+      productList: [],
+      fieldList: [],
+      tableHeight: '400px',
+      showFullDetail: false,
+      productId: '', // 查看全屏产品详情的 ID
+      totalInfo: { money: '0.00', discountRate: '0.00' },
+      total: 0,
+      currentPage: 1,
+      pageSize: 10,
+      pageSizes: [10, 30, 60, 100],
+      isLC: false
+    }
+  },
+  computed: {},
+  watch: {
+    id: function (val) {
+      this.list = []
+      this.getDetail()
+    }
+  },
+  mounted () {
+    this.getDetail()
+  },
+  activated: function () {},
+  deactivated: function () {},
+  methods: {
+    handleSizeChange (newSize) {
+      this.pageSize = newSize
+      this.getDetail()
+    },
+    handleCurrentChange (newPage) {
+      this.currentPage = newPage
+      this.getDetail()
+    },
+    getFieldList () {
+      this.fieldList = this.isLC ? [
+        { label: '产品线', prop: 'ProductLine' }
+      ] : [
+        { label: '产品类型', prop: 'ProductType' },
+        { label: 'SKU值', prop: 'SKU' }
+      ]
+      // this.fieldList.push({
+      //   prop: 'productName',
+      //   width: '200',
+      //   label: '产品名称'
+      // })
+      // this.fieldList.push({
+      //   prop: 'categoryName',
+      //   width: '200',
+      //   label: '产品类别'
+      // })
+      // this.fieldList.push({ prop: 'unit', width: '200', label: '单位' })
+      // this.fieldList.push({ prop: 'price', width: '200', label: '标准价格' })
+      // this.fieldList.push({ prop: 'salesPrice', width: '200', label: '售价' })
+      // this.fieldList.push({ prop: 'num', width: '200', label: '数量' })
+      // this.fieldList.push({
+      //   prop: 'discount',
+      //   width: '200',
+      //   label: '折扣(%)'
+      // })
+      // this.fieldList.push({ prop: 'subtotal', width: '200', label: '合计' })
+    },
+    getDetail () {
+      this.loading = true
+      const params = {}
+      params['Id'] = this.id
+      // params['PageSize'] = this.pageSize
+      // params['PageIndex'] = this.currentPage
+      this.getRequest()(params)
+        .then(res => {
+          this.nopermission = false
+          this.loading = false
+          this.list = res.data.Result || []
+          let data = []
+          if (this.list && this.list.ProjectProperty === 'LC协作') {
+            data = this.list.SalesChancePirates
+            this.isLC = true
+          } else {
+            data = this.list.Products
+            this.isLC = false
+          }
+          const newSelects = []
+          for (let i in data) {
+            newSelects.push(this.getShowItem(data[i]))
+          }
+          this.productList = newSelects
+          this.total = data.length
+          if (this.fieldList && this.fieldList.length === 0) {
+            this.getFieldList()
+          }
+          // this.total = res.data.Result.Count
+          // this.totalInfo.discountRate = res.data.discountRate
+        })
+        .catch(data => {
+          if (data.code === 102) {
+            this.nopermission = true
+          }
+          this.loading = false
+        })
+    },
+    getShowItem (data) {
+      const item = {}
+      if (!this.isLC) {
+        item.ProductType = data.ProductType
+        item.SKU = data.SKU
+        item.Amount = data.Amount
+        item.show = false
+        item.Id = data.Id
+      } else {
+        item.Amount = data.Amount
+        item.ProductLine = data.ProductLine
+        item.Comment = data.Comment
+        item.Department = data.Department
+        item.show = false
+        item.Id = data.Id
+      }
+      return item
+    },
+    getRequest () {
+      if (this.crmType === 'business' || this.crmType === 'businessChances') {
+        // return GetSalesChanceProductList
+        return GetSalesChanceDetail
+      }
+      // else if (this.crmType === 'contract') {
+      //   return crmContractProduct
+      // }
+    },
+    cancelEdit (row) {
+      row.show = false
+    },
+    getEditData (row) {
+      row.show = false
+      let list = JSON.parse(JSON.stringify(this.productList))
+      for (let i in list) {
+        list[i].Amount = JSON.parse(this.productList[i].Amount)
+        delete list[i].show
+        delete list[i].Id
+      }
+      if (this.isLC) {
+        this.list['SalesChancePirates'] = list
+      } else {
+        this.list['Products'] = list
+      }
+      console.log(list)
+      this.updateData('update')
+    },
+    // 删除操作
+    removeItem (row) {
+      console.log(row)
+      // this.productList.splice(index, 1)
+      // let list = JSON.parse(JSON.stringify(this.productList))
+      // for (let i in list) {
+      //   delete list[i].show
+      // }
+      // if (this.isLC) {
+      //   this.list['SalesChancePirates'] = list
+      // } else {
+      //   this.list['Products'] = list
+      // }
+      // this.updateData('delete')
+      this.$confirm('确定删除?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          DeleteSalesChanceProduct([{'Id': row.Id, 'PrdocutType': this.isLC ? 2 : 1}]).then(res => {
+            if (res.data.ErrorCode === 200) {
+              this.$message.success(res.data.Message)
+              this.getDetail()
+            } else {
+              this.$message.error(res.data.Message)
+            }
+          })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    },
+    updateData (sta) {
+      console.log(this.list, this.productList)
+      if (sta === 'update') {
+        for (let i in this.list) {
+          if (this.list[i] === '--') {
+            this.list[i] = ''
+          }
+        }
+      }
+      UpdateSalesChance(this.list)
+        .then(res => {
+          if (res.data.ErrorCode === 200) {
+            this.getDetail()
+            this.$message.success(
+              sta === 'update' ? '编辑成功' : '删除成功'
+            )
+          } else {
+            this.$message.error(res.data.Message)
+          }
+          this.loading = false
+        })
+        .catch(() => {
+          this.loading = false
+        })
+    },
+    // 当某一行被点击时会触发该事件
+    handleRowClick (row, column, event) {
+      // this.productId = row.productId
+      // this.showFullDetail = true
+    },
+    /** 通过回调控制表头style */
+    headerRowStyle ({ row, column, rowIndex, columnIndex }) {
+      return { textAlign: 'left' }
+    },
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      return { textAlign: 'left' }
+    },
+    /**
+     * 格式化表格
+     */
+    fieldFormatter (row, column) {
+      if (['price', 'subtotal', 'salesPrice'].includes(column.property)) {
+        return moneyFormat(row[column.property])
+      }
+      return row[column.property] || '--'
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+@import '../styles/relativecrm.scss';
+
+.handle-footer {
+  position: relative;
+  font-size: 12px;
+  padding: 8px 5px;
+  .discount-title {
+    color: #666;
+    .discount-title-value {
+      color: #333;
+    }
+  }
+  .total-info {
+    position: absolute;
+    right: 20px;
+    top: 5px;
+    .info-yellow {
+      color: #fd715a;
+    }
+  }
+}
+</style>
diff --git a/src/views/clients/components/RelativeReturnMoney.vue b/src/views/clients/components/RelativeReturnMoney.vue
new file mode 100644
index 0000000..8fa9a4e
--- /dev/null
+++ b/src/views/clients/components/RelativeReturnMoney.vue
@@ -0,0 +1,451 @@
+<template>
+  <div class="rc-cont">
+    <flexbox
+      v-if="!isSeas"
+      class="rc-head"
+      direction="row-reverse">
+      <!--<el-button
+        class="rc-head-item"
+        type="primary"
+        @click.native="createClick('plan')">新建回款计划</el-button>-->
+    </flexbox>
+    <el-table
+      :data="palnList"
+      :height="tableHeight"
+      :header-cell-style="headerRowStyle"
+      :cell-style="planCellStyle"
+      style="width: 100%;border: 1px solid #E6E6E6;margin-bottom: 30px;">
+      <el-table-column
+        v-for="(item, index) in planFieldList"
+        :key="index"
+        :prop="item.prop"
+        :label="item.label"
+        :formatter="planFieldFormatter"
+        show-overflow-tooltip>
+        <template
+          slot="header"
+          slot-scope="scope">
+          <div class="table-head-name">{{ scope.column.label }}</div>
+        </template>
+      </el-table-column>
+      <el-table-column
+        label="操作"
+        width="100"
+        v-if="crmType!=='businessCustomer'&& crmType!=='businessChances'">
+        <template
+          slot="header"
+          slot-scope="scope">
+          <div class="table-head-name">操作</div>
+        </template>
+        <template slot-scope="scope">
+          <flexbox justify="center">
+            <el-button
+              type="text"
+              @click.native="handleFile('edit', scope)">编辑</el-button>
+            <el-button
+              type="text"
+              @click.native="handleFile('delete', scope)">删除</el-button>
+          </flexbox>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!--<flexbox
+      class="rc-head"
+      direction="row-reverse"
+      style="margin-top: 15px;">
+      <el-button
+        v-if="!isSeas"
+        class="rc-head-item"
+        type="primary"
+        @click.native="createClick('money')">新建回款</el-button>
+    </flexbox>-->
+    <el-table
+      :data="list"
+      :height="tableHeight"
+      :header-cell-style="headerRowStyle"
+      :cell-style="cellStyle"
+      style="width: 100%;border: 1px solid #E6E6E6;"
+      @row-click="handleRowClick">
+      <el-table-column
+        v-for="(item, index) in fieldList"
+        :key="index"
+        :prop="item.prop"
+        :formatter="fieldFormatter"
+        :label="item.label"
+        show-overflow-tooltip>
+        <template
+          slot="header"
+          slot-scope="scope">
+          <div class="table-head-name">{{ scope.column.label }}</div>
+        </template>
+      </el-table-column>
+    </el-table>
+    <div class="p-contianer" v-show='total>0'>
+        <el-pagination
+          :current-page="currentPage"
+          :page-sizes="pageSizes"
+          :page-size.sync="pageSize"
+          :total="total"
+          class="p-bar"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"/>
+      </div>
+
+    <c-r-m-full-screen-detail
+      :visible.sync="showFullDetail"
+      :crm-type="showFullCrmType"
+      :id="showFullId"
+      @handle="detailHandle"/>
+    <c-r-m-create-view
+      v-if="isCreate"
+      :crm-type="createCrmType"
+      :action="createActionInfo"
+      @save-success="saveSuccess"
+      @hiden-view="isCreate=false"/>
+  </div>
+</template>
+
+<script type="text/javascript">
+import loading from '../mixins/loading'
+import CRMCreateView from './CRMCreateView'
+import {
+  GetCustomerPaymentRecordList,
+  GetCustomerPaymentPlanList
+} from '@/api/customermanagement/customerManage'
+// import {
+//   crmContractQueryReceivables,
+//   crmContractQueryReceivablesPlan
+// } from '@/api/clients/contract'
+// import {
+//   crmReceivablesPlanDeleteAPI
+// } from '@/api/clients/money'
+/** 注意  需要删除接口 */
+import { objDeepCopy, moneyFormat } from '@/utils'
+
+export default {
+  name: 'RelativeReturnMoney', // 相关回款  可能再很多地方展示 放到客户管理目录下
+
+  components: {
+    CRMCreateView,
+    CRMFullScreenDetail: () => import('./CRMFullScreenDetail.vue')
+  },
+
+  mixins: [loading],
+
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    /** 是公海 默认是客户 */
+    isSeas: {
+      type: Boolean,
+      default: false
+    },
+    /** 客户和 合同下 可新建 回款计划 */
+    detail: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+
+  data () {
+    return {
+      list: [],
+      fieldList: [],
+      tableHeight: '250px',
+      showFullDetail: false,
+      showFullCrmType: 'receivables',
+      showFullId: '', // 查看全屏详情的 ID
+      createCrmType: 'receivables_plan', // 创建回款计划
+      isCreate: false, // 新建回款回款
+      palnList: [],
+      planFieldList: [],
+      createActionInfo: {}, // 新建回款计划的时候 在客户 合同下导入关联信息
+      total: 0,
+      currentPage: 1,
+      pageSize: 10,
+      pageSizes: [10, 30, 60, 100]
+    }
+  },
+
+  computed: {},
+
+  watch: {
+    id: function (val) {
+      this.list = []
+      this.palnList = []
+      this.getList()
+      this.getPlanList()
+    }
+  },
+
+  mounted () {
+    this.planFieldList = [
+      { prop: 'num', width: '200', label: '期数' },
+      { prop: 'customerName', width: '200', label: '客户名称' },
+      { prop: 'contractNum', width: '200', label: '合同编号' },
+      { prop: 'money', width: '200', label: '计划回款金额' },
+      { prop: 'returnDate', width: '200', label: '计划回款日期' },
+      { prop: 'returnType', width: '200', label: '计划回款方式' },
+      { prop: 'remind', width: '200', label: '提前几日提醒' },
+      { prop: 'remark', width: '200', label: '备注' }
+    ]
+
+    this.getPlanList()
+
+    this.fieldList = [
+      { prop: 'receivablesNum', width: '200', label: '回款编号' },
+      { prop: 'contractName', width: '200', label: '合同名称' },
+      { prop: 'contractMoney', width: '200', label: '合同金额' },
+      { prop: 'receivablesMoney', width: '200', label: '回款金额' },
+      { prop: 'planNum', width: '200', label: '期数' },
+      { prop: 'ownerUserName', width: '200', label: '负责人' },
+      { prop: 'checkStatus', width: '200', label: '状态' },
+      { prop: 'returnTime', width: '200', label: '回款日期' }
+    ]
+    this.getList()
+  },
+
+  methods: {
+    handleSizeChange (newSize) {
+      this.pageSize = newSize
+      this.getDetail()
+    },
+    handleCurrentChange (newPage) {
+      this.currentPage = newPage
+      this.getDetail()
+    },
+    /** 格式化字段 */
+    planFieldFormatter (row, column) {
+      var aRules = this.formatterRules[column.property]
+      if (aRules) {
+        return aRules.formatter(row[column.property])
+      }
+      if (column.property === 'Sex') {
+        return { 1: '男', 2: '女' }[row.Sex]
+      } else if (column.property === 'IsCustomerDefault') {
+        return { true: '是', false: '否' }[row.IsCustomerDefault]
+      } else if (column.property === 'CompanyType') {
+        return {0: '暂无', 1: '国企', 2: '外企', 3: '民营', 4: '其他'}[row.CompanyType]
+      }
+      // 如果需要格式化
+      return row[column.property] || '--'
+    },
+    /**
+     * 回款计划列表
+     */
+    getPlanList () {
+      this.loading = true
+      const request = {
+        customer: GetCustomerPaymentPlanList,
+        businessCustomer: GetCustomerPaymentPlanList
+        // contract: crmContractQueryReceivablesPlan
+      }[this.crmType]
+      request(this.getParams())
+        .then(res => {
+          this.loading = false
+          this.palnList = res.data.Result.List
+        })
+        .catch(() => {
+          this.loading = false
+        })
+    },
+
+    /**
+     * 回款列表
+     */
+    getList () {
+      this.loading = true
+      const request = {
+        customer: GetCustomerPaymentRecordList,
+        businessCustomer: GetCustomerPaymentRecordList
+        // contract: crmContractQueryReceivables
+      }[this.crmType]
+      request(this.getParams())
+        .then(res => {
+          this.loading = false
+          this.list = res.data.Result.List
+          this.total = res.data.Result.Count
+        })
+        .catch(() => {
+          this.loading = false
+        })
+    },
+
+    /**
+     * 获取上传参数
+     */
+    getParams () {
+      if (this.crmType === 'customer' || this.crmType === 'businessCustomer') {
+        return { Id: this.id, PageSize: this.pageSize, PageIndex: this.currentPage }
+      } else if (this.crmType === 'contract' || this.crmType === 'businessContract') {
+        return { contractId: this.id, pageType: 0 }
+      }
+      return {}
+    },
+
+    /**
+     * 当某一行被点击时会触发该事件
+     */
+    handleRowClick (row, column, event) {
+      // this.showFullId = row.receivablesId
+      // this.showFullCrmType = 'receivables'
+      // this.showFullDetail = true
+    },
+
+    /**
+     * 通过回调控制style
+     */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      if (columnIndex === 0) {
+        return { color: '#4D88FF', textAlign: 'center', cursor: 'pointer' }
+      } else {
+        return { textAlign: 'left' }
+      }
+    },
+
+    /**
+     * 通过回调控制style
+     */
+    planCellStyle ({ row, column, rowIndex, columnIndex }) {
+      return { textAlign: 'left' }
+    },
+
+    /**
+     * 新建回款和回款计划
+     */
+    createClick (type) {
+      this.createActionInfo = {
+        type: 'relative',
+        crmType: this.crmType,
+        data: {}
+      }
+      if (type === 'money') {
+        if (this.crmType === 'contract') {
+          this.createActionInfo.data['customer'] = objDeepCopy(this.detail)
+          this.createActionInfo.data['contract'] = objDeepCopy(this.detail)
+        } else if (this.crmType === 'customer') {
+          this.createActionInfo.data['customer'] = this.detail
+        }
+        this.createCrmType = 'receivables'
+        this.isCreate = true
+      } else if (type === 'plan') {
+        if (this.crmType === 'contract') {
+          this.createActionInfo.data['customer'] = objDeepCopy(this.detail)
+          this.createActionInfo.data['contract'] = objDeepCopy(this.detail)
+        } else if (this.crmType === 'customer') {
+          this.createActionInfo.data['customer'] = this.detail
+        }
+        this.createCrmType = 'receivables_plan'
+        this.isCreate = true
+      }
+    },
+
+    /**
+     * 新建成功
+     */
+    saveSuccess () {
+      if (this.createCrmType === 'receivables') {
+        this.getList()
+      } else {
+        this.getPlanList()
+      }
+    },
+
+    /**
+     * 编辑操作
+     */
+    handleFile (type, item) {
+      if (type === 'edit') {
+        this.createActionInfo = { type: 'update', id: item.row.planId }
+        this.createCrmType = 'receivables_plan'
+        this.isCreate = true
+      } else if (type === 'delete') {
+        this.$confirm('您确定要删除吗?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+          .then(() => {
+            // crmReceivablesPlanDeleteAPI({
+            //   planIds: item.row.planId
+            // })
+            //   .then(res => {
+            //     this.palnList.splice(item.$index, 1)
+            //     this.$message.success('删除成功')
+            //   })
+            //   .catch(() => {})
+          })
+          .catch(() => {
+            this.$message({
+              type: 'info',
+              message: '已取消操作'
+            })
+          })
+      }
+    },
+
+    /**
+     * 格式化字段
+     */
+    fieldFormatter (row, column, cellValue) {
+      // 如果需要格式化
+      if (column.property === 'checkStatus') {
+        return this.getStatusName(row.checkStatus)
+      } else if (['contractMoney', 'receivablesMoney', 'money'].includes(column.property)) {
+        return moneyFormat(cellValue)
+      }
+      return cellValue
+    },
+
+    /**
+     * 对应的状态名
+     */
+    getStatusName (status) {
+      if (status === 0) {
+        return '待审核'
+      } else if (status === 1) {
+        return '通过'
+      } else if (status === 2) {
+        return '拒绝'
+      } else if (status === 3) {
+        return '审核中'
+      } else if (status === 4) {
+        return '撤回'
+      } else if (status === 5) {
+        return '未提交'
+      } else if (status === 6) {
+        return '已作废'
+      }
+      return ''
+    },
+
+    /**
+     * 通过回调控制表头style
+     */
+    headerRowStyle ({ row, column, rowIndex, columnIndex }) {
+      return { textAlign: 'left' }
+    },
+
+    /**
+     * 详情操作
+     */
+    detailHandle (data) {
+      if (data.type === 'delete') {
+        this.getList()
+      }
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+@import '../styles/relativecrm.scss';
+</style>
diff --git a/src/views/clients/components/RelativeSchedule.vue b/src/views/clients/components/RelativeSchedule.vue
new file mode 100644
index 0000000..7a71fcb
--- /dev/null
+++ b/src/views/clients/components/RelativeSchedule.vue
@@ -0,0 +1,230 @@
+<template>
+  <div
+    v-empty="nopermission"
+    class="rc-cont"
+    xs-empty-icon="nopermission"
+    xs-empty-text="暂无权限">
+    <flexbox
+      v-if="!isSeas"
+      class="rc-head"
+      direction="row-reverse">
+      <!--<el-button
+        class="rc-head-item"
+        type="primary"
+        @click.native="createClick">新建待办事项
+      </el-button> -->
+    </flexbox>
+    <el-table
+      :data="list"
+      :height="tableHeight"
+      :header-cell-style="headerRowStyle"
+      :cell-style="cellStyle"
+      style="width: 100%;border: 1px solid #E6E6E6;"
+      @row-click="handleRowClick">
+      <el-table-column
+        v-for="(item, index) in fieldList"
+        :key="index"
+        :prop="item.prop"
+        :formatter="fieldFormatter"
+        :label="item.label"
+        show-overflow-tooltip/>
+    </el-table>
+    <div class="p-contianer" v-show='total>0'>
+        <el-pagination
+          :current-page="currentPage"
+          :page-sizes="pageSizes"
+          :page-size.sync="pageSize"
+          :total="total"
+          class="p-bar"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"/>
+      </div>
+
+    <c-r-m-full-screen-detail
+      :visible.sync="showFullDetail"
+      :id="contractId"
+      crm-type="contract"/>
+    <c-r-m-create-view
+      v-if="isCreate"
+      :action="createActionInfo"
+      crm-type="contract"
+      @save-success="createSaveSuccess"
+      @hiden-view="isCreate=false"/>
+  </div>
+</template>
+
+<script type="text/javascript">
+import loading from '../mixins/loading'
+import CRMCreateView from './CRMCreateView'
+import { GetCustomerOrderList } from '@/api/customermanagement/customerManage'
+import { GetSalesChanceJobScheduleList } from '@/api/customermanagement/business'
+// import { moneyFormat } from '@/utils'
+
+export default {
+  name: 'RelativeSchedule', // 相关报价  可能再很多地方展示 放到客户管理目录下
+  components: {
+    CRMFullScreenDetail: () => import('./CRMFullScreenDetail.vue'),
+    CRMCreateView
+  },
+  mixins: [loading],
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    /** 是公海 默认是客户 */
+    isSeas: {
+      type: Boolean,
+      default: false
+    },
+    /** 联系人人下 新建商机 需要联系人里的客户信息  合同下需要客户和商机信息 */
+    detail: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  data () {
+    return {
+      nopermission: false,
+      list: [],
+      fieldList: [],
+      tableHeight: '400px',
+      showFullDetail: false,
+      isCreate: false, // 控制新建
+      contractId: '', // 查看全屏联系人详情的 ID
+      // 创建的相关信息
+      createActionInfo: { type: 'relative', crmType: this.crmType, data: {} },
+      total: 0,
+      currentPage: 1,
+      pageSize: 10,
+      pageSizes: [10, 30, 60, 100]
+    }
+  },
+  computed: {},
+  watch: {
+    id: function (val) {
+      this.list = []
+      this.getDetail()
+    }
+  },
+  mounted () {
+    this.getDetail()
+  },
+  activated: function () {},
+  deactivated: function () {},
+  methods: {
+    handleSizeChange (newSize) {
+      this.pageSize = newSize
+      this.getDetail()
+    },
+    handleCurrentChange (newPage) {
+      this.currentPage = newPage
+      this.getDetail()
+    },
+    /** 格式化字段 */
+    fieldFormatter (row, column) {
+      var aRules = this.formatterRules[column.property]
+      if (aRules) {
+        return aRules.formatter(row[column.property])
+      }
+      if (column.property === 'Sex') {
+        return { 1: '男', 2: '女' }[row.Sex]
+      } else if (column.property === 'IsCustomerDefault') {
+        return { true: '是', false: '否' }[row.IsCustomerDefault]
+      } else if (column.property === 'CompanyType') {
+        return {0: '暂无', 1: '国企', 2: '外企', 3: '民营', 4: '其他'}[row.CompanyType]
+      } else if (column.property === 'IsCompleted') {
+        return this.getSwitch(row.IsCompleted)
+      }
+      // 如果需要格式化
+      return row[column.property] || '--'
+    },
+    getFieldList () {
+      this.fieldList.push(
+        { prop: 'Content', label: '内容', width: '200' },
+        { prop: 'PlanTime', label: '计划时间', width: '200' },
+        { prop: 'CustomerName', label: '关联客户名称', width: '200' },
+        { prop: 'ContacterName', label: '关联联系人', width: '200' },
+        { prop: 'ContacterMobilePhone', label: '关联联系人方式', width: '100' },
+        { prop: 'IsCompleted', label: '是否完成', width: '200' }
+      )
+    },
+    getDetail () {
+      this.loading = true
+      const request = {
+        customer: GetCustomerOrderList,
+        business: GetSalesChanceJobScheduleList
+      }[this.crmType]
+      const params = {}
+      params['Id'] = this.id
+      params['PageSize'] = this.pageSize
+      params['PageIndex'] = this.currentPage
+      request(params)
+        .then(res => {
+          if (this.fieldList.length === 0) {
+            this.getFieldList()
+          }
+          this.nopermission = false
+          this.loading = false
+          this.list = res.data.Result.List
+          this.total = res.data.Result.Count
+        })
+        .catch(data => {
+          if (data.code === 102) {
+            this.nopermission = true
+          }
+          this.loading = false
+        })
+    },
+
+    /**
+     * 对应的状态名
+     */
+    getSwitch (type) {
+      console.log(type)
+      if (type === false) {
+        return '否'
+      } else if (type === true) {
+        return '是'
+      }
+      return '暂无'
+    },
+    // 当某一行被点击时会触发该事件
+    handleRowClick (row, column, event) {
+      // this.contractId = row.contractId
+      // this.showFullDetail = true
+    },
+    /** 通过回调控制表头style */
+    headerRowStyle ({ row, column, rowIndex, columnIndex }) {
+      return { textAlign: 'left' }
+    },
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      return { textAlign: 'left' }
+    },
+    /** 新建 */
+    createClick () {
+      /** 客户 和 商机 下新建合同 */
+      if (this.crmType === 'business') {
+        this.createActionInfo.data['customer'] = this.detail
+        this.createActionInfo.data['business'] = this.detail
+      } else if (this.crmType === 'customer') {
+        this.createActionInfo.data['customer'] = this.detail
+      }
+      this.isCreate = true
+    },
+    createSaveSuccess () {
+      this.getDetail()
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+@import '../styles/relativecrm.scss';
+</style>
diff --git a/src/views/clients/components/RelativeTeam.vue b/src/views/clients/components/RelativeTeam.vue
new file mode 100644
index 0000000..93c74b5
--- /dev/null
+++ b/src/views/clients/components/RelativeTeam.vue
@@ -0,0 +1,286 @@
+<template>
+  <div class="rc-cont">
+    <flexbox
+      v-if="!isSeas"
+      class="rc-head"
+      direction="row-reverse">
+      <el-button
+        class="rc-head-item"
+        type="primary"
+        @click.native="handleClick('remove')">移除</el-button>
+      <el-button
+        class="rc-head-item"
+        type="primary"
+        @click.native="handleClick('edit')">编辑</el-button>
+      <el-button
+        class="rc-head-item"
+        type="primary"
+        @click.native="handleClick('add')">添加团队成员</el-button>
+    </flexbox>
+    <el-table
+      :data="list"
+      :height="tableHeight"
+      :header-cell-style="headerRowStyle"
+      :cell-style="cellStyle"
+      style="width: 100%;border: 1px solid #E6E6E6;"
+      @row-click="handleRowClick"
+      @selection-change="handleSelectionChange">
+      <el-table-column
+        :selectable="handleSelectable"
+        show-overflow-tooltip
+        type="selection"
+        align="center"
+        width="55"/>
+      <el-table-column
+        v-for="(item, index) in fieldList"
+        :key="index"
+        :prop="item.prop"
+        :label="item.label"
+        show-overflow-tooltip/>
+    </el-table>
+    <teams-handle
+      :crm-type="crmType"
+      :selection-list="[detail]"
+      :dialog-visible.sync="teamsDialogShow"
+      title="添加团队成员"
+      @handle="handleCallBack"/>
+
+    <el-dialog
+      v-loading="loading"
+      :visible.sync="editPermissionShow"
+      :append-to-body="true"
+      title="编辑权限"
+      width="400px">
+      <div class="handle-box">
+        <flexbox class="handle-item">
+          <div class="handle-item-name">权限:</div>
+          <el-radio-group v-model="handleType">
+            <el-radio :label="1">只读</el-radio>
+            <el-radio :label="2">读写</el-radio>
+          </el-radio-group>
+        </flexbox>
+      </div>
+      <span
+        slot="footer"
+        class="dialog-footer">
+        <el-button @click.native="editPermissionShow=false">取消</el-button>
+        <el-button
+          type="primary"
+          @click.native="handleEditConfirm">保存</el-button>
+      </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script type="text/javascript">
+import loading from '../mixins/loading'
+import TeamsHandle from './selectionHandle/TeamsHandle' // 操作团队成员
+// import {
+//   crmCustomerTeamMembers,
+//   crmCustomerUpdateMembers,
+//   crmCustomerSettingTeamDelete
+// } from '@/api/customermanagement/customerManage'
+// import {
+//   crmBusinessTeamMembers,
+//   crmBusinessUpdateMembers,
+//   crmBusinessSettingTeamDelete
+// } from '@/api/clients/business'
+// import {
+//   crmContractTeamMembers,
+//   crmContractUpdateMembers,
+//   crmContractSettingTeamDelete
+// } from '@/api/clients/contract'
+
+export default {
+  name: 'RelativeTeam', // 相关团队  可能再很多地方展示 放到客户管理目录下
+  components: {
+    TeamsHandle
+  },
+  mixins: [loading],
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    /** 联系人人下 新建商机 需要联系人里的客户信息  合同下需要客户和商机信息 */
+    detail: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    /** 是公海 默认是客户 */
+    isSeas: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    return {
+      list: [],
+      fieldList: [],
+      tableHeight: '400px',
+      teamsDialogShow: false, // 是否展示添加团队成员窗口
+      handleType: 1, // 权限类型
+      editPermissionShow: false, // 编辑权限接口展示
+      selectionList: [] // 勾选的数据
+    }
+  },
+  computed: {},
+  watch: {
+    id: function (val) {
+      this.list = []
+      this.getDetail()
+    }
+  },
+  mounted () {
+    this.fieldList.push({ prop: 'realname', width: '200', label: '姓名' })
+    this.fieldList.push({ prop: 'name', width: '200', label: '职位' })
+    this.fieldList.push({ prop: 'groupRole', width: '200', label: '团队角色' })
+    this.fieldList.push({ prop: 'power', width: '200', label: '权限' })
+
+    this.getDetail()
+  },
+  activated: function () {},
+  deactivated: function () {},
+  methods: {
+    getDetail () {
+      this.loading = true
+      const request = {
+        // customer: crmCustomerTeamMembers,
+        // business: crmBusinessTeamMembers,
+        // contract: crmContractTeamMembers
+      }[this.crmType]
+      const params = {}
+      params[this.crmType + 'Id'] = this.id
+      request(params)
+        .then(res => {
+          this.loading = false
+          this.list = res.data
+        })
+        .catch(() => {
+          this.loading = false
+        })
+    },
+    // 当选择项发生变化时会触发该事件
+    handleSelectionChange (val) {
+      this.selectionList = val
+    },
+    handleClick (type) {
+      if (type === 'add') {
+        this.teamsDialogShow = true
+      } else {
+        if (this.selectionList.length === 0) {
+          this.$message.error('请勾选需要操作的团队成员')
+        } else {
+          if (type === 'edit') {
+            this.editPermissionShow = true
+          } else if (type === 'remove') {
+            this.$confirm('此操作将移除这些团队成员是否继续?', '提示', {
+              confirmButtonText: '确定',
+              cancelButtonText: '取消',
+              type: 'warning'
+            })
+              .then(() => {
+                var userIds = this.selectionList.map(function (
+                  item,
+                  index,
+                  array
+                ) {
+                  return item.id
+                })
+
+                const request = {
+                  // customer: crmCustomerSettingTeamDelete,
+                  // contract: crmContractSettingTeamDelete,
+                  // business: crmBusinessSettingTeamDelete
+                }[this.crmType]
+
+                var params = {
+                  ids: this.id,
+                  memberIds: userIds.join(',')
+                }
+
+                this.loading = true
+                request(params)
+                  .then(res => {
+                    this.$message({
+                      type: 'success',
+                      message: '操作成功'
+                    })
+                    this.loading = false
+                    this.getDetail()
+                  })
+                  .catch(() => {
+                    this.loading = false
+                  })
+              })
+              .catch(() => {
+                this.$message({
+                  type: 'info',
+                  message: '已取消删除'
+                })
+              })
+          }
+        }
+      }
+    },
+    /** 添加操作 */
+    handleCallBack (data) {
+      this.getDetail()
+    },
+    /** 编辑操作确定 */
+    handleEditConfirm () {
+      var userIds = this.selectionList.map(function (item, index, array) {
+        return item.id
+      })
+      this.loading = true
+      const request = {
+        // customer: crmCustomerUpdateMembers,
+        // business: crmBusinessUpdateMembers,
+        // contract: crmContractUpdateMembers
+      }[this.crmType]
+      request({
+        ids: this.id,
+        memberIds: userIds.join(','),
+        power: this.handleType
+      })
+        .then(res => {
+          this.editPermissionShow = false
+          this.$message({
+            type: 'success',
+            message: '操作成功'
+          })
+          this.loading = false
+          this.getDetail()
+        })
+        .catch(() => {
+          this.loading = false
+        })
+    },
+    // 返回值用来决定这一行的 CheckBox 是否可以勾选
+    handleSelectable (row, index) {
+      if (row.power === '负责人权限') {
+        return false
+      }
+      return true
+    },
+    // 当某一行被点击时会触发该事件
+    handleRowClick (row, column, event) {},
+    /** 通过回调控制表头style */
+    headerRowStyle ({ row, column, rowIndex, columnIndex }) {
+      return { textAlign: 'left' }
+    },
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      return { textAlign: 'left' }
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+@import '../styles/relativecrm.scss';
+</style>
diff --git a/src/views/clients/components/Sections.vue b/src/views/clients/components/Sections.vue
new file mode 100644
index 0000000..3cfdd0e
--- /dev/null
+++ b/src/views/clients/components/Sections.vue
@@ -0,0 +1,145 @@
+<template>
+  <div class="section">
+    <div
+      v-if="title && title.length > 0"
+      class="section-header">
+      <div
+        :style="{ 'border-left-color': mColor }"
+        class="section-mark"/>
+      <div class="section-title">{{ title }}</div>
+      <flexbox
+        v-if="showF"
+        class="f-container">
+        <div
+          v-for="(item, index) in fItems"
+          :key="index"
+          :class="{ 'f-item-select':fIndex==item.type }"
+          class="f-item"
+          @click="fClick(item)">{{ item.title }}</div>
+      </flexbox>
+    </div>
+    <div
+      :style="{ 'height': contentHeight }"
+      class="content">
+      <div
+        v-if="showNoData"
+        class="no-data-container">
+        <img
+          class="no-data"
+          src="@/assets/img/no_data.png" >
+        <div class="no-data-name">暂无数据</div>
+      </div>
+      <slot/>
+    </div>
+  </div>
+</template>
+<script type="text/javascript">
+export default {
+  name: 'Sections',
+  components: {},
+  props: {
+    title: {
+      type: String,
+      default: ''
+    },
+    mColor: {
+      type: String,
+      default: '#FF6767'
+    },
+    /** 内容区域固定高度 */
+    contentHeight: {
+      type: String,
+      default: '327px'
+    },
+    /** 展示客户工作台  重要提醒 时间筛选 */
+    showF: {
+      type: Boolean,
+      default: false
+    },
+    fItems: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    /** 展示无数据 */
+    showNoData: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    return {
+      fIndex: -1
+    }
+  },
+  computed: {},
+  mounted () {},
+  methods: {
+    fClick (item) {
+      this.fIndex = item.type
+      this.$emit('f-click', 'val')
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+.section {
+  position: relative;
+  background-color: white;
+  margin-top: 8px;
+}
+.section:first-child {
+  margin-top: 0;
+}
+
+.section-mark {
+  border-left-width: 2px;
+  border-left-style: solid;
+  height: 16px;
+}
+
+.section-header {
+  display: flex;
+  align-items: center;
+  padding: 5px 15px;
+}
+.section-title {
+  font-size: 18px;
+  color: #333;
+  font-weight: 550;
+  margin-left: 8px;
+  flex-shrink: 0;
+}
+
+.f-container {
+  width: auto;
+  margin-left: 40px;
+  .f-item {
+    padding: 2px 4px;
+    font-size: 12px;
+    margin-right: 10px;
+    color: #666;
+  }
+  .f-item-select {
+    border-radius: 2px;
+    background-color: #ff6767;
+    color: white;
+  }
+}
+
+.content {
+  overflow: auto;
+  .no-data-container {
+    text-align: center;
+    .no-data {
+      margin-top: 30px;
+    }
+    .no-data-name {
+      font-size: 12px;
+      margin-top: 8px;
+      color: #666;
+    }
+  }
+}
+</style>
diff --git a/src/views/clients/components/duplicateCheck/checkContent.vue b/src/views/clients/components/duplicateCheck/checkContent.vue
new file mode 100644
index 0000000..7fd34cd
--- /dev/null
+++ b/src/views/clients/components/duplicateCheck/checkContent.vue
@@ -0,0 +1,336 @@
+<template>
+  <div class="check-container">
+    <div class="condition-content">
+      <el-input placeholder="请输入客户名称" v-model="checkName" @keyup.enter.native="getList" v-focus >
+        <template slot="prepend">按客户名称</template>
+      </el-input>
+      <el-button
+        type="primary"
+        class="condition-button"
+        @click="getList">查询</el-button>
+    </div>
+    <div class="table-content" v-show='list.length>0'>
+      <el-table
+        v-loading="loading"
+        id="crm-table"
+        :data="list"
+        :cell-style="cellStyle"
+        :row-class-name="tableRowClassName"
+        :cell-class-name="tableCellClassName"
+        height="400"
+        border
+        highlight-current-row
+        style="width: 100%"
+        @row-click="handleRowClick">
+        <el-table-column
+          v-for="(item, index) in fieldList"
+          :key="index"
+          :prop="item.field"
+          :label="item.name"
+          show-overflow-tooltip>
+           <template
+            slot="header"
+            slot-scope="scope">
+            <div class="table-head-name">{{ scope.column.label }}</div>
+          </template>
+          <!--<template slot-scope="scope">
+            <span v-if="scope.row.index === rowIndex && scope.column.label==='销售负责人'"
+                 class='inputnum'>
+              <el-input v-model="scope.row[item.field]"
+                        ref='editInput'
+                        type="number"
+                        size="mini"
+                        @blur="inputBlur(scope)" />
+            </span>
+            <span class="inputnum" v-else>{{ scope.row[item.field] }}</span>
+          </template>-->
+        </el-table-column>
+        <!--<el-table-column
+          prop="operation"
+          label="操作"
+          width='150'>
+          <template slot-scope="scope">
+            <el-button type="text" size="small"  @click='editCustomer(scope.row)'>编辑</el-button>
+            <el-button type="text" size="small"  @click='deleteCustomer(scope.row.Id)'>删除</el-button>
+          </template>
+        </el-table-column>-->
+      </el-table>
+      <!--<div class="p-contianer" v-show='total>0'>
+        <el-pagination
+          :current-page="currentPage"
+          :page-sizes="pageSizes"
+          :page-size.sync="pageSize"
+          :total="total"
+          class="p-bar"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"/>
+      </div>-->
+    </div>
+    <!-- 编辑页面 -->
+    <c-r-m-create-view
+      v-if="isCreate"
+      :action="{type: 'update', id: editData.Id, data: editData}"
+      crm-type="customer"
+      @save-success="listHeadHandle"
+      @hiden-view="isCreate=false"/>
+    <!-- 相关详情页面 -->
+    <!--<c-r-m-all-detail
+      :visible.sync="showDview"
+      :crm-type="rowType"
+      :id="rowID"
+      :listener-ids="['duplicate-check-container']"/>-->
+  </div>
+</template>
+<script type="text/javascript">
+import CRMCreateView from '../CRMCreateView'
+import { CustomerRepeatCheck } from '@/api/common'
+import { DeleteCustomer } from '@/api/customermanagement/customerManage'
+// import { GetCustomerPageList } from '@/api/customermanagement/customerManage'
+// import { GetSalesChanceList } from '@/api/customermanagement/business'
+// import { GetContacterList } from '@/api/customermanagement/contacts'
+
+import { XhInput } from '@/components/CreateCom'
+import CRMAllDetail from '@/views/clients/components/CRMAllDetail'
+
+export default {
+  name: 'CheckContent', // 验重内容
+
+  components: {
+    XhInput,
+    CRMAllDetail,
+    CRMCreateView
+  },
+
+  props: {
+    type: {
+      required: true,
+      type: String
+    }
+  },
+
+  data () {
+    return {
+      checkName: '',
+      total: 0,
+      currentPage: 1,
+      pageSize: 10,
+      pageSizes: [10, 30, 60, 100],
+      loading: false,
+      list: [],
+
+      /** 控制详情展示 */
+      rowID: '', // 行信息
+      rowType: '', // 详情类型
+      showDview: false,
+      rowIndex: -1, // 行索引
+      columnIndex: -1, // 列索引
+      editData: {},
+      isCreate: false
+    }
+  },
+
+  computed: {
+    // 表头信息
+    fieldList () {
+      return [
+        { field: 'CustomerNumber', name: '客户编号' },
+        { field: 'CustomerName', name: '客户名称' },
+        // { field: 'ContacterName', name: '联系人' },
+        // { field: 'ContacterMobile', name: '联系方式' },
+        { field: 'ProvinceCode', name: '所属地区' },
+        { field: 'OwerUserName', name: '销售负责人' }
+      ]
+    }
+  },
+
+  watch: {},
+
+  mounted () {},
+  destroyed () {},
+
+  methods: {
+    handleSizeChange (newSize) {
+      this.pageSize = newSize
+      this.getList()
+    },
+    handleCurrentChange (newPage) {
+      this.currentPage = newPage
+      this.getList()
+    },
+    /** 获取列表数据 */
+    getList () {
+      const params = {
+        'Name': this.checkName
+      }
+      let pass = false
+      if (this.checkName === '') {
+        pass = false
+      } else {
+        pass = true
+      }
+
+      if (pass) {
+        this.loading = true
+        CustomerRepeatCheck(params)
+          .then(res => {
+            this.list = res.data.Result
+            this.total = res.data.Result.length
+
+            this.loading = false
+          })
+          .catch(() => {
+            this.loading = false
+          })
+      } else {
+        this.$message.error('查询条件不能为空')
+      }
+    },
+    // 把每一行的索引加到行数据中
+    tableRowClassName ({ row, rowIndex }) {
+      row.index = rowIndex
+    },
+    // 把每一列的索引加到列数据中
+    tableCellClassName ({ column, columnIndex }) {
+      column.index = columnIndex
+    },
+    tabClick (row, column, cell, event) {
+      // console.log(row, '单条数据', column, '列信息', cell, 'td实例', event)
+      // this.rowIndex = row.index
+      // this.columnIndex = column.index
+    },
+    // 输入框失去焦点事件(初始化中间变量)
+    inputBlur (scope) {
+      this.rowIndex = -1
+      this.columnIndex = -1
+    },
+    editCustomer (row) {
+      console.log(row)
+      this.rowIndex = row.index
+      this.editData = row
+      this.isCreate = true
+    },
+    listHeadHandle (data) {
+      console.log('cvvvvvvvvvvvvv', data)
+      this.currentPage = 1
+      this.getList()
+    },
+    deleteCustomer (id) {
+      this.$confirm('确定删除?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          DeleteCustomer([{'Id': id}]).then(res => {
+            if (res.data.ErrorCode === 200) {
+              this.$message.success(res.data.Message)
+              this.getList()
+            } else {
+              this.$message.error(res.data.Message)
+            }
+          })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    },
+    // 获取左边padding
+    getPaddingLeft (item, index) {
+      return index % 2 === 0 ? '0' : '30px'
+    },
+
+    // 获取左边padding
+    getPaddingRight (item, index) {
+      return index % 2 === 0 ? '30px' : '0'
+    },
+
+    /**
+     * 查看详情
+     */
+    handleRowClick (row, column, event) {
+      let type = this.type
+      if (column.property === 'CustomerName' && this.type === 'contacts') {
+        type = 'customer'
+      }
+      this.rowID = row[this.type + 'Id']
+      this.rowType = type
+      this.showDview = true
+    },
+
+    /**
+     * 通过回调控制style
+     */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      if (
+        column.property === 'name' ||
+        // column.property === 'CustomerName' ||
+        column.property === 'leadsName'
+      ) {
+        return { color: '#4D88FF', cursor: 'pointer' }
+      } else {
+        return ''
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../../styles/table.scss';
+.check-container {
+  height: 100%;
+  overflow-y: auto;
+  padding: 0 30px;
+}
+
+// 提示标志
+.wukong-help_tips {
+  color: #999;
+  font-size: 12px;
+}
+
+.wukong-help_tips:hover {
+  color: #ff6a00;
+}
+
+//  条件
+.condition-content {
+  display:flex;
+  align-items: center;
+  justify-content: center;
+  /deep/ .el-input-group{
+    height: 36px;
+  }
+  /deep/ .el-input-group--prepend .el-input__inner{
+    height: 36px;
+  }
+  .condition-item {
+    flex: 0 0 50%;
+    flex-shrink: 0;
+    /deep/ .el-form-item__label {
+      padding: 10px 0 0 0 !important;
+      line-height: 30px;
+      font-size: 13px;
+    }
+  }
+  .condition-button {
+    margin-left: 15px;
+    border-radius: 4px;
+    width: 82px;
+    height: 36px;
+  }
+}
+
+.el-form-item {
+  margin-bottom: 0px;
+}
+
+// 表内容
+.table-content {
+  margin-top: 20px;
+}
+</style>
diff --git a/src/views/clients/components/duplicateCheck/index.vue b/src/views/clients/components/duplicateCheck/index.vue
new file mode 100644
index 0000000..e774dbb
--- /dev/null
+++ b/src/views/clients/components/duplicateCheck/index.vue
@@ -0,0 +1,124 @@
+<template>
+  <create-view id="duplicate-check-container" :body-style="{ height: '100%'}">
+    <div class="container">
+      <div class="header">
+        客户查重
+        <img
+          class="close"
+          src="@/assets/img/task_close.png"
+          @click="hidenView" >
+      </div>
+      <el-tabs
+        v-model="tabActiveName"
+        class="content">
+        <check-content :type="crmType"/>
+      </el-tabs>
+    </div>
+  </create-view>
+</template>
+<script type="text/javascript">
+import CreateView from '@/components/CreateView'
+import CheckContent from './checkContent'
+
+export default {
+  name: 'DuplicateCheck', // 验重页面
+  components: {
+    CreateView,
+    CheckContent
+  },
+  props: {
+    crmType: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      tabActiveName: 'customer',
+      tabList: []
+    }
+  },
+  computed: {},
+  watch: {},
+  mounted () {
+    // 获取title展示名称
+    document.body.appendChild(this.$el)
+    if (this.crmType === 'customer') {
+      this.tabList.push(
+        { label: '客户', name: 'customer' }
+      )
+    } else if (this.crmType === 'contacts') {
+      this.tabList.push(
+        { label: '联系人', name: 'contacts' }
+      )
+      this.tabActiveName = 'contacts'
+    } else {
+      this.tabList = []
+    }
+  },
+  destroyed () {
+    // remove DOM node after destroy
+    if (this.$el && this.$el.parentNode) {
+      this.$el.parentNode.removeChild(this.$el)
+    }
+  },
+  methods: {
+    /**
+     * 关闭窗口
+     */
+    hidenView () {
+      this.$emit('hiden-view')
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.container {
+  overflow: hidden;
+  height: 100%;
+
+  .header {
+    padding: 0 10px;
+    height: 40px;
+    line-height: 40px;
+    font-size: 17px;
+    color: #333;
+    position: relative;
+
+    .close {
+      float: right;
+      display: block;
+      width: 40px;
+      height: 40px;
+      margin-right: -10px;
+      padding: 10px;
+      cursor: pointer;
+    }
+  }
+
+  .content {
+    height: calc(100% - 40px);
+    position: relative;
+    overflow: hidden;
+
+    /deep/ .el-tabs__header {
+      padding: 10px 20px 0;
+      margin-bottom: 0;
+
+      .el-tabs__nav-wrap::after {
+        height: 1px;
+      }
+    }
+
+    /deep/ .el-tabs__content {
+      overflow: hidden;
+      height: calc(100% - 50px);
+
+      .el-tab-pane {
+        overflow: hidden;
+        height: 100%;
+      }
+    }
+  }
+}
+</style>
diff --git a/src/views/clients/components/fieldsManager/FieldsSet.vue b/src/views/clients/components/fieldsManager/FieldsSet.vue
new file mode 100644
index 0000000..b1b747b
--- /dev/null
+++ b/src/views/clients/components/fieldsManager/FieldsSet.vue
@@ -0,0 +1,538 @@
+<template>
+  <el-dialog
+    :visible.sync="visible"
+    :append-to-body="true"
+    title="编辑列"
+    width="600px"
+    @close="handleCancel">
+    <div class="scene-name">您可通过拖拽管理列</div>
+    <flexbox class="scene-list">
+      <div class="scene-list-box">
+        <flexbox class="scene-list-head">
+          <el-checkbox
+            :indeterminate="isleftIndeterminate"
+            v-model="checkleftAll"
+            @change="handleleftCheckAllChange"/>
+          <div class="scene-list-head-name">显示的列</div>
+          <div class="scene-list-head-detail">{{ leftCheckItems.length + '/' + checkedLeftData.length }}</div>
+        </flexbox>
+        <div style="position: relative;">
+          <div class="scene-list-search">
+            <el-input
+              v-model="leftInput"
+              placeholder="请输入"
+              size="small"
+              suffix-icon="el-icon-search"
+              @input="inputLeftChange"/>
+          </div>
+          <div class="scene-list-body">
+            <draggable
+              v-model="checkedLeftData"
+              :move="leftMove"
+              :options="{group: 'list',forceFallback:true}"
+              style="min-height: 100px;"
+              @end="leftMoveEnd">
+              <flexbox
+                v-for="(item, index) in checkedLeftData"
+                v-if="item.show"
+                :key="index"
+                class="list-item">
+                <el-checkbox
+                  v-model="item.check"
+                  class="list-item-check"
+                  @change="leftCheckItemChange"/>
+                <div class="list-item-name">{{ item.name }}</div>
+              </flexbox>
+            </draggable>
+
+          </div>
+        </div>
+      </div>
+      <div class="scene-middle-list">
+        <el-button
+          :class="{'scene-middle-button-select':rightCheckItems.length > 0}"
+          :disabled="rightCheckItems.length === 0"
+          class="scene-middle-left-button"
+          @click="changePositon('left')">
+          <i class="el-icon-arrow-left scene-middle-icon"/>
+        </el-button>
+        <el-button
+          :class="{'scene-middle-button-select':leftCheckItems.length > 0}"
+          :disabled="leftCheckItems.length === 0"
+          class="scene-middle-right-button"
+          @click="changePositon('right')">
+          <i class="el-icon-arrow-right scene-middle-icon"/>
+        </el-button>
+      </div>
+      <div class="scene-list-box">
+        <flexbox class="scene-list-head">
+          <el-checkbox
+            :indeterminate="isrightIndeterminate"
+            v-model="checkrightAll"
+            @change="handlerightCheckAllChange"/>
+          <div class="scene-list-head-name">隐藏的列</div>
+          <div class="scene-list-head-detail">{{ rightCheckItems.length + '/' + checkedRightData.length }}</div>
+        </flexbox>
+        <div style="position: relative;">
+          <div class="scene-list-body">
+            <div class="scene-list-search">
+              <el-input
+                v-model="rightInput"
+                placeholder="请输入"
+                size="small"
+                suffix-icon="el-icon-search"
+                @input="inputRightChange"/>
+            </div>
+            <draggable
+              v-model="checkedRightData"
+              :move="rightMove"
+              :options="{group: 'list',forceFallback:true}"
+              style="min-height: 100px;"
+              @end="rightMoveEnd">
+              <flexbox
+                v-for="(item, index) in checkedRightData"
+                v-if="item.show"
+                :key="index"
+                class="list-item">
+                <el-checkbox
+                  v-model="item.check"
+                  class="list-item-check"
+                  @change="rightCheckItemChange"/>
+                <div class="list-item-name">{{ item.name }}</div>
+              </flexbox>
+            </draggable>
+          </div>
+        </div>
+      </div>
+    </flexbox>
+    <div class="handle-bar">
+      <div class="handle-bar-save">
+        <el-button @click.native="handleCancel">取消</el-button>
+        <el-button
+          type="primary"
+          @click.native="handleConfirm">保存</el-button>
+      </div>
+    </div>
+  </el-dialog>
+</template>
+
+<script type="text/javascript">
+// import {
+//   crmFieldConfigIndex,
+//   crmFieldConfig
+// } from '@/api/clients/common'
+// import crmTypeModel from '@/views/clients/model/crmTypeModel'
+import draggable from 'vuedraggable'
+
+export default {
+  name: 'FieldsSet', // 场景 设置
+  components: {
+    draggable
+  },
+  props: {
+    dialogVisible: {
+      type: Boolean,
+      required: true,
+      default: false
+    },
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    // 是否是公海 客户模块的辅助参数
+    isSeas: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    return {
+      visible: false, // 控制展示
+      isleftIndeterminate: false, // 标注头部是多选框效果
+      checkleftAll: false, // 关联全选操作多选框
+
+      leftInput: '',
+      checkedLeftData: [], // 数据源
+      leftCheckItems: [], // 选择的数据源
+
+      isrightIndeterminate: false,
+      checkrightAll: false,
+
+      rightInput: '',
+      checkedRightData: [],
+      rightCheckItems: [],
+
+      moveItem: {}, // 移动中的item
+      handlDefaultItem: {} // 设置默认的中间item
+    }
+  },
+  computed: {},
+  watch: {
+    dialogVisible: {
+      handler (val) {
+        this.visible = val
+        if (val) {
+          if (
+            this.checkedLeftData.length === 0 &&
+            this.checkedRightData.length === 0
+          ) {
+            this.getFieldConfigIndex()
+          }
+        }
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+  mounted () {
+    // 为了防止火狐浏览器拖拽的时候以新标签打开,此代码真实有效
+    document.body.ondrop = function (event) {
+      event.preventDefault()
+      event.stopPropagation()
+    }
+  },
+  methods: {
+    getFieldConfigIndex () {
+      // crmFieldConfigIndex({
+      //   label: this.isSeas ? crmTypeModel.pool : crmTypeModel[this.crmType]
+      // })
+      //   .then(res => {
+      //     this.checkedLeftData = res.data.value.map(function (item, index) {
+      //       item.check = false
+      //       item.show = true
+      //       return item
+      //     })
+      //     this.checkedRightData = res.data.hideValue.map(function (item, index) {
+      //       item.check = false
+      //       item.show = true
+      //       return item
+      //     })
+      //   })
+      //   .catch(() => {})
+    },
+    /**
+     * 搜索操作
+     */
+    inputLeftChange (val) {
+      this.checkedLeftData = this.checkedLeftData.map(function (item, index) {
+        if (item.name.indexOf(val) !== -1) {
+          item.show = true
+        } else {
+          item.show = false
+        }
+        return item
+      })
+    },
+    /**
+     * 搜索操作
+     */
+    inputRightChange (val) {
+      this.checkedRightData = this.checkedRightData.map(function (item, index) {
+        if (item.name.indexOf(val) !== -1) {
+          item.show = true
+        } else {
+          item.show = false
+        }
+        return item
+      })
+    },
+    /**
+     * 确定选择
+     */
+    handleConfirm () {
+      if (this.checkedLeftData.length < 2) {
+        this.$message.error('至少要显示两列')
+      } else {
+        // crmFieldConfig({
+        //   label: this.isSeas ? crmTypeModel.pool : crmTypeModel[this.crmType],
+        //   noHideIds: this.checkedLeftData
+        //     .map(item => {
+        //       return item.id
+        //     })
+        //     .join(','),
+        //   hideIds: this.checkedRightData
+        //     .map(item => {
+        //       return item.id
+        //     })
+        //     .join(',')
+        // })
+        //   .then(res => {
+        //     this.$message.success('操作成功')
+        //     this.$emit('set-success')
+        //     this.handleCancel()
+        //   })
+        //   .catch(() => {})
+      }
+    },
+    /**
+     * 取消选择
+     */
+    handleCancel () {
+      this.visible = false
+      this.$emit('update:dialogVisible', false)
+    },
+    /** 拖拽操作 */
+    rightMoveEnd (evt) {
+      this.moveItem.check = false
+      this.leftCheckItemChange()
+      this.rightCheckItemChange()
+    },
+    rightMove (obj) {
+      this.moveItem = obj.draggedContext.element
+    },
+    leftMoveEnd (evt) {
+      this.moveItem.check = false
+      this.leftCheckItemChange()
+      this.rightCheckItemChange()
+    },
+    leftMove (obj) {
+      this.moveItem = obj.draggedContext.element
+    },
+    // 选择全部
+    handleleftCheckAllChange (value) {
+      if (value) {
+        this.isleftIndeterminate = false
+      }
+      this.checkedLeftData = this.checkedLeftData.filter(function (
+        item,
+        index,
+        array
+      ) {
+        item.check = value
+        return item
+      })
+      this.leftCheckItems = value ? this.checkedLeftData : []
+    },
+    leftCheckItemChange () {
+      this.leftCheckItems = this.checkedLeftData.filter(function (
+        item,
+        index,
+        array
+      ) {
+        return item.check === true
+      })
+      if (this.leftCheckItems.length > 0) {
+        if (this.leftCheckItems.length === this.checkedLeftData.length) {
+          this.checkleftAll = true
+          this.isleftIndeterminate = false
+        } else {
+          this.checkleftAll = false
+          this.isleftIndeterminate = true
+        }
+      } else {
+        this.checkleftAll = false
+        this.isleftIndeterminate = false
+      }
+    },
+    // 选择全部
+    handlerightCheckAllChange (value) {
+      if (value) {
+        this.isrightIndeterminate = false
+      }
+      this.checkedRightData = this.checkedRightData.filter(function (
+        item,
+        index,
+        array
+      ) {
+        item.check = value
+        return item
+      })
+      this.rightCheckItems = value ? this.checkedRightData : []
+    },
+    rightCheckItemChange () {
+      this.rightCheckItems = this.checkedRightData.filter(function (
+        item,
+        index,
+        array
+      ) {
+        return item.check === true
+      })
+      if (this.rightCheckItems.length > 0) {
+        if (this.rightCheckItems.length === this.checkedRightData.length) {
+          this.checkrightAll = true
+          this.isrightIndeterminate = false
+        } else {
+          this.checkrightAll = false
+          this.isrightIndeterminate = true
+        }
+      } else {
+        this.checkrightAll = false
+        this.isrightIndeterminate = false
+      }
+    },
+    // 按钮操作
+    changePositon (type) {
+      var self = this
+      // 从右往左
+      if (type === 'left') {
+        this.checkedRightData = this.checkedRightData.filter(function (
+          item,
+          index,
+          array
+        ) {
+          var remove = false
+          self.rightCheckItems.forEach(function (element, index) {
+            if (item.id === element.id) {
+              remove = true
+            }
+          })
+          return !remove
+        })
+
+        this.rightCheckItems.forEach(function (element, index) {
+          element.check = false
+          self.checkedLeftData.push(element)
+        })
+
+        this.rightCheckItems = []
+        this.isrightIndeterminate = false
+        this.checkrightAll = false
+
+        // 刷新左侧效果
+        this.leftCheckItemChange()
+        this.rightCheckItemChange()
+      } else {
+        this.checkedLeftData = this.checkedLeftData.filter(function (
+          item,
+          index,
+          array
+        ) {
+          var remove = false
+          self.leftCheckItems.forEach(function (element, index) {
+            if (item.id === element.id) {
+              remove = true
+            }
+          })
+          return !remove
+        })
+
+        this.leftCheckItems.forEach(function (element, index) {
+          element.check = false
+          self.checkedRightData.push(element)
+        })
+
+        this.leftCheckItems = []
+        this.isleftIndeterminate = false
+        this.checkleftAll = false
+
+        // 刷新右侧效果
+        this.leftCheckItemChange()
+        this.rightCheckItemChange()
+      }
+    }
+  }
+}
+</script>
+<style rel="stylesheet/scss" lang="scss" scoped>
+.scene-name {
+  font-size: 12px;
+  padding-bottom: 5px;
+  color: #aaa;
+}
+
+.default-mark {
+  width: 4px;
+  height: 4px;
+  border-radius: 2px;
+  margin-right: 5px;
+}
+.default-mark-active {
+  background-color: #4D88FF;
+}
+
+.scene-list-search {
+  background-color: white;
+  position: absolute;
+  padding: 10px 20px;
+  top: 0;
+  left: 0;
+  z-index: 5;
+}
+
+.scene-list {
+  .scene-list-box {
+    flex: 1;
+    border: 1px solid #e6e6e6;
+    border-radius: 2px;
+    height: 360px;
+    position: relative;
+    padding: 15px;
+  }
+  .scene-middle-list {
+    width: 50px;
+    text-align: center;
+    button {
+      border: 1px solid #cccccc;
+      width: 34px;
+      height: 34px;
+      border-radius: 17px;
+      background-color: #f5f7fa;
+    }
+    .scene-middle-icon {
+      color: #cccccc;
+      font-size: 14px;
+    }
+    .scene-middle-left-button {
+    }
+    .scene-middle-right-button {
+      margin-top: 15px;
+      margin-left: 0;
+    }
+
+    .scene-middle-button-select {
+      border: 1px solid #4D88FF !important;
+      background-color: #4D88FF !important;
+      .scene-middle-icon {
+        color: white !important;
+      }
+    }
+  }
+  .scene-list-head {
+    padding-bottom: 15px;
+    border-bottom: 1px dashed #e6e6e6;
+    font-size: 13px;
+    .scene-list-head-name {
+      color: #333;
+      flex: 1;
+      margin: 0 8px;
+    }
+
+    .scene-list-head-detail {
+      color: #aaa;
+    }
+  }
+  .scene-list-body {
+    padding: 52px 0 5px 0;
+    height: 300px;
+    position: relative;
+    overflow-y: auto;
+  }
+
+  .list-item {
+    padding: 5px 0;
+    cursor: pointer;
+    .list-item-check {
+      margin-right: 8px;
+    }
+    .list-item-name {
+      font-size: 13px;
+      color: #333;
+      flex: 1;
+    }
+  }
+}
+
+.handle-bar {
+  font-size: 12px;
+  .handle-bar-save {
+    position: relative;
+    height: 30px;
+    button {
+      float: right;
+      margin-top: 10px;
+      margin-right: 10px;
+    }
+  }
+}
+</style>
diff --git a/src/views/clients/components/filterForm/filterContent.vue b/src/views/clients/components/filterForm/filterContent.vue
new file mode 100644
index 0000000..ef14a2a
--- /dev/null
+++ b/src/views/clients/components/filterForm/filterContent.vue
@@ -0,0 +1,156 @@
+<template>
+  <div class="wrapper">
+    <ul class="list">
+      <li
+        v-for="(item, index) in showObj.form"
+        :key="index"
+        class="list-item">
+        <span v-if="item.formType === 'date'">{{ item.name +'&nbsp;“' + item.value[0] + '-' + item.value[1] + '”' }}</span>
+        <span v-else-if="item.formType === 'datetime'">{{ item.name +'&nbsp;“' + item.value[0] + '-' + item.value[1] + '”' }}</span>
+        <span v-else-if="item.formType === 'business_type'">{{ item.name +'&nbsp;“' + getTypesName(item) + getStatusName(item) + '”' }}</span>
+        <span v-else-if="item.formType === 'map_address'">{{ `${item.name} ${item.address.state} ${item.address.city} ${item.address.area}` }}</span>
+        <span v-else-if="item.formType === 'checkStatus'">{{ item.name +'&nbsp;“' + optionsNames[item.condition]+ '”'+'&nbsp;'+ getCheckName(item) }}</span>
+        <span v-else-if="item.formType === 'user'">{{ item.name +'&nbsp;' + optionsNames[item.condition] + '“' + item.value[0].realname + '”' }}</span>
+        <span v-else-if="item.formType === 'category' && item.value.length > 0">{{ item.name +'&nbsp;“' + item.valueContent + '”' }}</span>
+        <span v-else>{{ item.name + '&nbsp;' + optionsNames[item.condition] + '“' + item.value + '”' }}</span>
+        <i
+          class="el-icon-close icon"
+          @click="handleDelete(item, index)"/>
+      </li>
+    </ul>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'FilterContent',
+  props: {
+    obj: {
+      type: Object,
+      required: true,
+      default: () => {
+        return {}
+      }
+    }
+  },
+  data () {
+    return {
+      // 获取条件名称
+      optionsNames: {
+        is: '等于',
+        isNot: '不等于',
+        contains: '包含',
+        notContains: '不包含',
+        startWith: '开始于',
+        endWith: '结束于',
+        isNull: '为空',
+        isNotNull: '不为空',
+        eq: '等于',
+        neq: '不等于',
+        gt: '大于',
+        egt: '大于等于',
+        lt: '小于',
+        elt: '小于等于'
+      },
+      // 展示信息
+      showObj: {}
+    }
+  },
+  computed: {},
+  watch: {
+    obj: function (val) {
+      this.showObj = val
+    }
+  },
+  mounted () {
+    this.showObj = this.obj
+  },
+  methods: {
+    /**
+     * 删除高级筛选条件
+     * @param index
+     */
+    handleDelete (item, index) {
+      this.$delete(this.showObj.obj, item.fieldName)
+      this.showObj.form.splice(index, 1)
+      this.$emit('delete', { item: item, index: index, obj: this.showObj })
+    },
+    // 商机组展示名称
+    getTypesName (data) {
+      if (data.typeId) {
+        const obj = data.typeOption.find(item => {
+          return item.typeId === data.typeId
+        })
+        return obj.name || ''
+      }
+      return ''
+    },
+    getCheckName (data) {
+      let value = ''
+      data.setting.forEach(item => {
+        if (item.value === data.value) {
+          value = item.name
+        }
+      })
+      return value
+    },
+    // 商机阶段展示名称
+    getStatusName (data) {
+      if (data.statusId) {
+        const obj = data.statusOption.find(item => {
+          return item.statusId === data.statusId
+        })
+        if (obj.name) {
+          return '-' + obj.name
+        }
+        return ''
+      }
+      return ''
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+@mixin left() {
+  display: flex;
+  justify-content: flex-start;
+  align-items: center;
+}
+@mixin center() {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+.wrapper {
+  width: 100%;
+  min-height: 50px;
+  background: white;
+  border-top: 1px solid #e1e1e1;
+  font-size: 13px;
+  overflow-x: scroll;
+  color: #aaa;
+  @include left;
+  .list {
+    width: 100%;
+    padding: 0 20px;
+    margin-bottom: 10px;
+    flex-shrink: 0;
+    @include left;
+    .list-item {
+      height: 30px;
+      padding: 0 10px;
+      margin: 10px 15px 0 0;
+      border: 1px solid #e1e1e1;
+      border-radius: 3px;
+      flex-shrink: 0;
+      @include center;
+      .icon {
+        margin-left: 20px;
+        cursor: pointer;
+      }
+    }
+  }
+}
+</style>
diff --git a/src/views/clients/components/filterForm/index.vue b/src/views/clients/components/filterForm/index.vue
new file mode 100644
index 0000000..f4e5f46
--- /dev/null
+++ b/src/views/clients/components/filterForm/index.vue
@@ -0,0 +1,648 @@
+<template>
+  <el-dialog
+    :visible.sync="visible"
+    title="高级筛选"
+    width="900px"
+    @close="handleCancel">
+    <div style="margin-bottom: 10px;">筛选条件</div>
+    <el-form
+      id="filter-container"
+      class="filter-container">
+      <el-form-item>
+        <template v-for="(formItem, index) in form">
+          <el-row :key="index">
+            <el-col :span="8">
+              <el-select
+                v-model="formItem.fieldName"
+                placeholder="请选择要筛选的字段名"
+                @change="fieldChange(formItem)">
+                <el-option
+                  v-for="item in fieldList"
+                  :key="item.field"
+                  :label="item.value"
+                  :value="item.field"/>
+              </el-select>
+            </el-col>
+
+            <el-col
+              v-if="showCalCondition(formItem.formType)"
+              :span="1">&nbsp;</el-col>
+            <el-col
+              v-if="showCalCondition(formItem.formType)"
+              :span="4">
+              <el-select
+                v-model="formItem.condition"
+                placeholder="请选择范围">
+                <el-option
+                  v-for="item in calConditionOptions(formItem.formType, formItem)"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value"/>
+              </el-select>
+            </el-col>
+
+            <!-- 商机组 -->
+            <el-col
+              v-if="formItem.formType === 'business_type'"
+              :span="1">&nbsp;</el-col>
+            <el-col
+              v-if="formItem.formType === 'business_type'"
+              :span="4">
+              <el-select
+                v-model="formItem.typeId"
+                placeholder="请选择"
+                @change="typeOptionsChange(formItem)">
+                <el-option
+                  v-for="item in formItem.typeOption"
+                  :key="item.typeId"
+                  :label="item.name"
+                  :value="item.typeId"/>
+              </el-select>
+            </el-col>
+
+            <el-col :span="1">&nbsp;</el-col>
+            <el-col :span="formItem.formType === 'datetime' || formItem.formType === 'date' || formItem.formType === 'map_address' ? 13 : 8">
+              <el-select
+                v-if="formItem.formType === 'select'"
+                v-model="formItem.value"
+                placeholder="请选择筛选条件">
+                <el-option
+                  v-for="item in formItem.setting"
+                  :key="item"
+                  :label="item"
+                  :value="item"/>
+              </el-select>
+              <el-select
+                v-else-if="formItem.formType === 'checkStatus'"
+                v-model="formItem.value"
+                placeholder="请选择筛选条件">
+                <el-option
+                  v-for="item in formItem.setting"
+                  :key="item.value"
+                  :label="item.name"
+                  :value="item.value"/>
+              </el-select>
+              <el-date-picker
+                v-else-if="formItem.formType === 'date' || formItem.formType === 'datetime'"
+                v-model="formItem.value"
+                :value-format="formItem.formType === 'date' ? 'yyyy-MM-dd' : 'yyyy-MM-dd HH:mm:ss'"
+                :type="formItem.formType === 'date' ? 'daterange' : 'datetimerange'"
+                style="padding: 0px 10px;"
+                range-separator="-"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"/>
+              <el-select
+                v-else-if="formItem.formType === 'business_type'"
+                v-model="formItem.statusId"
+                placeholder="请选择">
+                <el-option
+                  v-for="item in formItem.statusOption"
+                  :key="item.statusId"
+                  :label="item.name"
+                  :value="item.statusId"/>
+              </el-select>
+              <xh-user-cell
+                v-else-if="formItem.formType === 'user'"
+                :item="formItem"
+                :info-params="{m:'crm',c: crmType,a: 'index' }"
+                @value-change="arrayValueChange"/>
+              <xh-prouct-cate
+                v-else-if="formItem.formType === 'category'"
+                :item="formItem"
+                @value-change="arrayValueChange"/>
+              <v-distpicker
+                v-else-if="formItem.formType === 'map_address'"
+                :province="formItem.address.state"
+                :city="formItem.address.city"
+                :area="formItem.address.area"
+                @province="selectProvince($event,formItem)"
+                @city="selectCity($event,formItem)"
+                @area="selectArea($event,formItem)"/>
+              <el-input
+                v-else
+                v-model="formItem.value"
+                placeholder="请输入筛选条件"/>
+            </el-col>
+            <el-col
+              :span="1"
+              class="delete">
+              <i
+                class="el-icon-error delete-btn"
+                @click="handleDelete(index)"/>
+            </el-col>
+          </el-row>
+        </template>
+      </el-form-item>
+    </el-form>
+    <p
+      v-show="showErrors"
+      class="el-icon-warning warning-info">
+      <span class="desc">筛选条件中有重复项!</span>
+    </p>
+    <el-button
+      type="text"
+      @click="handleAdd">+ 添加筛选条件</el-button>
+   <!-- <div
+      v-if="!isSeas"
+      class="save">
+      <el-checkbox v-model="saveChecked">保存为场景</el-checkbox>
+      <el-input
+        v-show="saveChecked"
+        v-model.trim="saveName"
+        :maxlength="10"
+        class="name"
+        placeholder="请输入场景名称,最多10个字符"/>
+      <div
+        v-show="saveChecked"
+        class="save-setting">
+        <el-checkbox v-model="saveDefault">设置为默认</el-checkbox>
+      </div>
+    </div>-->
+    <div
+      slot="footer"
+      class="dialog-footer">
+      <el-button @click="handleCancel">取 消</el-button>
+      <el-button
+        type="primary"
+        @click="handleConfirm">确 定</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import { objDeepCopy } from '@/utils'
+import { XhUserCell, XhProuctCate } from '@/components/CreateCom'
+import VDistpicker from 'v-distpicker'
+/**
+ * fieldList: 高级筛选的字段
+ *     type:  date || datetime || select || 其他 input
+ */
+export default {
+  name: 'Index',
+  components: {
+    XhUserCell,
+    XhProuctCate,
+    VDistpicker
+  },
+  props: {
+    dialogVisible: {
+      type: Boolean,
+      required: true,
+      default: false
+    },
+    fieldList: {
+      type: Array,
+      required: true,
+      default: () => {
+        return []
+      }
+    },
+    obj: {
+      type: Object,
+      required: true,
+      default: () => {
+        return {}
+      }
+    },
+    /** 获取客户管理下列表权限内的员工列表 针对 usersList */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    // 辅助 使用 公海没有场景
+    isSeas: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    return {
+      form: [],
+      visible: false,
+      showErrors: false,
+      saveChecked: false, // 展示场景
+      saveDefault: false, // 设置为默认场景
+      saveName: null // 场景名称
+    }
+  },
+  watch: {
+    dialogVisible: {
+      handler (val) {
+        if (val) {
+          this.form = objDeepCopy(this.obj.form)
+          if (this.form.length === 0) {
+            this.form.push({
+              fieldName: '',
+              name: '',
+              formType: '',
+              condition: 'is',
+              value: '',
+              typeOption: [],
+              statusOption: [],
+              typeId: '',
+              statusId: '',
+              address: {
+                state: '',
+                city: '',
+                area: ''
+              }
+            })
+          }
+          console.log(this.form)
+          this.saveChecked = false
+          this.saveDefault = false
+          this.saveName = null
+        }
+        this.visible = this.dialogVisible
+      },
+      deep: true,
+      immediate: true
+    },
+
+    form () {
+      this.$nextTick(() => {
+        var container = document.getElementById('filter-container')
+        container.scrollTop = container.scrollHeight
+      })
+    }
+  },
+  methods: {
+    /**
+     * 位置更改
+     */
+    selectProvince (data, formItem) {
+      formItem.address.state = data.value
+    },
+    selectCity (data, formItem) {
+      formItem.address.city = data.value
+    },
+    selectArea (data, formItem) {
+      formItem.address.area = data.value
+    },
+
+    /**
+     * 商机组状态
+     */
+    typeOptionsChange (formItem) {
+      if (formItem.typeId) {
+        const obj = formItem.typeOption.find(item => {
+          return item.typeId === formItem.typeId
+        })
+        formItem.statusOption = obj.statusList || []
+      } else {
+        formItem.statusOption = []
+      }
+      formItem.statusId = ''
+    },
+    /**
+     * 用户创建人
+     * 产品类别
+     */
+    arrayValueChange (data) {
+      if (data.value.length > 0) {
+        data.item.value = data.value
+        data.item.valueContent = data.valueContent
+      } else {
+        data.item.value = []
+      }
+    },
+
+    /**
+     * 是否展示条件
+     */
+    showCalCondition (formType) {
+      if (
+        formType === 'date' ||
+        formType === 'datetime' ||
+        formType === 'business_type' ||
+        formType === 'category' ||
+        formType === 'map_address'
+      ) {
+        return false
+      }
+      return true
+    },
+    /** 条件数据源 */
+    calConditionOptions (formType, item) {
+      if (
+        formType === 'select' ||
+        formType === 'checkbox' ||
+        formType === 'user' ||
+        formType === 'checkStatus'
+      ) {
+        return [
+          { value: 'is', label: '等于', disabled: false },
+          { value: 'isNot', label: '不等于', disabled: false }
+        ]
+      } else if (
+        formType === 'module' ||
+        formType === 'text' ||
+        formType === 'textarea'
+      ) {
+        return [
+          { value: 'is', label: '等于', disabled: false },
+          { value: 'isNot', label: '不等于', disabled: false },
+          { value: 'contains', label: '包含', disabled: false },
+          { value: 'notContains', label: '不包含', disabled: false }
+        ]
+      } else if (formType === 'floatnumber' || formType === 'number') {
+        return [
+          { value: 'is', label: '等于', disabled: false },
+          { value: 'isNot', label: '不等于', disabled: false },
+          { value: 'contains', label: '包含', disabled: false },
+          { value: 'notContains', label: '不包含', disabled: false },
+          { value: 'isNull', label: '为空', disabled: false },
+          { value: 'isNotNull', label: '不为空', disabled: false },
+          { value: 'gt', label: '大于', disabled: false },
+          { value: 'egt', label: '大于等于', disabled: false },
+          { value: 'lt', label: '小于', disabled: false },
+          { value: 'elt', label: '小于等于', disabled: false }
+        ]
+      } else if (formType === 'category') {
+        return [
+          { value: 'is', label: '等于', disabled: false },
+          { value: 'isnot', label: '不等于', disabled: false },
+          { value: 'contains', label: '包含', disabled: false },
+          { value: 'not_contain', label: '不包含', disabled: false }
+        ]
+      } else {
+        return [
+          { value: 'is', label: '等于', disabled: false },
+          { value: 'isNot', label: '不等于', disabled: false },
+          { value: 'contains', label: '包含', disabled: false },
+          { value: 'notContains', label: '不包含', disabled: false },
+          { value: 'startWith', label: '开始于', disabled: false },
+          { value: 'endWith', label: '结束于', disabled: false },
+          { value: 'isNull', label: '为空', disabled: false },
+          { value: 'isNotNull', label: '不为空', disabled: false },
+          { value: 'gt', label: '大于', disabled: false },
+          { value: 'egt', label: '大于等于', disabled: false },
+          { value: 'lt', label: '小于', disabled: false },
+          { value: 'elt', label: '小于等于', disabled: false }
+        ]
+      }
+    },
+    /**
+     * 当前选择的字段名改变,判断是否有重复
+     * @param formItem
+     */
+    fieldChange (formItem) {
+      const obj = this.fieldList.find(item => {
+        return item.fieldName === formItem.fieldName
+      })
+      if (obj) {
+        formItem.formType = obj.formType
+        formItem.name = obj.name
+        if (formItem.formType === 'business_type') {
+          formItem.typeOption = obj.setting
+          formItem.statusOption = []
+          formItem.typeId = ''
+          formItem.statusId = ''
+          formItem.value = ''
+        } else if (
+          formItem.formType === 'select' ||
+          formItem.formType === 'checkStatus'
+        ) {
+          formItem.setting = obj.setting || []
+          formItem.value = ''
+        } else if (formItem.formType === 'map_address') {
+          formItem.address = {
+            state: '',
+            city: '',
+            area: ''
+          }
+        } else if (
+          formItem.formType === 'date' ||
+          formItem.formType === 'datetime' ||
+          formItem.formType === 'user' ||
+          formItem.formType === 'category'
+        ) {
+          formItem.value = []
+        } else {
+          formItem.value = ''
+        }
+      }
+
+      const arr = this.form.filter(item => {
+        return item.fieldName === formItem.fieldName
+      })
+      if (arr.length > 1) this.showErrors = true
+      else this.showErrors = false
+    },
+    /**
+     * 取消选择
+     */
+    handleCancel () {
+      this.$emit('update:dialogVisible', false)
+    },
+    /**
+     * 确定选择
+     */
+    handleConfirm () {
+      if (this.showErrors) {
+        this.$message.error('筛选条件中有重复项!')
+        return
+      }
+      if (this.saveChecked) {
+        if (!this.saveName || this.saveName === '') {
+          this.$message.error('场景名称不能为空!')
+          return
+        }
+      }
+      for (let i = 0; i < this.form.length; i++) {
+        const o = this.form[i]
+        if (!o.fieldName || o.fieldName === '') {
+          this.$message.error('要筛选的字段名称不能为空!')
+          return
+        }
+        if (o.formType === 'business_type') {
+          if (!o.typeId && !o.statusId) {
+            this.$message.error('请输入筛选条件的值!')
+            return
+          }
+        } else if (o.formType === 'map_address') {
+          if (!o.address.state && !o.address.city && !o.address.area) {
+            this.$message.error('请选择筛选条件的值!')
+            return
+          }
+        } else if (
+          o.formType === 'date' ||
+          o.formType === 'datetime' ||
+          o.formType === 'user' ||
+          o.formType === 'category'
+        ) {
+          if (!o.value || o.value.length === 0) {
+            this.$message.error('请选择筛选条件的值!')
+            return
+          }
+        } else if (!o.value && o.value !== 0) {
+          this.$message.error('请输入筛选条件的值!')
+          return
+        }
+      }
+      const obj = {}
+      this.form.forEach(o => {
+        if (o.formType === 'datetime' || o.formType === 'date') {
+          obj[o.fieldName] = {
+            start: o.value[0],
+            end: o.value[1],
+            formType: o.formType,
+            name: o.fieldName
+          }
+        } else if (o.formType === 'business_type') {
+          obj[o.fieldName] = {
+            typeId: o.typeId,
+            statusId: o.statusId,
+            formType: o.formType,
+            name: o.fieldName
+          }
+        } else if (o.formType === 'user') {
+          obj[o.fieldName] = {
+            condition: o.condition,
+            value: o.value[0].userId,
+            formType: o.formType,
+            name: o.fieldName
+          }
+        } else if (o.formType === 'category') {
+          obj[o.fieldName] = {
+            condition: 'is',
+            value: o.value[o.value.length - 1],
+            formType: o.formType,
+            name: o.fieldName
+          }
+        } else if (o.formType === 'map_address') {
+          let value = ''
+          for (const key in o.address) {
+            if (o.address[key]) {
+              value += o.address[key] + ','
+            }
+          }
+          obj[o.fieldName] = {
+            value: value,
+            formType: o.formType,
+            name: o.fieldName
+          }
+        } else {
+          obj[o.fieldName] = {
+            condition: o.condition,
+            value: o.value,
+            formType: o.formType,
+            name: o.fieldName
+          }
+        }
+      })
+      const data = {
+        obj: obj,
+        form: this.form,
+        saveChecked: this.saveChecked,
+        saveDefault: this.saveDefault,
+        saveName: this.saveName
+      }
+      this.$emit('filter', data)
+    },
+    /**
+     * 添加筛选条件
+     */
+    handleAdd () {
+      this.form.push({
+        fieldName: '',
+        condition: 'is',
+        value: '',
+        formType: '',
+        setting: [],
+        typeOption: [],
+        statusOption: [],
+        typeId: '',
+        statusId: ''
+      })
+    },
+    /**
+     * 删除筛选条件
+     * @param index
+     */
+    handleDelete (index) {
+      this.$confirm('您确定要删除这一条数据吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          this.form.splice(index, 1)
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+/deep/ .el-dialog__body {
+  padding: 10px 20px;
+}
+
+/deep/ .el-form-item__label {
+  width: 100%;
+  text-align: left;
+}
+.filter-container {
+  max-height: 300px;
+  overflow-y: auto;
+}
+
+.save {
+  margin-top: 10px;
+  .name {
+    width: 300px;
+    margin-left: 10px;
+    /deep/ .el-input__inner {
+      height: 32px;
+    }
+  }
+  .save-setting {
+    margin-top: 20px;
+  }
+}
+
+.el-form-item {
+  margin-bottom: 0;
+}
+
+.el-row {
+  margin-bottom: 20px;
+  .delete-btn {
+    margin-left: 15px;
+    color: #bbb;
+    cursor: pointer;
+  }
+  .el-select,
+  .el-date-editor {
+    width: 100%;
+  }
+}
+
+.warning-info {
+  width: 100%;
+  font-size: 14px;
+  color: #f56c6c;
+  margin-top: 10px;
+  .desc {
+    padding-left: 8px;
+  }
+}
+
+.distpicker-address-wrapper /deep/ select {
+  border-radius: 2px;
+  font-size: 13px;
+  height: 34px;
+  -webkit-appearance: none;
+  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAWCAYAAAAW5GZjAAAMHmlDQ1BEaXNwbGF5AABIx62Xd1RTyRrA55YkJCS0QASkhN4E6VV6jVSpgo2QBBJKDAlBxI4uKrgWVCxYkVUR21oAWWzYlUWw90URFGVdLNhAeZME0NXz/njnvDln7v3lm2++lrlzZgBQjWGLRNmoGgA5wjxxbGgAc2JyCpP0BBCBGiADXaDK5khE/jExEQC24fe/2/tbAJG9r9vKbIH/ralzeRIOAEgM5DSuhJMD+QgAuCtHJM4DgNAD5SYz8kSQiTBKoCmGAUI2lXGGgt1lnKbgCLlOfGwg5FQAlKhstjgDABVZXMx8Tga0o7IMsr2QKxBCboTsw+GzuZAHII/JyZkOWdUSsmXad3Yy/mUzbcQmm50xwopc5E0pSCARZbNngv93y8mWDvswgZ3KF4fFynKW1S1reriMqZAvCtOioiFrQL4h4Mr1ZdzFl4YlDOl/5EgCYc0AAwCUymUHhUPWg2wszI6KGJL7pAtCWJBh7dF4QR4rXjEX5Yqnxw7ZRwt4kuC4YWaL5b5kOiXSrAT/IZtb+DzWsM2GQn58kiJOtDVfkBgFWQXyA0lWXPiQzotCfmDUsI5YGiuLGf7nGEgXh8QqdDDTHMlwXpgnX8CKGuKIPH58mGIuNpXDlsemDTmTJ5kYMRwnlxcUrMgLK+IJE4bix8pEeQGxQ/pVouyYIX2skZcdKpMbQ26R5McNz+3Ng4tNkS8ORHkx8YrYcM1M9vgYRQy4NYgAgSAIMIEU9jQwHWQCQUtPXQ/8pRgJAWwgBhmAB2yHJMMzkuQjQviMA4Xgb0g8IBmZFyAf5YF8KP8yIlU8bUG6fDRfPiMLdEHOAeEgG/6WymcJR7wlgqdQIvjJOwfGmg27bOwnGVN1WEYMJgYRw4ghRCtcF/fBvfAI+PSD3RF3xz2G4/qmT+gitBGeEG4S2gl3pwmKxD9EzgSRoB3GGDKUXdr32eHm0KoLHoB7Q/vQNs7AdYEt7gw9+eO+0LcLlH4fq3Qk42+1HLJFtiej5FFkP7LljxGoWKu4jFiRVer7WijiShupVuDIyI95BH5XPy58h/+oiS3BDmMXsNPYJawRqwNM7CRWjzVjx2U8sjaeytfGsLdYeTxZ0I7gJ3/sIZ+yqknsa+y77QeGxkAeryBP9rEEThfNFAsy+HlMf7hb85gsIcduDNPR3gHuorK9X7G1vGXI93SEcfmbLPcUAB4lUJjxTcaGe9CxLgDo77/JTN7AZb8SgOOtHKk4XyHDZQ8CoABV+KXoAAO4d1nCjByBK/ACfiAYjAfRIB4kg6mwzny4TsVgBpgNFoBiUApWgrVgI9gKdoDdYB84BOpAIzgNzoMroBXcBPfhWukEL0EveA/6EQQhITSEjugghogZYoM4Iu6IDxKMRCCxSDKSimQgQkSKzEYWIqVIGbIR2Y5UI78jx5DTyCWkDbmLPEa6kTfIZxRDqagmqo+ao2NRd9QfDUfj0SloBpqLFqKL0OXoerQS3YvWoqfRK+hNtB19ifZhAFPGGJgRZou5Y4FYNJaCpWNibC5WgpVjldh+rAH+09exdqwH+4QTcTrOxG3heg3DE3AOnovPxZfhG/HdeC1+Fr+OP8Z78a8EGkGPYEPwJLAIEwkZhBmEYkI5YSfhKOEc/HY6Ce+JRCKDaEF0g99eMjGTOIu4jLiZeIB4ithG7CD2kUgkHZINyZsUTWKT8kjFpA2kvaSTpGukTtJHJWUlQyVHpRClFCWhUpFSudIepRNK15SeKfWT1chmZE9yNJlLnkleQa4iN5CvkjvJ/RR1igXFmxJPyaQsoKyn7KecozygvFVWVjZW9lCeoCxQnq+8Xvmg8kXlx8qfqBpUa2ogdTJVSl1O3UU9Rb1LfUuj0cxpfrQUWh5tOa2adob2iPZRha5ip8JS4arMU6lQqVW5pvJKlaxqpuqvOlW1ULVc9bDqVdUeNbKauVqgGlttrlqF2jG122p96nR1B/Vo9Rz1Zep71C+pP9cgaZhrBGtwNRZp7NA4o9FBx+gm9EA6h76QXkU/R+/UJGpaaLI0MzVLNfdptmj2amloOWslahVoVWgd12pnYAxzBouRzVjBOMS4xfg8Sn+U/yjeqKWj9o+6NuqD9mhtP22edon2Ae2b2p91mDrBOlk6q3TqdB7q4rrWuhN0Z+hu0T2n2zNac7TXaM7oktGHRt/TQ/Ws9WL1Zunt0GvW69M30A/VF+lv0D+j32PAMPAzyDRYY3DCoNuQbuhjKDBcY3jS8AVTi+nPzGauZ55l9hrpGYUZSY22G7UY9RtbGCcYFxkfMH5oQjFxN0k3WWPSZNJramgaaTrbtMb0nhnZzN2Mb7bO7ILZB3ML8yTzxeZ15s8ttC1YFoUWNRYPLGmWvpa5lpWWN6yIVu5WWVabrVqtUWsXa751hfVVG9TG1UZgs9mmbQxhjMcY4ZjKMbdtqbb+tvm2NbaP7Rh2EXZFdnV2r8aajk0Zu2rshbFf7V3ss+2r7O87aDiMdyhyaHB442jtyHGscLzhRHMKcZrnVO/02tnGmee8xfmOC90l0mWxS5PLF1c3V7HrftduN1O3VLdNbrfdNd1j3Je5X/QgeAR4zPNo9Pjk6eqZ53nI8x8vW68srz1ez8dZjOONqxrX4W3szfbe7t3uw/RJ9dnm0+5r5Mv2rfR94mfix/Xb6ffM38o/03+v/6sA+wBxwNGAD4GegXMCTwVhQaFBJUEtwRrBCcEbgx+FGIdkhNSE9Ia6hM4KPRVGCAsPWxV2m6XP4rCqWb3j3cbPGX82nBoeF74x/EmEdYQ4oiESjRwfuTryQZRZlDCqLhpEs6JXRz+MsYjJjfljAnFCzISKCV2xDrGzYy/E0eOmxe2Jex8fEL8i/n6CZYI0oSlRNXFyYnXih6SgpLKk9oljJ86ZeCVZN1mQXJ9CSklM2ZnSNyl40tpJnZNdJhdPvjXFYkrBlEtTdadmTz0+TXUae9rhVEJqUuqe1AF2NLuS3ZfGStuU1ssJ5KzjvOT6cddwu3nevDLes3Tv9LL05xneGaszuvm+/HJ+jyBQsFHwOjMsc2vmh6zorF1Zg9lJ2QdylHJSc44JNYRZwrPTDaYXTG8T2YiKRe25nrlrc3vF4eKdEkQyRVKfpwkP2c1SS+kv0sf5PvkV+R9nJM44XKBeICxonmk9c+nMZ4Uhhb/NwmdxZjXNNpq9YPbjOf5zts9F5qbNbZpnMm/RvM75ofN3L6AsyFrwZ5F9UVnRu4VJCxsW6S+av6jjl9BfaopVisXFtxd7Ld66BF8iWNKy1GnphqVfS7gll0vtS8tLB5Zxll3+1eHX9b8OLk9f3rLCdcWWlcSVwpW3Vvmu2l2mXlZY1rE6cnXtGuaakjXv1k5be6ncuXzrOso66br29RHr6zeYbli5YWAjf+PNioCKA5v0Ni3d9GEzd/O1LX5b9m/V31q69fM2wbY720O311aaV5bvIO7I39FVlVh14Tf336p36u4s3flll3BX++7Y3Wer3aqr9+jtWVGD1khruvdO3tu6L2hf/X7b/dsPMA6UHgQHpQdf/J76+61D4YeaDrsf3n/E7Mimo/SjJbVI7cza3jp+XXt9cn3bsfHHmhq8Go7+YffHrkajxorjWsdXnKCcWHRi8GThyb5TolM9pzNOdzRNa7p/ZuKZG2cnnG05F37u4vmQ82cu+F84edH7YuMlz0vHLrtfrrvieqW22aX56J8ufx5tcW2pvep2tb7Vo7WhbVzbiWu+105fD7p+/gbrxpWbUTfbbiXcunN78u32O9w7z+9m3319L/9e//35DwgPSh6qPSx/pPeo8i+rvw60u7Yffxz0uPlJ3JP7HZyOl08lTwc6F3XRusqfGT6rfu74vLE7pLv1xaQXnS9FL/t7iv9W/3vTK8tXR/7x+6e5d2Jv52vx68E3y97qvN31zvldU19M36P3Oe/7P5R81Pm4+5P7pwufkz4/658xQBpY/8XqS8PX8K8PBnMGB0VsMVt+FMBgR9PTAXizCwBaMjw7tAJAmaS4m8kborhPygn8N1bc3+TNFYBdfgAkzAcgAp5RtsBuBpkK37IjeLwfQJ2cRvpQk6Q7OSpsUeGNhfBxcPCtPgCkBgC+iAcH+zcPDn6pgsHeBeBUruJOKGuyO+g2Oxm1dr766W72H1oCcSjh6sMlAAAACXBIWXMAABYlAAAWJQFJUiTwAAAF9mlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDAgNzkuMTYwNDUxLCAyMDE3LzA1LzA2LTAxOjA4OjIxICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMTgtMDctMjdUMDc6NTY6NDctMDc6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDE4LTA3LTI3VDA3OjU5OjA4LTA3OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDE4LTA3LTI3VDA3OjU5OjA4LTA3OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgcGhvdG9zaG9wOklDQ1Byb2ZpbGU9IkRpc3BsYXkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OWVmMTg3ZTUtMWVmNy00NzlhLWE1Y2QtMmVkMTE5NjQ2Y2ZmIiB4bXBNTTpEb2N1bWVudElEPSJhZG9iZTpkb2NpZDpwaG90b3Nob3A6MTRmNTk5YTMtYTc1Zi05NDQxLTk3ZDQtMmY3OTNjNWQ3NTI3IiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6M2FmYmY3ZWYtNWFiOS00MTk4LWFjODUtNzY2NzE2NDk2ODM1Ij4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY3JlYXRlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDozYWZiZjdlZi01YWI5LTQxOTgtYWM4NS03NjY3MTY0OTY4MzUiIHN0RXZ0OndoZW49IjIwMTgtMDctMjdUMDc6NTY6NDctMDc6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE4IChNYWNpbnRvc2gpIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo5ZWYxODdlNS0xZWY3LTQ3OWEtYTVjZC0yZWQxMTk2NDZjZmYiIHN0RXZ0OndoZW49IjIwMTgtMDctMjdUMDc6NTk6MDgtMDc6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE4IChNYWNpbnRvc2gpIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDwvcmRmOlNlcT4gPC94bXBNTTpIaXN0b3J5PiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pr46tjAAAACBSURBVCjPY/j//z8DOgaCVVjFsSgMB2IQIxuvYiBgBuJHUMXfgVgCn+I+qEIYXoxVMRBYoymEYX9sio/hUHz79+/fCMVAUIxDIQy3Q9UxyAPxPwKKQdgEHKZAfI4IvJ8BW+DjwoNFMUkeJCnoSIoUkqOb5IREUhIlOfGTlK0IZVgAkODRpD7i30MAAAAASUVORK5CYII=);
+  background-position: calc(100% - 4px) 50%;
+  background-repeat: no-repeat;
+  background-size: 5px 11px;
+}
+</style>
diff --git a/src/views/clients/components/followLog/ExamineLog.vue b/src/views/clients/components/followLog/ExamineLog.vue
new file mode 100644
index 0000000..aaa3d39
--- /dev/null
+++ b/src/views/clients/components/followLog/ExamineLog.vue
@@ -0,0 +1,207 @@
+<template>
+  <div v-loading="loading">
+    <div v-empty="list.length === 0">
+      <div class="log-items">
+        <examine-cell
+          v-for="(item, index) in list"
+          :key="index"
+          :data="item"
+          @on-handle="examineCellHandle"/>
+        <div class="load">
+          <el-button
+            :loading="loadMoreLoading"
+            type="text">{{ loadMoreLoading ? '加载更多' : '没有更多了' }}</el-button>
+        </div>
+      </div>
+    </div>
+    <examine-handle
+      :show="showExamineHandle"
+      :id="rowID"
+      examine-type="oa_examine"
+      status="2"
+      @close="showExamineHandle = false"
+      @save="refreshList"/>
+    <examine-create-view
+      v-if="isCreate"
+      :category-id="createInfo.categoryId"
+      :category-title="createInfo.title"
+      :type="createInfo.type"
+      :action="createAction"
+      @save-success="refreshList"
+      @hiden-view="isCreate=false"/>
+    <c-r-m-full-screen-detail
+      :visible.sync="showFullDetail"
+      :crm-type="detailCRMType"
+      :id="rowID"/>
+  </div>
+</template>
+
+<script>
+// import ExamineCell from '@/views/OAManagement/examine/components/examineCell' // 跟进记录
+// import ExamineCreateView from '@/views/OAManagement/examine/components/examineCreateView'
+// import { crmQueryExamineRelation } from '@/api/clients/common'
+// import { oaExamineDelete } from '@/api/oamanagement/examine'
+
+export default {
+  /** 审批 跟进记录 */
+  name: 'ExamineLog',
+  components: {
+    // ExamineCell,
+    CRMFullScreenDetail: () =>
+      import('@/views/clients/components/CRMFullScreenDetail.vue'),
+    ExamineHandle: () => import('@/components/Examine/ExamineHandle')
+    // ExamineCreateView
+  },
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      loading: false,
+      loadMoreLoading: true,
+      isPost: false,
+      page: 1,
+      list: [], // 跟进记录列表
+      rowID: '', // 行信息
+      // 撤回操作
+      showExamineHandle: false,
+      isCreate: false, // 是编辑
+      createAction: { type: 'save' },
+      createInfo: {}, // 编辑所需要的id 标题名信息
+      // 详情
+      showFullDetail: false,
+      detailCRMType: ''
+    }
+  },
+  computed: {},
+  watch: {
+    id: function (val) {
+      this.refreshList()
+    }
+  },
+  mounted () {
+    // 分批次加载
+    const dom = document.getElementById('follow-log-content')
+    dom.onscroll = () => {
+      const scrollOff = dom.scrollTop + dom.clientHeight - dom.scrollHeight
+      // 滚动条到底部的条件
+      if (Math.abs(scrollOff) < 10 && this.loadMoreLoading === true) {
+        if (!this.isPost) {
+          this.isPost = true
+          this.page++
+          this.getList()
+        } else {
+          this.loadMoreLoading = false
+        }
+      }
+    }
+
+    this.getList()
+  },
+  activated: function () {},
+  deactivated: function () {},
+  methods: {
+    getList () {
+      this.loading = true
+      const params = { page: this.page, limit: 10 }
+      params[this.crmType + 'Ids'] = this.id
+      // crmQueryExamineRelation(params)
+      //   .then(res => {
+      //     this.list = this.list.concat(res.data.list)
+      //     if (res.data.list.length < 10) {
+      //       this.loadMoreLoading = false
+      //     } else {
+      //       this.loadMoreLoading = true
+      //     }
+      //     this.loading = false
+      //     this.isPost = false
+      //   })
+      //   .catch(() => {
+      //     this.isPost = false
+      //     this.loading = false
+      //   })
+    },
+    refreshList () {
+      this.page = 1
+      this.list = []
+      this.getList()
+    },
+    examineCellHandle (data) {
+      // 编辑
+      if (data.type === 'edit') {
+        data.data.item.title = data.data.item.categoryName
+        this.createInfo = data.data.item
+        this.createAction = {
+          type: 'update',
+          id: data.data.item.examineId,
+          data: data.data.item
+        }
+        this.isCreate = true
+        // 删除
+      } else if (data.type === 'delete') {
+        this.$confirm('确定删除?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+          .then(() => {
+            // oaExamineDelete({
+            //   examineId: data.data.item.examineId
+            // }).then(res => {
+            //   this.refreshList()
+            //   this.$message({
+            //     type: 'success',
+            //     message: '删除成功!'
+            //   })
+            // })
+          })
+          .catch(() => {
+            this.$message({
+              type: 'info',
+              message: '已取消删除'
+            })
+          })
+        // 撤回
+      } else if (data.type === 'withdraw') {
+        // this.rowID = data.data.item.examineId
+        // this.showExamineHandle = true
+        // 详情
+      } else if (data.type === 'view') {
+        // this.detailCRMType = 'examine'
+        // this.rowID = data.data.item.examineId
+        // this.showFullDetail = true
+      } else if (data.type === 'related-detail') {
+        // this.rowID = data.data.item[data.data.type + 'Id']
+        // this.detailCRMType = data.data.type
+        // this.showFullDetail = true
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.log-items {
+  min-height: 400px;
+  position: relative;
+  padding: 10px 20px;
+}
+
+.load {
+  color: #999;
+  font-size: 13px;
+  margin: 0 auto 15px;
+  text-align: center;
+  .el-button,
+  .el-button:focus {
+    color: #ccc;
+    cursor: auto;
+  }
+}
+</style>
diff --git a/src/views/clients/components/followLog/JournalLog.vue b/src/views/clients/components/followLog/JournalLog.vue
new file mode 100644
index 0000000..9975476
--- /dev/null
+++ b/src/views/clients/components/followLog/JournalLog.vue
@@ -0,0 +1,279 @@
+<template>
+  <div v-loading="loading">
+    <div v-empty="list.length === 0">
+      <div class="log-items">
+        <journal-cell
+          v-for="(item, index) in list"
+          :key="index"
+          :data="item"
+          class="list-cell"
+          @on-handle="jourecallCellHandle"/>
+        <div class="load">
+          <el-button
+            :loading="loadMoreLoading"
+            type="text">{{ loadMoreLoading ? '加载更多' : '没有更多了' }}</el-button>
+        </div>
+      </div>
+    </div>
+    <c-r-m-full-screen-detail
+      :visible.sync="showFullDetail"
+      :crm-type="detailCRMType"
+      :id="rowID"/>
+    <new-dialog
+      v-if="showNewDialog"
+      :form-data="formData"
+      :dialog-title="dialogTitle"
+      :img-file-list="imgFileList"
+      :accessory-file-list="accessoryFileList"
+      :new-loading="newLoading"
+      @close="showNewDialog=false"
+      @submitBtn="submitBtn"/>
+  </div>
+</template>
+
+<script>
+// API
+// import { journalDelete, journalEdit } from '@/api/oamanagement/journal'
+import JournalCell from '@/views/OAManagement/journal/journalCell' // 办公日志
+// import { crmQueryLogRelation } from '@/api/clients/common'
+
+export default {
+  /** 日志 跟进记录 */
+  name: 'JournalLog',
+  components: {
+    JournalCell,
+    CRMFullScreenDetail: () =>
+      import('@/views/clients/components/CRMFullScreenDetail.vue'),
+    NewDialog: () => import('@/views/OAManagement/journal/newDialog')
+  },
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      loading: false,
+      loadMoreLoading: true,
+      isPost: false,
+      page: 1,
+      list: [], // 跟进记录列表
+      rowID: '', // 行信息
+      // 详情
+      showFullDetail: false,
+      detailCRMType: '',
+      // 编辑
+      // 显示新建页面
+      showNewDialog: false,
+      // 新建数据
+      formData: {},
+      // 弹出框标题
+      dialogTitle: '',
+      // 图片数组
+      imgFileList: [],
+      // 附件数组
+      accessoryFileList: [],
+      newLoading: false
+    }
+  },
+  computed: {},
+  watch: {
+    id: function (val) {
+      this.refreshList()
+    }
+  },
+  mounted () {
+    // 分批次加载
+    const dom = document.getElementById('follow-log-content')
+    dom.onscroll = () => {
+      const scrollOff = dom.scrollTop + dom.clientHeight - dom.scrollHeight
+      // 滚动条到底部的条件
+      if (Math.abs(scrollOff) < 10 && this.loadMoreLoading === true) {
+        if (!this.isPost) {
+          this.isPost = true
+          this.page++
+          this.getList()
+        } else {
+          this.loadMoreLoading = false
+        }
+      }
+    }
+
+    this.getList()
+  },
+  activated: function () {},
+  deactivated: function () {},
+  methods: {
+    getList () {
+      this.loading = true
+      const params = { page: this.page, limit: 10 }
+      params[this.crmType + 'Ids'] = this.id
+      // crmQueryLogRelation(params)
+      //   .then(res => {
+      //     this.list = this.list.concat(res.data.list)
+      //     if (res.data.list.length < 10) {
+      //       this.loadMoreLoading = false
+      //     } else {
+      //       this.loadMoreLoading = true
+      //     }
+      //     this.loading = false
+      //     this.isPost = false
+      //   })
+      //   .catch(() => {
+      //     this.isPost = false
+      //     this.loading = false
+      //   })
+    },
+    refreshList () {
+      this.page = 1
+      this.list = []
+      this.getList()
+    },
+    jourecallCellHandle (data) {
+      // 编辑按钮
+      if (data.type === 'edit') {
+        const val = data.data.item
+        this.showNewDialog = true
+        this.dialogTitle = '编辑日志'
+        this.formData = val
+        this.imgFileList = []
+        if (val.imgList) {
+          for (const item of val.imgList) {
+            item.url = item.filePath
+            this.imgFileList.push(item)
+          }
+        }
+        // 附件
+        this.accessoryFileList = []
+        if (val.fileList) {
+          for (const item of val.fileList) {
+            item.url = item.filePath
+            this.accessoryFileList.push(item)
+          }
+        }
+        // 员工部门赋值
+        this.formData.depData = val.sendStructList ? val.sendStructList : []
+        this.formData.sentWhoList = val.sendUserList ? val.sendUserList : []
+        // 删除按钮
+      } else if (data.type === 'delete') {
+        this.$confirm('确定删除?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+          .then(() => {
+            // journalDelete({ logId: data.data.item.logId }).then(res => {
+            //   this.$message({
+            //     type: 'success',
+            //     message: '删除成功!'
+            //   })
+            //   for (const i in this.list) {
+            //     if (this.list[i].logId === data.data.item.logId) {
+            //       this.list.splice(i, 1)
+            //       break
+            //     }
+            //   }
+            // })
+          })
+          .catch(() => {
+            this.$message({
+              type: 'info',
+              message: '已取消删除'
+            })
+          })
+        // 相关详情
+      } else if (data.type === 'related-detail') {
+        // this.rowID = data.data.item.key
+        // this.detailCRMType = data.data.type
+        // this.showFullDetail = true
+      }
+    },
+    // 新建提交
+    submitBtn (key, file, img, relevanceAll) {
+      this.newLoading = true
+      console.log(relevanceAll, '==relevanceAll==')
+      const imgList = []
+      const fileList = []
+      // 获取部门
+      const dep = []
+      if (this.formData.depData) {
+        for (const j of this.formData.depData) {
+          dep.push(j.id)
+        }
+      }
+      // 获取员工
+      const staff = []
+      if (this.formData.sentWhoList) {
+        for (const h of this.formData.sentWhoList) {
+          staff.push(h.id)
+        }
+      }
+      for (const item of this.imgFileList) {
+        imgList.push(item.fileId)
+      }
+      for (const item of this.accessoryFileList) {
+        fileList.push(item.fileId)
+      }
+      // let obj = {}
+      // if (!relevanceAll) {
+      //   obj = {}
+      // } else {
+      //   obj = relevanceAll
+      // }
+      // const pramas = {
+      //   logId: this.formData.logId,
+      //   categoryId: key,
+      //   content: this.formData.content,
+      //   tomorrow: this.formData.tomorrow,
+      //   question: this.formData.question,
+      //   file: fileList.concat(imgList),
+      //   sendUserIds: staff.join(','),
+      //   sendStructureIds: dep.join(','),
+      //   customerIds: obj.customerIds.join(','),
+      //   contactsIds: obj.contactsIds.join(','),
+      //   businessIds: obj.businessIds.join(','),
+      //   contractIds: obj.contractIds.join(',')
+      // }
+      // journalEdit(pramas)
+      // .then(res => {
+      //   this.refreshList()
+      //   this.showNewDialog = false
+      //   this.$message.success('编辑成功')
+      //   this.newLoading = false
+      // })
+      // .catch(() => {
+      //   this.newLoading = false
+      //   this.$message.error('编辑失败')
+      // })
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.log-items {
+  min-height: 400px;
+  position: relative;
+}
+
+.load {
+  color: #999;
+  font-size: 13px;
+  margin: 0 auto 15px;
+  text-align: center;
+  .el-button,
+  .el-button:focus {
+    color: #ccc;
+    cursor: auto;
+  }
+}
+
+.list-cell {
+  margin-bottom: 20px;
+  border-radius: 4px;
+}
+</style>
diff --git a/src/views/clients/components/followLog/RecordLog.vue b/src/views/clients/components/followLog/RecordLog.vue
new file mode 100644
index 0000000..1a462b2
--- /dev/null
+++ b/src/views/clients/components/followLog/RecordLog.vue
@@ -0,0 +1,169 @@
+<template>
+  <div v-loading="loading">
+    <div v-empty="list.length === 0">
+      <div class="log-items">
+        <follow-record-cell
+          v-for="(item, index) in list"
+          :item="item"
+          :index="index"
+          :crm-type="crmType"
+          :key="index"
+          @on-handle="cellHandle"/>
+        <div class="load">
+          <el-button
+            :loading="loadMoreLoading"
+            type="text">{{ loadMoreLoading ? '加载更多' : '没有更多了' }}</el-button>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import FollowRecordCell from './components/FollowRecordCell' // 跟进记录
+// import { crmLeadsRecordIndex } from '@/api/customermanagement/clue'
+import { GetBusinessFollowRecordList } from '@/api/common'
+// import { GetCustomerFollowRecordList } from '@/api/customermanagement/customerManage'
+// import { crmContactsRecordIndex } from '@/api/customermanagement/contacts'
+// import { GetSalesChanceFollowList } from '@/api/customermanagement/business'
+// import { crmContractRecordIndex } from '@/api/customermanagement/contract'
+export default {
+  /** 线索管理 的 线索详情 的 跟进记录 */
+  name: 'RecordLog',
+  components: {
+    FollowRecordCell
+  },
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      loading: false,
+      loadMoreLoading: true,
+      isPost: false,
+      page: 1,
+      list: [] // 跟进记录列表
+    }
+  },
+  computed: {},
+  watch: {
+    id: function (val) {
+      console.log(val)
+      this.refreshList()
+    }
+  },
+  mounted () {
+    this.$bus.on('follow-log-refresh', data => {
+      if (data.type === 'record-log') {
+        this.refreshList()
+      }
+    })
+
+    // 分批次加载
+    const dom = document.getElementById('follow-log-content')
+    dom.onscroll = () => {
+      const scrollOff = dom.scrollTop + dom.clientHeight - dom.scrollHeight
+      // 滚动条到底部的条件
+      if (Math.abs(scrollOff) < 10 && this.loadMoreLoading === true) {
+        if (!this.isPost) {
+          this.isPost = true
+          this.page++
+          this.getList()
+        } else {
+          this.loadMoreLoading = false
+        }
+      }
+    }
+
+    this.getList()
+  },
+  activated: function () {},
+  deactivated: function () {},
+
+  beforeDestroy () {
+    this.$bus.off('follow-log-refresh')
+  },
+  methods: {
+    getList () {
+      this.loading = true
+      let request = {
+        customer: GetBusinessFollowRecordList,
+        // leads: crmLeadsRecordIndex,
+        contacts: GetBusinessFollowRecordList,
+        business: GetBusinessFollowRecordList
+      // contract: crmContractRecordIndex
+      }[this.crmType]
+
+      const params = {
+        PageIndex: this.page,
+        PageSize: 10
+      }
+      params['BusinessOperationType'] = {
+        customer: 1,
+        contacts: 2,
+        business: 3
+      }[this.crmType]
+      params['SourceId'] = this.id
+      // if (request === 'GetBusinessFollowRecordList') {
+      // } else {
+      //   params['Id'] = this.id
+      // }
+      console.log(params)
+      request(params)
+        .then(res => {
+          this.list = this.list.concat(res.data.Result.List)
+          if (res.data.Result.length < 10) {
+            this.loadMoreLoading = false
+          } else {
+            this.loadMoreLoading = true
+          }
+          this.loading = false
+          this.isPost = false
+        })
+        .catch(() => {
+          this.isPost = false
+          this.loading = false
+        })
+    },
+    refreshList () {
+      this.page = 1
+      this.list = []
+      this.getList()
+    },
+    /**
+     * 行布局删除
+     */
+    cellHandle (data) {
+      console.log(data)
+      if (data.type === 'delete') {
+        this.list.splice(data.data.index, 1)
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.log-items {
+  min-height: 400px;
+  position: relative;
+}
+
+.load {
+  color: #999;
+  font-size: 13px;
+  margin: 0 auto 15px;
+  text-align: center;
+  .el-button,
+  .el-button:focus {
+    color: #ccc;
+    cursor: auto;
+  }
+}
+</style>
diff --git a/src/views/clients/components/followLog/ScheduleLog.vue b/src/views/clients/components/followLog/ScheduleLog.vue
new file mode 100644
index 0000000..2862d2c
--- /dev/null
+++ b/src/views/clients/components/followLog/ScheduleLog.vue
@@ -0,0 +1,199 @@
+<template>
+  <div v-loading="loading">
+    <div v-empty="list.length === 0">
+      <div class="log-items">
+        <follow-schedule-cell
+          v-for="(item, index) in list"
+          :key="index"
+          :data="item"
+          @on-handle="examineCellHandle"/>
+        <div class="load">
+          <el-button
+            :loading="loadMoreLoading"
+            type="text">{{ loadMoreLoading ? '加载更多' : '没有更多了' }}</el-button>
+        </div>
+      </div>
+    </div>
+    <c-r-m-full-screen-detail
+      :visible.sync="showFullDetail"
+      :crm-type="detailCRMType"
+      :id="rowID"/>
+    <!-- 编辑日程 -->
+    <create-schedule
+      v-if="showDialog"
+      :text="newText"
+      :form-data="formData"
+      :append-to-body="true"
+      @onSubmit="onSubmit"
+      @closeDialog="showDialog=false"/>
+  </div>
+</template>
+
+<script>
+// import { crmQueryEventRelation } from '@/api/clients/common'
+import FollowScheduleCell from './components/FollowScheduleCell'
+// import { scheduleDelete } from '@/api/oamanagement/schedule'
+// import CreateSchedule from '@/views/OAManagement/schedule/components/createSchedule'
+
+export default {
+  /** 日程 跟进记录 */
+  name: 'ScheduleLog',
+  components: {
+    FollowScheduleCell,
+    CRMFullScreenDetail: () =>
+      import('@/views/clients/components/CRMFullScreenDetail.vue')
+    // CreateSchedule
+  },
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      loading: false,
+      loadMoreLoading: true,
+      isPost: false,
+      page: 1,
+      list: [], // 跟进记录列表
+      // 详情
+      showFullDetail: false,
+      detailCRMType: '',
+      rowID: '', // 行信息
+      showDialog: false,
+      formData: {
+        checkList: []
+      },
+      newtext: ''
+    }
+  },
+  computed: {},
+  watch: {
+    id: function (val) {
+      this.refreshList()
+    }
+  },
+  mounted () {
+    // 分批次加载
+    const dom = document.getElementById('follow-log-content')
+    dom.onscroll = () => {
+      const scrollOff = dom.scrollTop + dom.clientHeight - dom.scrollHeight
+      // 滚动条到底部的条件
+      if (Math.abs(scrollOff) < 10 && this.loadMoreLoading === true) {
+        if (!this.isPost) {
+          this.isPost = true
+          this.page++
+          this.getList()
+        } else {
+          this.loadMoreLoading = false
+        }
+      }
+    }
+
+    this.getList()
+  },
+  activated: function () {},
+  deactivated: function () {},
+  methods: {
+    getList () {
+      this.loading = true
+      const params = { page: this.page, limit: 10 }
+      params[this.crmType + 'Ids'] = this.id
+      // crmQueryEventRelation(params)
+      //   .then(res => {
+      //     this.list = this.list.concat(res.data.list)
+      //     if (res.data.list.length < 10) {
+      //       this.loadMoreLoading = false
+      //     } else {
+      //       this.loadMoreLoading = true
+      //     }
+      //     this.loading = false
+      //     this.isPost = false
+      //   })
+      //   .catch(() => {
+      //     this.isPost = false
+      //     this.loading = false
+      //   })
+    },
+    refreshList () {
+      this.page = 1
+      this.list = []
+      this.getList()
+    },
+    examineCellHandle (data) {
+      // 编辑
+      if (data.type === 'edit') {
+        this.newText = '编辑日程'
+        const val = data.data.item
+        val.startTime = val.startTime
+        val.endTime = val.endTime
+        val.ownerUserIds = []
+        for (const k of val.ownerList) {
+          val.ownerUserIds.push(k.userId)
+        }
+        this.formData = val
+        this.showDialog = true
+      } else if (data.type === 'delete') {
+        this.$confirm('确定删除?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+          .then(() => {
+            // scheduleDelete({ eventId: data.data.item.eventId }).then(res => {
+            //   this.refreshList()
+            //   this.$message({
+            //     type: 'success',
+            //     message: '删除成功!'
+            //   })
+            // })
+          })
+          .catch(() => {
+            this.$message({
+              type: 'info',
+              message: '已取消删除'
+            })
+          })
+      } else if (data.type === 'related-detail') {
+        // this.rowID = data.data.item[data.data.type + 'Id']
+        // this.detailCRMType = data.data.type
+        // this.showFullDetail = true
+      }
+    },
+    // 提交
+    onSubmit (data, file) {
+      this.refreshList()
+      if (this.newText === '创建日程') {
+        this.$message.success('新建成功')
+        this.showDialog = false
+      } else {
+        this.$message.success('编辑成功')
+        this.showDialog = false
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.log-items {
+  min-height: 400px;
+  position: relative;
+}
+
+.load {
+  color: #999;
+  font-size: 13px;
+  margin: 0 auto 15px;
+  text-align: center;
+  .el-button,
+  .el-button:focus {
+    color: #ccc;
+    cursor: auto;
+  }
+}
+</style>
diff --git a/src/views/clients/components/followLog/TaskLog.vue b/src/views/clients/components/followLog/TaskLog.vue
new file mode 100644
index 0000000..c8c3db9
--- /dev/null
+++ b/src/views/clients/components/followLog/TaskLog.vue
@@ -0,0 +1,192 @@
+<template>
+  <div v-loading="loading">
+    <div v-empty="list.length === 0">
+      <div class="log-items">
+        <task-cell
+          v-for="(item, index) in list"
+          :data="item"
+          :data-index="index"
+          :key="index"
+          @on-handle="taskCellHandle"/>
+        <div class="load">
+          <el-button
+            :loading="loadMoreLoading"
+            type="text">{{ loadMoreLoading ? '加载更多' : '没有更多了' }}</el-button>
+        </div>
+      </div>
+    </div>
+    <!-- 详情 -->
+    <div
+      v-if="taskDetailShow"
+      ref="taskShade"
+      class="full-container">
+      <particulars
+        :id="taskID"
+        :detail-index="detailIndex"
+        class="d-view"
+        @on-handle="detailHandle"
+        @close="closeBtn"/>
+    </div>
+  </div>
+</template>
+
+<script>
+import listTaskDetail from '@/views/OAManagement/task/mixins/listTaskDetail.js'
+import TaskCell from '@/views/OAManagement/task/components/taskCell' // 任务
+
+// import { crmQueryTaskRelation } from '@/api/clients/common'
+import { getMaxIndex } from '@/utils'
+
+export default {
+  /** 任务 跟进记录 */
+  name: 'TaskLog',
+  components: {
+    TaskCell,
+    Particulars: () =>
+      import('@/views/OAManagement/task/components/particulars')
+  },
+  mixins: [listTaskDetail],
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      loading: false,
+      loadMoreLoading: true,
+      isPost: false,
+      page: 1,
+      list: [] // 跟进记录列表
+    }
+  },
+  computed: {},
+  watch: {
+    id: function (val) {
+      this.refreshList()
+    }
+  },
+  mounted () {
+    // 分批次加载
+    const dom = document.getElementById('follow-log-content')
+    dom.onscroll = () => {
+      const scrollOff = dom.scrollTop + dom.clientHeight - dom.scrollHeight
+      // 滚动条到底部的条件
+      if (Math.abs(scrollOff) < 10 && this.loadMoreLoading === true) {
+        if (!this.isPost) {
+          this.isPost = true
+          this.page++
+          this.getList()
+        } else {
+          this.loadMoreLoading = false
+        }
+      }
+    }
+
+    this.getList()
+  },
+  activated: function () {},
+  deactivated: function () {},
+  methods: {
+    getList () {
+      this.loading = true
+      const params = { page: this.page, limit: 10 }
+      params[this.crmType + 'Ids'] = this.id
+      // crmQueryTaskRelation(params)
+      //   .then(res => {
+      //     res.data.list.forEach(item => {
+      //       if (item.status === 5) {
+      //         item.checked = true
+      //       }
+      //     })
+      //     this.list = this.list.concat(res.data.list)
+      //     if (res.data.list.length < 10) {
+      //       this.loadMoreLoading = false
+      //     } else {
+      //       this.loadMoreLoading = true
+      //     }
+      //     this.loading = false
+      //     this.isPost = false
+      //   })
+      //   .catch(() => {
+      //     this.isPost = false
+      //     this.loading = false
+      //   })
+    },
+    refreshList () {
+      this.page = 1
+      this.list = []
+      this.getList()
+    },
+    taskCellHandle (data) {
+      if (data.type === 'view') {
+        this.showDetailView(data.data.item, data.data.index, () => {
+          this.$nextTick(() => {
+            document.body.appendChild(this.$refs.taskShade)
+            this.$refs.taskShade.style.zIndex = getMaxIndex()
+            this.$refs.taskShade.addEventListener(
+              'click',
+              this.handleDocumentClick,
+              false
+            )
+          })
+        })
+      }
+    },
+    // 点击显示详情
+    handleDocumentClick (e) {
+      e.stopPropagation()
+      if (this.$refs.taskShade === e.target) {
+        this.taskDetailShow = false
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.log-items {
+  min-height: 400px;
+  position: relative;
+}
+
+.load {
+  color: #999;
+  font-size: 13px;
+  margin: 0 auto 15px;
+  text-align: center;
+  .el-button,
+  .el-button:focus {
+    color: #ccc;
+    cursor: auto;
+  }
+}
+
+.d-view {
+   position: fixed;
+  // width: 950px;
+  // top: 0px;
+  width: 100%;
+  top: 300px;
+  bottom: 0px;
+  right: 0px;
+  // background: #FFFFFF;
+  box-shadow: 0px -4px 12px 0px rgba(61, 121, 204, 0.2);
+  border-radius: 24px 24px 0px 0px;
+}
+
+.full-container {
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  overflow: auto;
+  margin: 0;
+  background-color: rgba(0, 0, 0, 0.3);
+}
+</style>
diff --git a/src/views/clients/components/followLog/components/FollowRecordCell.vue b/src/views/clients/components/followLog/components/FollowRecordCell.vue
new file mode 100644
index 0000000..16741c7
--- /dev/null
+++ b/src/views/clients/components/followLog/components/FollowRecordCell.vue
@@ -0,0 +1,437 @@
+<template>
+  <div class="fl-c">
+    <!--<flexbox class="fl-h">
+      <div
+        v-photo="{img: item.userImg, realname: item.realname}"
+        v-lazy:background-image="$options.filters.filterUserLazyImg(item.userImg)"
+        class="div-photo fl-h-img"/>
+      <div class="fl-h-b">
+        <div class="fl-h-name">{{ item.Title }}</div>
+        <div class="fl-h-time">{{ item.FollowTime }}</div>
+      </div>
+      <flexbox class="fl-h-mark">
+        <img
+          class="fl-h-mark-img"
+          src="@/assets/img/person_dot.png" v-if=
+        "crmType === 'customer'">
+        <img
+          class="fl-h-mark-img"
+          src="@/assets/img/follow_record.png" v-if=
+        "crmType === 'contacts'">
+        <img
+          class="fl-h-mark-img"
+          src="@/assets/img/business_dot.png" v-if=
+        "crmType === 'business'">
+        <div class="fl-h-mark-name">跟进记录</div>
+      </flexbox>
+      <el-dropdown
+        trigger="click"
+        @command="handleCommand">
+        <i
+          style="color:#CDCDCD;margin-left: 8px;"
+          class="el-icon-arrow-down el-icon-more"/>
+        <el-dropdown-menu slot="dropdown">
+          <el-dropdown-item :command="beforeHandleCommand(item.Id,'edit')">编辑</el-dropdown-item>
+          <el-dropdown-item :command="beforeHandleCommand(item.Id,'delete')">删除</el-dropdown-item>
+        </el-dropdown-menu>
+      </el-dropdown>
+    </flexbox>
+    <div class="fl-b">
+      <div class="fl-b-content">{{ item.Content }}</div>
+      <flexbox
+        v-if="item.img && item.img.length > 0"
+        class="fl-b-images"
+        wrap="wrap">
+        <div
+          v-lazy:background-image="file.filePath"
+          v-for="(file, index) in item.img"
+          :key="file.filePath"
+          class="fl-b-img-item"
+          @click="previewImg(item.img, index)"/>
+      </flexbox>
+      <div
+        v-if="item.file && item.file.length > 0"
+        class="fl-b-files">
+        <flexbox
+          v-for="(file, index) in item.file"
+          :key="index"
+          class="cell">
+          <img
+            class="cell-head"
+            src="@/assets/img/relevance_file.png" >
+          <div class="cell-body">{{ file.name }}<span style="color: #ccc;">({{ file.size }})</span></div>
+          <el-button
+            type="primary"
+            icon="el-icon-download"
+            @click="downloadFile(file)">下载</el-button>
+        </flexbox>
+      </div>
+      <div
+        v-if="item.FollowWay || item.FollowTime || item.CompletedTime"
+        class="follow">
+        <span
+          v-if="item.FollowWay"
+          class="follow-info">跟进方式:{{ item.FollowWay | typeFollowWay }}</span>
+        <span
+          v-if="item.FollowTime"
+          class="follow-info">下次跟进时间:{{ item.FollowTime }}</span>
+          <span
+          v-if="item.CompletedTime"
+          class="follow-info">跟进完成时间:{{ item.CompletedTime }}</span>
+      </div>
+      <div
+        v-if="item.contactsList && item.contactsList.length > 0"
+        class="fl-b-other">
+        <div class="fl-b-other-name">关联联系人</div>
+        <div>
+          <flexbox
+            v-for="(item, index) in item.contactsList"
+            :key="index"
+            class="cell"
+            @click.native="checkRelationDetail('contacts', item.contactsId)">
+            <i
+              :style="{'opacity': index === 0 ? 1 : 0}"
+              class="wukong wukong-contacts cell-head crm-type"/>
+            <div
+              class="cell-body"
+              style="color: #6394E5;cursor: pointer;">{{ item.name }}</div>
+          </flexbox>
+        </div>
+      </div>
+      <div
+        v-if="item.businessList && item.businessList.length > 0"
+        class="fl-b-other">
+        <div class="fl-b-other-name">关联商机</div>
+        <div>
+          <flexbox
+            v-for="(item, index) in item.businessList"
+            :key="index"
+            class="cell"
+            @click.native="checkRelationDetail('business', item.businessId)">
+            <i
+              :style="{'opacity': index === 0 ? 1 : 0}"
+              class="wukong wukong-business cell-head crm-type"/>
+            <div
+              class="cell-body"
+              style="color: #6394E5;cursor: pointer;">{{ item.businessName }}</div>
+          </flexbox>
+        </div>
+      </div>
+      <slot/>
+    </div>-->
+
+    <el-table
+      :data="list"
+      :height="tableHeight"
+      :header-cell-style="headerRowStyle"
+      :cell-style="cellStyle"
+      style="width: 100%;border: 1px solid #E6E6E6;"
+      @row-click="handleRowClick"
+      @selection-change="selectionList = $event">
+      <el-table-column
+        v-for="(item, index) in fieldList"
+        :key="index"
+        :prop="item.prop"
+        :label="item.label"
+        :formatter="fieldFormatter"
+        show-overflow-tooltip/>
+    </el-table>
+    <div class="p-contianer" v-show='item.length>0'>
+      <el-pagination
+        :current-page="currentPage"
+        :page-sizes="pageSizes"
+        :page-size.sync="pageSize"
+        :total="item.length"
+        class="p-bar"
+        layout="total, sizes, prev, pager, next, jumper"
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"/>
+    </div>
+    <!--跟进 -->
+    <el-dialog
+      v-loading="followLoading"
+      v-if="isFollowDialog"
+      title="编辑跟进记录"
+      :visible.sync="isFollowDialog"
+      :close-on-click-modal="false"
+      :modal-append-to-body="true"
+      :append-to-body="true"
+      :before-close="followHandleClose"
+      width="60%">
+        <mix-add
+          ref="mixadd"
+          :crm-type="crmType"
+          :id="id"
+          :isEdit='true'
+          :show-relative-business="true"
+          :show-relative-contacts="true"
+          @mixadd-info="submitInfo"/>
+      <span
+        slot="footer"
+        class="dialog-footer">
+        <el-button
+          type="primary"
+          @click="followDialogSubmit">保 存</el-button>
+        <el-button @click="followHandleClose">取 消</el-button>
+      </span>
+    </el-dialog>
+
+    <c-r-m-full-screen-detail
+      :visible.sync="showFullDetail"
+      :crm-type="relationCrmType"
+      :id="relationID"/>
+  </div>
+</template>
+
+<script>
+import MixAdd from '../../../components/MixAdd'
+import { downloadFile } from '@/utils'
+// import { crmRecordDelete } from '@/api/clients/common'
+
+export default {
+  /** 客户管理 的 客户详情 的 跟进记录cell */
+  name: 'FollowRecordCell',
+  components: {
+    MixAdd,
+    CRMFullScreenDetail: () =>
+      import('@/views/clients/components/CRMFullScreenDetail.vue')
+  },
+  filters: {
+    /** 根据type 找到组件 */
+    typeFollowWay (formType) {
+      switch (formType) {
+        case 0:
+          return '暂无'
+        case 1:
+          return '电话'
+        case 2:
+          return '在线沟通'
+        case 3:
+          return '邮件或短信'
+        case 4:
+          return '上门拜访'
+      }
+    }
+  },
+  props: {
+    item: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    index: [String, Number]
+  },
+  data () {
+    return {
+      showFullDetail: false, // 查看相关客户管理详情
+      relationID: '', // 相关ID参数
+      relationCrmType: '', // 相关类型
+      isFollowDialog: false,
+      followLoading: false,
+      id: '',
+      list: [],
+      fieldList: [],
+      tableHeight: '400px',
+      total: 0,
+      currentPage: 1,
+      pageSize: 10,
+      pageSizes: [10, 30, 60, 100]
+    }
+  },
+  computed: {
+  },
+  mounted () {
+    this.fieldList.push(
+      { prop: 'SalesChanceName', label: '商机名称', width: '300' },
+      { prop: 'Contacter', label: '联系人', width: '400' },
+      { prop: 'FollowTime', label: '下次跟进时间', width: '400' },
+      { prop: 'CompletedTime', label: '跟进完成时间', width: '400' },
+      { prop: 'FollowWay', label: '跟进方式', width: '400' },
+      { prop: 'DocumentType', label: '销售负责人', width: '200' },
+      { prop: 'Content', label: '跟进内容', width: '100' },
+      { prop: 'Files', label: '附件', width: '200' }
+    )
+
+    console.log(this.item)
+  },
+  methods: {
+    /** 通过回调控制表头style */
+    headerRowStyle ({ row, column, rowIndex, columnIndex }) {
+      return { textAlign: 'left' }
+    },
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      return { textAlign: 'left' }
+    },
+    // 当某一行被点击时会触发该事件
+    handleRowClick (row, column, event) {},
+    /** 格式化字段 */
+    fieldFormatter (row, column) {
+      // 如果需要格式化
+      if (column.property === 'FileType') {
+        return this.getStatusName(row.FileType)
+      }
+      return row[column.property] || '--'
+    },
+    handleSizeChange (newSize) {
+      this.$emit('on-handle', {size: newSize})
+      // this.queryInfo.pagesize = newSize
+    },
+    handleCurrentChange (newPage) {
+      this.$emit('on-handle', {page: newPage})
+      // this.queryInfo.pagenum = newPage
+    },
+    previewImg (list, index) {
+      this.$bus.emit('preview-image-bus', {
+        index: index,
+        data: list.map(function (item, index, array) {
+          item.url = item.filePath
+          return item
+        })
+      })
+    },
+    downloadFile (file) {
+      downloadFile({ path: file.filePath, name: file.name })
+    },
+    /**
+     * 删除跟进记录
+     */
+    beforeHandleCommand (id, command) { // index我这里是遍历的角标,即你需要传递的额外参数
+      return {
+        'id': id,
+        'command': command
+      }
+    },
+
+    handleCommand (command) {
+      console.log(command)
+      if (command.command === 'delete') {
+        this.$confirm('确定删除?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+          .then(() => {
+          // crmRecordDelete({
+          //   recordId: this.item.recordId
+          // })
+          //   .then(res => {
+          //     this.$emit('on-handle', {
+          //       type: command,
+          //       data: { item: this.item, index: this.index }
+          //     })
+          //     this.$message.success('操作成功')
+          //   })
+          //   .catch(() => {})
+          })
+          .catch(() => {
+            this.$message({
+              type: 'info',
+              message: '已取消操作'
+            })
+          })
+      } else if (command.command === 'edit') {
+        this.id = command.id
+        this.isFollowDialog = true
+      }
+    },
+    followDialogSubmit () {
+      this.isFollowDialog = false
+      this.$refs.mixadd.resetInfo()
+    },
+    followHandleClose () {
+      this.isFollowDialog = false
+      this.$refs.mixadd.resetInfo()
+    },
+    /** 快捷添加框内 返回的数据用于上传 */
+    submitInfo (data) {
+      console.log(data)
+      if (data.isEvent && !data.nextTime) {
+        this.$message.error('请选择下次联系时间')
+        return
+      } else if (!data.content) {
+        this.$message.error('请输入跟进内容')
+        return
+      }
+
+      var params = {}
+      params.SourceId = this.id
+      params.Title = data.title
+      params.Content = data.content
+      params.FollowType = data.followTypeId
+      params.FollowWay = data.wayTypeId
+      // var businessIds = data.business.map(function (element, index, array) {
+      //   return element.businessId
+      // })
+      // var contactsIds = data.contacts.map(function (element, index, array) {
+      //   return element.contactsId
+      // })
+
+      // params.batchId = data.batchId
+      // params.businessIds = businessIds.join(',')
+      // params.contactsIds = contactsIds.join(',')
+
+      params.IsCompleted = data.isEvent
+      params.FollowTime = data.nextTime || ''
+
+      this.sendLoading = true
+      if (data.isEvent) {
+        // MakeFollowRecordCompleted({'Id': this.id}).then(res => {
+        //   this.$message.success('完成跟进')
+        // })
+      }
+      // AddFollowRecord(params)
+      //   .then(res => {
+      this.sendLoading = false
+      //     this.$message.success('发布成功')
+      //     // 重置页面
+      this.$refs.mixadd.resetInfo()
+      //     // this.isEvent = false
+      //     // this.nextTime = ''
+      //     // 刷新数据
+      //     this.$bus.emit('follow-log-refresh', { type: 'record-log' })
+      //   })
+      //   .catch(() => {
+      //     this.sendLoading = false
+      //   })
+    },
+    /**
+     * 查看相关客户管理详情
+     */
+    checkRelationDetail (type, id) {
+      // this.relationID = id
+      // this.relationCrmType = type
+      // this.showFullDetail = true
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../styles/followcell.scss';
+@import '../../../styles/relativecrm.scss';
+@import '../../../styles/table.scss';
+.follow {
+  .follow-info {
+    padding: 5px 10px;
+    background-color: #f5f7fa;
+    color: #999;
+    height: 40px;
+    line-height: 40px;
+    border-radius: 28px;
+    font-size: 12px;
+    margin-right: 10px;
+  }
+}
+
+.crm-type {
+  color: rgb(99, 148, 229);
+  font-size: 14px;
+}
+</style>
diff --git a/src/views/clients/components/followLog/components/FollowRecordTable.vue b/src/views/clients/components/followLog/components/FollowRecordTable.vue
new file mode 100644
index 0000000..44af116
--- /dev/null
+++ b/src/views/clients/components/followLog/components/FollowRecordTable.vue
@@ -0,0 +1,449 @@
+<template>
+  <div
+    v-empty="nopermission"
+    class="rc-cont"
+    xs-empty-icon="nopermission"
+    xs-empty-text="暂无权限">
+
+    <el-table
+      v-loading="loading"
+      id="crm-table"
+      :data="list"
+      class="n-table--border"
+      border
+      highlight-current-row
+      :height="tableHeight"
+      :header-cell-style="headerRowStyle"
+      :cell-style="cellStyle"
+      style="width: 100%; z-index: 0;border: 1px solid #E6E6E6;"
+      @row-click="handleRowClick">
+      <el-table-column
+        v-for="(item, index) in fieldList"
+        :key="index"
+        :prop="item.prop"
+        :label="item.label"
+        :width="item.width"
+        :formatter="fieldFormatter"
+        show-overflow-tooltip>
+        <template
+          slot="header"
+          slot-scope="scope">
+          <div class="table-head-name">
+            {{ scope.column.label }}
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column
+        prop="Files">
+        <template
+          slot="header"
+          slot-scope="scope">
+          <div class="table-head-name">
+            附件
+          </div>
+        </template>
+        <template slot-scope="scope">
+          <el-popover
+            :offset="250"
+            placement="right"
+            popper-class="no-padding-popover"
+            width="200"
+            trigger="click">
+              <div class="pop-container">
+                <flexbox class="pop-header">
+                  <div class="pop-name">附件</div>
+                  <!--<div class="detail"></div>-->
+                  <img
+                    class="pop-close"
+                    src="@/assets/img/task_close.png"
+                    @click="hidenRelationInput" >
+                </flexbox>
+                <flexbox class="pop-content">
+                  <div style="height: 200px;">
+                    <div class='el-scrollbar' style="height: 100%; width: 160px;">
+                      <div class='el-select-dropdown__wrap el-scrollbar__wrap' style="margin-bottom: -7px; margin-right: -7px;">
+                        <ul class="el-scrollbar__view el-select-dropdown__list">
+                          <li class='el-select-dropdown__item'
+                          :class="item.DocumentName === proValue?'selected':''"
+                          v-for="(item, index) in scope.row.Files"
+                          :key="index"
+                          @click="handleFile(item, index)"
+                          >{{item.DocumentName}}
+                          <!--<a :disabled="item.DocumentName === 'srting'" :href="headUrl + item.DocumentFileName" :download="item.DocumentName">{{item.DocumentName}}</a>-->
+                          </li>
+                        </ul>
+                      </div>
+                    </div>
+                  </div>
+                  <div
+                    v-if="scope.row.Files&&scope.row.Files.length<1"
+                    class="no-data-container">
+                    <img
+                      class="no-data"
+                      src="@/assets/img/no_data.png" >
+                    <div class="no-data-name">暂无数据</div>
+                  </div>
+                </flexbox>
+              </div>
+            <div slot="reference">查看附件</div>
+          </el-popover>
+        </template>
+      </el-table-column>
+      <el-table-column
+        prop="operation"
+        v-if="crmType!=='businessChances' && crmType!=='businessCustomer'">
+        <template
+          slot="header"
+          slot-scope="scope">
+          <div class="table-head-name">操作</div>
+        </template>
+        <template slot-scope="scope">
+          <el-button type="text" size="small"  @click='deleteLog(scope.row)'>删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <div class="p-contianer" v-show='total'>
+      <el-pagination
+        :current-page="currentPage"
+        :page-sizes="pageSizes"
+        :page-size.sync="pageSize"
+        :total="total"
+        class="p-bar"
+        layout="total, sizes, prev, pager, next, jumper"
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"/>
+    </div>
+    <!--跟进 -->
+    <el-dialog
+      v-loading="followLoading"
+      v-if="isFollowDialog"
+      title="编辑跟进记录"
+      :visible.sync="isFollowDialog"
+      :close-on-click-modal="false"
+      :modal-append-to-body="true"
+      :append-to-body="true"
+      :before-close="followHandleClose"
+      width="60%">
+        <mix-add
+          ref="mixadd"
+          :crm-type="crmType"
+          :id="id"
+          :isEdit='true'
+          :show-relative-business="true"
+          :show-relative-contacts="true"
+          @mixadd-info="submitInfo"/>
+      <span
+        slot="footer"
+        class="dialog-footer">
+        <el-button
+          type="primary"
+          @click="followDialogSubmit">保 存</el-button>
+        <el-button @click="followHandleClose">取 消</el-button>
+      </span>
+    </el-dialog>
+
+  </div>
+</template>
+
+<script>
+import MixAdd from '../../../components/MixAdd'
+import { GetBusinessFollowRecordList, DeleteFollowRecord } from '@/api/common'
+import { ResouceUrl } from '@/utils/baseconfig'
+import { downloadFile } from '@/utils'
+// import { crmRecordDelete } from '@/api/clients/common'
+
+export default {
+  /** 客户管理 的 客户详情 的 跟进记录cell */
+  name: 'FollowRecordTable',
+  components: {
+    MixAdd,
+    CRMFullScreenDetail: () =>
+      import('@/views/clients/components/CRMFullScreenDetail.vue')
+  },
+  filters: {
+    /** 根据type 找到组件 */
+    typeFollowWay (formType) {
+      switch (formType) {
+        case 0:
+          return '暂无'
+        case 1:
+          return '电话'
+        case 2:
+          return '在线沟通'
+        case 3:
+          return '邮件或短信'
+        case 4:
+          return '上门拜访'
+      }
+    }
+  },
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      loading: false,
+      isFollowDialog: false,
+      followLoading: false,
+      nopermission: false,
+      list: [],
+      fieldList: [
+        // { prop: 'SalesChanceName', label: '商机名称', width: '180' },
+        { prop: 'Contacter', label: '联系人' },
+        { prop: 'FollowTime', label: '跟进时间' },
+        // { prop: 'CompletedTime', label: '跟进完成时间' },
+        { prop: 'FollowWayString', label: '跟进方式' },
+        { prop: 'CreateUserName', label: '跟进人' },
+        { prop: 'Content', label: '跟进内容' }
+      ],
+      tableHeight: '400px',
+      total: 0,
+      currentPage: 1,
+      pageSize: 10,
+      pageSizes: [10, 30, 60, 100],
+      proValue: ''
+    }
+  },
+  computed: {
+  },
+  watch: {
+  },
+  mounted () {
+    this.headUrl = ResouceUrl
+    this.$bus.on('follow-log-refresh', data => {
+      if (data.type === 'follow-record-table') {
+        this.getFieldList()
+      }
+    })
+    this.getFieldList()
+  },
+  methods: {
+    getFieldList () {
+      if (this.crmType === 'customer' || this.crmType === 'businessCustomer') {
+        this.fieldList = [
+          { prop: 'SalesChanceName', label: '商机名称' },
+          { prop: 'Contacter', label: '联系人' },
+          // { prop: 'FollowTime', label: '本次跟进时间' },
+          { prop: 'CompletedTime', label: '跟进完成时间' },
+          { prop: 'FollowWayString', label: '跟进方式' },
+          { prop: 'CreateUserName', label: '跟进人' },
+          { prop: 'Content', label: '跟进内容' }
+        ]
+      } else if (this.crmType === 'contacts') {
+        this.fieldList = [
+          { prop: 'SalesChanceName', label: '商机名称', width: '180' },
+          // { prop: 'Contacter', label: '联系人' },
+          // { prop: 'FollowTime', label: '本次跟进时间' },
+          { prop: 'CompletedTime', label: '跟进完成时间' },
+          { prop: 'FollowWayString', label: '跟进方式' },
+          { prop: 'CreateUserName', label: '跟进人' },
+          { prop: 'Content', label: '跟进内容' }
+        ]
+      }
+      this.getList()
+    },
+    getList () {
+      this.loading = true
+      let request = {
+        customer: GetBusinessFollowRecordList,
+        businessCustomer: GetBusinessFollowRecordList,
+        // leads: crmLeadsRecordIndex,
+        contacts: GetBusinessFollowRecordList,
+        business: GetBusinessFollowRecordList,
+        businessChances: GetBusinessFollowRecordList
+      // contract: crmContractRecordIndex
+      }[this.crmType]
+
+      const params = {
+        PageIndex: this.currentPage,
+        PageSize: this.pageSize
+      }
+      params['BusinessOperationType'] = {
+        customer: 1,
+        businessCustomer: 1,
+        contacts: 2,
+        business: 3,
+        businessChances: 3
+      }[this.crmType]
+      params['SourceId'] = this.id
+      // if (request === 'GetBusinessFollowRecordList') {
+      // } else {
+      //   params['Id'] = this.id
+      // }
+      request(params)
+        .then(res => {
+          this.loading = false
+          if (res.data.ErrorCode === 200) {
+            this.list = res.data.Result.List
+            this.total = res.data.Result.Count
+          } else {
+            this.list = []
+            this.total = 0
+          }
+        })
+        .catch(() => {
+          this.loading = false
+        })
+    },
+    handleFile (data, index) {
+      this.proValue = data
+      downloadFile({ path: data.DocumentFileName, name: data.DocumentName })
+    },
+    hidenRelationInput () {
+      this.proValue = ''
+      document.querySelector('#app').click()
+    },
+    deleteLog (row) {
+      console.log(row)
+      this.$confirm('确定删除?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          DeleteFollowRecord([{'Id': row.Id}]).then(res => {
+            if (res.data.ErrorCode === 200) {
+              this.$message.success(res.data.Message)
+              this.getList()
+            } else {
+              this.$message.error(res.data.Message)
+            }
+          })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    },
+    /** 通过回调控制表头style */
+    headerRowStyle ({ row, column, rowIndex, columnIndex }) {
+      return { textAlign: 'left' }
+    },
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      if (
+        column.property === 'Files'
+      ) {
+        return { color: '#4D88FF', cursor: 'pointer', textAlign: 'left' }
+      } else {
+        return { textAlign: 'left' }
+      }
+    },
+    // 当某一行被点击时会触发该事件
+    handleRowClick (row, column, event) {
+      if (column.property === 'Files') {
+        console.log('yesss')
+      }
+    },
+    /** 格式化字段 */
+    fieldFormatter (row, column) {
+      // 如果需要格式化
+      if (column.property === 'Files') {
+        return row[column.property].DocumentName || '--'
+      }
+      return row[column.property] || '--'
+    },
+    handleSizeChange (newSize) {
+      this.pageSize = newSize
+      this.currentPage = 1
+      this.getList()
+      // this.queryInfo.pagesize = newSize
+    },
+    handleCurrentChange (newPage) {
+      this.currentPage = newPage
+      this.getList()
+      // this.queryInfo.pagenum = newPage
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../../../styles/relativecrm.scss';
+.rc-cont{
+  padding: 0;
+}
+.el-table /deep/ thead th:nth-last-child(2), thead td {
+  border-right: 0;
+  font-weight: 600;
+}
+.el-scrollbar__wrap{
+  overflow-x:hidden;
+  }
+.pop-container {
+  position: relative;
+}
+
+.pop-header {
+  padding: 16px 30px;
+  flex-shrink: 0;
+  border-bottom: 1px solid #F1F1F1;
+  margin-bottom: 13px;
+  .pop-name {
+    font-size: 16px;
+    font-weight: 550;
+    padding: 0 10px;
+    color: #333;
+  }
+  .pop-detail {
+    font-size: 12px;
+    padding: 0 10px;
+    color: #aaaaaa;
+    border-left: 1px solid #aaaaaa;
+  }
+  .pop-close {
+    position: absolute;
+    top: 16px;
+    right: 10px;
+    width: 25px;
+    height: 25px;
+  }
+}
+.pop-content{
+  padding: 0 30px;
+  .pop-cropper-box{
+    display:flex;
+    flex-direction: row;
+    align-items: center;
+    margin-bottom: 30px;
+    .pop-searchTitle{
+      font-size: 14px;
+      width: 124px;
+      color: #333;
+    }
+    .pop-searchInput{
+      margin-right: 20px;
+    }
+  }
+  .no-data-container {
+    position: absolute;
+    top: 40px;
+    left: 50px;
+    text-align: center;
+    .no-data {
+      margin-top: 30px;
+      width: 100px;
+    }
+    .no-data-name {
+      font-size: 12px;
+      margin-top: 8px;
+      color: #666;
+    }
+  }
+}
+.el-select-dropdown__item{
+  padding: 0 3px;
+}
+.crm-type {
+  color: rgb(99, 148, 229);
+  font-size: 14px;
+}
+</style>
diff --git a/src/views/clients/components/followLog/components/FollowScheduleCell.vue b/src/views/clients/components/followLog/components/FollowScheduleCell.vue
new file mode 100644
index 0000000..a198680
--- /dev/null
+++ b/src/views/clients/components/followLog/components/FollowScheduleCell.vue
@@ -0,0 +1,252 @@
+<template>
+  <div class="fl-c">
+    <flexbox class="fl-h">
+      <div
+        v-photo="data.createUser"
+        v-lazy:background-image="$options.filters.filterUserLazyImg(data.createUser.img)"
+        class="div-photo fl-h-img"/>
+      <div class="fl-h-b">
+        <div class="fl-h-name">{{ data.createUser.realname }}</div>
+        <div class="fl-h-time">{{ data.createTime }}</div>
+      </div>
+      <el-dropdown
+        v-if="data.permission && (data.permission.isUpdate === 1 || data.permission.isDelete === 1)"
+        trigger="click"
+        @command="handleCommand">
+        <i
+          style="color:#CDCDCD;"
+          class="el-icon-arrow-down el-icon-more"/>
+        <el-dropdown-menu slot="dropdown">
+          <el-dropdown-item
+            v-if="data.permission && data.permission.isUpdate === 1"
+            command="edit">编辑</el-dropdown-item>
+          <el-dropdown-item
+            v-if="data.permission && data.permission.isDelete === 1"
+            command="delete">删除</el-dropdown-item>
+        </el-dropdown-menu>
+      </el-dropdown>
+    </flexbox>
+    <div class="fl-b">
+      <div>
+        <div
+          :style="{'background-color': data.color ? data.color : '#fff'}"
+          class="state-color"/>{{ data.title }}
+      </div>
+      <div class="fl-b-des">
+        <flexbox class="fl-b-des-item">
+          <div class="fl-b-des-item-name">参与人:</div>
+          <div class="owner-list">
+            <span
+              v-for="(k, j) in data.ownerList"
+              :key="j">
+              <el-tooltip
+                placement="bottom"
+                effect="light"
+                popper-class="tooltip-change-border">
+                <div slot="content">
+                  <span>{{ k.realname }}</span>
+                </div>
+                <div
+                  v-photo="k"
+                  v-lazy:background-image="$options.filters.filterUserLazyImg(k.img)"
+                  :key="k.img"
+                  class="div-photo header-circle"/>
+              </el-tooltip>
+            </span>
+          </div>
+        </flexbox>
+        <flexbox class="fl-b-des-item">
+          <div class="fl-b-des-item-name">开始时间:</div>
+          <div>{{ data.startTime }}</div>
+        </flexbox>
+        <flexbox class="fl-b-des-item">
+          <div class="fl-b-des-item-name">结束时间:</div>
+          <div>{{ data.endTime }}</div>
+        </flexbox>
+        <flexbox class="fl-b-des-item">
+          <div class="fl-b-des-item-name">备注:</div>
+          <div>{{ data.remark }}</div>
+        </flexbox>
+      </div>
+      <!-- 关联业务 -->
+      <div
+        v-if="data.contactsList.length > 0 || data.customerList.length > 0 || data.businessList.length > 0 || data.contractList.length > 0"
+        class="related-business">
+        <div class="label">关联业务</div>
+        <p
+          v-for="(contacts, i) in data.contactsList"
+          :key="'contacts' + i"
+          @click="checkRelatedDetail('contacts',contacts)">
+          <img
+            src="@/assets/img/relevance_business.png"
+            alt="">
+          联系人-{{ contacts.name }}
+        </p>
+        <p
+          v-for="(customer, i) in data.customerList"
+          :key="'customer' + i"
+          @click="checkRelatedDetail('customer',customer)">
+          <img
+            src="@/assets/img/relevance_business.png"
+            alt="">
+          客户-{{ customer.customerName }}
+        </p>
+        <p
+          v-for="(business, i) in data.businessList"
+          :key="'business' + i"
+          @click="checkRelatedDetail('business',business)">
+          <img
+            src="@/assets/img/relevance_business.png"
+            alt="">
+          商机-{{ business.businessName }}
+        </p>
+        <p
+          v-for="(contract, i) in data.contractList"
+          :key="'contract' + i"
+          @click="checkRelatedDetail('contract',contract)">
+          <img
+            src="@/assets/img/relevance_business.png"
+            alt="">
+          合同-{{ contract.name }}
+        </p>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  /** 客户管理 的 客户详情 的 任务cell */
+  name: 'FollowScheduleCell',
+  components: {},
+  filters: {
+    getRemindtypeText: function (remindtype) {
+      switch (remindtype) {
+        case 0:
+          return '无'
+        case 1:
+          return '准时提醒'
+        case 2:
+          return '5分钟前'
+        case 3:
+          return '15分钟前'
+        case 4:
+          return '30分钟前'
+        case 5:
+          return '一个小时前'
+        case 6:
+          return '二个小时前'
+        case 7:
+          return '一天前'
+        case 8:
+          return '二天前'
+        case 9:
+          return '一周前'
+      }
+      return ''
+    }
+  },
+  props: {
+    data: Object
+  },
+  data () {
+    return {}
+  },
+  computed: {},
+  mounted () {},
+  methods: {
+    // 关联详情
+    checkRelatedDetail (type, data) {
+      this.$emit('on-handle', {
+        type: 'related-detail',
+        data: { type: type, item: data }
+      })
+    },
+    handleCommand (command) {
+      this.$emit('on-handle', {
+        type: command,
+        data: { item: this.data }
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../styles/followcell.scss';
+.fl-h-state {
+  width: auto;
+  .fl-h-state-mark {
+    margin-right: 8px;
+    width: 10px;
+    height: 10px;
+    border-radius: 5px;
+  }
+  .fl-h-state-name {
+    font-size: 13px;
+    color: #333;
+  }
+}
+
+.el-checkbox /deep/ .el-checkbox__label {
+  font-size: 13px;
+}
+
+.fl-b-des {
+  margin: 15px 0;
+  .fl-b-des-item {
+    font-size: 12px;
+    color: #777;
+    margin: 8px 0;
+    .fl-b-des-item-name {
+      width: 60px;
+      margin-right: 10px;
+    }
+  }
+}
+
+.state-color {
+  width: 15px;
+  height: 15px;
+  display: inline-block;
+  border-radius: 7.5px;
+  margin-right: 2px;
+}
+
+// 关联业务
+.related-business {
+  margin: 15px 0;
+  .label {
+    font-size: 13px;
+    margin-bottom: 7px;
+  }
+  p {
+    cursor: pointer;
+    color: #4D88FF;
+    background: #f5f7fa;
+    line-height: 30px;
+    margin-bottom: 5px;
+    font-size: 13px;
+    padding-left: 7px;
+    border-radius: 2px;
+    img {
+      width: 16px;
+      vertical-align: middle;
+    }
+  }
+}
+
+// 参与人
+.owner-list {
+  display: inline-block;
+  vertical-align: middle;
+  span {
+    display: inline-block;
+  }
+  .div-photo {
+    width: 25px;
+    height: 25px;
+    margin-right: 10px;
+  }
+}
+</style>
diff --git a/src/views/clients/components/followLog/styles/followcell.scss b/src/views/clients/components/followLog/styles/followcell.scss
new file mode 100644
index 0000000..bcdef7e
--- /dev/null
+++ b/src/views/clients/components/followLog/styles/followcell.scss
@@ -0,0 +1,174 @@
+/** 跟进记录相关的 日志 审批任务 日程 项目 公共css */
+.fl-c {
+  background-color: white;
+  padding: 10px 20px;
+  position: relative;
+}
+
+/** 头部布局 名字 头像 */
+.fl-h {
+  .fl-h-img {
+    display: block;
+    width: 34px;
+    height: 34px;
+    border-radius: 17px;
+    margin-right: 8px;
+  }
+
+  .fl-h-b {
+    flex: 1;
+
+    .fl-h-name {
+      font-size: 13px;
+      color: #333;
+    }
+
+    .fl-h-time {
+      font-size: 12px;
+      color: #999;
+      margin-top: 3px;
+    }
+  }
+}
+
+/** 头部 右侧 布局*/
+.fl-h-handle {
+  width: auto;
+
+  .fl-h-handle-name {
+    font-size: 13px;
+    color: #333;
+    margin-right: 6px;
+  }
+}
+
+.fl-h-mark {
+  width: auto;
+
+  .fl-h-mark-img {
+    display: block;
+    width: 14px;
+    height: 14px;
+    margin-right: 8px;
+  }
+
+  .fl-h-mark-name {
+    font-size: 12px;
+    color: #333;
+  }
+}
+
+/** 内容区域 */
+.fl-b {
+  margin: 20px 0 0 40px;
+
+  .fl-b-content {
+    font-size: 13px;
+    color: #333;
+    margin-bottom: 10px;
+    white-space: pre-wrap;
+    word-wrap: break-word;
+    letter-spacing: 0.5px;
+    line-height: 18px;
+  }
+
+  .fl-b-images {
+    margin-top: 5px;
+    width: 310px;
+
+    .fl-b-img-item {
+      width: 98px;
+      height: 98px;
+      display: inline-block;
+      margin: 0 4px 4px 0;
+      background-size: contain;
+      background-repeat: no-repeat;
+      background-position: center;
+      position: relative;
+      cursor: pointer;
+    }
+  }
+
+  .fl-b-other {
+    margin: 8px 0;
+
+    .fl-b-other-name {
+      margin: 10px 0;
+      color: #666;
+      font-size: 13px;
+    }
+  }
+}
+
+.fl-c:before {
+  content: " ";
+  position: absolute;
+  top: 0;
+  right: 0;
+  height: 1px;
+  border-top: 1px solid #e5e5e5;
+  color: #e5e5e5;
+  -webkit-transform-origin: 0 0;
+  transform-origin: 0 0;
+  -webkit-transform: scaleY(0.5);
+  transform: scaleY(0.5);
+  left: 15px;
+  z-index: 2;
+}
+
+.fl-c:first-child:before {
+  display: none;
+}
+
+/** 附件 */
+.fl-b-files {
+  margin-top: 10px;
+}
+
+/** 关联附件 联系人 客户 行布局 */
+.cell {
+  padding: 8px;
+  background-color: #F5F7FA;
+  border-radius: 2px;
+  position: relative;
+
+  .cell-head {
+    display: block;
+    width: 15px;
+    height: 15px;
+    margin-right: 8px;
+  }
+
+  .cell-body {
+    flex: 1;
+    color: #333;
+    font-size: 12px;
+  }
+
+  .cell-foot {
+    display: block;
+    width: 20px;
+    padding: 0 4px;
+    margin-right: 8px;
+  }
+}
+
+.cell:before {
+  content: " ";
+  position: absolute;
+  top: 0;
+  right: 0;
+  height: 1px;
+  border-top: 1px solid #e5e5e5;
+  color: #e5e5e5;
+  -webkit-transform-origin: 0 0;
+  transform-origin: 0 0;
+  -webkit-transform: scaleY(0.5);
+  transform: scaleY(0.5);
+  left: 30px;
+  z-index: 2;
+}
+
+.cell:first-child:before {
+  display: none;
+}
diff --git a/src/views/clients/components/sceneForm/SceneCreate.vue b/src/views/clients/components/sceneForm/SceneCreate.vue
new file mode 100644
index 0000000..de6e141
--- /dev/null
+++ b/src/views/clients/components/sceneForm/SceneCreate.vue
@@ -0,0 +1,640 @@
+<template>
+  <el-dialog
+    :title="edit_id ? '编辑场景' : '新建场景'"
+    :visible.sync="visible"
+    :append-to-body="true"
+    width="800px"
+    @close="handleCancel">
+    <div class="scene-name-container">
+      <div class="scene-name">场景名称</div>
+      <el-input
+        v-model.trim="saveName"
+        :maxlength="10"
+        class="scene-input"
+        placeholder="请输入场景名称,最多10个字符"/>
+    </div>
+    <div class="scene-name">筛选条件</div>
+    <el-form
+      id="scene-filter-container"
+      class="filter-container">
+      <el-form-item>
+        <template v-for="(formItem, index) in form">
+          <el-row :key="index">
+            <el-col :span="8">
+              <el-select
+                v-model="formItem.fieldName"
+                placeholder="请选择要筛选的字段名"
+                @change="fieldChange(formItem)">
+                <el-option
+                  v-for="item in fieldList"
+                  :key="item.fieldName"
+                  :label="item.name"
+                  :value="item.fieldName"/>
+              </el-select>
+            </el-col>
+
+            <el-col
+              v-if="formItem.formType !== 'date' && formItem.formType !== 'datetime' && formItem.formType !== 'business_type'"
+              :span="1">&nbsp;</el-col>
+            <el-col
+              v-if="formItem.formType !== 'date' && formItem.formType !== 'datetime' && formItem.formType !== 'business_type'"
+              :span="4">
+              <el-select
+                v-model="formItem.condition"
+                placeholder="请选择范围">
+                <el-option
+                  v-for="item in calConditionOptions(formItem.formType, formItem)"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value"/>
+              </el-select>
+            </el-col>
+
+            <!-- 商机组 -->
+            <el-col
+              v-if="formItem.formType === 'business_type'"
+              :span="1">&nbsp;</el-col>
+            <el-col
+              v-if="formItem.formType === 'business_type'"
+              :span="4">
+              <el-select
+                v-model="formItem.typeId"
+                placeholder="请选择"
+                @change="typeOptionsChange(formItem)">
+                <el-option
+                  v-for="item in formItem.typeOption"
+                  :key="item.typeId"
+                  :label="item.name"
+                  :value="item.typeId"/>
+              </el-select>
+            </el-col>
+
+            <el-col :span="1">&nbsp;</el-col>
+            <el-col :span="formItem.formType === 'datetime' || formItem.formType === 'date' ? 13 : 8">
+              <el-select
+                v-if="formItem.formType === 'select'"
+                v-model="formItem.value"
+                placeholder="请选择筛选条件">
+                <el-option
+                  v-for="item in formItem.setting"
+                  :key="item"
+                  :label="item"
+                  :value="item"/>
+              </el-select>
+              <el-select
+                v-else-if="formItem.formType === 'checkStatus'"
+                v-model="formItem.value"
+                placeholder="请选择筛选条件">
+                <el-option
+                  v-for="item in formItem.setting"
+                  :key="item.value"
+                  :label="item.name"
+                  :value="item.value"/>
+              </el-select>
+              <el-date-picker
+                v-else-if="formItem.formType === 'date' || formItem.formType === 'datetime'"
+                v-model="formItem.value"
+                :value-format="formItem.formType === 'date' ? 'yyyy-MM-dd' : 'yyyy-MM-dd HH:mm:ss'"
+                :type="formItem.formType === 'date' ? 'daterange' : 'datetimerange'"
+                style="padding: 0px 10px;"
+                range-separator="-"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"/>
+              <el-select
+                v-else-if="formItem.formType === 'business_type'"
+                v-model="formItem.statusId"
+                placeholder="请选择">
+                <el-option
+                  v-for="item in formItem.statusOption"
+                  :key="item.statusId"
+                  :label="item.name"
+                  :value="item.statusId"/>
+              </el-select>
+              <xh-user-cell
+                v-else-if="formItem.formType === 'user'"
+                :item="formItem"
+                :value="formItem.value"
+                @value-change="userValueChange"/>
+              <el-input
+                v-else
+                v-model="formItem.value"
+                placeholder="请输入筛选条件"/>
+            </el-col>
+            <el-col
+              :span="1"
+              class="delete">
+              <i
+                class="el-icon-error delete-btn"
+                @click="handleDelete(index)"/>
+            </el-col>
+          </el-row>
+        </template>
+      </el-form-item>
+    </el-form>
+    <p
+      v-show="showErrors"
+      class="el-icon-warning warning-info">
+      <span class="desc">筛选条件中有重复项!</span>
+    </p>
+    <el-button
+      type="text"
+      @click="handleAdd">+ 添加筛选条件</el-button>
+    <div class="save">
+      <div class="save-setting">
+        <el-checkbox v-model="saveDefault">设置为默认</el-checkbox>
+      </div>
+    </div>
+    <div
+      slot="footer"
+      class="dialog-footer">
+      <el-button @click="handleCancel">取 消</el-button>
+      <el-button
+        type="primary"
+        @click="handleConfirm">确 定</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+// import crmTypeModel from '@/views/clients/model/crmTypeModel'
+// import { crmSceneSave, crmSceneUpdate } from '@/api/clients/common'
+import {
+  objDeepCopy
+} from '@/utils'
+import { XhUserCell } from '@/components/CreateCom'
+
+/**
+ * fieldList: 高级筛选的字段
+ *     type:  date || datetime || select || 其他 input
+ */
+export default {
+  name: 'SceneCreate', // 新建场景
+  components: {
+    XhUserCell
+  },
+  props: {
+    dialogVisible: {
+      type: Boolean,
+      required: true,
+      default: false
+    },
+    fieldList: {
+      type: Array,
+      required: true,
+      default: () => {
+        return []
+      }
+    },
+    obj: {
+      type: Object,
+      default: () => {
+        return {}
+      },
+      required: true
+    },
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    /** 名字和 默认 id 编辑的时候需要 */
+    name: {
+      type: String,
+      default: ''
+    },
+    isDefault: {
+      type: Boolean,
+      default: false
+    },
+    edit_id: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      form: [],
+      visible: false, // 控制展示
+      showErrors: false,
+      saveDefault: false, // 设置为默认场景
+      saveName: null // 场景名称
+    }
+  },
+  watch: {
+    dialogVisible: {
+      handler (val) {
+        if (val) {
+          // 处理编辑数据
+          if (this.edit_id) {
+            this.form = []
+            for (const field in this.obj.obj) {
+              const element = this.obj.obj[field]
+              const item = this.getItem()
+              item.fieldName = element.name
+              item.condition = element.condition
+              item.formType = element.formType
+              if (element.formType === 'date') {
+                item.value = [element.start_date, element.end_date]
+              } else if (element.formType === 'datetime') {
+                item.value = [element.start, element.end]
+              } else if (element.formType === 'business_type') {
+                item.typeId = element.typeId
+                item.statusId = element.statusId
+                item.typeOption = element.setting
+                if (element.typeId) {
+                  const obj = element.setting.find(typeItem => {
+                    return typeItem.typeId === element.typeId
+                  })
+                  if (obj) {
+                    item.statusOption = obj.statusList
+                  } else {
+                    item.statusOption = []
+                  }
+                }
+              } else if (element.formType === 'user') {
+                item.value = element.setting ? [element.setting] : []
+              } else {
+                item.setting = element.setting
+                item.value = element.value
+              }
+              this.form.push(item)
+            }
+          } else {
+            this.form = objDeepCopy(this.obj.form)
+            if (this.form.length === 0) {
+              this.form.push(this.getItem())
+            }
+          }
+
+          /** 只有编辑会牵扯到这两个字段赋值 */
+          if (this.name) {
+            this.saveName = this.name
+          } else {
+            this.saveName = ''
+          }
+          if (this.isDefault) {
+            this.saveDefault = this.isDefault
+          } else {
+            this.saveDefault = false
+          }
+        }
+        this.visible = this.dialogVisible
+      },
+      deep: true,
+      immediate: true
+    },
+
+    form () {
+      this.$nextTick(() => {
+        var container = document.getElementById('scene-filter-container')
+        container.scrollTop = container.scrollHeight
+      })
+    }
+  },
+  methods: {
+    getItem () {
+      return {
+        fieldName: '',
+        name: '',
+        formType: '',
+        condition: 'is',
+        value: '',
+        typeOption: [],
+        statusOption: [],
+        typeId: '',
+        statusId: ''
+      }
+    },
+    /**
+     * 商机组状态
+     */
+    typeOptionsChange (formItem) {
+      if (formItem.typeId) {
+        const obj = formItem.typeOption.find(item => {
+          return item.typeId === formItem.typeId
+        })
+        formItem.statusOption = obj.statusList || []
+      } else {
+        formItem.statusOption = []
+      }
+      formItem.statusId = ''
+    },
+    /**
+     * 用户创建人
+     */
+    userValueChange (data) {
+      if (data.value.length > 0) {
+        data.item.value = data.value
+      } else {
+        data.item.value = []
+      }
+    },
+    /** 条件数据源 */
+    calConditionOptions (formType, item) {
+      if (
+        formType === 'select' ||
+        formType === 'checkbox' ||
+        formType === 'user' ||
+        formType === 'checkStatus'
+      ) {
+        return [
+          { value: 'is', label: '等于', disabled: false },
+          { value: 'isNot', label: '不等于', disabled: false }
+        ]
+      } else if (
+        formType === 'module' ||
+        formType === 'text' ||
+        formType === 'textarea'
+      ) {
+        return [
+          { value: 'is', label: '等于', disabled: false },
+          { value: 'isNot', label: '不等于', disabled: false },
+          { value: 'contains', label: '包含', disabled: false },
+          { value: 'notContains', label: '不包含', disabled: false }
+        ]
+      } else if (formType === 'floatnumber' || formType === 'number') {
+        return [
+          { value: 'is', label: '等于', disabled: false },
+          { value: 'isNot', label: '不等于', disabled: false },
+          { value: 'contains', label: '包含', disabled: false },
+          { value: 'notContains', label: '不包含', disabled: false },
+          { value: 'isNull', label: '为空', disabled: false },
+          { value: 'isNotNull', label: '不为空', disabled: false },
+          { value: 'gt', label: '大于', disabled: false },
+          { value: 'egt', label: '大于等于', disabled: false },
+          { value: 'lt', label: '小于', disabled: false },
+          { value: 'elt', label: '小于等于', disabled: false }
+        ]
+      } else {
+        return [
+          { value: 'is', label: '等于', disabled: false },
+          { value: 'isNot', label: '不等于', disabled: false },
+          { value: 'contains', label: '包含', disabled: false },
+          { value: 'notContains', label: '不包含', disabled: false },
+          { value: 'startWith', label: '开始于', disabled: false },
+          { value: 'endWith', label: '结束于', disabled: false },
+          { value: 'isNull', label: '为空', disabled: false },
+          { value: 'isNotNull', label: '不为空', disabled: false },
+          { value: 'gt', label: '大于', disabled: false },
+          { value: 'egt', label: '大于等于', disabled: false },
+          { value: 'lt', label: '小于', disabled: false },
+          { value: 'elt', label: '小于等于', disabled: false }
+        ]
+      }
+    },
+    /**
+     * 当前选择的字段名改变,判断是否有重复
+     * @param formItem
+     */
+    fieldChange (formItem) {
+      const obj = this.fieldList.find(item => {
+        return item.fieldName === formItem.fieldName
+      })
+      if (obj) {
+        formItem.formType = obj.formType
+        formItem.name = obj.name
+        if (formItem.formType === 'business_type') {
+          formItem.typeOption = obj.setting
+          formItem.statusOption = []
+          formItem.typeId = ''
+          formItem.statusId = ''
+        } else if (
+          formItem.formType === 'select' ||
+          formItem.formType === 'checkStatus'
+        ) {
+          formItem.setting = obj.setting || []
+        } else if (
+          formItem.formType === 'date' ||
+          formItem.formType === 'datetime' ||
+          formItem.formType === 'user'
+        ) {
+          formItem.value = []
+        }
+      }
+
+      const arr = this.form.filter(item => {
+        return item.fieldName === formItem.fieldName
+      })
+      if (arr.length > 1) this.showErrors = true
+      else this.showErrors = false
+    },
+    /**
+     * 取消选择
+     */
+    handleCancel () {
+      this.visible = false
+      this.$emit('update:dialogVisible', false)
+    },
+    /**
+     * 确定选择
+     */
+    handleConfirm () {
+      if (this.showErrors) {
+        this.$message.error('筛选条件中有重复项!')
+        return
+      }
+      if (!this.saveName || this.saveName === '') {
+        this.$message.error('场景名称不能为空!')
+        return
+      }
+      for (let i = 0; i < this.form.length; i++) {
+        const o = this.form[i]
+        if (!o.fieldName || o.fieldName === '') {
+          this.$message.error('要筛选的字段名称不能为空!')
+          return
+        }
+
+        if (o.formType === 'business_type') {
+          if (!o.typeId && !o.statusId) {
+            this.$message.error('请输入筛选条件的值!')
+            return
+          }
+        } else if (
+          o.formType === 'date' ||
+          o.formType === 'datetime' ||
+          o.formType === 'user'
+        ) {
+          if (!o.value || o.value.length === 0) {
+            this.$message.error('请输入筛选条件的值!')
+            return
+          }
+        } else if (!o.value) {
+          this.$message.error('请输入筛选条件的值!')
+          return
+        }
+      }
+      const obj = {}
+      this.form.forEach(o => {
+        if (o.formType === 'datetime' || o.formType === 'date') {
+          obj[o.fieldName] = {
+            start: o.value[0],
+            end: o.value[1],
+            formType: o.formType,
+            name: o.fieldName
+          }
+        } else if (o.formType === 'business_type') {
+          obj[o.fieldName] = {
+            typeId: o.typeId,
+            statusId: o.statusId,
+            formType: o.formType,
+            name: o.fieldName
+          }
+        } else if (o.formType === 'user') {
+          obj[o.fieldName] = {
+            condition: o.condition,
+            value: o.value[0].userId,
+            formType: o.formType,
+            setting: o.value[0],
+            name: o.fieldName
+          }
+        } else {
+          obj[o.fieldName] = {
+            condition: o.condition,
+            value: o.value,
+            formType: o.formType,
+            name: o.fieldName
+          }
+        }
+      })
+      const data = {
+        obj: obj,
+        form: this.form,
+        saveDefault: this.saveDefault,
+        saveName: this.saveName
+      }
+      this.requestCreateScene(data)
+    },
+    // 创建场景
+    requestCreateScene (data) {
+      /** 编辑操作 */
+      if (this.edit_id) {
+        // crmSceneUpdate({
+        //   isDefault: data.saveDefault ? 1 : 0,
+        //   name: data.saveName,
+        //   sceneId: this.edit_id,
+        //   data: JSON.stringify(data.obj)
+        // })
+        //   .then(res => {
+        //     this.$message({
+        //       type: 'success',
+        //       message: '编辑成功'
+        //     })
+        //     // 新建成功
+        //     this.$emit('saveSuccess')
+        //     this.handleCancel()
+        //   })
+        //   .catch(() => {})
+      } else {
+        // crmSceneSave({
+        //   type: crmTypeModel[this.crmType],
+        //   isDefault: data.saveDefault ? 1 : 0,
+        //   name: data.saveName,
+        //   data: JSON.stringify(data.obj)
+        // })
+        //   .then(res => {
+        //     this.$message({
+        //       type: 'success',
+        //       message: '创建成功'
+        //     })
+        //     // 新建成功
+        //     this.$emit('saveSuccess')
+        //     this.handleCancel()
+        //   })
+        //   .catch(() => {})
+      }
+    },
+    /**
+     * 添加筛选条件
+     */
+    handleAdd () {
+      this.form.push(this.getItem())
+    },
+    /**
+     * 删除筛选条件
+     * @param index
+     */
+    handleDelete (index) {
+      this.$confirm('您确定要删除这一条数据吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          this.form.splice(index, 1)
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+/deep/ .el-dialog__body {
+  padding: 10px 20px;
+}
+
+/deep/ .el-form-item__label {
+  width: 100%;
+  text-align: left;
+}
+.filter-container {
+  max-height: 200px;
+  overflow-y: auto;
+}
+
+.save {
+  margin-top: 10px;
+  .name {
+    width: 300px;
+    margin-left: 10px;
+    /deep/ .el-input__inner {
+      height: 32px;
+    }
+  }
+  .save-setting {
+    margin-top: 20px;
+  }
+}
+
+.el-form-item {
+  margin-bottom: 0;
+}
+
+.el-row {
+  margin-bottom: 20px;
+  .delete-btn {
+    margin-left: 15px;
+    color: #bbb;
+    cursor: pointer;
+  }
+  .el-select,
+  .el-date-editor {
+    width: 100%;
+  }
+}
+
+.warning-info {
+  width: 100%;
+  font-size: 14px;
+  color: #f56c6c;
+  margin-top: 10px;
+  .desc {
+    padding-left: 8px;
+  }
+}
+
+.scene-name-container {
+  padding-bottom: 15px;
+  .scene-input {
+    width: 300px;
+  }
+}
+.scene-name {
+  margin-bottom: 10px;
+}
+</style>
diff --git a/src/views/clients/components/sceneForm/SceneList.vue b/src/views/clients/components/sceneForm/SceneList.vue
new file mode 100644
index 0000000..5ff4f6b
--- /dev/null
+++ b/src/views/clients/components/sceneForm/SceneList.vue
@@ -0,0 +1,160 @@
+<template>
+  <div class="scene-container">
+    <div class="scene-list">
+      <div
+        v-for="(item, index) in sceneList"
+        :key="index"
+        :class="{'scene-list-item-select':item.sceneId === sceneSelectId}"
+        class="scene-list-item"
+        @click="selectScene(item, index)">
+        {{ item.name }}
+      </div>
+    </div>
+    <div>
+      <flexbox
+        class="handle-button"
+        @click.native="addScene">
+        <img
+          class="handle-button-icon"
+          src="@/assets/img/scene_add.png" >
+        <div class="handle-button-name">新建场景</div>
+      </flexbox>
+      <flexbox
+        class="handle-button"
+        @click.native="setScene">
+        <img
+          class="handle-button-icon"
+          src="@/assets/img/scene_set.png" >
+        <div class="handle-button-name">管理</div>
+      </flexbox>
+    </div>
+
+  </div>
+</template>
+
+<script type="text/javascript">
+// import crmTypeModel from '@/views/clients/model/crmTypeModel'
+import { mapGetters } from 'vuex'
+// import { crmSceneIndex } from '@/api/clients/common'
+
+export default {
+  name: 'SceneList', // 客户管理下 重要提醒 回款计划提醒
+  components: {},
+  props: {
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      // 场景列表
+      sceneSelectId: -1,
+      sceneList: []
+    }
+  },
+  computed: {
+    ...mapGetters(['crm'])
+  },
+  watch: {},
+  mounted () {
+    if (this.crm[this.crmType].index) {
+      this.getSceneList()
+    }
+  },
+  methods: {
+    getSceneList () {
+      // crmSceneIndex({
+      //   type: crmTypeModel[this.crmType]
+      // })
+      //   .then(res => {
+      //     const defaultScenes = res.data.filter(function (item, index) {
+      //       return item.isDefault === 1
+      //     })
+
+      //     if (defaultScenes && defaultScenes.length > 0) {
+      //       const defaultScene = defaultScenes[0]
+      //       this.sceneSelectId = defaultScene.sceneId
+      //       this.$emit('scene', {
+      //         id: defaultScene.sceneId,
+      //         name: defaultScene.name,
+      //         bydata: defaultScene.bydata || ''
+      //       })
+      //     } else {
+      //       this.sceneSelectId = ''
+      //       this.$emit('scene', { id: '', name: '', bydata: '' })
+      //     }
+
+      //     this.sceneList = res.data
+      //   })
+      //   .catch(() => {
+      //     this.$emit('scene', { id: '', name: '', bydata: '' })
+      //   })
+    },
+
+    // 选择场景、
+    selectScene (item, index) {
+      this.sceneSelectId = item.sceneId
+      this.$emit('scene', {
+        id: item.sceneId,
+        name: item.name,
+        bydata: item.bydata
+      })
+      this.$emit('hidden-scene')
+    },
+    // 添加场景
+    addScene () {
+      this.$emit('scene-handle', { type: 'add' })
+    },
+    // 设置场景
+    setScene () {
+      this.$emit('scene-handle', { type: 'set' })
+    }
+  }
+}
+</script>
+<style rel="stylesheet/less" lang="less" scoped>
+.scene-container {
+  position: relative;
+  width: 150px;
+}
+
+.scene-list {
+  max-height: 240px;
+  overflow-y: auto;
+  font-size: 12px;
+  .scene-list-item {
+    color: #333;
+    padding: 10px 15px;
+    cursor: pointer;
+    background-color: white;
+  }
+  .scene-list-item:hover {
+    background-color: #f7f8fa;
+    // color: #4D88FF;//
+  }
+
+  .scene-list-item-select {
+    // color: #4D88FF;//
+    background-color: #f7f8fa;
+  }
+}
+
+.handle-button {
+  padding: 10px 20px;
+  cursor: pointer;
+  .handle-button-icon {
+    display: block;
+    width: 15px;
+    height: 15px;
+    margin-right: 8px;
+  }
+  .handle-button-name {
+    font-size: 12px;
+  }
+}
+.handle-button:hover {
+  // color: #4D88FF;//
+}
+</style>
diff --git a/src/views/clients/components/sceneForm/SceneSet.vue b/src/views/clients/components/sceneForm/SceneSet.vue
new file mode 100644
index 0000000..10d40d6
--- /dev/null
+++ b/src/views/clients/components/sceneForm/SceneSet.vue
@@ -0,0 +1,648 @@
+<template>
+  <el-dialog
+    :visible.sync="visible"
+    :append-to-body="true"
+    title="场景管理"
+    width="700px"
+    @close="handleCancel">
+    <div class="scene-name">您可通过拖拽管理标签</div>
+    <flexbox class="scene-list">
+      <div class="scene-list-box">
+        <flexbox class="scene-list-head">
+          <el-checkbox
+            :indeterminate="isleftIndeterminate"
+            v-model="checkleftAll"
+            @change="handleleftCheckAllChange"/>
+          <div class="scene-list-head-name">显示的标签</div>
+          <div class="scene-list-head-detail">{{ leftCheckItems.length + '/' + checkedLeftData.length }}</div>
+        </flexbox>
+        <div class="scene-list-body">
+          <flexbox
+            v-for="(item, index) in checkedLeftData"
+            v-if="item.isSystem === 1"
+            :key="index"
+            class="list-item">
+            <div
+              :class="{'default-mark-active': item.sceneId === defaultId}"
+              class="default-mark"/>
+            <el-checkbox
+              v-model="item.check"
+              :disabled="true"
+              class="list-item-check"
+              @change="leftCheckItemChange"/>
+            <div class="list-item-name">{{ item.name }}</div>
+            <div class="list-item-handle">
+              <el-dropdown
+                trigger="click"
+                @command="defaultHandle">
+                <i
+                  class="el-icon-arrow-down"
+                  @click="itemHandle('default', item, index)"/>
+                <el-dropdown-menu slot="dropdown">
+                  <el-dropdown-item>设置为默认标签</el-dropdown-item>
+                </el-dropdown-menu>
+              </el-dropdown>
+            </div>
+          </flexbox>
+          <draggable
+            v-model="checkedLeftData"
+            :move="leftMove"
+            :options="{group: 'list',forceFallback:false, fallbackClass:'draggingStyle'}"
+            style="min-height: 100px;"
+            @end="leftMoveEnd">
+            <flexbox
+              v-for="(item, index) in checkedLeftData"
+              v-if="item.isSystem !== 1"
+              :key="index"
+              class="list-item">
+              <div
+                :class="{'default-mark-active': item.sceneId === defaultId}"
+                class="default-mark"/>
+              <el-checkbox
+                v-model="item.check"
+                class="list-item-check"
+                @change="leftCheckItemChange"/>
+              <div class="list-item-name">{{ item.name }}</div>
+              <div class="list-item-handle">
+                <i
+                  class="el-icon-edit"
+                  @click="itemHandle('edit', item, index)"/>
+                <i
+                  class="el-icon-delete"
+                  @click="itemHandle('delete', item, index)"/>
+                <el-dropdown @command="defaultHandle">
+                  <i
+                    class="el-icon-arrow-down"
+                    @click="itemHandle('default', item, index)"/>
+                  <el-dropdown-menu slot="dropdown">
+                    <el-dropdown-item>设置为默认标签</el-dropdown-item>
+                  </el-dropdown-menu>
+                </el-dropdown>
+              </div>
+            </flexbox>
+          </draggable>
+
+        </div>
+      </div>
+      <div class="scene-middle-list">
+        <el-button
+          :class="{'scene-middle-button-select':rightCheckItems.length > 0}"
+          :disabled="rightCheckItems.length === 0"
+          class="scene-middle-left-button"
+          @click="changePositon('left')">
+          <i class="el-icon-arrow-left scene-middle-icon"/>
+        </el-button>
+        <el-button
+          :class="{'scene-middle-button-select':leftCheckItems.length > 0}"
+          :disabled="leftCheckItems.length === 0"
+          class="scene-middle-right-button"
+          @click="changePositon('right')">
+          <i class="el-icon-arrow-right scene-middle-icon"/>
+        </el-button>
+      </div>
+      <div class="scene-list-box">
+        <flexbox class="scene-list-head">
+          <el-checkbox
+            :indeterminate="isrightIndeterminate"
+            v-model="checkrightAll"
+            @change="handlerightCheckAllChange"/>
+          <div class="scene-list-head-name">隐藏的标签</div>
+          <div class="scene-list-head-detail">{{ rightCheckItems.length + '/' + checkedRightData.length }}</div>
+        </flexbox>
+        <div class="scene-list-body">
+          <draggable
+            v-model="checkedRightData"
+            :move="rightMove"
+            :options="{group: 'list',forceFallback:false, fallbackClass:'draggingStyle'}"
+            style="min-height: 100px;"
+            @end="rightMoveEnd">
+            <flexbox
+              v-for="(item, index) in checkedRightData"
+              :key="index"
+              class="list-item">
+              <el-checkbox
+                v-model="item.check"
+                style="margin-left:9px;"
+                class="list-item-check"
+                @change="rightCheckItemChange"/>
+              <div class="list-item-name">{{ item.name }}</div>
+            </flexbox>
+          </draggable>
+        </div>
+      </div>
+    </flexbox>
+    <div class="handle-bar">
+      <div
+        class="handle-bar-add"
+        @click="addAndEditScene('add',{})">+ 新建场景</div>
+      <div class="handle-bar-save">
+        <el-button @click.native="handleCancel">取消</el-button>
+        <el-button
+          type="primary"
+          @click.native="handleConfirm">保存</el-button>
+      </div>
+    </div>
+    <scene-create
+      :field-list="fieldList"
+      :crm-type="crmType"
+      :dialog-visible.sync="showCreateScene"
+      :obj="filterObj"
+      :name="filterName"
+      :edit_id="filterEditId"
+      :is-default="filterDefault"
+      @saveSuccess="getSceneList"/>
+  </el-dialog>
+</template>
+
+<script type="text/javascript">
+// import crmTypeModel from '@/views/clients/model/crmTypeModel'
+// import {
+//   crmSceneSetIndex,
+//   crmSceneSort,
+//   crmSceneDefaults,
+//   crmSceneDelete,
+//   filterIndexfields
+// } from '@/api/clients/common'
+import draggable from 'vuedraggable'
+import SceneCreate from './SceneCreate' // 新建编辑场景
+
+export default {
+  name: 'SceneSet', // 场景 设置
+  components: {
+    draggable,
+    SceneCreate
+  },
+  props: {
+    dialogVisible: {
+      type: Boolean,
+      required: true,
+      default: false
+    },
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      defaultId: '', // 默认场景id
+      visible: false, // 控制展示
+      isleftIndeterminate: false, // 标注头部是多选框效果
+      checkleftAll: false, // 关联全选操作多选框
+
+      checkedLeftData: [], // 数据源
+      leftCheckItems: [], // 选择的数据源
+
+      isrightIndeterminate: false,
+      checkrightAll: false,
+
+      checkedRightData: [],
+      rightCheckItems: [],
+
+      moveItem: {}, // 移动中的item
+      handlDefaultItem: {}, // 设置默认的中间item
+
+      /** 添加 编辑 场景 */
+      showCreateScene: false, // 展示场景添加
+      fieldList: [],
+      filterObj: { form: [] }, // 筛选确定数据
+      filterName: '',
+      filterDefault: false,
+      filterEditId: '' // 编辑id
+    }
+  },
+  computed: {},
+  watch: {
+    dialogVisible: {
+      handler (val) {
+        this.visible = val
+        if (val) {
+          this.getSceneList()
+        }
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+  mounted () {},
+  methods: {
+    getSceneList () {
+      // crmSceneSetIndex({
+      //   type: crmTypeModel[this.crmType]
+      // })
+      //   .then(res => {
+      //     this.checkedLeftData = res.data.value.map(function (item, index) {
+      //       item.check = false
+      //       return item
+      //     })
+      //     this.checkedRightData = res.data.hide_value.map(function (
+      //       item,
+      //       index
+      //     ) {
+      //       item.check = false
+      //       return item
+      //     })
+      //     var defaultScene = this.checkedLeftData.filter(function (item, index) {
+      //       return item.isDefault === 1
+      //     })
+      //     // 如果有默认场景
+      //     if (defaultScene && defaultScene.length > 0) {
+      //       this.defaultId = defaultScene[0].sceneId
+      //     } else {
+      //       this.defaultId = ''
+      //     }
+      //   })
+      //   .catch(() => {})
+    },
+    /**
+     * 确定选择
+     */
+    handleConfirm () {
+      // 如果选择默认的 不包含在左侧列表 重置为没有默认
+      var self = this
+      var leftTemps = this.checkedLeftData.filter(function (item, index) {
+        return item.sceneId === self.defaultId
+      })
+      if (leftTemps.length === 0) {
+        this.defaultId = ''
+      }
+      // crmSceneSort({
+      //   type: crmTypeModel[this.crmType],
+      //   noHideIds: this.checkedLeftData
+      //     .map(function (item, index, array) {
+      //       return item.sceneId
+      //     })
+      //     .join(','),
+      //   hideIds: this.checkedRightData
+      //     .map(function (item, index, array) {
+      //       return item.sceneId
+      //     })
+      //     .join(',')
+      // })
+      //   .then(res => {
+      //     this.$message({
+      //       type: 'success',
+      //       message: '操作成功'
+      //     })
+      //     this.handleCancel()
+      //     this.$emit('save-success')
+      //   })
+      //   .catch(() => {})
+    },
+    /** 事项操作 */
+    itemHandle (type, item, index) {
+      if (type === 'edit') {
+        this.addAndEditScene('edit', item)
+      } else if (type === 'delete') {
+        this.$confirm('您确定要删除这一条数据吗?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+          .then(() => {
+            // crmSceneDelete({
+            //   sceneId: item.sceneId
+            // })
+            //   .then(res => {
+            //     this.$message({
+            //       type: 'success',
+            //       message: '删除成功'
+            //     })
+            //     this.checkedLeftData.splice(index, 1)
+            //     this.leftCheckItemChange()
+            //     this.$emit('save-success')
+            //   })
+            //   .catch(() => {})
+          })
+          .catch(() => {
+            this.$message({
+              type: 'info',
+              message: '已取消删除'
+            })
+          })
+      } else if (type === 'default') {
+        this.handlDefaultItem = item
+      }
+    },
+    /** 操作默认 */
+    defaultHandle () {
+      // crmSceneDefaults({
+      //   sceneId: this.handlDefaultItem.sceneId
+      // })
+      //   .then(res => {
+      //     this.$message({
+      //       type: 'success',
+      //       message: '操作成功'
+      //     })
+      //     this.defaultId = this.handlDefaultItem.sceneId
+      //   })
+      //   .catch(() => {})
+    },
+    /** 添加编辑场景 */
+    addAndEditScene (type, data) {
+      // filterIndexfields({
+      //   label: crmTypeModel[this.crmType]
+      // })
+      //   .then(res => {
+      //     this.fieldList = res.data
+      //     if (type === 'edit') {
+      //       this.filterObj = { form: [], obj: data.data }
+      //       this.filterName = data.name
+      //       this.filterDefault = data.isDefault === 1
+      //       this.filterEditId = data.sceneId.toString()
+      //     } else {
+      //       this.filterObj = { form: [] }
+      //       this.filterEditId = ''
+      //       this.filterName = ''
+      //       this.filterDefault = false
+      //     }
+      //     this.showCreateScene = true
+      //   })
+      //   .catch(() => {})
+    },
+    /**
+     * 取消选择
+     */
+    handleCancel () {
+      this.visible = false
+      this.$emit('update:dialogVisible', false)
+    },
+    /** 拖拽操作 */
+    rightMoveEnd (evt) {
+      this.moveItem.check = false
+      this.leftCheckItemChange()
+      this.rightCheckItemChange()
+    },
+    rightMove (obj) {
+      this.moveItem = obj.draggedContext.element
+    },
+    leftMoveEnd (evt) {
+      this.moveItem.check = false
+      this.leftCheckItemChange()
+      this.rightCheckItemChange()
+    },
+    leftMove (obj) {
+      this.moveItem = obj.draggedContext.element
+    },
+    // 选择全部
+    handleleftCheckAllChange (value) {
+      if (value) {
+        this.isleftIndeterminate = false
+      }
+      this.checkedLeftData = this.checkedLeftData.filter(function (
+        item,
+        index,
+        array
+      ) {
+        item.check = value
+        return item
+      })
+      this.leftCheckItems = value ? this.checkedLeftData : []
+    },
+    leftCheckItemChange () {
+      this.leftCheckItems = this.checkedLeftData.filter(function (
+        item,
+        index,
+        array
+      ) {
+        return item.check === true
+      })
+      if (this.leftCheckItems.length > 0) {
+        if (this.leftCheckItems.length === this.checkedLeftData.length) {
+          this.checkleftAll = true
+          this.isleftIndeterminate = false
+        } else {
+          this.checkleftAll = false
+          this.isleftIndeterminate = true
+        }
+      } else {
+        this.checkleftAll = false
+        this.isleftIndeterminate = false
+      }
+    },
+    // 选择全部
+    handlerightCheckAllChange (value) {
+      if (value) {
+        this.isrightIndeterminate = false
+      }
+      this.checkedRightData = this.checkedRightData.filter(function (
+        item,
+        index,
+        array
+      ) {
+        item.check = value
+        return item
+      })
+      this.rightCheckItems = value ? this.checkedRightData : []
+    },
+    rightCheckItemChange () {
+      this.rightCheckItems = this.checkedRightData.filter(function (
+        item,
+        index,
+        array
+      ) {
+        return item.check === true
+      })
+      if (this.rightCheckItems.length > 0) {
+        if (this.rightCheckItems.length === this.checkedRightData.length) {
+          this.checkrightAll = true
+          this.isrightIndeterminate = false
+        } else {
+          this.checkrightAll = false
+          this.isrightIndeterminate = true
+        }
+      } else {
+        this.checkrightAll = false
+        this.isrightIndeterminate = false
+      }
+    },
+    // 按钮操作
+    changePositon (type) {
+      var self = this
+      // 从右往左
+      if (type === 'left') {
+        this.checkedRightData = this.checkedRightData.filter(function (
+          item,
+          index,
+          array
+        ) {
+          var remove = false
+          self.rightCheckItems.forEach(function (element, index) {
+            if (item.sceneId === element.sceneId) {
+              remove = true
+            }
+          })
+          return !remove
+        })
+
+        this.rightCheckItems.forEach(function (element, index) {
+          element.check = false
+          self.checkedLeftData.push(element)
+        })
+
+        this.rightCheckItems = []
+        this.isrightIndeterminate = false
+        this.checkrightAll = false
+
+        // 刷新左侧效果
+        this.leftCheckItemChange()
+        this.rightCheckItemChange()
+      } else {
+        this.checkedLeftData = this.checkedLeftData.filter(function (
+          item,
+          index,
+          array
+        ) {
+          var remove = false
+          self.leftCheckItems.forEach(function (element, index) {
+            if (item.sceneId === element.sceneId) {
+              remove = true
+            }
+          })
+          return !remove
+        })
+
+        this.leftCheckItems.forEach(function (element, index) {
+          element.check = false
+          self.checkedRightData.push(element)
+        })
+
+        this.leftCheckItems = []
+        this.isleftIndeterminate = false
+        this.checkleftAll = false
+
+        // 刷新右侧效果
+        this.leftCheckItemChange()
+        this.rightCheckItemChange()
+      }
+    }
+  }
+}
+</script>
+<style rel="stylesheet/less" lang="less" scoped>
+.scene-name {
+  font-size: 12px;
+  padding-bottom: 5px;
+  color: #aaa;
+}
+
+.default-mark {
+  width: 4px;
+  height: 4px;
+  border-radius: 2px;
+  margin-right: 5px;
+}
+.default-mark-active {
+  // background-color: #4D88FF;
+}
+
+.scene-list {
+  .scene-list-box {
+    flex: 1;
+    border: 1px solid #e6e6e6;
+    border-radius: 2px;
+    height: 300px;
+    position: relative;
+    padding: 15px;
+  }
+  .scene-middle-list {
+    width: 50px;
+    text-align: center;
+    button {
+      border: 1px solid #cccccc;
+      width: 34px;
+      height: 34px;
+      border-radius: 17px;
+      background-color: #f5f7fa;
+    }
+    .scene-middle-icon {
+      color: #cccccc;
+      font-size: 14px;
+    }
+    .scene-middle-left-button {
+    }
+    .scene-middle-right-button {
+      margin-top: 15px;
+      margin-left: 0;
+    }
+
+    .scene-middle-button-select {
+      border: 1px solid #4D88FF !important;
+      background-color: #4D88FF !important;
+      .scene-middle-icon {
+        color: white !important;
+      }
+    }
+  }
+  .scene-list-head {
+    padding-bottom: 15px;
+    padding-left: 9px;
+    border-bottom: 1px dashed #e6e6e6;
+    font-size: 13px;
+    .scene-list-head-name {
+      color: #333;
+      flex: 1;
+      margin: 0 8px;
+    }
+
+    .scene-list-head-detail {
+      color: #aaa;
+    }
+  }
+  .scene-list-body {
+    padding: 5px 0;
+    height: 240px;
+    position: relative;
+    overflow-y: auto;
+  }
+
+  .list-item {
+    padding: 5px 0;
+    cursor: pointer;
+    .list-item-check {
+      margin-right: 8px;
+    }
+    .list-item-name {
+      font-size: 13px;
+      color: #333;
+      flex: 1;
+    }
+    .list-item-handle {
+      flex-shrink: 0;
+      display: none;
+      i {
+        color: #aaa;
+        font-size: 12px;
+        margin-right: 5px;
+      }
+      i:hover {
+        color: #4D88FF;
+      }
+    }
+  }
+
+  .list-item:hover {
+    .list-item-handle {
+      display: block;
+    }
+  }
+}
+
+.handle-bar {
+  font-size: 12px;
+  .handle-bar-add {
+    cursor: pointer;
+    color: #4D88FF;
+    padding: 20px 10px;
+  }
+  .handle-bar-save {
+    position: relative;
+    height: 30px;
+    button {
+      float: right;
+      margin-right: 10px;
+    }
+  }
+}
+</style>
diff --git a/src/views/clients/components/selectionHandle/AllocHandle.vue b/src/views/clients/components/selectionHandle/AllocHandle.vue
new file mode 100644
index 0000000..f336db9
--- /dev/null
+++ b/src/views/clients/components/selectionHandle/AllocHandle.vue
@@ -0,0 +1,154 @@
+<template>
+  <el-dialog
+    v-loading="loading"
+    :visible.sync="visible"
+    :append-to-body="true"
+    title="批量分配"
+    width="400px"
+    @close="handleCancel">
+    <div class="handle-box">
+      <flexbox
+        class="handle-item"
+        align="stretch">
+        <div
+          class="handle-item-name"
+          style="margin-top: 8px;">请选择:</div>
+        <xh-user-cell
+          class="handle-item-content"
+          placeholder="点击选择"
+          @value-change="userChage"/>
+      </flexbox>
+    </div>
+    <span
+      slot="footer"
+      class="dialog-footer">
+      <el-button @click.native="handleCancel">取消</el-button>
+      <el-button
+        type="primary"
+        @click.native="handleConfirm">保存</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+import { XhUserCell } from '@/components/CreateCom'
+// import { crmCustomerDistribute } from '@/api/customermanagement/customerManage'
+
+export default {
+  /** 客户管理 的 勾选后的 公海分配 操作 */
+  name: 'AllocHandle',
+  components: {
+    XhUserCell
+  },
+  mixins: [],
+  props: {
+    dialogVisible: {
+      type: Boolean,
+      required: true,
+      default: false
+    },
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    /** 转移数据 */
+    selectionList: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    }
+  },
+  data () {
+    return {
+      loading: true,
+      visible: false,
+      usersList: []
+    }
+  },
+  computed: {},
+  watch: {
+    dialogVisible: {
+      handler (val) {
+        this.visible = val
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+  mounted () {
+    this.visible = this.dialogVisible
+  },
+  methods: {
+    /**
+     * 取消选择
+     */
+    handleCancel () {
+      this.visible = false
+      this.$emit('update:dialogVisible', false)
+    },
+    /** 负责人更改 */
+    userChage (data) {
+      this.usersList = data.value
+    },
+    handleConfirm () {
+      // 移除操作不可移除客户负责人
+      if (this.usersList.length === 0) {
+        this.$message.error('请选择负责人')
+      } else {
+        var self = this
+        var actionIds = this.selectionList.map(function (item, index, array) {
+          return item[self.crmType + 'Id']
+        })
+        var params = {
+          userId: this.usersList[0].userId
+        }
+        params.ids = actionIds.join(',')
+        this.loading = true
+        // crmCustomerDistribute(params)
+        //   .then(res => {
+        //     this.$message({
+        //       type: 'success',
+        //       message: '操作成功'
+        //     })
+        //     this.loading = false
+        //     this.$emit('handle', {
+        //       type: 'alloc'
+        //     })
+        //     this.handleCancel()
+        //   })
+        //   .catch(() => {
+        //     this.loading = false
+        //   })
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.handle-box {
+  color: #333;
+  font-size: 12px;
+}
+.handle-item {
+  padding-bottom: 15px;
+  .handle-item-name {
+    flex-shrink: 0;
+    width: 90px;
+  }
+  .handle-item-content {
+    flex: 1;
+  }
+}
+.handle-bar {
+  position: relative;
+  margin-top: 10px;
+  height: 30px;
+  button {
+    float: right;
+    margin-right: 10px;
+  }
+}
+</style>
diff --git a/src/views/clients/components/selectionHandle/DealStatusHandle.vue b/src/views/clients/components/selectionHandle/DealStatusHandle.vue
new file mode 100644
index 0000000..90ed902
--- /dev/null
+++ b/src/views/clients/components/selectionHandle/DealStatusHandle.vue
@@ -0,0 +1,150 @@
+<template>
+  <el-dialog
+    v-loading="loading"
+    :visible="visible"
+    :append-to-body="true"
+    title="客户成交状态"
+    width="400px"
+    @close="handleCancel">
+    <div class="handle-box">
+      <flexbox
+        class="handle-item"
+        align="stretch">
+        <div
+          class="handle-item-name"
+          style="margin-top: 8px;">成交状态:</div>
+        <el-select
+          v-model="status"
+          class="handle-item-content"
+          placeholder="请选择">
+          <el-option
+            v-for="item in options"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"/>
+        </el-select>
+      </flexbox>
+    </div>
+    <span
+      slot="footer"
+      class="dialog-footer">
+      <el-button @click.native="handleCancel">取消</el-button>
+      <el-button
+        type="primary"
+        @click.native="handleConfirm">保存</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+// import { crmCustomerDealStatusAPI } from '@/api/customermanagement/customerManage'
+
+export default {
+  /** 客户管理  成交状态 操作 */
+  name: 'DealStatusHandle',
+  components: {},
+  mixins: [],
+  props: {
+    visible: {
+      type: Boolean,
+      required: true,
+      default: false
+    },
+    crmType: {
+      type: String,
+      default: ''
+    },
+    // 勾选数据
+    selectionList: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    }
+  },
+  data () {
+    return {
+      loading: true,
+      status: 1,
+      options: [
+        {
+          label: '已成交',
+          value: 1
+        },
+        {
+          label: '未成交',
+          value: 0
+        }
+      ]
+    }
+  },
+  computed: {},
+  watch: {},
+  mounted () {},
+  methods: {
+    /**
+     * 取消选择
+     */
+    handleCancel () {
+      this.status = 1
+      this.$emit('update:visible', false)
+    },
+
+    /**
+     * 点击确定
+     */
+    handleConfirm () {
+      var self = this
+      var actionIds = this.selectionList.map(function (item, index, array) {
+        return item[self.crmType + 'Id']
+      }).join(',')
+      var params = {
+        dealStatus: this.status
+      }
+      params.ids = actionIds
+      this.loading = true
+      // crmCustomerDealStatusAPI(params)
+      //   .then(res => {
+      //     this.$message({
+      //       type: 'success',
+      //       message: '操作成功'
+      //     })
+      //     this.loading = false
+      //     this.$emit('handle', {
+      //       type: 'deal_status'
+      //     })
+      //     this.handleCancel()
+      //   })
+      //   .catch(() => {
+      //     this.loading = false
+      //   })
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.handle-box {
+  color: #333;
+  font-size: 12px;
+}
+.handle-item {
+  padding-bottom: 15px;
+  .handle-item-name {
+    flex-shrink: 0;
+    width: 90px;
+  }
+  .handle-item-content {
+    flex: 1;
+  }
+}
+.handle-bar {
+  position: relative;
+  margin-top: 10px;
+  height: 30px;
+  button {
+    float: right;
+    margin-right: 10px;
+  }
+}
+</style>
diff --git a/src/views/clients/components/selectionHandle/TeamsHandle.vue b/src/views/clients/components/selectionHandle/TeamsHandle.vue
new file mode 100644
index 0000000..cefc3fa
--- /dev/null
+++ b/src/views/clients/components/selectionHandle/TeamsHandle.vue
@@ -0,0 +1,230 @@
+<template>
+  <el-dialog
+    v-loading="loading"
+    :title="title"
+    :visible.sync="visible"
+    :append-to-body="true"
+    width="400px"
+    @close="handleCancel">
+    <div class="handle-box">
+      <flexbox
+        class="handle-item"
+        align="stretch">
+        <div
+          class="handle-item-name"
+          style="margin-top: 8px;">选择团队成员:</div>
+        <xh-user-cell
+          :radio="false"
+          class="handle-item-content"
+          placeholder="点击选择(多选)"
+          @value-change="userChage"/>
+        <div
+          v-if="title!='添加团队成员'"
+          class="tips">此操作不可移除数据负责人</div>
+      </flexbox>
+      <flexbox
+        v-if="title=='添加团队成员'"
+        class="handle-item">
+        <div class="handle-item-name">权限:</div>
+        <el-radio-group v-model="handleType">
+          <el-radio :label="1">只读</el-radio>
+          <el-radio :label="2">读写</el-radio>
+        </el-radio-group>
+      </flexbox>
+      <flexbox
+        v-if="title=='添加团队成员' && crmType === 'customer'"
+        class="handle-item">
+        <div class="handle-item-name">同时添加至:</div>
+        <el-checkbox-group v-model="addsTypes">
+          <!-- <el-checkbox label="1">联系人</el-checkbox> -->
+          <el-checkbox label="2">商机</el-checkbox>
+          <el-checkbox label="3">合同</el-checkbox>
+        </el-checkbox-group>
+      </flexbox>
+    </div>
+    <span
+      slot="footer"
+      class="dialog-footer">
+      <el-button @click.native="handleCancel">取消</el-button>
+      <el-button
+        type="primary"
+        @click.native="handleConfirm">保存</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+import { XhUserCell } from '@/components/CreateCom'
+// import {
+//   crmCustomerSettingTeamSave,
+//   crmCustomerSettingTeamDelete
+// } from '@/api/customermanagement/customerManage'
+// import {
+//   crmContractSettingTeamSave,
+//   crmContractSettingTeamDelete
+// } from '@/api/clients/contract'
+
+// import {
+//   crmBusinessSettingTeamSave,
+//   crmBusinessSettingTeamDelete
+// } from '@/api/clients/business'
+
+export default {
+  /** 客户管理 的 勾选后的 团队成员 操作 移除操作不可移除客户负责人 */
+  name: 'TeamsHandle',
+  components: {
+    XhUserCell
+  },
+  mixins: [],
+  props: {
+    dialogVisible: {
+      type: Boolean,
+      required: true,
+      default: false
+    },
+    title: {
+      type: String,
+      default: ''
+    },
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    /** 转移数据 */
+    selectionList: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    }
+  },
+  data () {
+    return {
+      loading: false, // 加载动画
+      visible: false,
+
+      usersList: [], // 变更负责人
+      handleType: 1, // 操作类型
+      addsTypes: [] // 添加至
+    }
+  },
+  computed: {},
+  watch: {
+    dialogVisible: {
+      handler (val) {
+        this.visible = val
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+  mounted () {
+    this.visible = this.dialogVisible
+  },
+  methods: {
+    /**
+     * 取消选择
+     */
+    handleCancel () {
+      this.visible = false
+      this.$emit('update:dialogVisible', false)
+    },
+    /** 负责人更改 */
+    userChage (data) {
+      this.usersList = data.value
+    },
+    handleConfirm () {
+      // 移除操作不可移除客户负责人
+      if (this.usersList.length === 0) {
+        this.$message.error('请选择团队成员')
+      } else {
+        var self = this
+        var actionIds = this.selectionList.map(function (item, index, array) {
+          return item[self.crmType + 'Id']
+        })
+        var userIds = this.usersList.map(function (item, index, array) {
+          return item.userId
+        })
+        var params = {
+          ids: actionIds.join(','),
+          memberIds: userIds.join(',')
+        }
+        if (this.crmType === 'customer' && this.title === '添加团队成员') {
+          // 只有客户下面同时添加到
+          params.changeType = this.addsTypes.join(',')
+        }
+
+        let request
+        if (this.title === '添加团队成员') {
+          // 1只读,2读写
+          params.power = this.handleType
+          request = {
+            // customer: crmCustomerSettingTeamSave,
+            // contract: crmContractSettingTeamSave,
+            // business: crmBusinessSettingTeamSave
+          }[this.crmType]
+        } else {
+          request = {
+            // customer: crmCustomerSettingTeamDelete,
+            // contract: crmContractSettingTeamDelete,
+            // business: crmBusinessSettingTeamDelete
+          }[this.crmType]
+        }
+
+        this.loading = true
+
+        request(params)
+          .then(res => {
+            this.$message({
+              type: 'success',
+              message: '操作成功'
+            })
+            this.loading = false
+            this.handleCancel()
+            this.$emit('handle', {
+              type: this.title === '添加团队成员' ? 'add_user' : 'delete_user'
+            })
+          })
+          .catch(() => {
+            this.loading = false
+          })
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.tips {
+  color: #777;
+  font-size: 12px;
+  position: absolute;
+  bottom: -2px;
+  right: 125px;
+}
+.handle-box {
+  color: #333;
+  font-size: 12px;
+}
+.handle-item {
+  padding-bottom: 15px;
+  position: relative;
+  .handle-item-name {
+    flex-shrink: 0;
+    width: 90px;
+  }
+  .handle-item-content {
+    flex: 1;
+  }
+}
+.handle-bar {
+  position: relative;
+  margin-top: 10px;
+  height: 30px;
+  button {
+    float: right;
+    margin-right: 10px;
+  }
+}
+</style>
diff --git a/src/views/clients/components/selectionHandle/TransferHandle.vue b/src/views/clients/components/selectionHandle/TransferHandle.vue
new file mode 100644
index 0000000..d4c5f1c
--- /dev/null
+++ b/src/views/clients/components/selectionHandle/TransferHandle.vue
@@ -0,0 +1,219 @@
+<template>
+  <el-dialog
+    v-loading="loading"
+    :visible.sync="visible"
+    :append-to-body="true"
+    title="批量转移"
+    width="400px"
+    @close="handleCancel">
+    <div class="handle-box">
+      <flexbox class="handle-item">
+        <div class="handle-item-name">变更负责人为:</div>
+        <xh-user-cell
+          class="handle-item-content"
+          placeholder="点击选择"
+          @value-change="userChage"/>
+      </flexbox>
+      <flexbox
+        v-if="showRemoveType"
+        class="handle-item">
+        <div class="handle-item-name">将原负责人:</div>
+        <el-radio-group v-model="removeType">
+          <el-radio :label="1">移出</el-radio>
+          <el-radio :label="2">转为团队成员</el-radio>
+        </el-radio-group>
+      </flexbox>
+      <flexbox
+        v-if="removeType === 2"
+        class="handle-item">
+        <div class="handle-item-name">权限:</div>
+        <el-radio-group v-model="handleType">
+          <el-radio :label="1">只读</el-radio>
+          <el-radio :label="2">读写</el-radio>
+        </el-radio-group>
+      </flexbox>
+      <!-- 仅客户下可进行同时变成负责人 -->
+      <flexbox
+        v-if="crmType === 'customer'"
+        class="handle-item">
+        <div class="handle-item-name">同时变更负责人至:</div>
+        <el-checkbox-group v-model="addsTypes">
+          <el-checkbox label="1" checked>联系人</el-checkbox>
+          <el-checkbox label="2">商机</el-checkbox>
+          <el-checkbox label="3">合同</el-checkbox>
+        </el-checkbox-group>
+      </flexbox>
+    </div>
+    <span
+      slot="footer"
+      class="dialog-footer">
+      <el-button @click.native="handleCancel">取消</el-button>
+      <el-button
+        type="primary"
+        @click.native="handleConfirm">保存</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+import { XhUserCell } from '@/components/CreateCom'
+// import { crmCustomerTransfer } from '@/api/customermanagement/customerManage'
+// import { crmContactsTransfer } from '@/api/clients/contacts'
+// import { crmBusinessTransfer } from '@/api/clients/business'
+// import { crmContractTransfer } from '@/api/clients/contract'
+// import { crmLeadsTransfer } from '@/api/clients/clue'
+
+export default {
+  /** 客户管理 的 勾选后的 转移 操作 */
+  name: 'TransferHandle',
+  components: {
+    XhUserCell
+  },
+  mixins: [],
+  props: {
+    dialogVisible: {
+      type: Boolean,
+      required: true,
+      default: false
+    },
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    /** 转移数据 */
+    selectionList: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    }
+  },
+  data () {
+    return {
+      loading: false, // 加载动画
+      visible: false,
+
+      usersList: [], // 变更负责人
+      removeType: 1, // 移动类型
+      handleType: 1, // 操作类型
+      addsTypes: [] // 添加至
+    }
+  },
+  computed: {
+    // 是否展示移除操作类型
+    showRemoveType () {
+      if (this.crmType === 'leads' || this.crmType === 'contacts') {
+        return false
+      }
+      return true
+    }
+  },
+  watch: {
+    dialogVisible: {
+      handler (val) {
+        this.visible = val
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+  mounted () {
+    this.visible = this.dialogVisible
+  },
+  methods: {
+    /**
+     * 取消选择
+     */
+    handleCancel () {
+      this.visible = false
+      this.$emit('update:dialogVisible', false)
+    },
+    /** 负责人更改 */
+    userChage (data) {
+      this.usersList = data.value
+    },
+    handleConfirm () {
+      if (this.usersList.length === 0) {
+        this.$message.error('请选择变更负责人')
+      } else {
+        this.loading = true
+        this.getRequest()(this.getParams())
+          .then(res => {
+            this.$message({
+              type: 'success',
+              message: '操作成功'
+            })
+            this.loading = false
+            this.handleCancel()
+            this.$emit('handle', { type: 'transfer' })
+          })
+          .catch(() => {
+            this.loading = false
+          })
+      }
+    },
+    getRequest () {
+      // if (this.crmType === 'leads') {
+      //   return crmLeadsTransfer
+      // } else if (this.crmType === 'customer') {
+      //   return crmCustomerTransfer
+      // } else if (this.crmType === 'contacts') {
+      //   return crmContactsTransfer
+      // } else if (this.crmType === 'business') {
+      //   return crmBusinessTransfer
+      // } else if (this.crmType === 'contract') {
+      //   return crmContractTransfer
+      // }
+    },
+    getParams () {
+      var ownerUserId = this.usersList[0].userId
+      var params = {
+        newOwnerUserId: ownerUserId,
+        transferType: this.removeType
+      }
+      if (this.removeType === 2) {
+        // 1移出,2转为团队成员
+        params.power = this.handleType
+      }
+
+      var self = this
+      var actionId = this.selectionList.map(function (item, index, array) {
+        return item[self.crmType + 'Id']
+      })
+      params[this.crmType + 'Ids'] = actionId.join(',')
+      if (this.crmType === 'customer') {
+        // 只有客户下面有同时变更
+        params.changeType = this.addsTypes.join(',')
+      }
+      return params
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.handle-box {
+  color: #333;
+  font-size: 12px;
+}
+.handle-item {
+  padding-bottom: 15px;
+  .handle-item-name {
+    flex-shrink: 0;
+    width: 110px;
+  }
+  .handle-item-content {
+    flex: 1;
+  }
+}
+.handle-bar {
+  position: relative;
+  margin-top: 10px;
+  height: 30px;
+  button {
+    float: right;
+    margin-right: 10px;
+  }
+}
+</style>
diff --git a/src/views/clients/contacts/ContactsDetail.vue b/src/views/clients/contacts/ContactsDetail.vue
new file mode 100644
index 0000000..3f18c5c
--- /dev/null
+++ b/src/views/clients/contacts/ContactsDetail.vue
@@ -0,0 +1,240 @@
+<template>
+  <slide-view
+    v-empty="!canShowDetail"
+    :listener-ids="listenerIDs"
+    :no-listener-ids="noListenerIDs"
+    :no-listener-class="noListenerClass"
+    :body-style="{padding: 0, height: '100%'}"
+    xs-empty-icon="nopermission"
+    xs-empty-text="暂无权限"
+    @side-close="hideView">
+    <flexbox
+      v-loading="loading"
+      v-if="canShowDetail"
+      direction="column"
+      align="stretch"
+      class="d-container">
+      <c-r-m-detail-head
+        :detail="detailData"
+        :head-details="headDetails"
+        :id="id"
+        crm-type="contacts"
+        @handle="detailHeadHandle"
+        @close="hideView"/>
+      <div class="tabs">
+        <el-tabs
+          v-model="tabCurrentName"
+          @tab-click="handleClick">
+          <el-tab-pane
+            v-for="(item, index) in tabnames"
+            :key="index"
+            :label="item.label"
+            :name="item.name"/>
+        </el-tabs>
+      </div>
+      <div
+        id="follow-log-content"
+        class="t-loading-content"
+        :style="'height:' + contentStyleObj.height">
+          <!--<c-r-m-base-info
+            :ref="tabnames[0].name"
+            class="scroll-item"
+            :detail="detailData"
+            :id="id"
+            crm-type="contacts" />
+          <contacts-follow
+            :ref="tabnames[1].name"
+            class="scroll-item"
+            :detail="detailData"
+            :id="id"
+            crm-type="contacts" />
+            <relative-business
+            :ref="tabnames[2].name"
+            class="scroll-item"
+            :detail="detailData"
+            :id="id"
+            crm-type="contacts" />
+            <relative-files
+            :ref="tabnames[3].name"
+            class="scroll-item"
+            :detail="detailData"
+            :id="id"
+            crm-type="contacts" />
+            <relative-handle
+            :ref="tabnames[4].name"
+            class="scroll-item"
+            :detail="detailData"
+            :id="id"
+            crm-type="contacts" />-->
+        <keep-alive>
+          <component
+            :is="tabName"
+            :detail="detailData"
+            :id="id"
+            crm-type="contacts"/>
+        </keep-alive>
+      </div>
+    </flexbox>
+    <c-r-m-create-view
+      v-if="isCreate"
+      :action="{type: 'update', id: id, batchId: detailData.batchId}"
+      crm-type="contacts"
+      @save-success="editSaveSuccess"
+      @hiden-view="isCreate=false"/>
+  </slide-view>
+</template>
+
+<script>
+import { GetContacterDetail } from '@/api/customermanagement/contacts'
+
+import SlideView from '@/components/SlideView'
+import CRMDetailHead from '../components/CRMDetailHead'
+import ContactsFollow from './components/ContactsFollow' // 跟进记录
+import CRMBaseInfo from '../components/CRMBaseInfo' // 联系人基本信息
+
+import RelativeBusiness from '../components/RelativeBusiness' // 相关商机
+import RelativeHandle from '../components/RelativeHandle' // 相关操作
+import RelativeFiles from '../components/RelativeFiles' // 相关附件
+import CRMCreateView from '../components/CRMCreateView' // 新建页面
+
+import detail from '../mixins/detail'
+
+export default {
+  /** 联系人管理 的 联系人详情 */
+  name: 'ContactsDetail',
+  components: {
+    SlideView,
+    CRMDetailHead,
+    ContactsFollow,
+    CRMBaseInfo,
+    RelativeBusiness,
+    RelativeHandle,
+    RelativeFiles,
+    CRMCreateView
+  },
+  mixins: [detail],
+  props: {
+    // 详情信息id
+    id: [String, Number],
+    // 监听的dom 进行隐藏详情
+    listenerIDs: {
+      type: Array,
+      default: () => {
+        return ['crm-main-container']
+      }
+    },
+    // 不监听
+    noListenerIDs: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    noListenerClass: {
+      type: Array,
+      default: () => {
+        return ['el-table__body']
+      }
+    }
+  },
+  data () {
+    return {
+      loading: false, // 展示加载loading
+      crmType: 'contacts',
+      detailData: {}, // 详情的完整信息
+      headDetails: [
+        { title: '联系人', value: '' },
+        { title: '客户名称', value: '' },
+        { title: '职务', value: '' },
+        { title: '手机', value: '' },
+        { title: '创建时间', value: '' }
+      ],
+      tabCurrentName: 'basicinfo',
+      isCreate: false, // 编辑操作
+      contentStyleObj: {
+        height: '100px'
+      }
+    }
+  },
+  computed: {
+    tabName () {
+      if (this.tabCurrentName === 'followlog') {
+        return 'contacts-follow'
+      } else if (this.tabCurrentName === 'basicinfo') {
+        return 'c-r-m-base-info'
+      } else if (this.tabCurrentName === 'business') {
+        return 'relative-business'
+      } else if (this.tabCurrentName === 'file') {
+        return 'relative-files'
+      } else if (this.tabCurrentName === 'operationlog') {
+        return 'relative-handle'
+      }
+      return ''
+    },
+    tabnames () {
+      var tempsTabs = []
+      // if (this.crm.contacts && this.crm.contacts.read) {
+      tempsTabs.push({ label: '基本信息', name: 'basicinfo' })
+      // }
+      tempsTabs.push({ label: '跟进记录', name: 'followlog' })
+      // if (this.crm.business && this.crm.business.index) {
+      // tempsTabs.push({ label: '商机', name: 'business' })
+      // }
+      // tempsTabs.push({ label: '附件', name: 'file' })
+      tempsTabs.push({ label: '操作记录', name: 'operationlog' })
+      return tempsTabs
+    }
+  },
+  created () {
+    this.getHight()
+    window.addEventListener('resize', this.getHight)
+  },
+  mounted () {},
+  destroyed () {
+    window.removeEventListener('resize', this.getHight)
+  },
+  methods: {
+    getHight () {
+      // this.contentStyleObj.height = (window.innerHeight - 600) + 'px'
+    },
+    getDetial () {
+      this.loading = true
+      GetContacterDetail({
+        Id: this.id
+      })
+        .then(res => {
+          if (res.data.ErrorCode === 500) {
+            this.loading = false
+            this.$message.error(res.data.Message)
+          } else {
+            this.loading = false
+            this.detailData = res.data.Result
+            // 负责人
+            this.headDetails[0].value = res.data.Result.RealName
+            this.headDetails[1].value = res.data.Result.CoustomerName
+            this.headDetails[2].value = res.data.Result.JobPosition || '暂无'
+            this.headDetails[3].value = res.data.Result.MobilePhone || '暂无'
+            this.headDetails[4].value = res.data.Result.CreateTime || '暂无'
+          }
+        })
+        .catch(() => {
+          this.loading = false
+        })
+    },
+    //* * 点击关闭按钮隐藏视图 */
+    hideView () {
+      this.$emit('hide-view')
+    },
+    //* * tab标签点击 */
+    handleClick (tab, event) {},
+    editSaveSuccess () {
+      this.$emit('handle', { type: 'save-success' })
+      this.getDetial()
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../styles/crmdetail.scss';
+</style>
diff --git a/src/views/clients/contacts/ContactsIndex.vue b/src/views/clients/contacts/ContactsIndex.vue
new file mode 100644
index 0000000..40e7d66
--- /dev/null
+++ b/src/views/clients/contacts/ContactsIndex.vue
@@ -0,0 +1,315 @@
+<template>
+  <div class='contacter'>
+    <c-r-m-list-head
+        ref="listHead"
+        title="客户联系人"
+        main-title="客户管理" />
+
+     <c-r-m-table-head
+      ref="crmTableHead"
+      :crm-type="crmType"
+      :fieldList='fieldList'
+      @exportFile="exportFile"
+      @importFile='importFile'
+      @filter="handleFilter"
+      @handle="handleHandle"
+      @on-handle="listHeadHandle"
+      @scene="handleScene"
+      @queryList='queryList'/>
+
+     <el-card class="el-card">
+      <el-table
+        v-loading="loading"
+        id="crm-table"
+        :data="list"
+        :height="tableHeight"
+        :cell-style="cellStyle"
+        class="n-table--border"
+        border
+        highlight-current-row
+        style="width: 100%; z-index: 0;"
+        @row-click="handleRowClick"
+        @sort-change="sortChange"
+        @header-dragend="handleHeaderDragend"
+        @selection-change="handleSelectionChange">
+        <el-table-column
+          show-overflow-tooltip
+          type="selection"
+          align="center"/>
+        <el-table-column
+          v-for="(item, index) in fieldList"
+          :key="index"
+          :fixed="index==0"
+          :prop="item.field"
+          :label="item.value"
+          :width="item.width"
+          :formatter="fieldFormatter"
+          sortable="custom"
+          show-overflow-tooltip>
+          <template
+            slot="header"
+            slot-scope="scope">
+            <div class="table-head-name">{{ scope.column.label }}</div>
+          </template>
+        </el-table-column>
+         <el-table-column
+          prop="operation">
+          <template
+            slot="header"
+            slot-scope="scope">
+            <div class="table-head-name">操作</div>
+          </template>
+          <template slot-scope="scope">
+          <el-button type="text" size="small"  @click='editList(scope.row)'>编辑 |</el-button>
+            <el-button type="text" size="small"  @click='deleteCustomer(scope.row.Id)'>删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="p-contianer">
+        <el-pagination
+          :current-page="currentPage"
+          :page-sizes="pageSizes"
+          :page-size.sync="pageSize"
+          :total="total"
+          class="p-bar"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"/>
+      </div>
+    </el-card>
+    <!-- 导入导出页面 -->
+    <c-r-m-import
+      :show="showCRMImport"
+      :crm-type="crmType"
+      @close="showCRMImport=false"
+      @queryList='queryList'/>
+    <c-r-m-export
+      :show="showCRMExport"
+      :crm-type="crmType"
+      :search="search"
+      :filter-obj="filterObj"
+      :head-obj="headObj"
+      :is-seas="false"
+      :export-params="exportParams"
+      @close="showCRMExport=false"
+      @queryList='queryList'/>
+      <!-- 编辑页面 -->
+    <c-r-m-create-view
+      v-if="isCreate"
+      :action="{type: 'update', id: editData.Id, data: editData}"
+      :crm-type="crmType"
+      @save-success="listHeadHandle"
+      @hiden-view="isCreate=false"/>
+    <!-- 相关详情页面 -->
+    <c-r-m-all-detail
+      :visible.sync="showDview"
+      :crm-type="rowType"
+      :id="rowID"
+      class="d-view"
+      @handle="handleHandle"/>
+    <fields-set
+      :crm-type="crmType"
+      :dialog-visible.sync="showFieldSet"
+      @set-success="setSave"/>
+  </div>
+</template>
+
+<script>
+import CRMAllDetail from '@/views/clients/components/CRMAllDetail'
+import CRMCreateView from '../components/CRMCreateView'
+import table from '../mixins/table'
+import CRMImport from '../components/CRMImport'
+import CRMExport from '../components/CRMExport'
+import { DeleteContacter } from '@/api/customermanagement/contacts'
+// import { UploadFileAsync } from '@/api/common'
+export default {
+  /** 客户管理 的 联系人列表 */
+  name: 'ContactsIndex',
+  components: {
+    CRMAllDetail,
+    CRMCreateView,
+    CRMImport,
+    CRMExport
+  },
+  mixins: [table],
+  computed: {
+  },
+  data () {
+    return {
+      crmType: 'contacts',
+      loading: false,
+      choosedScene: '2',
+      // 导入
+      showCRMImport: false,
+      // 导出
+      showCRMExport: false,
+      // 导出选中参数
+      exportParams: {},
+      fieldList: [
+        { field: 'RealName', value: '联系人姓名', width: '150' },
+        { field: 'CustomerName', value: '客户名称', width: '200' },
+        { field: 'JobPosition', value: '职务' },
+        { field: 'MobilePhone', value: '手机号' },
+        { field: 'OfficePhone', value: '座机号' },
+        { field: 'Email', value: '邮箱' },
+        { field: 'OwerUserName', value: '销售负责人' },
+        { field: 'CreateTime', value: '创建时间' }
+      ]
+
+    }
+  },
+  mounted () {
+  },
+  methods: {
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      if (column.property === 'RealName' || column.property === 'CustomerName') {
+        return { color: '#4D88FF', cursor: 'pointer' }
+      } else {
+        return ''
+      }
+    },
+    queryList (data) {
+      this.headObj = data
+      this.getList(data)
+    },
+    /** 筛选操作 */
+    handleFilter (data) {
+      console.log(data)
+      this.filterObj = data
+      var offsetHei = document.documentElement.clientHeight
+      var removeHeight = Object.keys(this.filterObj).length > 0 ? 310 : 240
+      this.tableHeight = offsetHei - removeHeight
+      this.currentPage = 1
+      this.getList()
+    },
+    deleteCustomer (id) {
+      this.$confirm('确定删除?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          DeleteContacter([{'Id': id}]).then(res => {
+            if (res.data.ErrorCode === 200) {
+              this.$message.success(res.data.Message)
+              this.getList()
+            } else {
+              this.$message.error(res.data.Message)
+            }
+          })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    },
+    exportFile () {
+      this.showCRMExport = true
+    },
+    importFile () {
+      this.showCRMImport = true
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../styles/table.scss';
+.contacter{}
+.new-dialog-title {
+  padding-left: 10px;
+  margin-bottom: 3px;
+  border-left: 2px solid #4D88FF;
+}
+.new-conDialog-form {
+  height: 47vh;
+  overflow-y: auto;
+  padding: 20px;
+  display: flex;
+  flex-wrap: wrap;
+}
+.new-conDialog-form /deep/ .el-form-item {
+  // width: 50%;
+  margin: 0;
+  padding-bottom: 10px;
+}
+.new-conDialog-form /deep/ .el-form-item .el-form-item__label {
+  line-height: normal;
+  font-size: 13px;
+  color: #333333;
+  position: relative;
+  padding-bottom: 8px;
+}
+.new-conDialog-form /deep/ .crm-create-item.el-form-item .el-form-item__content {
+  width: 70%;
+}
+.new-conDialog-form /deep/ .crm-create-block-item.el-form-item .el-form-item__content {
+  width: 90%;
+}
+.new-conDialog-form /deep/ .crm-create-item.el-form-item .el-form-item__content .el-input.is-disabled .el-input__inner{
+  cursor: pointer;
+}
+.crm-create-item {
+  flex: 0 0 45%;
+  flex-shrink: 0;
+  // overflow: hidden;
+  padding-bottom: 10px;
+}
+
+// 占用一整行
+.crm-create-block-item {
+  flex: 0 0 100%;
+  flex-shrink: 0;
+  padding-bottom: 10px;
+}
+.container {
+  position: relative;
+}
+
+.header {
+  height: 40px;
+  padding: 0 10px;
+  flex-shrink: 0;
+  .name {
+    font-size: 13px;
+    padding: 0 10px;
+    color: #333;
+  }
+  .detail {
+    font-size: 12px;
+    padding: 0 10px;
+    color: #aaaaaa;
+    border-left: 1px solid #aaaaaa;
+  }
+  .close {
+    position: absolute;
+    width: 40px;
+    height: 40px;
+    top: 0;
+    right: 10px;
+    padding: 10px;
+  }
+}
+.content{
+  .cropper-box{
+    display:flex;
+    flex-direction: row;
+    align-items: center;
+    padding: 0 20px;
+    .searchTitle{
+      font-size: 14px;
+      width: 124px;
+      color: #333;
+    }
+    .searchInput{
+      margin-right: 20px;
+    }
+  }
+}
+.p-contianer .p-bar{
+  margin: 5px 0 0 14px;
+}
+</style>
diff --git a/src/views/clients/contacts/components/ContactsFollow.vue b/src/views/clients/contacts/components/ContactsFollow.vue
new file mode 100644
index 0000000..bbe0059
--- /dev/null
+++ b/src/views/clients/contacts/components/ContactsFollow.vue
@@ -0,0 +1,184 @@
+<template>
+  <div class="f-container">
+    <div v-loading="sendLoading" v-show="crmType === 'business'">
+      <mix-add
+        ref="mixadd"
+        :crm-type="crmType"
+        :id="id"
+        :show-relative-business="true"
+        :show-relative-contacts="true"
+        @mixadd-info="submitInfo"/>
+    </div>
+    <div class="log-cont">
+      <!--<flexbox>
+        <flexbox
+          v-for="(item, index) in logTypes"
+          :key="index"
+          style="width: auto;"
+          @click.native="logTabsClick(item,index)">
+          <div
+            :style="{ color: logType==item.type ? '#F18C70' : '#777'}"
+            class="log-tabs-item">{{ item.name }}</div>
+          <div
+            v-if="logTypes.length -1 !== index"
+            class="log-tabs-line"/>
+        </flexbox>
+      </flexbox> -->
+      <keep-alive>
+        <component
+          :is="componentsName"
+          :id="id"
+          :crm-type="crmType"/>
+      </keep-alive>
+    </div>
+  </div>
+</template>
+
+<script>
+import MixAdd from '../../components/MixAdd'
+import RecordLog from '../../components/followLog/RecordLog' // 跟进记录
+import JournalLog from '../../components/followLog/JournalLog' // 日志列表
+import ExamineLog from '../../components/followLog/ExamineLog' // 审批列表
+import TaskLog from '../../components/followLog/TaskLog' // 任务日志列表
+import ScheduleLog from '../../components/followLog/ScheduleLog' // 日程日志列表
+import FollowRecordTable from '../../components/followLog/components/FollowRecordTable' // 跟进记录
+import { AddFollowRecord, MakeFollowRecordCompleted } from '@/api/customermanagement/customerManage'
+import followLogType from '@/views/clients/mixins/followLogType'
+
+export default {
+  /** 联系人 的 联系人详情 的 跟进记录 */
+  name: 'ContactsFollow',
+  components: {
+    MixAdd,
+    RecordLog,
+    JournalLog,
+    ExamineLog,
+    TaskLog,
+    ScheduleLog,
+    FollowRecordTable
+  },
+  mixins: [followLogType],
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    /** 是公海 默认是客户 */
+    isSeas: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    return {
+      sendLoading: false,
+      logType: 'record'
+    }
+  },
+  computed: {
+    logTypes () {
+      // if (this.oa) {
+      return [
+        { type: 'record', name: '跟进记录' }
+        // { type: 'log', name: '日志' },
+        // { type: 'examine', name: '审批' },
+        // { type: 'task', name: '任务' },
+        // { type: 'schedule', name: '日程' }
+      ]
+      // } else {
+      //   return [{ type: 'record', name: '跟进记录' }]
+      // }
+    },
+
+    componentsName () {
+      return 'FollowRecordTable'
+      // if (this.logType === 'record') {
+      //   return 'RecordLog'
+      // } else if (this.logType === 'log') {
+      //   return 'JournalLog'
+      // } else if (this.logType === 'examine') {
+      //   return 'ExamineLog'
+      // } else if (this.logType === 'task') {
+      //   return 'TaskLog'
+      // } else if (this.logType === 'schedule') {
+      //   return 'ScheduleLog'
+      // }
+      // return ''
+    }
+  },
+  watch: {
+    id: function (val) {}
+  },
+  mounted () {},
+  activated: function () {},
+  deactivated: function () {},
+  methods: {
+    /** 发布 时候的类型选择 */
+    logTabsClick (item, index) {
+      this.logType = item.type
+    },
+    /** 告诉mixad 返回数据 */
+    // sendInfo () {
+    //   this.$refs.mixadd.$emit('submit-info')
+    // },
+    /** 快捷添加框内 返回的数据用于上传 */
+    submitInfo (data) {
+      if (data.isEvent && !data.nextTime) {
+        this.$message.error('请选择下次联系时间')
+        return
+      } else if (!data.content) {
+        this.$message.error('请输入跟进内容')
+        return
+      }
+
+      var params = {}
+      params.SourceId = this.id
+      params.Title = data.title
+      params.Content = data.content
+      params.FollowType = data.followTypeId
+      params.FollowWay = data.wayTypeId
+      // var businessIds = data.business.map(function (element, index, array) {
+      //   return element.businessId
+      // })
+      // var contactsIds = data.contacts.map(function (element, index, array) {
+      //   return element.contactsId
+      // })
+
+      // params.batchId = data.batchId
+      // params.businessIds = businessIds.join(',')
+      // params.contactsIds = contactsIds.join(',')
+
+      params.IsCompleted = data.isEvent
+      params.FollowTime = data.nextTime || ''
+
+      this.sendLoading = true
+      if (data.isEvent) {
+        MakeFollowRecordCompleted({'Id': this.id}).then(res => {
+          this.$message.success('完成跟进')
+        })
+      }
+      AddFollowRecord(params)
+        .then(res => {
+          this.sendLoading = false
+          this.$message.success('发布成功')
+          // 重置页面
+          this.$refs.mixadd.resetInfo()
+          // this.isEvent = false
+          // this.nextTime = ''
+          // 刷新数据
+          this.$bus.emit('follow-log-refresh', { type: 'record-log' })
+        })
+        .catch(() => {
+          this.sendLoading = false
+        })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../../styles/followlog.scss';
+</style>
diff --git a/src/views/clients/contract/ContractDetail.vue b/src/views/clients/contract/ContractDetail.vue
new file mode 100644
index 0000000..f57b989
--- /dev/null
+++ b/src/views/clients/contract/ContractDetail.vue
@@ -0,0 +1,217 @@
+<template>
+  <slide-view
+    v-empty="!canShowDetail"
+    :listener-ids="listenerIDs"
+    :no-listener-ids="noListenerIDs"
+    :no-listener-class="noListenerClass"
+    :body-style="{padding: 0, height: '100%'}"
+    xs-empty-icon="nopermission"
+    xs-empty-text="暂无权限"
+    @side-close="hideView">
+    <flexbox
+      v-loading="loading"
+      v-if="canShowDetail"
+      direction="column"
+      align="stretch"
+      class="d-container">
+      <c-r-m-detail-head
+        :detail="detailData"
+        :head-details="headDetails"
+        :id="id"
+        crm-type="contract"
+        @handle="detailHeadHandle"
+        @close="hideView"/>
+      <div class="examine-info">
+        <examine-info
+          :id="id"
+          :record-id="detailData.examineRecordId"
+          :owner-user-id="detailData.ownerUserId"
+          class="examine-info-border"
+          examine-type="crm_contract"/>
+      </div>
+      <div class="tabs">
+        <el-tabs
+          v-model="tabCurrentName"
+          @tab-click="handleClick">
+          <el-tab-pane
+            v-for="(item, index) in tabnames"
+            :key="index"
+            :label="item.label"
+            :name="item.name"/>
+        </el-tabs>
+      </div>
+      <div
+        id="follow-log-content"
+        class="t-loading-content">
+        <keep-alive>
+          <component
+            :is="tabName"
+            :detail="detailData"
+            :id="id"
+            crm-type="contract"/>
+        </keep-alive>
+      </div>
+    </flexbox>
+    <c-r-m-create-view
+      v-if="isCreate"
+      :action="{type: 'update', id: id, batchId: detailData.batchId}"
+      crm-type="contract"
+      @save-success="editSaveSuccess"
+      @hiden-view="isCreate=false"/>
+  </slide-view>
+</template>
+
+<script>
+// import { crmContractRead } from '@/api/customermanagement/contract'
+
+import SlideView from '@/components/SlideView'
+import CRMDetailHead from '../components/CRMDetailHead'
+import ContractFollow from './components/ContractFollow' // 跟进记录
+import CRMBaseInfo from '../components/CRMBaseInfo' // 商机基本信息
+import RelativeHandle from '../components/RelativeHandle' // 相关操作
+import RelativeTeam from '../components/RelativeTeam' // 相关团队
+import RelativeProduct from '../components/RelativeProduct' // 相关团队
+import RelativeReturnMoney from '../components/RelativeReturnMoney' // 相关回款
+import RelativeFiles from '../components/RelativeFiles' // 相关附件
+import ExamineInfo from '@/components/Examine/ExamineInfo'
+
+import CRMCreateView from '../components/CRMCreateView' // 新建页面
+
+import detail from '../mixins/detail'
+
+export default {
+  /** 客户管理 的 合同详情 */
+  name: 'ContractDetail',
+  components: {
+    SlideView,
+    CRMDetailHead,
+    ContractFollow,
+    CRMBaseInfo,
+    RelativeHandle,
+    RelativeTeam,
+    RelativeProduct,
+    RelativeReturnMoney,
+    RelativeFiles,
+    ExamineInfo,
+    CRMCreateView
+  },
+  mixins: [detail],
+  props: {
+    // 详情信息id
+    id: [String, Number],
+    // 监听的dom 进行隐藏详情
+    listenerIDs: {
+      type: Array,
+      default: () => {
+        return ['crm-main-container']
+      }
+    },
+    // 不监听
+    noListenerIDs: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    noListenerClass: {
+      type: Array,
+      default: () => {
+        return ['el-table__body']
+      }
+    }
+  },
+  data () {
+    return {
+      loading: false, // 展示加载loading
+      crmType: 'contract',
+      detailData: {}, // read 详情
+      headDetails: [
+        { title: '合同编号', value: '' },
+        { title: '客户名称', value: '' },
+        { title: '合同金额(元)', value: '' },
+        { title: '签约时间', value: '' },
+        { title: '回款金额(元)', value: '' },
+        { title: '负责人', value: '' }
+      ],
+      tabCurrentName: 'basicinfo',
+      isCreate: false // 编辑操作
+    }
+  },
+  computed: {
+    tabName () {
+      if (this.tabCurrentName === 'followlog') {
+        return 'contract-follow'
+      } else if (this.tabCurrentName === 'basicinfo') {
+        return 'c-r-m-base-info'
+      } else if (this.tabCurrentName === 'team') {
+        return 'relative-team'
+      } else if (this.tabCurrentName === 'contract') {
+        return 'relative-contract'
+      } else if (this.tabCurrentName === 'operationlog') {
+        return 'relative-handle'
+      } else if (this.tabCurrentName === 'product') {
+        return 'relative-product'
+      } else if (this.tabCurrentName === 'returnedmoney') {
+        return 'relative-return-money'
+      } else if (this.tabCurrentName === 'file') {
+        return 'relative-files'
+      }
+      return ''
+    },
+    tabnames () {
+      var tempsTabs = []
+      tempsTabs.push({ label: '跟进记录', name: 'followlog' })
+      if (this.crm.contract && this.crm.contract.read) {
+        tempsTabs.push({ label: '基本信息', name: 'basicinfo' })
+      }
+      if (this.crm.product && this.crm.product.index) {
+        tempsTabs.push({ label: '产品', name: 'product' })
+      }
+      if (this.crm.receivables && this.crm.receivables.index) {
+        tempsTabs.push({ label: '回款信息', name: 'returnedmoney' })
+      }
+      tempsTabs.push({ label: '相关团队', name: 'team' })
+      tempsTabs.push({ label: '附件', name: 'file' })
+      tempsTabs.push({ label: '操作记录', name: 'operationlog' })
+      return tempsTabs
+    }
+  },
+  mounted () {},
+  methods: {
+    getDetial () {
+      this.loading = true
+      // crmContractRead({
+      //   contractId: this.id
+      // })
+      //   .then(res => {
+      //     this.loading = false
+      //     this.detailData = res.data // 创建回款计划的时候使用
+
+      //     this.headDetails[0].value = res.data.num
+      //     this.headDetails[1].value = res.data.customerName
+      //     this.headDetails[2].value = this.moneyFormat(res.data.money)
+      //     this.headDetails[3].value = res.data.orderDate
+      //     this.headDetails[4].value = this.moneyFormat(res.data.receivablesMoney)
+      //     this.headDetails[5].value = res.data.ownerUserName
+      //   })
+      //   .catch(() => {
+      //     this.loading = false
+      //   })
+    },
+    //* * 点击关闭按钮隐藏视图 */
+    hideView () {
+      this.$emit('hide-view')
+    },
+    //* * tab标签点击 */
+    handleClick (tab, event) {},
+    editSaveSuccess () {
+      this.$emit('handle', { type: 'save-success' })
+      this.getDetial()
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../styles/crmdetail.scss';
+</style>
diff --git a/src/views/clients/contract/ContractIndex.vue b/src/views/clients/contract/ContractIndex.vue
new file mode 100644
index 0000000..5042c5d
--- /dev/null
+++ b/src/views/clients/contract/ContractIndex.vue
@@ -0,0 +1,265 @@
+<template>
+  <div>
+    <c-r-m-list-head
+      ref="listHead"
+      title="合同管理"
+      main-title="客户管理"/>
+      <c-r-m-table-head
+        ref="crmTableHead"
+        :crm-type="crmType"
+        :fieldList='fieldList'
+        @filter="handleFilter"
+        @handle="handleHandle"
+        @on-handle="listHeadHandle"
+        @scene="handleScene"
+        @queryList='queryList'/>
+      <el-card class="el-card">
+        <el-table
+          v-loading="loading"
+          id="crm-table"
+          :data="list"
+          :height="tableHeight"
+          :cell-style="cellStyle"
+          class="n-table--border"
+          border
+          highlight-current-row
+          style="width: 100%; z-index: 0;"
+          @row-click="handleRowClick"
+          @sort-change="sortChange"
+          @header-dragend="handleHeaderDragend"
+          @selection-change="handleSelectionChange">
+          <el-table-column
+            show-overflow-tooltip
+            type="selection"
+            align="left"
+            width="55"/>
+          <el-table-column
+            v-for="(item, index) in fieldList"
+            :key="index"
+            :prop="item.field"
+            :label="item.value"
+            :width="item.width"
+            :formatter="fieldFormatter"
+            sortable="custom"
+            show-overflow-tooltip>
+            <template
+              slot="header"
+              slot-scope="scope">
+              <div class="table-head-name">
+                  {{ scope.column.label }}
+                  <c-r-m-table-filter
+                    :show="scope.column.label==='合同类型'"
+                    :tableType="scope.column.label"
+                    @queryList="queryList">
+                  </c-r-m-table-filter>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column prop="BeforeSealFile" label="盖章前合同">
+            <template
+              slot="header"
+              slot-scope="scope">
+              <div class="table-head-name">{{ scope.column.label }}</div>
+            </template>
+            <template slot-scope="scope">
+              <span>{{scope.row.BeforeSealFile===''?'--':'点击下载'}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="SealFile" label="盖章后合同">
+            <template
+              slot="header"
+              slot-scope="scope">
+              <div class="table-head-name">{{ scope.column.label }}</div>
+            </template>
+            <template slot-scope="scope">
+              <span>{{scope.row.SealFile===''?'--':'点击下载'}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column
+            prop="operation"
+            width="150">
+            <template
+              slot="header"
+              slot-scope="scope">
+              <div class="table-head-name">操作</div>
+            </template>
+            <template slot-scope="scope">
+            <el-button type="text" size="small" :disabled="!scope.row.IsCanEdit"  @click='editList(scope.row)'>编辑 |</el-button>
+            <el-button type="text" size="small" :disabled="!scope.row.IsCanDelete"  @click='deleteModule(scope.row.Id)'>删除</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="p-contianer"  v-show='total>0'>
+          <el-pagination
+            :current-page="currentPage"
+            :page-sizes="pageSizes"
+            :page-size.sync="pageSize"
+            :total="total"
+            class="p-bar"
+            layout="total, sizes, prev, pager, next, jumper"
+            @size-change="handleSizeChange"
+            @current-change="handleCurrentChange"/>
+        </div>
+      </el-card>
+    <el-dialog title="编辑合同" :visible.sync="isCreate" :modal-append-to-body="false" width="30%">
+      <c-r-m-create-file-view
+        v-if="isCreate"
+        :id="rowID"
+        :action="createActionInfo"
+        crm-type="contract"
+        @save-success="createSaveSuccess"
+        @hiden-view="isCreate=false"/>
+    </el-dialog>
+    <!-- 相关详情页面 -->
+    <c-r-m-all-detail
+      :visible.sync="showDview"
+      :crm-type="rowType"
+      :id="rowID"
+      class="d-view"
+      @handle="handleHandle"/>
+    <fields-set
+      :crm-type="crmType"
+      :dialog-visible.sync="showFieldSet"
+      @set-success="setSave"/>
+  </div>
+</template>
+
+<script>
+import CRMAllDetail from '@/views/clients/components/CRMAllDetail'
+import table from '../mixins/table'
+import CRMTableFilter from '../components/CRMTableFilter'
+import CRMCreateFileView from '@/views/clients/components/CRMCreateFileView'
+import { DeleteAgreenment } from '@/api/customermanagement/contract'
+
+export default {
+  /** 客户管理 的 合同列表 */
+  name: 'ContractIndex',
+  components: {
+    CRMAllDetail,
+    CRMTableFilter,
+    CRMCreateFileView
+  },
+  mixins: [table],
+  data () {
+    return {
+      crmType: 'contract',
+      isCreate: false,
+      // 创建的相关信息
+      createActionInfo: { type: 'update', crmType: this.crmType, data: {} },
+      fieldList: [],
+      moneyData: null // 合同列表金额
+    }
+  },
+  computed: {
+    moneyPageData () {
+      // 未勾选展示合同总金额信息
+      if (this.selectionList.length === 0 && this.moneyData) {
+        return this.moneyData
+      } else {
+        let contractMoney = 0.0
+        let receivedMoney = 0.0
+        for (let index = 0; index < this.selectionList.length; index++) {
+          const element = this.selectionList[index]
+          // 2 审核通过的合同
+          if (element.checkStatus === 1) {
+            contractMoney += parseFloat(element.money)
+            receivedMoney += parseFloat(element.receivedMoney)
+          }
+        }
+        return {
+          contractMoney: contractMoney.toFixed(2),
+          receivedMoney: receivedMoney.toFixed(2)
+        }
+      }
+    }
+  },
+  mounted () {
+    this.getFieldList()
+  },
+  methods: {
+    getFieldList () {
+      this.fieldList.push(
+        { field: 'AgreeNumber', value: '合同编号' },
+        { field: 'AgreeName', value: '合同名称' },
+        { field: 'Comment', value: '合同备注' },
+        { field: 'CustomerName', value: '客户名称' },
+        { field: 'SalesChanceName', value: '商机名称' },
+        { field: 'AuditStatus', value: '是否审核', width: '100' },
+        { field: 'AuditUserName', value: '审核人' },
+        { field: 'SealTypeString', value: '合同类型' },
+        { field: 'IsSeal', value: '是否盖章', width: '100' },
+        { field: 'SealUserName', value: '盖章上传人' },
+        { field: 'CreateTime', value: '创建时间' },
+        { field: 'ExpressNumber', value: '快递单号' },
+        { field: 'ExpressComment', value: '快递备注信息' }
+        // { field: 'BeforeSealFile', value: '盖章前合同' },
+        // { field: 'SealFile', value: '盖章后合同' }
+      )
+    },
+    queryList (data) {
+      this.getList(data)
+    },
+    /** 编辑 */
+    editList (row) {
+      console.log(row)
+      this.createActionInfo.data = row
+      this.isCreate = true
+    },
+    deleteModule (id) {
+      this.$confirm('确定删除?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          DeleteAgreenment([{'Id': id}]).then(res => {
+            if (res.data.ErrorCode === 200) {
+              this.$message.success(res.data.Message)
+              this.getList()
+            } else {
+              this.$message.error(res.data.Message)
+            }
+          })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    },
+    createSaveSuccess () {
+      this.getList()
+      this.isCreate = false
+    },
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      if (column.property === 'BeforeSealFile' || column.property === 'SealFile' || column.property === 'SalesChanceName' ||
+        column.property === 'CustomerName') {
+        return { color: '#4D88FF', cursor: 'pointer' }
+      } else if (column.property === 'AuditStatus') {
+        if (row[column.property] === '审批中') {
+          return { color: '#FF8800' }
+        } else if (row[column.property] === '通过') {
+          return { color: '#2DB300' }
+        } else if (row[column.property] === '驳回') {
+          return { color: '#FF4D4D' }
+        }
+      } else {
+        return { textAlign: 'left' }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../styles/table.scss';
+.money-bar {
+  color: #99a9bf;
+  line-height: 44px !important;
+  position: absolute;
+  left: 20px;
+  top: 0;
+}
+</style>
diff --git a/src/views/clients/contract/components/ContractFollow.vue b/src/views/clients/contract/components/ContractFollow.vue
new file mode 100644
index 0000000..bf3cfa4
--- /dev/null
+++ b/src/views/clients/contract/components/ContractFollow.vue
@@ -0,0 +1,197 @@
+<template>
+  <div class="f-container">
+    <div v-loading="sendLoading" v-show="crmType === 'business'">
+      <mix-add
+        ref="mixadd"
+        :crm-type="crmType"
+        :id="id"
+        @mixadd-info="submitInfo"/>
+      <flexbox class="se-section">
+        <div class="se-name">记录类型</div>
+        <el-dropdown
+          style="margin-right: 20px;"
+          trigger="click"
+          @command="handleTypeDrop">
+          <flexbox class="se-select">
+            <div class="se-select-name">{{ followType ? followType : '请选择' }}</div>
+            <i
+              class="el-icon-arrow-down el-icon--right"
+              style="color:#ccc;"/>
+          </flexbox>
+          <el-dropdown-menu slot="dropdown">
+            <el-dropdown-item
+              v-for="(item, index) in followTypes"
+              :key="index"
+              :command="item.type">{{ item.name }}</el-dropdown-item>
+          </el-dropdown-menu>
+        </el-dropdown>
+        <div class="se-name">下次联系时间</div>
+        <el-date-picker
+          v-model="nextTime"
+          :default-value="new Date"
+          :editable="false"
+          class="se-datepicker"
+          type="datetime"
+          placeholder="选择日期"
+          value-format="yyyy-MM-dd HH:mm:ss"/>
+        <el-checkbox
+          v-if="showOAPermission"
+          v-model="isEvent">添加到日程提醒</el-checkbox>
+        <el-button
+          class="se-send"
+          type="primary"
+          @click.native="sendInfo">发布</el-button>
+      </flexbox>
+    </div>
+    <div class="log-cont">
+      <flexbox style="border-bottom: 1px solid #E6E6E6;">
+        <flexbox
+          v-for="(item, index) in logTypes"
+          :key="index"
+          style="width: auto;"
+          @click.native="logTabsClick(item,index)">
+          <div
+            :style="{ color: logType==item.type ? '#F18C70' : '#777'}"
+            class="log-tabs-item">{{ item.name }}</div>
+          <div
+            v-if="logTypes.length -1 !== index"
+            class="log-tabs-line"/>
+        </flexbox>
+      </flexbox>
+      <keep-alive>
+        <component
+          :is="componentsName"
+          :id="id"
+          :crm-type="crmType"/>
+      </keep-alive>
+    </div>
+  </div>
+</template>
+
+<script>
+import MixAdd from '../../components/MixAdd'
+import RecordLog from '../../components/followLog/RecordLog' // 跟进记录
+import JournalLog from '../../components/followLog/JournalLog' // 日志列表
+import ExamineLog from '../../components/followLog/ExamineLog' // 审批列表
+import TaskLog from '../../components/followLog/TaskLog' // 任务日志列表
+import ScheduleLog from '../../components/followLog/ScheduleLog' // 日程日志列表
+// import { crmContractRecordSave } from '@/api/customermanagement/contract'
+import followLogType from '@/views/clients/mixins/followLogType'
+
+export default {
+  /** 客户管理 的 合同详情 的 跟进记录 */
+  name: 'ContractFollow',
+  components: {
+    MixAdd,
+    RecordLog,
+    JournalLog,
+    ExamineLog,
+    TaskLog,
+    ScheduleLog
+  },
+  mixins: [followLogType],
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    }
+  },
+  data () {
+    return {
+      sendLoading: false,
+      /** 下次联系时间 */
+      nextTime: '',
+      /** 是否添加日程提醒 */
+      isEvent: false,
+      logType: 'record'
+    }
+  },
+  computed: {
+    logTypes () {
+      if (this.oa) {
+        return [
+          { type: 'record', name: '跟进记录' },
+          { type: 'log', name: '日志' },
+          { type: 'examine', name: '审批' },
+          { type: 'task', name: '任务' },
+          { type: 'schedule', name: '日程' }
+        ]
+      } else {
+        return [{ type: 'record', name: '跟进记录' }]
+      }
+    },
+
+    componentsName () {
+      if (this.logType === 'record') {
+        return 'RecordLog'
+      } else if (this.logType === 'log') {
+        return 'JournalLog'
+      } else if (this.logType === 'examine') {
+        return 'ExamineLog'
+      } else if (this.logType === 'task') {
+        return 'TaskLog'
+      } else if (this.logType === 'schedule') {
+        return 'ScheduleLog'
+      }
+      return ''
+    }
+  },
+  mounted () {},
+  activated: function () {},
+  deactivated: function () {},
+  methods: {
+    /** 发布 时候的类型选择 */
+    handleTypeDrop (command) {
+      this.followType = command
+    },
+    logTabsClick (item, index) {
+      this.logType = item.type
+    },
+    /** 告诉mixad 返回数据 */
+    sendInfo () {
+      this.$refs.mixadd.$emit('submit-info')
+    },
+    /** 快捷添加框内 返回的数据用于上传 */
+    submitInfo (data) {
+      if (this.isEvent && !this.nextTime) {
+        this.$message.error('请选择下次联系时间')
+        return
+      } else if (!data.content) {
+        this.$message.error('请输入跟进内容')
+        return
+      }
+
+      var params = {}
+      params.typesId = this.id
+      params.content = data.content
+      params.category = this.followType
+      params.batchId = data.batchId
+      params.isEvent = this.isEvent ? 1 : 0
+      params.nextTime = this.nextTime || ''
+
+      this.sendLoading = true
+      // crmContractRecordSave(params)
+      //   .then(res => {
+      //     this.sendLoading = false
+      //     this.$message.success('发布成功')
+      //     // 重置页面
+      //     this.$refs.mixadd.resetInfo()
+      //     this.isEvent = false
+      //     this.nextTime = ''
+      //     // 刷新数据
+      //     this.$bus.emit('follow-log-refresh', { type: 'record-log' })
+      //   })
+      //   .catch(() => {
+      //     this.sendLoading = false
+      //   })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../../styles/followlog.scss';
+</style>
diff --git a/src/views/clients/customer/CustomerDetail.vue b/src/views/clients/customer/CustomerDetail.vue
new file mode 100644
index 0000000..ec0ea7c
--- /dev/null
+++ b/src/views/clients/customer/CustomerDetail.vue
@@ -0,0 +1,329 @@
+<template>
+  <slide-view
+    v-empty="!canShowDetail"
+    :listener-ids="listenerIDs"
+    :no-listener-ids="noListenerIDs"
+    :no-listener-class="noListenerClass"
+    :body-style="{padding: 0, height: '100%'}"
+    xs-empty-icon="nopermission"
+    xs-empty-text="暂无权限"
+    @side-close="hideView">
+    <flexbox
+      v-loading="loading"
+      v-if="canShowDetail"
+      direction="column"
+      align="stretch"
+      class="d-container">
+      <c-r-m-detail-head
+        :is-seas="isSeasDetail"
+        :detail="detailData"
+        :head-details="headDetails"
+        :id="id"
+        crm-type="customer"
+        @handle="detailHeadHandle"
+        @close="hideView"/>
+      <div class="tabs">
+        <el-tabs
+          v-model="tabCurrentName"
+          @tab-click="handleClick">
+          <el-tab-pane
+            v-for="(item, index) in tabnames"
+            :key="index"
+            :label="item.label"
+            :name="item.name"/>
+        </el-tabs>
+      </div>
+      <div
+        id="follow-log-content"
+        class="t-loading-content"
+        :style="'height:' + contentStyleObj.height">
+            <!-- @scroll="onScroll" @tab-click="jump"
+            <c-r-m-base-info
+              :ref="tabnames[0].name"
+              class="scroll-item"
+              :detail="detailData"
+              :id="id"
+              :is-seas="isSeasDetail"
+              crm-type="customer" />
+            <relative-contacts
+              :ref="tabnames[1].name"
+              class="scroll-item"
+              :detail="detailData"
+              :id="id"
+              :is-seas="isSeasDetail"
+              crm-type="customer" />
+            <relative-business
+              :ref="tabnames[2].name"
+              class="scroll-item"
+              :detail="detailData"
+              :id="id"
+              :is-seas="isSeasDetail"
+              crm-type="customer"/>
+            <customer-follow
+              :ref="tabnames[3].name"
+              class="scroll-item"
+              :detail="detailData"
+              :id="id"
+              :is-seas="isSeasDetail"
+              crm-type="customer" />
+            <relative-contract
+              :ref="tabnames[4].name"
+              class="scroll-item"
+              :detail="detailData"
+              :id="id"
+              :is-seas="isSeasDetail"
+              crm-type="customer" />
+            <relative-return-money
+              :ref="tabnames[5].name"
+              class="scroll-item"
+              :detail="detailData"
+              :id="id"
+              :is-seas="isSeasDetail"
+              crm-type="customer"/>
+            <relative-files
+              :ref="tabnames[6].name"
+              class="scroll-item"
+              :detail="detailData"
+              :id="id"
+              :is-seas="isSeasDetail"
+              crm-type="customer" />
+            <relative-handle
+              :ref="tabnames[7].name"
+              class="scroll-item"
+              :detail="detailData"
+              :id="id"
+              :is-seas="isSeasDetail"
+              crm-type="customer" />-->
+        <keep-alive>
+          <component
+            class="scroll-item"
+            :is="tabName"
+            :detail="detailData"
+            :id="id"
+            :is-seas="isSeasDetail"
+            crm-type="customer"/>
+        </keep-alive>
+      </div>
+    </flexbox>
+    <c-r-m-create-view
+      v-if="isCreate"
+      :action="{type: 'update', id: id, batchId: detailData.batchId}"
+      crm-type="customer"
+      @save-success="editSaveSuccess"
+      @hiden-view="isCreate=false"/>
+  </slide-view>
+</template>
+
+<script>
+import { GetCustomerDetail } from '@/api/customermanagement/customerManage'
+
+import SlideView from '@/components/SlideView'
+import CRMDetailHead from '../components/CRMDetailHead'
+import CustomerFollow from './components/CustomerFollow' // 跟进记录
+import CRMBaseInfo from '../components/CRMBaseInfo' // 基本信息
+import RelativeContacts from '../components/RelativeContacts' // 相关联系人
+import RelativeBusiness from '../components/RelativeBusiness' // 相关商机
+import RelativeContract from '../components/RelativeContract' // 相关合同
+import RelativeReturnMoney from '../components/RelativeReturnMoney' // 相关回款
+import RelativeFiles from '../components/RelativeFiles' // 相关附件
+import RelativeHandle from '../components/RelativeHandle' // 相关操作
+import RelativeTeam from '../components/RelativeTeam' // 相关团队
+
+import CRMCreateView from '../components/CRMCreateView' // 新建页面
+
+import detail from '../mixins/detail'
+// import test from './test'
+
+export default {
+  /** 客户管理 的 客户详情 */
+  name: 'CustomerDetail',
+  components: {
+    SlideView,
+    CustomerFollow,
+    CRMDetailHead,
+    CRMBaseInfo,
+    RelativeContacts,
+    RelativeBusiness,
+    RelativeContract,
+    RelativeReturnMoney,
+    RelativeFiles,
+    RelativeHandle,
+    RelativeTeam,
+    CRMCreateView
+  },
+  mixins: [detail],
+  props: {
+    // 详情信息id
+    id: [String, Number],
+    // 监听的dom 进行隐藏详情
+    listenerIDs: {
+      type: Array,
+      default: () => {
+        return ['crm-main-container']
+      }
+    },
+    // 不监听
+    noListenerIDs: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    noListenerClass: {
+      type: Array,
+      default: () => {
+        return ['el-table__body']
+      }
+    }
+  },
+  data () {
+    return {
+      loading: false, // 展示加载loading
+      crmType: 'customer',
+      detailData: {}, // read 详情
+      headDetails: [
+        { title: '客户状态', value: '' },
+        { title: '负责人', value: '' },
+        { title: '更新时间', value: '' }
+      ],
+      tabCurrentName: 'basicinfo',
+      isCreate: false, // 编辑操作
+      contentStyleObj: {
+        height: '100px'
+      }
+    }
+  },
+  computed: {
+    tabName () {
+      if (this.tabCurrentName === 'followlog') {
+        return 'customer-follow'
+      } else if (this.tabCurrentName === 'basicinfo') {
+        return 'c-r-m-base-info'
+      } else if (this.tabCurrentName === 'contacts') {
+        return 'relative-contacts'
+      } else if (this.tabCurrentName === 'team') {
+        return 'relative-team'
+      } else if (this.tabCurrentName === 'business') {
+        return 'relative-business'
+      } else if (this.tabCurrentName === 'contract') {
+        return 'relative-contract'
+      } else if (this.tabCurrentName === 'returnedmoney') {
+        return 'relative-return-money'
+      } else if (this.tabCurrentName === 'file') {
+        return 'relative-files'
+      } else if (this.tabCurrentName === 'operationlog') {
+        return 'relative-handle'
+      }
+      return ''
+    },
+    tabnames () {
+      var tempsTabs = []
+      // if (this.crm.customer && this.crm.customer.read) {
+      tempsTabs.push({ label: '基本信息', name: 'basicinfo' })
+      // }
+      tempsTabs.push({ label: '联系人', name: 'contacts' })
+      tempsTabs.push({ label: '商机', name: 'business' })
+
+      tempsTabs.push({ label: '跟进记录', name: 'followlog' })
+
+      // if (this.crm.contacts && this.crm.contacts.index) {
+      // }
+      // tempsTabs.push({ label: '相关团队', name: 'team' })
+      // if (this.crm.business && this.crm.business.index) {
+      // }
+      // if (this.crm.contract && this.crm.contract.index) {
+      tempsTabs.push({ label: '合同', name: 'contract' })
+      // }
+      // if (this.crm.receivables && this.crm.receivables.index) {
+      tempsTabs.push({ label: '回款信息', name: 'returnedmoney' })
+      // }
+      // tempsTabs.push({ label: '附件', name: 'file' })
+      tempsTabs.push({ label: '操作记录', name: 'operationlog' })
+      return tempsTabs
+    },
+    /**
+     * isSeas 是从公海模块传入的 配合详情is_pool字段确定
+     */
+    isSeasDetail () {
+      // if (this.detailData && this.detailData.hasOwnProperty('isPool')) {
+      //   return this.detailData.isPool === 1
+      // }
+      // return this.isSeas
+      return false
+    }
+  },
+  created () {
+    this.getHight()
+    window.addEventListener('resize', this.getHight)
+  },
+  mounted () {},
+  destroyed () {
+    window.removeEventListener('resize', this.getHight)
+  },
+  methods: {
+    getHight () {
+      // this.contentStyleObj.height = (window.innerHeight - 600) + 'px'
+    },
+    getDetial () {
+      this.loading = true
+      console.log(this.id)
+      GetCustomerDetail({
+        Id: this.id
+      })
+        .then(res => {
+          console.log(res.data)
+          this.loading = false
+          this.detailData = res.data.Result
+          // 负责人
+          // this.headDetails[0].value = res.data.Result.客户级别
+          switch (res.data.Result.CustomerStatus) {
+            case 0:
+              this.headDetails[0].value = '暂无'
+              break
+            case 1:
+              this.headDetails[0].value = '潜在客户'
+              break
+            case 2:
+              this.headDetails[0].value = '高意向潜在客户'
+              break
+            case 3:
+              this.headDetails[0].value = '试用客户'
+              break
+            case 4:
+              this.headDetails[0].value = '成交客户'
+              break
+            case 5:
+              this.headDetails[0].value = '失败关闭'
+              break
+            case 6:
+              this.headDetails[0].value = '销售线索'
+              break
+            case 7:
+              this.headDetails[0].value = '在谈客户'
+              break
+            case 8:
+              this.headDetails[0].value = '在谈休眠客户'
+              break
+          }
+          this.headDetails[1].value = res.data.Result.SaleName || '暂无'
+          this.headDetails[2].value = res.data.Result.NextFollowTime
+        })
+        .catch(() => {
+          this.loading = false
+        })
+    },
+    //* * 点击关闭按钮隐藏视图 */
+    hideView () {
+      this.$emit('hide-view')
+    },
+    editSaveSuccess () {
+      this.$emit('handle', { type: 'save-success' })
+      this.getDetial()
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../styles/crmdetail.scss';
+</style>
diff --git a/src/views/clients/customer/clientsManage.vue b/src/views/clients/customer/clientsManage.vue
new file mode 100644
index 0000000..a497754
--- /dev/null
+++ b/src/views/clients/customer/clientsManage.vue
@@ -0,0 +1,663 @@
+<template>
+  <div class='customer'>
+    <c-r-m-list-head
+      ref="listHead"
+      title="客户管理"
+      main-title="客户管理" />
+
+    <c-r-m-table-head
+      ref="crmTableHead"
+      :crm-type="crmType"
+      :fieldList='fieldList'
+      @exportFile="exportFile"
+      @importFile='importFile'
+      @filter="handleFilter"
+      @handle="handleHandle"
+      @on-handle="listHeadHandle"
+      @scene="handleScene"
+      @queryList='queryList'/>
+
+    <el-card class="el-card">
+      <el-table
+        v-loading="loading"
+        id="crm-table"
+        :data="list"
+        :height="tableHeight"
+        :cell-style="cellStyle"
+        class="n-table--border"
+        border
+        highlight-current-row
+        style="width: 100%; z-index:0;"
+        @row-click="handleRowClick"
+        @sort-change="sortChange"
+        @header-dragend="handleHeaderDragend"
+        @selection-change="handleSelectionChange">
+        <!--<el-table-column
+          show-overflow-tooltip
+          type="selection"
+          align="center"/>-->
+        <el-table-column
+          v-for="(item, index) in fieldList"
+          :key="index"
+          :prop="item.field"
+          :label="item.value"
+          :width="item.width"
+          :formatter="fieldFormatter"
+          sortable="custom"
+          show-overflow-tooltip>
+          <template
+            slot="header"
+            slot-scope="scope">
+            <div class="table-head-name">
+              {{ scope.column.label }}
+              <c-r-m-table-filter
+              :show="scope.column.label==='企业性质' || scope.column.label==='行业细分'"
+              :tableType="scope.column.label"
+              @queryList="queryList">
+              </c-r-m-table-filter>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          prop="operation">
+          <template
+            slot="header"
+            slot-scope="scope">
+            <div class="table-head-name">操作</div>
+          </template>
+          <template slot-scope="scope">
+            <el-button type="text" size="small"  @click='editList(scope.row)'>编辑</el-button>
+            <!--<el-button type="text" size="small"  @click='deleteCustomer(scope.row.Id)'>删除</el-button>
+            <el-button type="text" size="small"  @click='followCustomer(scope.row)'>跟进</el-button> -->
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="p-contianer" v-show='total>0'>
+        <el-pagination
+          :current-page="currentPage"
+          :page-sizes="pageSizes"
+          :page-size.sync="pageSize"
+          :total="total"
+          class="p-bar"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"/>
+      </div>
+    </el-card>
+
+    <!--跟进 -->
+     <create-view
+     v-if="isFollowDialog"
+    :loading="followLoading"
+    :body-style="{ height: '100%'}">
+      <flexbox
+        direction="column"
+        align="stretch"
+        class="crm-create-container">
+        <flexbox class="crm-create-header">
+          <div style="flex:1;font-size:18px;color:#333;font-weight: 700;">跟进记录</div>
+          <img
+            class="close"
+            src="@/assets/img/task_close.png"
+            @click="followHandleClose" >
+        </flexbox>
+        <div class="crm-create-flex">
+          <create-sections title="基本信息">
+            <flexbox
+              direction="column"
+              align="stretch">
+              <div class="crm-create-body">
+                <el-form
+                  ref="followDialogRef"
+                  label-position="left"
+                  label-width="auto"
+                  class="crm-create-box"
+                  :model="followForm"
+                  :rules="followFormRules">
+                  <el-form-item
+                    v-for="(item, index) in followList"
+                    :label="item.value"
+                    :prop="item.field"
+                    :class="{ 'crm-create-block-item': item.showblock, 'crm-create-item': !item.showblock }"
+                    :style="{'padding-left': getPaddingLeft(item, index), 'padding-right': getPaddingRight(item, index)}"
+                    :key="index">
+                    <span slot="label">{{ item.value }}:</span>
+                    <template v-if="item.type === 'select'">
+                      <el-select
+                        style="width: 100%;"
+                        v-model="followForm[item.field]"
+                        filterable
+                        placeholder="请选择"
+                        @change='getSelectVal(item.field)'>
+                        <el-option
+                          v-for="(optionItem, index) in optionsList[item.field].list"
+                          :key="index"
+                          :label="optionItem"
+                          :value="index"/>
+                      </el-select>
+                    </template>
+                    <template v-else-if="item.type === 'datetime'">
+                      <el-date-picker
+                        v-model="followForm[item.field]"
+                        style="width: 100%;"
+                        type="datetime"
+                        value-format="yyyy-MM-dd HH:mm:ss"
+                        placeholder="选择日期"/>
+                    </template>
+                    <el-input placeholder="请输入内容" type="textarea" v-model="followForm[item.field]"  v-else-if="item.type === 'textarea'">
+                      </el-input>
+                    <el-tooltip effect="light" :disabled='!item.tips' :content="item.tips" placement="right" v-else>
+                      <el-input
+                        v-model="followForm[item.field]"
+                        :disabled="item.disabled "/>
+                    </el-tooltip>
+                  </el-form-item>
+                </el-form>
+                </div>
+            </flexbox>
+          </create-sections>
+          <div class="handle-bar">
+            <el-button
+              class="handle-button"
+              @click.native="followHandleClose">取消</el-button>
+            <el-button
+              class="handle-button"
+              type="primary"
+              @click.native="followDialogSubmit">保存</el-button>
+          </div>
+        </div>
+      </flexbox>
+    </create-view>
+    <c-r-m-import
+      :show="showCRMImport"
+      :crm-type="crmType"
+      @close="showCRMImport=false"
+      @queryList='queryList'/>
+    <c-r-m-export
+      :show="showCRMExport"
+      :crm-type="crmType"
+      :search="search"
+      :filter-obj="filterObj"
+      :head-obj="headObj"
+      :is-seas="false"
+      :export-params="exportParams"
+      @close="showCRMExport=false"
+      @queryList='queryList'/>
+    <!-- 相关详情页面 -->
+    <c-r-m-all-detail
+      :key='timer'
+      :visible.sync="showDview"
+      :crm-type="rowType"
+      :id="rowID"
+      class="d-view"
+      @handle="handleHandle"/>
+      <!-- 编辑页面 -->
+    <c-r-m-create-view
+      v-if="isCreate"
+      :action="{type: 'update', id: editData.Id, data: editData}"
+      :crm-type="crmType"
+      @save-success="listHeadHandle"
+      @hiden-view="isCreate=false"/>
+    <fields-set
+      :crm-type="crmType"
+      :dialog-visible.sync="showFieldSet"
+      @set-success="setSave"/>
+  </div>
+</template>
+
+<script>
+import table from '../mixins/table'
+import CreateView from '@/components/CreateView'
+import CreateSections from '@/components/CreateSections'
+import CRMCreateView from '../components/CRMCreateView'
+import CRMImport from '../components/CRMImport'
+import CRMExport from '../components/CRMExport'
+import CRMTableFilter from '../components/CRMTableFilter'
+import CRMAllDetail from '@/views/clients/components/CRMAllDetail'
+import BusinessCheck from './components/BusinessCheck' // 相关商机
+import { DeleteCustomer } from '@/api/customermanagement/customerManage'
+// import moment from 'moment'
+// import { getDateFromTimestamp } from '@/utils'
+import {
+  XhCustomerAddress
+} from '@/components/CreateCom'
+export default {
+  name: 'ClientManage',
+  components: {
+    CRMAllDetail,
+    CRMCreateView,
+    BusinessCheck,
+    CRMImport,
+    CRMExport,
+    XhCustomerAddress,
+    CreateView,
+    CreateSections,
+    CRMTableFilter
+  },
+  filters: {
+    /** 根据type 找到组件 */
+    typeToComponentName (formType) {
+      if (formType === 'map_address') {
+        return 'XhCustomerAddress'
+      }
+    }
+  },
+  mixins: [table],
+  computed: {
+    followList: function () {
+      return [
+        { field: 'CustomerName', value: '客户名称', showblock: false },
+        { field: 'ChanceName', value: '关联商机', showblock: false },
+        { field: 'SalesChanceStage', value: '销售进度', showblock: false, type: 'select' },
+        { field: 'NextFollowTime', value: '下次联系时间', showblock: false, type: 'datetime' },
+        { field: 'RealName', value: '联系人姓名', showblock: false },
+        { field: 'ContacterMobile', value: '联系方式', showblock: false, type: 'select' },
+        { field: 'Command', value: '描述', showblock: false, type: 'textarea' }
+      ]
+    }
+  },
+  data () {
+    return {
+      timer: '',
+      fieldList: [
+        { field: 'CustomerNumber', value: '客户编号' },
+        { field: 'CustomerName', value: '客户名称' },
+        { field: 'Contacter', value: '联系人' },
+        { field: 'ContactMobile', value: '手机号' },
+        { field: 'OfficePhone', value: '座机号' },
+        { field: 'CompanyType', value: '企业性质' },
+        { field: 'ProvinceCode', value: '所属地区' },
+        { field: 'FirmSize', value: '设计人员数' },
+        { field: 'Industry', value: '行业细分' },
+        // { field: 'BusinessScope', value: '业务范围' },
+        { field: 'Address', value: '通信地址' },
+        { field: 'PostNumber', value: '邮政编码' },
+        { field: 'SaleName', value: '销售负责人' },
+        // { field: 'Comment', value: '备注' }
+        { field: 'CreateUserName', value: '创建人' }
+      ],
+      formInline: {},
+      optionsList: {
+        SalesChanceStage: {
+          field: 'SalesChanceStage',
+          list: ['初期沟通', '需求分析', '方案报价', '商务谈判', '成功', '成功', '搁置']
+        },
+        ContacterMobile: {
+          field: 'ContacterMobile',
+          list: ['电话', '微信', '信息', '其他']
+        }
+      },
+      // 导入
+      showCRMImport: false,
+      // 导出
+      showCRMExport: false,
+      // 导出选中参数
+      exportParams: {},
+      crmType: 'customer',
+      loading: false,
+      addLoading: false,
+      rightsList: [],
+      radioInput: '',
+      otherInput: '',
+      isOtherOpt: false,
+      // 跟进弹窗
+      isFollowDialog: false,
+      followLoading: false,
+      followFormRules: {
+        CustomerName: [
+          { required: true, message: '联系人不能为空', trigger: 'blur' }
+        ]
+      },
+      followForm: {}
+    }
+  },
+  mounted () {
+  },
+  methods: {
+    // 获取左边padding
+    getPaddingLeft (item, index) {
+      if (item.showblock && item.showblock === true) {
+        return '25px'
+      }
+      return item.styleIndex % 2 === 0 ? '0' : '25px'
+    },
+    // 获取左边padding
+    getPaddingRight (item, index) {
+      if (item.showblock && item.showblock === true) {
+        return '0'
+      }
+
+      return item.styleIndex % 2 === 0 ? '25px' : '0'
+    },
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      if (
+        column.property === 'CustomerName' ||
+        column.property === 'businessCheck'
+      ) {
+        return { color: '#4D88FF', cursor: 'pointer' }
+      } else {
+        return ''
+      }
+    },
+    // ----delete
+    deleteCustomer (id) {
+      this.$confirm('确定删除?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          DeleteCustomer([{'Id': id}]).then(res => {
+            if (res.data.ErrorCode === 200) {
+              this.$message.success(res.data.Message)
+              this.getList()
+            } else {
+              this.$message.error(res.data.Message)
+            }
+          })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    },
+    followCustomer (row) {
+      // this.isFollowDialog = true
+      this.rowID = row.Id
+      this.rowType = 'customer'
+      this.showDview = true
+      this.timer = new Date().getTime()
+    },
+    followHandleClose () {
+      this.isFollowDialog = false
+      this.$refs.followDialogRef.resetFields()
+    },
+    followDialogSubmit () {
+      this.isFollowDialog = false
+      this.$refs.followDialogRef.resetFields()
+    },
+    /**
+     * 新建客户同时新建联系人
+     */
+    relativeBusinessClick (data) {
+      this.rowID = data.businessId
+      this.rowType = 'business'
+      this.showDview = true
+    },
+    // 商机信息查看
+    businessCheckClick (e, scope) {
+      if (scope.row.businessCount === 0) {
+        return
+      }
+      this.$set(scope.row, 'show', !scope.row.show)
+      // const popoverEl = e.target.parentNode
+      // popoverEl.__vue__.showPopper = !scope.row.show
+    },
+    businessClose (e, scope) {
+      // const popoverEl = e.parentNode
+      // popoverEl.__vue__.showPopper = false
+      this.$set(scope.row, 'show', false)
+    },
+    exportFile () {
+      this.showCRMExport = true
+    },
+    importFile () {
+      this.showCRMImport = true
+    },
+    queryList (data) {
+      console.log(data)
+      this.headObj = data
+      this.getList(data)
+    }
+
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../styles/table.scss';
+.crm-create-container {
+  position: relative;
+  height: 100%;
+}
+
+.crm-create-flex {
+  position: relative;
+  overflow-x: hidden;
+  overflow-y: auto;
+  flex: 1;
+}
+
+.crm-create-header {
+  height: 40px;
+  margin-bottom: 20px;
+  padding: 0 10px;
+  flex-shrink: 0;
+  display: flex;
+  .close {
+    display: block;
+    // width: 15px;
+    // height: 15px;
+    margin-right: -10px;
+    padding: 10px;
+    cursor: pointer;
+  }
+}
+
+.crm-create-body {
+  flex: 1;
+  // overflow-x: hidden;
+  // overflow-y: auto;
+  max-height: 500px;
+}
+
+/** 将其改变为flex布局 */
+.crm-create-box {
+  display: flex;
+  flex-wrap: wrap;
+  padding: 0 10px;
+}
+
+.crm-create-item {
+  flex: 0 0 45%;
+  flex-shrink: 0;
+  // overflow: hidden;
+  padding-bottom: 30px;
+}
+
+// 占用一整行
+.crm-create-block-item {
+  flex: 0 0 100%;
+  flex-shrink: 0;
+  padding-bottom: 10px;
+}
+
+.el-form-item /deep/ .el-form-item__label {
+  // line-height: 32px;
+  font-size: 13px;
+  color: #333333;
+  position: relative;
+  padding-left: 8px;
+  padding-bottom: 0;
+}
+
+.el-form /deep/ .el-form-item {
+  margin-bottom: 0px;
+}
+
+.el-form /deep/ .el-form-item.is-required .el-form-item__label:before {
+  content: '*';
+  color: #f56c6c;
+  margin-right: 4px;
+  position: absolute;
+  left: 0;
+  top: 8px;
+}
+
+.handle-bar {
+  position: relative;
+  .handle-button {
+    float: right;
+    margin-top: 5px;
+    margin-right: 20px;
+  }
+}
+
+.el-button + .el-button {
+  margin-left: 0;
+}
+.container{
+  position: relative;
+  .popover-foot{
+    position: relative;
+    left: 38%;
+    width: 100%;
+    margin-bottom: 30px;
+  }
+}
+.content {
+  position: relative;
+  padding: 32px 40px;
+  display: flex;
+  flex-direction: column;
+  margin-bottom: 40px;
+  height: 355px;
+  overflow: hidden;
+  overflow-y: auto;
+  border-bottom: 1px solid #f1f1f1;
+  .content-wrap{
+    width: 100%;
+  }
+  .otherOpt{
+    margin-bottom: 15px;
+    width: 100%;
+  }
+  p{
+    margin-bottom: 36px;
+    font-size: 14px;
+    font-weight: 550;
+    color: #333;
+
+  }
+  .con-group{
+    margin-bottom: 28px;
+  }
+  .content-wrap /deep/.el-radio-group .el-radio{
+    margin-right: 64px;
+    margin-bottom: 12px;
+  }
+  .content-wrap /deep/.el-radio-group .el-radio .el-radio__label{
+    font-weight: 400;
+    color: #666666;
+    font-size: 14px;
+  }
+}
+.header {
+  padding: 16px 30px;
+  flex-shrink: 0;
+  border-bottom: 1px solid #F1F1F1;
+  .name {
+    font-size: 13px;
+    padding: 0 10px;
+    color: #333;
+  }
+  .detail {
+    font-size: 12px;
+    padding: 0 10px;
+    color: #aaaaaa;
+    border-left: 1px solid #aaaaaa;
+  }
+  .close {
+    position: absolute;
+    width: 40px;
+    height: 40px;
+    top: 5px;
+    right: 10px;
+    padding: 10px;
+  }
+}
+.customer{
+  // .xr-btn--orange{
+  //   background-color: #ff6a00;
+  //   border-color: #ff6a00;
+  // }
+  .customerName{
+    cursor:pointer;
+    // color: #ff6a00
+  }
+}
+</style>
+<style lang="scss">
+.customer{
+  /deep/.el-input .el-input-group__append{
+    // background-color: #ff7d00;
+    // border-color: #ff7d00;
+    // color: #fff;
+  }
+}
+/* 新建和编辑 */
+.new-dialog-title {
+  padding-left: 10px;
+  margin-bottom: 3px;
+  border-left: 2px solid #4D88FF;
+}
+.user-dialog{
+  height: 20vh;
+}
+.base-dialog{
+  height: 35vh;
+}
+.followDialog{
+  height: 35vh;
+}
+.new-cusDialog-form {
+  overflow-y: auto;
+  padding: 20px;
+  display: flex;
+  flex-wrap: wrap;
+}
+
+.new-cusDialog-form /deep/ .el-form-item {
+  // width: 50%;
+  margin: 0;
+  padding-bottom: 10px;
+}
+.new-cusDialog-form /deep/ .el-form-item .el-form-item__label {
+  line-height: normal;
+  font-size: 13px;
+  color: #333333;
+  position: relative;
+  padding-bottom: 8px;
+}
+.new-cusDialog-form /deep/ .crm-create-item.el-form-item .el-form-item__content {
+  width: 70%;
+}
+.new-cusDialog-form /deep/ .crm-create-block-item.el-form-item .el-form-item__content {
+  width: 90%;
+}
+.new-cusDialog-form /deep/ .crm-create-item.el-form-item .el-form-item__content .el-input.is-disabled .el-input__inner{
+  cursor: pointer;
+}
+.crm-create-item {
+  flex: 0 0 45%;
+  flex-shrink: 0;
+  // overflow: hidden;
+  padding-bottom: 10px;
+}
+
+// 占用一整行
+.crm-create-block-item {
+  flex: 0 0 100%;
+  flex-shrink: 0;
+  padding-bottom: 10px;
+}
+.nav-dialog-div {
+  margin-bottom: 20px;
+}
+.nav-dialog-div /deep/ .el-input {
+  width: auto;
+}
+</style>
diff --git a/src/views/clients/customer/components/BusinessCheck.vue b/src/views/clients/customer/components/BusinessCheck.vue
new file mode 100644
index 0000000..ee6bd92
--- /dev/null
+++ b/src/views/clients/customer/components/BusinessCheck.vue
@@ -0,0 +1,170 @@
+<template>
+  <div
+    v-empty="!canShowIndex"
+    class="container"
+    xs-empty-icon="nopermission"
+    xs-empty-text="暂无权限">
+    <flexbox class="header">
+      <div class="name">{{ data.row.customerName }}</div>
+      <div class="detail">商机({{ list.length }})</div>
+      <img
+        class="close"
+        src="@/assets/img/task_close.png"
+        @click="hidenView" >
+    </flexbox>
+    <el-table
+      v-loading="loading"
+      :data="list"
+      :cell-style="cellStyle"
+      :header-cell-style="headerCellStyle"
+      height="250"
+      style="margin-right:3px;"
+      highlight-current-row
+      @row-click="handleRowClick">
+      <el-table-column
+        v-for="(item, index) in fieldList"
+        :key="index"
+        :prop="item.prop"
+        :label="item.label"
+        align="center"
+        header-align="center"
+        show-overflow-tooltip/>
+    </el-table>
+  </div>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+// import { crmCustomerQueryBusiness } from '@/api/customermanagement/customerManage'
+
+export default {
+  /** 客户管理 的 客户列表  相关商机列表 */
+  name: 'BusinessCheck',
+  components: {},
+  props: {
+    show: Boolean,
+    data: {
+      type: Object,
+      default: () => {
+        return {
+          row: {
+            name: ''
+          }
+        }
+      }
+    }
+  },
+  data () {
+    return {
+      loading: false,
+      list: [],
+      fieldList: []
+    }
+  },
+  computed: {
+    ...mapGetters(['crm']),
+    canShowIndex () {
+      // return this.crm.business && this.crm.business.index
+      return 2
+    }
+  },
+  watch: {
+    show: {
+      handler (val) {
+        if (
+          this.canShowIndex &&
+          val &&
+          this.data.row &&
+          this.data.row.businessCount > 0 &&
+          this.list.length === 0
+        ) {
+          this.getDetail()
+        }
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+  mounted () {
+    this.fieldList.push({
+      prop: 'businessName',
+      width: '200',
+      label: '商机名称'
+    })
+    this.fieldList.push({
+      prop: 'money',
+      width: '200',
+      label: '商机金额'
+    })
+    this.fieldList.push({
+      prop: 'customerName',
+      width: '200',
+      label: '客户名称'
+    })
+    this.fieldList.push({ prop: 'typeName', width: '200', label: '商机状态组' })
+    this.fieldList.push({ prop: 'statusName', width: '200', label: '状态' })
+  },
+  methods: {
+    getDetail () {
+      this.loading = true
+      // crmCustomerQueryBusiness({
+      //   pageType: 0,
+      //   customerId: this.data.row.customerId
+      // })
+      //   .then(res => {
+      //     this.loading = false
+      //     this.list = res.data
+      //   })
+      //   .catch(() => {
+      //     this.loading = false
+      //   })
+    },
+    hidenView () {
+      document.querySelector('#app').click()
+      this.$emit('close', this.$el, this.data)
+    },
+    // 当某一行被点击时会触发该事件
+    handleRowClick (row, column, event) {
+      this.$emit('click', row)
+    },
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      return { fontSize: '12px', textAlign: 'center', cursor: 'pointer' }
+    },
+    headerCellStyle ({ row, column, rowIndex, columnIndex }) {
+      return { fontSize: '12px', textAlign: 'center' }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.container {
+  position: relative;
+}
+
+.header {
+  height: 40px;
+  padding: 0 10px;
+  flex-shrink: 0;
+  .name {
+    font-size: 13px;
+    padding: 0 10px;
+    color: #333;
+  }
+  .detail {
+    font-size: 12px;
+    padding: 0 10px;
+    color: #aaaaaa;
+    border-left: 1px solid #aaaaaa;
+  }
+  .close {
+    position: absolute;
+    width: 40px;
+    height: 40px;
+    top: 0;
+    right: 10px;
+    padding: 10px;
+  }
+}
+</style>
diff --git a/src/views/clients/customer/components/CustomerFollow.vue b/src/views/clients/customer/components/CustomerFollow.vue
new file mode 100644
index 0000000..67accb2
--- /dev/null
+++ b/src/views/clients/customer/components/CustomerFollow.vue
@@ -0,0 +1,184 @@
+<template>
+  <div class="f-container">
+    <div v-loading="sendLoading" v-show="crmType === 'business'">
+      <mix-add
+        ref="mixadd"
+        :crm-type="crmType"
+        :id="id"
+        :show-relative-business="true"
+        :show-relative-contacts="true"
+        @mixadd-info="submitInfo"/>
+    </div>
+    <div class="log-cont">
+      <!--<flexbox>
+        <flexbox
+          v-for="(item, index) in logTypes"
+          :key="index"
+          style="width: auto;"
+          @click.native="logTabsClick(item,index)">
+          <div
+            :style="{ color: logType==item.type ? '#F18C70' : '#777'}"
+            class="log-tabs-item">{{ item.name }}</div>
+          <div
+            v-if="logTypes.length -1 !== index"
+            class="log-tabs-line"/>
+        </flexbox>
+      </flexbox>-->
+      <keep-alive>
+        <component
+          :is="componentsName"
+          :id="id"
+          :crm-type="crmType"/>
+      </keep-alive>
+    </div>
+  </div>
+</template>
+
+<script>
+import MixAdd from '../../components/MixAdd'
+import RecordLog from '../../components/followLog/RecordLog' // 跟进记录
+import JournalLog from '../../components/followLog/JournalLog' // 日志列表
+import ExamineLog from '../../components/followLog/ExamineLog' // 审批列表
+import TaskLog from '../../components/followLog/TaskLog' // 任务日志列表
+import ScheduleLog from '../../components/followLog/ScheduleLog' // 日程日志列表
+import FollowRecordTable from '../../components/followLog/components/FollowRecordTable' // 跟进记录
+import { AddFollowRecord, MakeFollowRecordCompleted } from '@/api/customermanagement/customerManage'
+import followLogType from '@/views/clients/mixins/followLogType'
+
+export default {
+  /** 客户管理 的 客户详情 的 跟进记录 */
+  name: 'CustomerFollow',
+  components: {
+    MixAdd,
+    RecordLog,
+    JournalLog,
+    ExamineLog,
+    TaskLog,
+    ScheduleLog,
+    FollowRecordTable
+  },
+  mixins: [followLogType],
+  props: {
+    /** 模块ID */
+    id: [String, Number],
+    /** 没有值就是全部类型 有值就是当个类型 */
+    crmType: {
+      type: String,
+      default: ''
+    },
+    /** 是公海 默认是客户 */
+    isSeas: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    return {
+      sendLoading: false,
+      logType: 'record'
+    }
+  },
+  computed: {
+    logTypes () {
+      // if (this.oa) {
+      return [
+        { type: 'record', name: '跟进记录' }
+        // { type: 'log', name: '日志' },
+        // { type: 'examine', name: '审批' },
+        // { type: 'task', name: '任务' },
+        // { type: 'schedule', name: '日程' }
+      ]
+      // } else {
+      //   return [{ type: 'record', name: '跟进记录' }]
+      // }
+    },
+
+    componentsName () {
+      // if (this.logType === 'record') {
+      return 'FollowRecordTable'
+      // } else if (this.logType === 'log') {
+      //   return 'JournalLog'
+      // } else if (this.logType === 'examine') {
+      //   return 'ExamineLog'
+      // } else if (this.logType === 'task') {
+      //   return 'TaskLog'
+      // } else if (this.logType === 'schedule') {
+      //   return 'ScheduleLog'
+      // }
+      // return ''
+    }
+  },
+  watch: {
+    id: function (val) {}
+  },
+  mounted () {},
+  activated: function () {},
+  deactivated: function () {},
+  methods: {
+    /** 发布 时候的类型选择 */
+    logTabsClick (item, index) {
+      this.logType = item.type
+    },
+    /** 告诉mixad 返回数据 */
+    // sendInfo () {
+    //   this.$refs.mixadd.$emit('submit-info')
+    // },
+    /** 快捷添加框内 返回的数据用于上传 */
+    submitInfo (data) {
+      console.log(data)
+      if (data.isEvent && !data.nextTime) {
+        this.$message.error('请选择下次联系时间')
+        return
+      } else if (!data.content) {
+        this.$message.error('请输入跟进内容')
+        return
+      }
+
+      var params = {}
+      params.SourceId = this.id
+      params.Title = data.title
+      params.Content = data.content
+      params.FollowType = data.followTypeId
+      params.FollowWay = data.wayTypeId
+      // var businessIds = data.business.map(function (element, index, array) {
+      //   return element.businessId
+      // })
+      // var contactsIds = data.contacts.map(function (element, index, array) {
+      //   return element.contactsId
+      // })
+
+      // params.batchId = data.batchId
+      // params.businessIds = businessIds.join(',')
+      // params.contactsIds = contactsIds.join(',')
+
+      params.IsCompleted = data.isEvent
+      params.FollowTime = data.nextTime || ''
+
+      this.sendLoading = true
+      if (data.isEvent) {
+        MakeFollowRecordCompleted({'Id': this.id}).then(res => {
+          this.$message.success('完成跟进')
+        })
+      }
+      AddFollowRecord(params)
+        .then(res => {
+          this.sendLoading = false
+          this.$message.success('发布成功')
+          // 重置页面
+          this.$refs.mixadd.resetInfo()
+          // this.isEvent = false
+          // this.nextTime = ''
+          // 刷新数据
+          this.$bus.emit('follow-log-refresh', { type: 'follow-record-table' })
+        })
+        .catch(() => {
+          this.sendLoading = false
+        })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../../styles/followlog.scss';
+</style>
diff --git a/src/views/clients/customer/test.vue b/src/views/clients/customer/test.vue
new file mode 100644
index 0000000..609efdb
--- /dev/null
+++ b/src/views/clients/customer/test.vue
@@ -0,0 +1,151 @@
+<template>
+<div class="custom-demo-view" style="padding: 1rem;">
+    <div>
+        <el-tabs v-if="reload" v-model="tabIndex" @tab-click="jump">
+            <el-tab-pane :label="tabs[0].title" v-if="tabs[0].isShow" name="0"></el-tab-pane>
+            <el-tab-pane :label="tabs[1].title" v-if="tabs[1].isShow" name="1"></el-tab-pane>
+            <el-tab-pane :label="tabs[2].title" v-if="tabs[2].isShow" name="2"></el-tab-pane>
+        </el-tabs>
+    </div>
+    <div class="scroll-content" @scroll="onScroll" :style="'overflow-x: hidden; overflow-y: auto;height:' + contentStyleObj.height">
+        <!-- 用户管理 -->
+        <div :ref="tabs[0].refName" class="scroll-item" style="padding-top: 1rem;">
+            <div class="line-title">
+            <h2>{{tabs[0].title}}</h2>
+            </div>
+            <div>
+                <p style="height:40px" v-for="item in [0,1,2,4,5,6,7,8,9,10,11,12,13,14,15,16]" :key="item">待发货符合规范化如故</p>
+            </div>
+        </div>
+        <!-- 配置管理 -->
+        <div :ref="tabs[1].refName" class="scroll-item" style="padding-top: 1rem;">
+            <div class="line-title">
+            <h2>{{tabs[1].title}}</h2>
+            </div>
+            <div>
+                <p style="height:40px" v-for="item in [0,1,2,4,5,6,7,8,9,10,11,12,13,14,15,16]" :key="item">新能说出的基本功发到你DNF不得发布</p>
+            </div>
+        </div>
+        <!-- 角色管理 -->
+        <div :ref="tabs[2].refName" class="scroll-item" style="padding-top: 1rem;top:5px;">
+            <div class="line-title">
+            <h2>{{tabs[2].title}}</h2>
+            </div>
+            <div>
+                <p v-for="item in [0,1,2,4,5,6,7,8,9,10,11,12,13,14,15,16]" :key="item">新水泥厂剧场版</p>
+            </div>
+        </div>
+    </div>
+  </div>
+</template>
+<script>
+export default {
+  name: 'test',
+  data () {
+    return {
+      reload: true,
+      tabIndex: '0',
+      contentStyleObj: {
+        height: '100px'
+      },
+      tabs: [
+        {
+          isShow: true,
+          title: '用户管理',
+          refName: 'setOneRef'
+        },
+        {
+          isShow: true,
+          title: '配置管理',
+          refName: 'setTwoRef'
+        },
+        {
+          isShow: true,
+          title: '角色管理',
+          refName: 'setThreeRef'
+        }
+      ]
+    }
+  },
+  methods: {
+    refresh () {
+      this.reload = false
+      this.$nextTick(() => (this.reload = true))
+    },
+    // tab click
+    jump (index, info) {
+      let target = document.querySelector('.scroll-content')
+      let scrollItems = document.querySelectorAll('.scroll-item')
+      console.log(target, scrollItems)
+      // 判断滚动条是否滚动到底部
+      if (target.scrollHeight <= target.scrollTop + target.clientHeight) {
+        this.tabIndex = index.index.toString()
+      }
+      let totalY = scrollItems[index.index].offsetTop - scrollItems[0].offsetTop // 锚点元素距离其offsetParent(这里是body)顶部的距离(待滚动的距离)
+      let distance = document.querySelector('.scroll-content').scrollTop // 滚动条距离滚动区域顶部的距离
+      // let distance = document.body.scrollTop || document.documentElement.scrollTop || window.pageYOffset // 滚动条距离滚动区域顶部的距离(滚动区域为窗口)
+      // 滚动动画实现, 使用setTimeout的递归实现平滑滚动,将距离细分为50小段,10ms滚动一次
+      // 计算每一小段的距离
+      let step = totalY / 50
+      if (totalY > distance) {
+        smoothDown(document.querySelector('.scroll-content'))
+      } else {
+        let newTotal = distance - totalY
+        step = newTotal / 50
+        smoothUp(document.querySelector('.scroll-content'))
+      }
+
+      // 参数element为滚动区域
+      function smoothDown (element) {
+        if (distance < totalY) {
+          distance += step
+          element.scrollTop = distance
+          setTimeout(smoothDown.bind(this, element), 10)
+        } else {
+          element.scrollTop = totalY
+        }
+      }
+
+      // 参数element为滚动区域
+      function smoothUp (element) {
+        if (distance > totalY) {
+          distance -= step
+          element.scrollTop = distance
+          setTimeout(smoothUp.bind(this, element), 10)
+        } else {
+          element.scrollTop = totalY
+        }
+      }
+    },
+    // 滚动条滚动
+    onScroll (e) {
+      let scrollItems = document.querySelectorAll('.scroll-item')
+      for (let i = scrollItems.length - 1; i >= 0; i--) {
+        // 判断滚动条滚动距离是否大于当前滚动项可滚动距离
+        let judge = e.target.scrollTop >= scrollItems[i].offsetTop - scrollItems[0].offsetTop - 400
+        if (judge) {
+          this.tabIndex = i.toString()
+          break
+        }
+      }
+    },
+    getHight () {
+      this.contentStyleObj.height = (window.innerHeight - 190) + 'px'
+    }
+  },
+  created () {
+    this.getHight()
+    window.addEventListener('resize', this.getHight)
+  },
+  destroyed () {
+    window.removeEventListener('resize', this.getHight)
+  }
+}
+</script>
+<style lang="less" scoped>
+.custom-demo-view{
+  width: 100%;
+  height: 100%;
+  background: #f1f1f1;
+}
+</style>
diff --git a/src/views/clients/mixins/detail.js b/src/views/clients/mixins/detail.js
new file mode 100644
index 0000000..99141eb
--- /dev/null
+++ b/src/views/clients/mixins/detail.js
@@ -0,0 +1,127 @@
+import {
+  mapGetters
+} from 'vuex'
+
+import { moneyFormat } from '@/utils'
+
+export default {
+  data () {
+    return {}
+  },
+  props: {
+    /** 是公海 默认是客户 */
+    isSeas: {
+      type: Boolean,
+      default: false
+    }
+  },
+
+  computed: {
+    ...mapGetters(['crm']),
+    // 能否查看详情
+    canShowDetail () {
+      // if (this.detailData.length === 0) {
+      //   return false
+      // }
+      // return this.crm && this.crm[this.crmType] && this.crm[this.crmType].read
+      return true
+    }
+  },
+
+  watch: {
+    id: function () {
+      if (this.canShowDetail) {
+        this.getDetial()
+      }
+    }
+  },
+
+  mounted () {
+    if (this.canShowDetail) {
+      this.getDetial()
+    }
+  },
+
+  methods: {
+    /** 顶部头 操作 */
+    detailHeadHandle (data) {
+      console.log(data)
+      if (data.type === 'edit') {
+        this.isCreate = true
+      } else if (data.type === 'delete') {
+        this.hideView()
+      } else if (data.type === 'discard') {
+        this.getDetial()
+      }
+      this.$emit('handle', data)
+    },
+    moneyFormat (money) {
+      return moneyFormat(money)
+    },
+    //* * tab标签点击 */
+    handleClick (tab, event) {},
+    // 滚动条滚动
+    onScroll (e) {
+      console.log('onscrll事件')
+      let scrollItems = document.querySelectorAll('.scroll-item')
+      console.log(scrollItems)
+      for (let i = scrollItems.length - 1; i >= 0; i--) {
+        // 判断滚动条滚动距离是否大于当前滚动项可滚动距离
+        let judge = e.target.scrollTop >= scrollItems[i].offsetTop - scrollItems[0].offsetTop
+        // console.log(e.target.scrollTop, scrollItems[i].offsetTop, scrollItems[0].offsetTop)
+        if (judge) {
+          this.tabCurrentName = this.tabnames[i].name
+
+          break
+        }
+      }
+    },
+    jump (index, info) {
+      console.log(index, info, this.tabCurrentName)
+      let target = document.querySelector('.t-loading-content')
+      let scrollItems = document.querySelectorAll('.scroll-item')
+      // 判断滚动条是否滚动到底部
+      if (target.scrollHeight <= target.scrollTop + target.clientHeight) {
+        this.tabCurrentName = this.tabnames[index.index].name
+      }
+      let totalY = scrollItems[index.index].offsetTop - scrollItems[0].offsetTop // 锚点元素距离其offsetParent(这里是body)顶部的距离(待滚动的距离)
+      let distance = document.querySelector('.t-loading-content').scrollTop // 滚动条距离滚动区域顶部的距离
+      // let distance = document.body.scrollTop || document.documentElement.scrollTop || window.pageYOffset // 滚动条距离滚动区域顶部的距离(滚动区域为窗口)
+      // 滚动动画实现, 使用setTimeout的递归实现平滑滚动,将距离细分为50小段,10ms滚动一次
+      // 计算每一小段的距离
+      let step = totalY / 50
+      if (totalY > distance) {
+        smoothDown(document.querySelector('.t-loading-content'))
+      } else {
+        let newTotal = distance - totalY
+        step = newTotal / 50
+        smoothUp(document.querySelector('.t-loading-content'))
+      }
+
+      // 参数element为滚动区域
+      function smoothDown (element) {
+        if (distance < totalY) {
+          distance += step
+          element.scrollTop = distance
+          setTimeout(smoothDown.bind(this, element), 10)
+        } else {
+          element.scrollTop = totalY
+        }
+      }
+
+      // 参数element为滚动区域
+      function smoothUp (element) {
+        if (distance > totalY) {
+          distance -= step
+          element.scrollTop = distance
+          setTimeout(smoothUp.bind(this, element), 10)
+        } else {
+          element.scrollTop = totalY
+        }
+      }
+    }
+  },
+
+  deactivated: function () { }
+
+}
diff --git a/src/views/clients/mixins/followLogType.js b/src/views/clients/mixins/followLogType.js
new file mode 100644
index 0000000..37dbe98
--- /dev/null
+++ b/src/views/clients/mixins/followLogType.js
@@ -0,0 +1,102 @@
+// import {
+//   crmSettingRecordListAPI
+// } from '@/api/clients/common'
+import { GetCustomerContacterList } from '@/api/customermanagement/customerManage'
+import { mapGetters } from 'vuex'
+
+export default {
+  data () {
+    return {
+      /** 记录类型 */
+      followTypes: [],
+      followType: '',
+      wayTypes: [],
+      wayType: '',
+      contactTypes: [],
+      contactType: ''
+    }
+  },
+
+  computed: {
+    ...mapGetters([
+      'oa'
+    ]),
+    showOAPermission () {
+      // return this.oa
+      return true
+    }
+  },
+
+  created () {
+    this.getFollowLogType()
+    console.log('ccccccccc', this.detail)
+    // if (this.detail) {
+    //   this.getContact()
+    // }
+  },
+
+  methods: {
+    /**
+     * 获取详情
+     */
+    getFollowLogType () {
+      this.loading = true
+      this.loading = false
+      this.followTypes = [
+        { type: 0, name: '默认其他' },
+        { type: 1, name: '客户' },
+        { type: 2, name: '联系人' },
+        { type: 3, name: '商机' },
+        { type: 4, name: '合同管理' },
+        { type: 5, name: '工单' },
+        { type: 6, name: '报价单' },
+        { type: 7, name: '合同' },
+        { type: 8, name: '日程' },
+        { type: 9, name: '开票' },
+        { type: 10, name: '回款' },
+        { type: 11, name: '审批' }
+      ]
+      this.followType = this.followTypes[0].name
+      this.wayTypes = [
+        { type: 1, name: '电话' },
+        { type: 2, name: '在线沟通' },
+        { type: 3, name: '邮件或短信' },
+        { type: 4, name: '上门拜访' }
+      ]
+      this.wayType = this.wayTypes[0].name
+      this.wayTypeId = this.wayTypes[0].type
+      if (this.crmType === 'business') {
+        this.getContact()
+      }
+    },
+    getContact () {
+      let params = {
+        'PageIndex': 1,
+        'PageSize': 9999,
+        Id: this.detail.CustomerId
+      }
+      GetCustomerContacterList(params).then(res => {
+        if (res.data.ErrorCode === 200 && res.data.Result !== 0) {
+          let dataList = res.data.Result.List || []
+          if (res.data.Result.Count > 0) {
+            this.contactTypes = dataList.map(item => {
+              return {
+                type: item.Id,
+                name: item.RealName
+              }
+            })
+          } else {
+            this.contactTypes = [{type: '',
+              name: '暂无数据'}]
+          }
+          this.contactType = this.contactTypes[0].name
+          this.contactTypeId = this.contactTypes[0].type
+        } else {
+          this.$message.error(res.data.Message)
+        }
+      })
+    }
+  },
+  deactivated: function () { }
+
+}
diff --git a/src/views/clients/mixins/loading.js b/src/views/clients/mixins/loading.js
new file mode 100644
index 0000000..23a0dd5
--- /dev/null
+++ b/src/views/clients/mixins/loading.js
@@ -0,0 +1,29 @@
+import {
+  Loading
+} from 'element-ui'
+
+export default {
+  data () {
+    return {
+      loading: false,
+      tab_loading: null // 放在 tabs-content 里客户的
+    }
+  },
+
+  watch: {
+    loading: function (val) {
+      if (val) {
+        this.tab_loading = Loading.service({
+          target: document.querySelector('.t-loading-content')
+        })
+      } else {
+        this.tab_loading.close()
+      }
+    }
+  },
+
+  mounted () {},
+
+  deactivated: function () {}
+
+}
diff --git a/src/views/clients/mixins/table.js b/src/views/clients/mixins/table.js
new file mode 100644
index 0000000..3f82c7d
--- /dev/null
+++ b/src/views/clients/mixins/table.js
@@ -0,0 +1,791 @@
+/** crm自定义列表 公共逻辑 */
+import {
+  mapGetters
+} from 'vuex'
+// import crmTypeModel from '@/views/clients/model/crmTypeModel'
+import CRMListHead from '../components/CRMListHead'
+import CRMTableHead from '../components/CRMTableHead'
+import FieldsSet from '../components/fieldsManager/FieldsSet'
+import Lockr from 'lockr'
+import { Loading } from 'element-ui'
+// import { moneyFormat } from '@/utils'
+import { GetCustomerPageList } from '@/api/customermanagement/customerManage'
+import { GetContacterList } from '@/api/customermanagement/contacts'
+import { GetSalesChanceList } from '@/api/customermanagement/business'
+import { GetAgreementList, GetManagementAgreementList } from '@/api/customermanagement/contract'
+import { GetQuotationSheetList, GetManagementQuotationSheetList } from '@/api/customermanagement/offer'
+import { GetOtherCustomerPageList, GetOtherSalesChanceList, GetOtherAgreementList } from '@/api/businessIntelligence/index'
+import { downloadFile } from '@/utils'
+
+export default {
+  components: {
+    CRMListHead,
+    CRMTableHead,
+    FieldsSet
+  },
+  data () {
+    return {
+      loading: false, // 加载动画
+      tableHeight: document.documentElement.clientHeight - 360, // 表的高度
+      list: [],
+      fieldList: [],
+      sortData: {}, // 字段排序
+      currentPage: 1,
+      // Lockr.get('crmPageSizes')
+      pageSize: 10,
+      pageSizes: [10, 30, 60, 100],
+      total: 0,
+      search: '', // 搜索内容
+      /** 控制详情展示 */
+      rowID: '', // 行信息
+      rowType: '', // 详情类型
+      showDview: false,
+      /** 高级筛选 */
+      filterObj: {}, // 筛选确定数据
+      headObj: {}, // 筛选顶部数据
+      sceneId: '', // 场景筛选ID
+      sceneName: '', // 场景名字
+      /** 列表展示字段管理 */
+      showFieldSet: false,
+      /** 勾选行 */
+      // 勾选数据 用于全局导出
+      selectionList: [],
+      /** 格式化规则 */
+      formatterRules: {},
+      isCreate: false,
+      editData: {},
+      filterFormerData: {} // 筛选值
+    }
+  },
+
+  computed: {
+    ...mapGetters(['crm'])
+  },
+
+  mounted () {
+    /** 控制table的高度 */
+    window.onresize = () => {
+      this.updateTableHeight()
+    }
+    this.getList()
+  },
+
+  methods: {
+    /** 获取列表数据 */
+    getList (data) {
+      let isFilter
+      if (data) {
+        this.currentPage = 1
+        this.pageSize = 10
+        if (data.list) {
+          // 头部筛选
+          isFilter = 1
+          this.filterFormerData = data.list
+        } else if (data.tableType) {
+          // 表头筛选
+          isFilter = 2
+        }
+      }
+      let isFilterBoo = Object.values(this.filterFormerData).length > 0
+      this.loading = true
+      let crmIndexRequest = this.getIndexRequest()
+      let params = {}
+      if (this.crmType === 'customer' || this.crmType === 'businessCustomer') {
+        params = {
+          'PageIndex': this.currentPage,
+          'PageSize': this.pageSize,
+          'SelectOwnedType': isFilterBoo ? this.filterFormerData.customer : 0,
+          'SalesChanceStage': isFilterBoo ? this.filterFormerData.businessType : '',
+          'Name': isFilterBoo ? this.filterFormerData.user : '',
+          'ProvinceCode': isFilterBoo ? this.filterFormerData.area : '',
+          'CreateStartTime': '',
+          'CreateEndTime': '',
+          'StartFollowTime': '',
+          'EndFolowTime': '',
+          'CompanyType': isFilter === 2 ? Lockr.get('comType') : '',
+          'CustomerIndustry': isFilter === 2 ? Lockr.get('casType') : ''
+        }
+        if (isFilterBoo) {
+          params['DepartmentUserType'] = this.filterFormerData.userType
+          params['Id'] = this.filterFormerData.customer
+          params['BrachUserId'] = this.filterFormerData.BrachUserId
+        }
+      } else if (this.crmType === 'contacts') {
+        params = {
+          'PageIndex': this.currentPage,
+          'PageSize': this.pageSize,
+          'SalesChanceStage': isFilterBoo ? this.filterFormerData.businessType : '',
+          'SelectOwnedType': isFilterBoo ? this.filterFormerData.customer : 0,
+          'BrachUserId': isFilterBoo ? this.filterFormerData.BrachUserId : '',
+          'ProvinceCode': isFilterBoo ? this.filterFormerData.area : '',
+          'Name': isFilterBoo ? this.filterFormerData.user : ''
+        }
+      } else if (this.crmType === 'business' || this.crmType === 'businessChances') {
+        params = {
+          'PageIndex': this.currentPage,
+          'PageSize': this.pageSize,
+          'SalesChanceStage': isFilterBoo ? this.filterFormerData.businessType : '',
+          'SelectOwnedType': isFilterBoo ? this.filterFormerData.customer : 0,
+          'Name': isFilterBoo ? this.filterFormerData.user : '',
+          'SalesChanceType': isFilterBoo ? this.filterFormerData.businessType : '',
+          'ProvinceCode': isFilterBoo ? this.filterFormerData.area : '',
+          'CreateStartTime': '',
+          'CreateEndTime': '',
+          'ProjectProperty': isFilter === 2 ? (data.tableType === '项目属性' ? data.value : '') : '',
+          'UploadStatusName': isFilter === 2 ? (data.tableType === '提交' ? data.value : '') : '',
+          'ReportStatusName': isFilter === 2 ? (data.tableType === '审批' ? data.value : '') : ''
+        }
+        if (isFilterBoo) {
+          params['DepartmentUserType'] = this.filterFormerData.userType
+          params['Id'] = this.filterFormerData.customer
+          params['BrachUserId'] = this.filterFormerData.BrachUserId
+        }
+      } else if (this.crmType === 'contract' || this.crmType === 'offers' || this.crmType === 'businessContract') {
+        params = {
+          'PageIndex': this.currentPage,
+          'PageSize': this.pageSize,
+          'SelectOwnedType': isFilterBoo ? this.filterFormerData.customer : 0,
+          'AuditStatus': 0,
+          'SealStatus': 0,
+          'Name': isFilterBoo ? this.filterFormerData.user : '',
+          'CreateStartTime': '',
+          'CreateEndTime': ''
+        }
+        if (isFilterBoo) {
+          params['DepartmentUserType'] = this.filterFormerData.userType
+          params['Id'] = this.filterFormerData.customer
+          params['BrachUserId'] = this.filterFormerData.BrachUserId
+        }
+        if (isFilter === 2) {
+          params['SealType'] = data.value
+        }
+      } else if (this.crmType === 'sealContract' || this.crmType === 'sealOffers') {
+        params = {
+          'PageIndex': this.currentPage,
+          'PageSize': this.pageSize,
+          'AuditStatus': 0,
+          'SealStatus': 0,
+          'Name': isFilterBoo ? this.filterFormerData.user : '',
+          'CreateStartTime': '',
+          'CreateEndTime': ''
+        }
+        if (isFilterBoo) {
+          params['DepartmentUserType'] = this.filterFormerData.userType
+          params['Id'] = this.filterFormerData.customer
+        }
+        if (isFilter === 2) {
+          params['SealType'] = data.value
+        }
+      }
+      crmIndexRequest(params)
+        .then(res => {
+          if (res.data.ErrorCode === 200) {
+            if (res.data.Result.Count > 0) {
+              this.list = res.data.Result.List
+            } else {
+              this.list = []
+            }
+            this.total = res.data.Result.Count
+            this.loading = false
+          } else {
+            this.$message.error(res.data.Message)
+            this.loading = false
+          }
+        })
+        .catch(() => {
+          this.loading = false
+        })
+    },
+    // 列表编辑
+    editList (row) {
+      console.log(row)
+      this.isCreate = true
+      this.editData = row
+    },
+    /** 获取列表请求 */
+    getIndexRequest () {
+      if (this.crmType === 'leads') {
+        // return crmLeadsIndex
+      } else if (this.crmType === 'customer') {
+        return GetCustomerPageList
+      } else if (this.crmType === 'contacts') {
+        return GetContacterList
+      } else if (this.crmType === 'business') {
+        return GetSalesChanceList
+      } else if (this.crmType === 'contract') {
+        return GetAgreementList
+      } else if (this.crmType === 'offers') {
+        return GetQuotationSheetList
+      } else if (this.crmType === 'sealContract') {
+        return GetManagementAgreementList
+      } else if (this.crmType === 'sealOffers') {
+        return GetManagementQuotationSheetList
+      } else if (this.crmType === 'receivables') {
+        // return crmReceivablesIndex
+      } else if (this.crmType === 'businessCustomer') {
+        return GetOtherCustomerPageList
+      } else if (this.crmType === 'businessContract') {
+        return GetOtherAgreementList
+      } else if (this.crmType === 'businessChances') {
+        return GetOtherSalesChanceList
+      }
+    },
+    /** 获取字段 */
+    getFieldList () {
+      if (this.fieldList.length === 0) {
+        this.loading = true
+      } else {
+        // 获取好字段开始请求数据
+        this.getList()
+      }
+    },
+    /** 格式化字段 */
+    fieldFormatter (row, column) {
+      // var aRules = this.formatterRules[column.property]
+      // if (aRules) {
+      //   return aRules.formatter(row[column.property])
+      // }
+      if (column.property === 'ReportStatus') {
+        switch (row[column.property]) {
+          case 0:
+            row[column.property] = '--'
+            break
+          case 1:
+            row[column.property] = '待提交'
+            break
+          case 2:
+            row[column.property] = '已提交'
+            break
+          case 3:
+            row[column.property] = '报备成功'
+            break
+          case 4:
+            row[column.property] = '报备失败'
+            break
+        }
+      } else if (column.property === 'SalesChanceStage') {
+        switch (row[column.property]) {
+          case 0:
+            row[column.property] = '--'
+            break
+          case 1:
+            row[column.property] = '初期沟通'
+            break
+          case 2:
+            row[column.property] = '需求分析'
+            break
+          case 3:
+            row[column.property] = '方案报价'
+            break
+          case 4:
+            row[column.property] = '商务谈判'
+            break
+
+          case 5:
+            row[column.property] = '成功'
+            break
+          case 6:
+            row[column.property] = '搁置'
+            break
+        }
+      } else if (column.property === 'UploadStatus') {
+        switch (row[column.property]) {
+          case 0:
+            row[column.property] = '--'
+            break
+          case 1:
+            row[column.property] = '待上传'
+            break
+          case 2:
+            row[column.property] = '审核中'
+            break
+          case 3:
+            row[column.property] = '已上传'
+            break
+        }
+      } else if (column.property === 'Sex') {
+        return { 1: '男', 2: '女' }[row.Sex]
+      } else if (column.property === 'IsCustomerDefault') {
+        return { true: '是', false: '否' }[row.IsCustomerDefault]
+      } else if (column.property === 'CompanyType') {
+        return {0: '暂无', 1: '国企', 2: '外企', 3: '民营', 4: '其他'}[row.CompanyType]
+      } else if (column.property === 'ExpectedAmount') {
+        return '¥' + JSON.parse(row.ExpectedAmount)
+      } else if (column.property === 'ChanceRequestType') {
+        switch (row[column.property]) {
+          case 0:
+            row[column.property] = 'Other'
+            break
+          case 1:
+            row[column.property] = 'LC'
+            break
+          case 2:
+            row[column.property] = 'ACAD'
+            break
+          case 3:
+            row[column.property] = 'AEC'
+            break
+          case 4:
+            row[column.property] = 'MFG'
+            break
+          case 5:
+            row[column.property] = 'MNE'
+            break
+        }
+      } else if (column.property === 'AuditStatus') {
+        switch (row[column.property]) {
+          case 0:
+            row[column.property] = '--'
+            break
+          case 1:
+            row[column.property] = '审批中'
+            break
+          case 2:
+            row[column.property] = '通过'
+            break
+          case 3:
+            row[column.property] = '驳回'
+            break
+        }
+      } else if (column.property === 'SealType') {
+        switch (row[column.property]) {
+          case 1:
+            row[column.property] = '合同章'
+            break
+          case 2:
+            row[column.property] = '公章'
+            break
+        }
+      } else if (column.property === 'IsSeal') {
+        switch (row[column.property]) {
+          case false:
+            row[column.property] = '否'
+            break
+          case true:
+            row[column.property] = '是'
+            break
+        }
+      } else if (column.property === 'TrackStatus') {
+        switch (row['IsAutoPassed']) {
+          case false:
+            row[column.property] = row[column.property]
+            break
+          case true:
+            row[column.property] = '通过'
+            break
+        }
+      }
+      // 如果需要格式化
+      return row[column.property] || '--'
+    },
+    /** */
+    /** */
+    /** 搜索操作 */
+    crmSearch (value) {
+      this.currentPage = 1
+      this.search = value
+      if (this.fieldList.length) {
+        this.getList()
+      }
+    },
+    /** 列表操作 */
+    // 当某一行被点击时会触发该事件
+    handleRowClick (row, column, event) {
+      console.log(row)
+      if (column.type === 'selection') {
+        return // 多选布局不能点击
+      }
+      if (this.crmType === 'leads') {
+        if (column.property === 'leadsName') {
+          this.rowID = row.leadsId
+          this.showDview = true
+        } else {
+          this.showDview = false
+        }
+      } else if (this.crmType === 'customer') {
+        if (column.property === 'businessCheck' && row.businessCount > 0) {
+          return // 列表查看商机不展示详情
+        }
+        if (column.property === 'CustomerName') {
+          this.rowID = row.Id
+          this.rowType = 'customer'
+          this.showDview = true
+          console.log('yesss')
+        }
+      } else if (this.crmType === 'contacts') {
+        if (column.property === 'CustomerName') {
+          this.rowID = row.CustomerId
+          this.rowType = 'customer'
+          this.showDview = true
+        } else if (column.property === 'RealName') {
+          this.rowID = row.Id
+          this.rowType = 'contacts'
+          this.showDview = true
+        } else {
+          this.showDview = false
+        }
+      } else if (this.crmType === 'business') {
+        if (column.property === 'CustomerName') {
+          this.isFollow = false
+          this.rowID = row.CustomerId
+          this.rowType = 'customer'
+          this.showDview = true
+        } else if (column.property === 'ChanceName') {
+          this.isFollow = false
+          this.rowID = row.Id
+          this.rowType = 'business'
+          this.showDview = true
+        }
+      } else if (this.crmType === 'contract') {
+        if (column.property === 'CustomerName') {
+          this.rowID = row.CustomerId
+          this.rowType = 'customer'
+          this.showDview = true
+        } else if (column.property === 'SalesChanceName') {
+          this.rowID = row.SalesChanceId
+          this.rowType = 'business'
+          this.showDview = true
+        } else if (column.property === 'ContacterName') {
+          this.rowID = row.contactsId
+          this.rowType = 'contacts'
+          this.showDview = true
+        } else if (column.property === 'BeforeSealFile' || column.property === 'SealFile') {
+          if (column.property === 'BeforeSealFile' && row.BeforeSealFile !== '') {
+            this.handleFile(column, row)
+          }
+          if (column.property === 'SealFile' && row.SealFile !== '') {
+            this.handleFile(column, row)
+          }
+        }
+      } else if (this.crmType === 'offers') {
+        if (column.property === 'CustomerName') {
+          this.rowID = row.CustomerId
+          this.rowType = 'customer'
+          this.showDview = true
+        } else if (column.property === 'SalesChanceName') {
+          this.rowID = row.SalesChanceId
+          this.rowType = 'business'
+          this.showDview = true
+        } else if (column.property === 'ContacterName') {
+          this.rowID = row.contactsId
+          this.rowType = 'contacts'
+          this.showDview = true
+        } else if (column.property === 'BeforeSealFile' || column.property === 'SealFile') {
+          if (column.property === 'BeforeSealFile' && row.BeforeSealFile !== '') {
+            this.handleFile(column, row)
+          }
+          if (column.property === 'SealFile' && row.SealFile !== '') {
+            this.handleFile(column, row)
+          }
+        }
+      } else if (this.crmType === 'sealContract') {
+        if (column.property === 'CustomerName') {
+          this.rowID = row.CustomerId
+          this.rowType = 'businessCustomer'
+          this.showDview = true
+        } else if (column.property === 'SalesChanceName') {
+          this.rowID = row.SalesChanceId
+          this.rowType = 'businessChances'
+          this.showDview = true
+        } else if (column.property === 'BeforeSealFile' || column.property === 'SealFile') {
+          if (column.property === 'BeforeSealFile' && row.BeforeSealFile !== '') {
+            this.handleFile(column, row)
+          }
+          if (column.property === 'SealFile' && row.SealFile !== '') {
+            this.handleFile(column, row)
+          }
+        }
+      } else if (this.crmType === 'sealOffers') {
+        if (column.property === 'CustomerName') {
+          this.rowID = row.CustomerId
+          this.rowType = 'businessCustomer'
+          this.showDview = true
+        } else if (column.property === 'SalesChanceName') {
+          this.rowID = row.SalesChanceId
+          this.rowType = 'businessChances'
+          this.showDview = true
+        } else if (column.property === 'BeforeSealFile' || column.property === 'SealFile') {
+          if (column.property === 'BeforeSealFile' && row.BeforeSealFile !== '') {
+            this.handleFile(column, row)
+          }
+          if (column.property === 'SealFile' && row.SealFile !== '') {
+            this.handleFile(column, row)
+          }
+        }
+      } else if (this.crmType === 'businessCustomer') {
+        if (column.property === 'businessCheck' && row.businessCount > 0) {
+          return // 列表查看商机不展示详情
+        }
+        if (column.property === 'CustomerName') {
+          this.rowID = row.Id
+          this.rowType = 'businessCustomer'
+          this.showDview = true
+          console.log('yesss')
+        }
+      } else if (this.crmType === 'businessChances') {
+        if (column.property === 'CustomerName') {
+          this.isFollow = false
+          this.rowID = row.CustomerId
+          this.rowType = 'businessCustomer'
+          this.showDview = true
+        } else if (column.property === 'ChanceName') {
+          this.isFollow = false
+          this.rowID = row.Id
+          this.rowType = 'businessChances'
+          this.showDview = true
+        }
+      } else if (this.crmType === 'businessContract') {
+        if (column.property === 'CustomerName') {
+          this.rowID = row.CustomerId
+          this.rowType = 'businessCustomer'
+          this.showDview = true
+        } else if (column.property === 'SalesChanceName') {
+          this.rowID = row.SalesChanceId
+          this.rowType = 'businessChances'
+          this.showDview = true
+        } else if (column.property === 'BeforeSealFile' || column.property === 'SealFile') {
+          if (column.property === 'BeforeSealFile' && row.BeforeSealFile !== '') {
+            this.handleFile(column, row)
+          }
+          if (column.property === 'SealFile' && row.SealFile !== '') {
+            this.handleFile(column, row)
+          }
+        }
+      } else if (this.crmType === 'receivables') {
+        if (column.property === 'CustomerName') {
+          this.rowID = row.Id
+          this.rowType = 'customer'
+          this.showDview = true
+        } else if (column.property === 'contractNum') {
+          this.rowID = row.contractId
+          this.rowType = 'contract'
+          this.showDview = true
+        } else if (column.property === 'number') {
+          this.rowID = row.receivablesId
+          this.rowType = 'receivables'
+          this.showDview = true
+        } else {
+          this.showDview = false
+        }
+      }
+      if (this.showDview) {
+        this.timer = new Date().getTime()
+      }
+    },
+    handleFile (column, data) {
+      if (column.property === 'BeforeSealFile') {
+        downloadFile({ path: data.BeforeSealFile, name: data.BeforeSealFile })
+      } else if (column.property === 'SealFile') {
+        downloadFile({ path: data.SealFile, name: data.SealFile })
+      }
+    },
+    /**
+     * 导出 线索 客户 联系人 产品
+     * @param {*} data
+     */
+    // 导出操作
+    exportInfos () {
+      var params = {
+        search: this.search
+      }
+      if (this.sceneId) {
+        params.sceneId = this.sceneId
+      }
+      if (this.filterObj && Object.keys(this.filterObj).length > 0) {
+        params.data = this.filterObj
+      }
+      let request
+      // 公海的请求
+      // if (this.isSeas) {
+      //   request = crmCustomerPoolExcelAllExport
+      // } else {
+      //   request = {
+      //     customer: crmCustomerExcelAllExport,
+      //     leads: crmLeadsExcelAllExport,
+      //     contacts: crmContactsExcelAllExport,
+      //     product: crmProductExcelAllExport
+      //   }[this.crmType]
+      // }
+      const loading = Loading.service({ fullscreen: true, text: '导出中...' })
+      request(params)
+        .then(res => {
+          var blob = new Blob([res.data], {
+            type: 'application/vnd.ms-excel;charset=utf-8'
+          })
+          var downloadElement = document.createElement('a')
+          var href = window.URL.createObjectURL(blob) // 创建下载的链接
+          downloadElement.href = href
+          downloadElement.download =
+            decodeURI(
+              res.headers['content-disposition'].split('filename=')[1]
+            ) || '' // 下载后文件名
+          document.body.appendChild(downloadElement)
+          downloadElement.click() // 点击下载
+          document.body.removeChild(downloadElement) // 下载完成移除元素
+          window.URL.revokeObjectURL(href) // 释放掉blob对象
+          loading.close()
+        })
+        .catch(() => {
+          loading.close()
+        })
+    },
+    /** 筛选操作 */
+    handleFilter (data) {
+      this.filterObj = data
+      var offsetHei = document.documentElement.clientHeight
+      var removeHeight = Object.keys(this.filterObj).length > 0 ? 310 : 240
+      this.tableHeight = offsetHei - removeHeight
+      this.currentPage = 1
+      this.getList()
+    },
+    /** 场景操作 */
+    handleScene (data) {
+      this.sceneId = data.id
+      this.sceneName = data.name
+      this.currentPage = 1
+      this.getFieldList()
+    },
+    /** 勾选操作 */
+    handleHandle (data) {
+      if (data.type === 'alloc' || data.type === 'get' || data.type === 'transfer' || data.type === 'transform' || data.type === 'delete' || data.type === 'put_seas') {
+        this.showDview = false
+      }
+
+      if (data.type !== 'edit') {
+        this.getList()
+      }
+    },
+    /** 自定义字段管理 */
+    setSave () {
+      this.fieldList = []
+      this.getFieldList()
+    },
+    /** */
+    /** 页面头部操作 */
+    listHeadHandle (data) {
+      console.log('cvvvvvvvvvvvvv', data)
+      // if (data.type === 'save-success') {
+      // 重新请求第一页数据
+      this.currentPage = 1
+      this.getList()
+      // }
+    },
+    // 设置点击
+    handleTableSet () {
+      this.showFieldSet = true
+    },
+    /**
+     * 字段排序
+     */
+    sortChange (column, prop, order) {
+      this.currentPage = 1
+      this.sortData = column
+      this.getList()
+    },
+    /** 勾选操作 */
+    // 当选择项发生变化时会触发该事件
+    handleSelectionChange (val) {
+      console.log(val)
+      this.selectionList = val // 勾选的行
+      this.$refs.crmTableHead.headSelectionChange(val)
+    },
+    // 当拖动表头改变了列的宽度的时候会触发该事件
+    handleHeaderDragend (newWidth, oldWidth, column, event) {
+      if (column.property) {
+        // const crmType = this.isSeas ? this.crmType + '_pool' : this.crmType
+        // crmFieldColumnWidth({
+        //   types: 'crm_' + crmType,
+        //   field: column.property,
+        //   width: newWidth
+        // })
+        //   .then(res => {
+        //   })
+        //   .catch(() => { })
+      }
+    },
+    // 更改每页展示数量
+    handleSizeChange (val) {
+      // Lockr.set('crmPageSizes', val)
+      this.pageSize = val
+      this.getList()
+    },
+    // 更改当前页数
+    handleCurrentChange (val) {
+      this.currentPage = val
+      this.getList()
+    },
+    // 0待审核、1审核中、2审核通过、3已拒绝 4已撤回 5未提交 修正 以 getStatusName 为准
+    getStatusStyle (status) {
+      if (status === 0) {
+        return {
+          'border-color': '#E6A23C',
+          'background-color': '#FDF6EC',
+          'color': '#E6A23C'
+        }
+      } else if (status === 3) {
+        return {
+          'border-color': '#409EFF',
+          'background-color': '#ECF5FF',
+          'color': '#409EFF'
+        }
+      } else if (status === 1) {
+        return {
+          'border-color': '#67C23A',
+          'background-color': '#F0F9EB',
+          'color': '#67C23A'
+        }
+      } else if (status === 2) {
+        return {
+          'border-color': '#F56C6B',
+          'background-color': '#FEF0F0',
+          'color': '#F56C6B'
+        }
+      } else if (status === 4 || status === 5) {
+        return {
+          'background-color': '#FFFFFF'
+        }
+      } else if (status === 6) {
+        return {
+          'border-color': '#E9E9EB',
+          'background-color': '#F4F4F5',
+          'color': '#909399'
+        }
+      }
+    },
+    getStatusName (status) {
+      if (status === 0) {
+        return '待审核'
+      } else if (status === 1) {
+        return '通过'
+      } else if (status === 2) {
+        return '拒绝'
+      } else if (status === 3) {
+        return '审核中'
+      } else if (status === 4) {
+        return '撤回'
+      } else if (status === 5) {
+        return '未提交'
+      } else if (status === 6) {
+        return '已作废'
+      }
+      return ''
+    },
+
+    /**
+     * 更新表高
+     */
+    updateTableHeight () {
+      var offsetHei = document.documentElement.clientHeight
+      var removeHeight = Object.keys(this.filterObj).length > 0 ? 310 : 240
+      this.tableHeight = offsetHei - removeHeight
+    },
+    /**
+     * 导出
+     */
+    exportData (params) {
+      this.$refs.listHead.handleTypeDrop('out', params)
+    }
+  },
+
+  beforeDestroy () { }
+}
diff --git a/src/views/clients/model/crmTypeModel.js b/src/views/clients/model/crmTypeModel.js
new file mode 100644
index 0000000..92e4b92
--- /dev/null
+++ b/src/views/clients/model/crmTypeModel.js
@@ -0,0 +1,12 @@
+export default {
+  leads: 1,
+  customer: 2,
+  contacts: 3,
+  product: 4,
+  business: 5,
+  contract: 6,
+  receivables: 7,
+  // 公海 8
+  receivables_plan: 8,
+  pool: 9
+}
diff --git a/src/views/clients/offers/OfferIndex.vue b/src/views/clients/offers/OfferIndex.vue
new file mode 100644
index 0000000..a33d8b5
--- /dev/null
+++ b/src/views/clients/offers/OfferIndex.vue
@@ -0,0 +1,261 @@
+<template>
+  <div>
+    <c-r-m-list-head
+      ref="listHead"
+      title="报价管理"
+      main-title="客户管理"/>
+      <c-r-m-table-head
+        ref="crmTableHead"
+        :crm-type="crmType"
+        :fieldList='fieldList'
+        @filter="handleFilter"
+        @handle="handleHandle"
+        @on-handle="listHeadHandle"
+        @scene="handleScene"
+        @queryList='queryList'/>
+      <el-card class="el-card">
+        <el-table
+          v-loading="loading"
+          id="crm-table"
+          :data="list"
+          :height="tableHeight"
+          :cell-style="cellStyle"
+          class="n-table--border"
+          border
+          highlight-current-row
+          style="width: 100%; z-index: 0;"
+          @row-click="handleRowClick"
+          @sort-change="sortChange"
+          @header-dragend="handleHeaderDragend"
+          @selection-change="handleSelectionChange">
+          <el-table-column
+            show-overflow-tooltip
+            type="selection"
+            align="left"
+            width="55"/>
+          <el-table-column
+            v-for="(item, index) in fieldList"
+            :key="index"
+            :prop="item.field"
+            :label="item.value"
+            :width="item.width"
+            :formatter="fieldFormatter"
+            sortable="custom"
+            show-overflow-tooltip>
+            <template
+              slot="header"
+              slot-scope="scope">
+              <div class="table-head-name">
+                  {{ scope.column.label }}
+                  <c-r-m-table-filter
+                    :show="scope.column.label==='合同类型'"
+                    :tableType="scope.column.label"
+                    @queryList="queryList">
+                  </c-r-m-table-filter>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column prop="BeforeSealFile" label="盖章前文件">
+            <template
+              slot="header"
+              slot-scope="scope">
+              <div class="table-head-name">{{ scope.column.label }}</div>
+            </template>
+            <template slot-scope="scope">
+              <span>{{scope.row.BeforeSealFile===''?'--':'点击下载'}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="SealFile" label="盖章后文件">
+            <template
+              slot="header"
+              slot-scope="scope">
+              <div class="table-head-name">{{ scope.column.label }}</div>
+            </template>
+            <template slot-scope="scope">
+              <span>{{scope.row.SealFile===''?'--':'点击下载'}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column
+            prop="operation"
+            width="150">
+            <template
+              slot="header"
+              slot-scope="scope">
+              <div class="table-head-name">操作</div>
+            </template>
+            <template slot-scope="scope">
+            <el-button type="text" size="small" :disabled="!scope.row.IsCanEdit"  @click='editList(scope.row)'>编辑 |</el-button>
+            <el-button type="text" size="small" :disabled="!scope.row.IsCanDelete"  @click='deleteModule(scope.row.Id)'>删除</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="p-contianer"  v-show='total>0'>
+          <el-pagination
+            :current-page="currentPage"
+            :page-sizes="pageSizes"
+            :page-size.sync="pageSize"
+            :total="total"
+            class="p-bar"
+            layout="total, sizes, prev, pager, next, jumper"
+            @size-change="handleSizeChange"
+            @current-change="handleCurrentChange"/>
+        </div>
+      </el-card>
+    <el-dialog title="编辑报价" :visible.sync="isCreate" :modal-append-to-body="false" width="30%">
+      <c-r-m-create-file-view
+        v-if="isCreate"
+        :id="rowID"
+        :action="createActionInfo"
+        crm-type="offers"
+        @save-success="createSaveSuccess"
+        @hiden-view="isCreate=false"/>
+    </el-dialog>
+    <!-- 相关详情页面 -->
+    <c-r-m-all-detail
+      :visible.sync="showDview"
+      :crm-type="rowType"
+      :id="rowID"
+      class="d-view"
+      @handle="handleHandle"/>
+    <fields-set
+      :crm-type="crmType"
+      :dialog-visible.sync="showFieldSet"
+      @set-success="setSave"/>
+  </div>
+</template>
+
+<script>
+import CRMAllDetail from '@/views/clients/components/CRMAllDetail'
+import table from '../mixins/table'
+import CRMTableFilter from '../components/CRMTableFilter'
+import CRMCreateFileView from '@/views/clients/components/CRMCreateFileView'
+import { DeleteQuotationSheet } from '@/api/customermanagement/offer'
+
+export default {
+  /** 客户管理 的 合同列表 */
+  name: 'OfferIndex',
+  components: {
+    CRMAllDetail,
+    CRMTableFilter,
+    CRMCreateFileView
+  },
+  mixins: [table],
+  data () {
+    return {
+      crmType: 'offers',
+      isCreate: false,
+      // 创建的相关信息
+      createActionInfo: { type: 'update', crmType: this.crmType, data: {} },
+      fieldList: [],
+      moneyData: null // 合同列表金额
+    }
+  },
+  computed: {
+    moneyPageData () {
+      // 未勾选展示合同总金额信息
+      if (this.selectionList.length === 0 && this.moneyData) {
+        return this.moneyData
+      } else {
+        let contractMoney = 0.0
+        let receivedMoney = 0.0
+        for (let index = 0; index < this.selectionList.length; index++) {
+          const element = this.selectionList[index]
+          // 2 审核通过的合同
+          if (element.checkStatus === 1) {
+            contractMoney += parseFloat(element.money)
+            receivedMoney += parseFloat(element.receivedMoney)
+          }
+        }
+        return {
+          contractMoney: contractMoney.toFixed(2),
+          receivedMoney: receivedMoney.toFixed(2)
+        }
+      }
+    }
+  },
+  created () {
+    this.getFieldList()
+  },
+  methods: {
+    getFieldList () {
+      this.fieldList.push(
+        { field: 'QuotationNumber', value: '报价单编号' },
+        { field: 'QuotationName', value: '报价单名称' },
+        { field: 'CustomerName', value: '客户名称' },
+        { field: 'SalesChanceName', value: '商机名称' },
+        { field: 'AuditStatus', value: '是否审批' },
+        { field: 'AuditUserName', value: '审批人' },
+        { field: 'IsSeal', value: '是否盖章' },
+        { field: 'SealUserName', value: '盖章上传人' },
+        { field: 'CreateTime', value: '创建时间' },
+        { field: 'Comment', value: '备注' }
+        // { field: 'BeforeSealFile', value: '盖章前文件' },
+        // { field: 'SealFile', value: '盖章后文件' }
+      )
+    },
+    queryList (data) {
+      this.getList(data)
+    },
+    /** 编辑 */
+    editList (row) {
+      this.createActionInfo.data = row
+      this.isCreate = true
+    },
+    deleteModule (id) {
+      this.$confirm('确定删除?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          DeleteQuotationSheet([{'Id': id}]).then(res => {
+            if (res.data.ErrorCode === 200) {
+              this.$message.success(res.data.Message)
+              this.getList()
+            } else {
+              this.$message.error(res.data.Message)
+            }
+          })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    },
+    createSaveSuccess () {
+      this.getList()
+      this.isCreate = false
+    },
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      if (column.property === 'BeforeSealFile' || column.property === 'SealFile' || column.property === 'SalesChanceName' ||
+        column.property === 'CustomerName') {
+        return { color: '#4D88FF', cursor: 'pointer' }
+      } else if (column.property === 'AuditStatus') {
+        if (row[column.property] === '审批中') {
+          return { color: '#FF8800' }
+        } else if (row[column.property] === '通过') {
+          return { color: '#2DB300' }
+        } else if (row[column.property] === '驳回') {
+          return { color: '#FF4D4D' }
+        }
+      } else {
+        return { textAlign: 'left' }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../styles/table.scss';
+.money-bar {
+  color: #99a9bf;
+  line-height: 44px !important;
+  position: absolute;
+  left: 20px;
+  top: 0;
+}
+</style>
diff --git a/src/views/clients/product/ProductIndex.vue b/src/views/clients/product/ProductIndex.vue
new file mode 100644
index 0000000..04ab2dc
--- /dev/null
+++ b/src/views/clients/product/ProductIndex.vue
@@ -0,0 +1,591 @@
+<template>
+  <div class="employee-dep-management">
+    <p class="title">产品列表 </p>
+    <div class="system-content">
+      <!-- 左边导航栏 -->
+      <div
+        v-loading="depLoading"
+        class="system-view-nav">
+        <div class='system-nav-title'>
+          产品类型
+        </div>
+        <el-tree
+          ref="tree"
+          :data="treeData"
+          :expand-on-click-node="false"
+          node-key="DepartmentId"
+          :props="defaultProps"
+          highlight-current
+          @node-click="changeDepClick">
+          <flexbox
+            slot-scope="{ node, data }"
+            class="node-data">
+            <el-tooltip :content="data.TypeName" placement="top">
+              <div class="node-label">{{ data.TypeName }}</div>
+            </el-tooltip>
+          </flexbox>
+        </el-tree>
+      </div>
+      <!-- 右边内容 -->
+      <div class="system-view-table flex-index">
+        <div
+          class="table-top">
+          <el-input
+            class="search-container"
+            v-model="searchName"
+            placeholder="请输入你要搜索的内容"
+            @keyup.enter.native="searchClick"/>
+          <el-button class="searchBtn" type="primary" @click="searchClick">搜索</el-button>
+        </div>
+        <div class="flex-box">
+          <el-table
+            v-loading="loading"
+            id="crm-table"
+            :data="tableData"
+            :height="tableHeight"
+            :cell-style="cellStyle"
+            class="n-table--border"
+            border
+            highlight-current-row
+            style="width: 100%"
+            @row-click="rowClick">
+            <el-table-column
+              v-for="(item, index) in fieldList"
+              :key="index"
+              :prop="item.field"
+              :label="item.name"
+              :formatter="fieldFormatter"
+              show-overflow-tooltip>
+              <template
+                slot="header"
+                slot-scope="scope">
+                <div class="table-head-name">{{ scope.column.label }}</div>
+              </template>
+            </el-table-column>
+            <el-table-column/>
+          </el-table>
+          <div class="p-contianer" v-if='total>0'>
+            <el-pagination
+              :current-page="currentPage"
+              :page-sizes="pageSizes"
+              :page-size.sync="pageSize"
+              :total="total"
+              class="p-bar"
+              layout="total, sizes, prev, pager, next, jumper"
+              @size-change="handleSizeChange"
+              @current-change="handleCurrentChange"/>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { GetAutoProductTypeList, GetAutoProductListAsync } from '@/api/customermanagement/product'
+
+export default {
+  /** 系统管理 的 员工部门管理 */
+  name: 'ProductIndex',
+  components: {
+  },
+  data () {
+    return {
+      treeData: [],
+      depLoading: false, // 左侧部门loading效果
+      // 列表
+      loading: false, // 表的加载动画
+      searchName: '', // 搜索
+      selectModel: '', // 状态值 用于筛选
+      /** 列表 */
+      fieldList: [
+        { name: '产品线', field: 'ProductLine', formType: 'text' },
+        { name: '产品类型', field: 'ProductType', formType: 'text' },
+        { name: 'SKU值', field: 'SKU', formType: 'text' },
+        { name: '产品名称', field: 'ProductName', formType: 'text' },
+        { name: '产品描述', field: 'ProductDesc', formType: 'text' },
+        { name: '产品更新时间', field: 'LastUpdateTime', formType: 'text' },
+        { name: '产品是否在线', field: 'Status', formType: 'text' },
+        { name: '市场参考价(¥)', field: 'ETP', formType: 'text' },
+        { name: '建议经销商转售价(¥)', field: 'RTP', formType: 'text' }
+      ],
+      tableData: [],
+      tableHeight: document.documentElement.clientHeight - 360, // 表的高度
+      /** 分页逻辑 */
+      structureValue: '', // 左侧列表选中的值 用于筛选
+      currentPage: 1,
+      pageSize: 10,
+      pageSizes: [10, 20, 45, 60],
+      total: 0,
+      defaultProps: {
+        children: 'ProductResultList',
+        label: 'TypeName'
+      }
+    }
+  },
+  computed: {
+  },
+  mounted () {
+    var self = this
+    /** 控制table的高度 */
+    window.onresize = function () {
+      self.tableHeight = document.documentElement.clientHeight - 260
+    }
+    // 部门树形列表
+    this.treeListFun()
+  },
+  methods: {
+    // 第一列点击事件
+    rowClick (row, column, event) {
+    },
+    changeDepClick (data) {
+      console.log(data)
+      this.structureValue = data.ParameterLink
+      this.usersListFun()
+    },
+    // 获取树形列表
+    treeListFun () {
+      this.depLoading = true
+      GetAutoProductTypeList()
+        .then(res => {
+          if (res.data.ErrorCode === 200) {
+            this.treeData = res.data.Result
+            this.structureValue = res.data.Result[0].ParameterLink
+            this.tableTopName = res.data.Result[0].TypeName
+            this.usersListFun()
+            this.depLoading = false
+          } else {
+            this.depLoading = false
+          }
+        })
+        .catch(() => {
+          this.depLoading = false
+        })
+    },
+    // 搜索框
+    searchClick () {
+      this.currentPage = 1
+      this.usersListFun()
+    },
+
+    // 更改每页展示数量
+    handleSizeChange (val) {
+      this.pageSize = val
+      this.usersListFun()
+    },
+    // 更改当前页数
+    handleCurrentChange (val) {
+      this.currentPage = val
+      this.usersListFun()
+    },
+    // 勾选
+    handleSelectionChange (val) {
+      this.selectionList = val // 勾选的行
+    },
+    // 用户列表
+    usersListFun () {
+      this.loading = true
+      GetAutoProductListAsync({
+        PageIndex: this.currentPage,
+        PageSize: this.pageSize,
+        Name: this.searchName,
+        TypeName: this.structureValue
+      })
+        .then(res => {
+          this.tableData = res.data.Result.List
+          this.total = res.data.Result.Count
+          this.loading = false
+        })
+        .catch(() => {
+          this.loading = false
+        })
+    },
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      return { textAlign: 'left' }
+    },
+    // 列表信息格式化
+    fieldFormatter (row, column) {
+      if (column.property === 'Status') {
+        switch (row[column.property]) {
+          case true:
+            row[column.property] = '是'
+            break
+          case false:
+            row[column.property] = '否'
+            break
+        }
+      }
+      return row[column.property] || '--'
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.employee-dep-management {
+  /* padding: 0 20px 20px; */
+  height: 100%;
+  box-sizing: border-box;
+  display: flex;
+  flex-direction: column;
+}
+.system-content {
+  position: relative;
+  height: 100%;
+  flex: 1;
+  display: flex;
+  overflow: hidden;
+}
+.system-view-nav {
+  width: 240px;
+  height: 100%;
+  overflow: auto;
+  margin-right: 10px;
+  background: #F8F8F8;
+  border: 1px solid #e6e6e6;
+  /deep/ .el-tree{
+    background-color: #F8F8F8;
+  }
+  .system-nav-title{
+      padding: 15px;
+      font-size: 14px;
+      font-weight: 600;
+      border-bottom: 1px solid #e6e6e6;
+    }
+}
+.title {
+  font-size: 18px;
+  height: 40px;
+  line-height: 40px;
+  margin: 10px 0;
+  color: #333;
+  padding: 0 20px;
+}
+.system-view-table {
+  background: #fff;
+  border: 1px solid #e6e6e6;
+  /* flex: 1; */
+  position: absolute;
+  top: 0;
+  left: 250px;
+  bottom: 0;
+  right: 0;
+}
+
+.table-top {
+    padding: 0 30px;
+    height: 50px;
+    display: flex;
+    align-items: center;
+    margin-top: 30px;
+  .table-top__title{
+    font-size: 16px;
+    color: #333;
+  }
+}
+
+.status {
+  display: inline-block;
+  margin-left: 50px;
+}
+.status > span {
+  margin-right: 10px;
+}
+
+.status-name {
+  .user-img {
+    width: 32px;
+    min-width: 32px;
+    min-height: 32px;
+    height: 32px;
+    margin-right: 8px;
+    border-radius: 50%;
+  }
+  div {
+    width: 6px;
+    height: 6px;
+    border-radius: 3px;
+  }
+  color:  #ff6a00;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  justify-content: left;
+}
+/* 详情 */
+.employee-dep-management /deep/ .el-dialog__wrapper {
+  margin-top: 60px !important;
+}
+// .employee-dep-management /deep/ .position-flxed-animation {
+//   left: 70%;
+//   height: 100%;
+//   color: red;
+//   margin: 0 !important;
+// }
+.dialog-top > img {
+  vertical-align: middle;
+  margin-right: 10px;
+  height: 36px;
+}
+.dialog-btn-group {
+  float: right;
+}
+.dialog-remark {
+  font-size: 14px;
+  color: #999;
+  margin-top: 10px;
+}
+.dialog-content {
+  margin-top: 20px;
+  padding-top: 20px;
+  border-top: 1px solid #e6e6e6;
+}
+.dialog-content > div {
+  padding: 10px 0;
+}
+.dialog-content > div > label {
+  color: #777;
+  width: 30%;
+  display: inline-block;
+}
+/* 新建和编辑 */
+.new-dialog-title {
+  padding-left: 10px;
+  margin-bottom: 3px;
+  border-left: 2px solid #4D88FF;
+}
+.new-dialog-form {
+  height: 47vh;
+  overflow-y: auto;
+  padding: 20px;
+}
+.new-dialog-form /deep/ .el-form-item {
+  width: 50%;
+  margin: 0;
+  padding-bottom: 10px;
+}
+.new-dialog-form /deep/ .el-form-item .el-form-item__label {
+  padding: 0;
+}
+.new-dialog-form /deep/ .el-form-item .el-form-item__content {
+  width: 70%;
+}
+.nav-dialog-div {
+  margin-bottom: 20px;
+}
+.nav-dialog-div /deep/ .el-input {
+  width: auto;
+}
+/** 树形结构 */
+.el-tree /deep/ .el-tree-node__content {
+  height: 30px;
+   &:hover{
+    color: #4D88FF;
+    background-color: #EBF1FF;
+  }
+  .node-data {
+    .node-img {
+      width: 15px;
+      height: 15px;
+      display: block;
+      margin-right: 8px;
+      margin-left: 24px;
+    }
+    .node-label {
+      margin-right: 8px;
+    }
+    .node-label-set {
+      display: none;
+    }
+  }
+
+  .node-data:hover .node-label-set {
+    display: block;
+  }
+}
+.el-tree /deep/ .el-tree-node.is-current > .el-tree-node__content {
+  background-color: #4D88FF;
+  color: #fff;
+  .node-label-set {
+    display: block;
+  }
+}
+.system-view-nav /deep/ .el-tree-node > .el-tree-node__children {
+  overflow: visible;
+}
+.system-view-nav /deep/ .el-tree > .el-tree-node {
+  min-width: 100%;
+  display: inline-block !important;
+}
+/* 搜索框图标按钮 */
+.icon-search .el-icon-search {
+  position: absolute;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  width: 40px;
+  line-height: 40px;
+  text-align: center;
+  cursor: pointer;
+  font-size: 20px;
+  color: #ccc;
+}
+/* 设置flex布局 */
+.flex-index {
+  display: flex;
+  flex-direction: column;
+}
+/* 设置占位 */
+.flex-box {
+  flex: 1;
+  border-bottom: 1px solid #e6e6e6;
+  padding: 24px 30px;
+}
+/* 搜索框 */
+.icon-search {
+  width: 280px;
+  position: relative;
+}
+.search-container {
+    width: 224px;
+}
+.search-container /deep/ .el-input__inner{
+  height: 32px;
+}
+.search-container /deep/ .el-input-group__append{
+  background-color: #4D88FF;
+  border-radius: 0px 3px 3px 0px;
+  color: #fff;
+  border: 1px solid #4D88FF;
+}
+.searchBtn{
+  width: 58px;
+  height: 32px;
+  margin-left: 24px;
+}
+.lt{
+  margin-left: 0;
+}
+.new-dialog-form /deep/ .el-select {
+  display: block;
+}
+
+/** 分页布局 */
+.p-contianer {
+  position: relative;
+  background-color: white;
+  height: 44px;
+  .p-bar {
+    float: right;
+    margin: 5px 0 0 0;
+    font-size: 14px !important;
+  }
+}
+
+/** 勾选操作 */
+.selection-bar {
+  font-size: 12px;
+  height: 54px;
+  min-height: 54px;
+  padding: 0 20px;
+  color: #777;
+
+  .selected—title {
+    flex-shrink: 0;
+    padding-right: 20px;
+    border-right: 1px solid #e6e6e6;
+    .selected—count {
+      color:  #ff6a00;
+    }
+  }
+}
+
+.selection-items-box {
+  .selection-item {
+    width: auto;
+    padding: 15px;
+    .selection-item-icon {
+      display: block;
+      margin-right: 5px;
+      width: 15px;
+      height: 15px;
+    }
+    .selection-item-name {
+      cursor: pointer;
+      color: #777;
+    }
+    .selection-item-name:hover {
+      color:  #ff6a00;
+    }
+  }
+}
+.new-dialog-form
+  /deep/
+  .el-form-item
+  .el-form-item__content
+  .el-select-group__wrap:not(:last-of-type)::after {
+  display: none;
+}
+.new-dialog-form /deep/ .el-form-item .el-form-item__content .el-select-group {
+  padding-left: 10px;
+}
+.new-dialog-form
+  /deep/
+  .el-form-item
+  .el-form-item__content
+  .el-select-group__title {
+  border-bottom: 1px solid #e4e7ed;
+  padding: 0 0 7px;
+  margin: 0 20px 5px;
+}
+
+.status-des {
+  font-size: 12px;
+  color: #777777;
+  margin: 0 5px;
+  position: absolute;
+  left: 0;
+  top: 7px;
+  .status-des-item {
+    margin: 8px;
+    display: inline-block;
+    div {
+      display: inline-block;
+      width: 6px;
+      height: 6px;
+      border-radius: 3px;
+      margin-right: 5px;
+    }
+  }
+}
+
+// 提示
+// 提示标志
+.wukong-help_tips {
+  color: #999;
+  font-size: 14px;
+  margin-left: 3px;
+  cursor: pointer;
+}
+
+.wukong-help_tips:hover {
+  color:  #ff6a00;
+}
+
+// 修改密码和修改登录名的样式
+.el-password {
+  .el-form-item {
+    margin-bottom: 5px;
+  }
+}
+
+.el-dialog__wrapper /deep/.el-dialog__body {
+  padding: 20px;
+}
+
+.tips {
+  font-size: 13px;
+  color: #999;
+}
+@import '../styles/table.scss';
+</style>
diff --git a/src/views/clients/sealContract/SealContractDetail.vue b/src/views/clients/sealContract/SealContractDetail.vue
new file mode 100644
index 0000000..c0c8cdc
--- /dev/null
+++ b/src/views/clients/sealContract/SealContractDetail.vue
@@ -0,0 +1,217 @@
+<template>
+  <slide-view
+    v-empty="!canShowDetail"
+    :listener-ids="listenerIDs"
+    :no-listener-ids="noListenerIDs"
+    :no-listener-class="noListenerClass"
+    :body-style="{padding: 0, height: '100%'}"
+    xs-empty-icon="nopermission"
+    xs-empty-text="暂无权限"
+    @side-close="hideView">
+    <flexbox
+      v-loading="loading"
+      v-if="canShowDetail"
+      direction="column"
+      align="stretch"
+      class="d-container">
+      <c-r-m-detail-head
+        :detail="detailData"
+        :head-details="headDetails"
+        :id="id"
+        crm-type="contract"
+        @handle="detailHeadHandle"
+        @close="hideView"/>
+      <div class="examine-info">
+        <examine-info
+          :id="id"
+          :record-id="detailData.examineRecordId"
+          :owner-user-id="detailData.ownerUserId"
+          class="examine-info-border"
+          examine-type="crm_contract"/>
+      </div>
+      <div class="tabs">
+        <el-tabs
+          v-model="tabCurrentName"
+          @tab-click="handleClick">
+          <el-tab-pane
+            v-for="(item, index) in tabnames"
+            :key="index"
+            :label="item.label"
+            :name="item.name"/>
+        </el-tabs>
+      </div>
+      <div
+        id="follow-log-content"
+        class="t-loading-content">
+        <keep-alive>
+          <component
+            :is="tabName"
+            :detail="detailData"
+            :id="id"
+            crm-type="contract"/>
+        </keep-alive>
+      </div>
+    </flexbox>
+    <c-r-m-create-view
+      v-if="isCreate"
+      :action="{type: 'update', id: id, batchId: detailData.batchId}"
+      crm-type="contract"
+      @save-success="editSaveSuccess"
+      @hiden-view="isCreate=false"/>
+  </slide-view>
+</template>
+
+<script>
+// import { crmContractRead } from '@/api/customermanagement/contract'
+
+import SlideView from '@/components/SlideView'
+import CRMDetailHead from '../components/CRMDetailHead'
+import ContractFollow from './components/ContractFollow' // 跟进记录
+import CRMBaseInfo from '../components/CRMBaseInfo' // 商机基本信息
+import RelativeHandle from '../components/RelativeHandle' // 相关操作
+import RelativeTeam from '../components/RelativeTeam' // 相关团队
+import RelativeProduct from '../components/RelativeProduct' // 相关团队
+import RelativeReturnMoney from '../components/RelativeReturnMoney' // 相关回款
+import RelativeFiles from '../components/RelativeFiles' // 相关附件
+import ExamineInfo from '@/components/Examine/ExamineInfo'
+
+import CRMCreateView from '../components/CRMCreateView' // 新建页面
+
+import detail from '../mixins/detail'
+
+export default {
+  /** 客户管理 的 合同详情 */
+  name: 'SealContractDetail',
+  components: {
+    SlideView,
+    CRMDetailHead,
+    ContractFollow,
+    CRMBaseInfo,
+    RelativeHandle,
+    RelativeTeam,
+    RelativeProduct,
+    RelativeReturnMoney,
+    RelativeFiles,
+    ExamineInfo,
+    CRMCreateView
+  },
+  mixins: [detail],
+  props: {
+    // 详情信息id
+    id: [String, Number],
+    // 监听的dom 进行隐藏详情
+    listenerIDs: {
+      type: Array,
+      default: () => {
+        return ['crm-main-container']
+      }
+    },
+    // 不监听
+    noListenerIDs: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    noListenerClass: {
+      type: Array,
+      default: () => {
+        return ['el-table__body']
+      }
+    }
+  },
+  data () {
+    return {
+      loading: false, // 展示加载loading
+      crmType: 'contract',
+      detailData: {}, // read 详情
+      headDetails: [
+        { title: '合同编号', value: '' },
+        { title: '客户名称', value: '' },
+        { title: '合同金额(元)', value: '' },
+        { title: '签约时间', value: '' },
+        { title: '回款金额(元)', value: '' },
+        { title: '负责人', value: '' }
+      ],
+      tabCurrentName: 'basicinfo',
+      isCreate: false // 编辑操作
+    }
+  },
+  computed: {
+    tabName () {
+      if (this.tabCurrentName === 'followlog') {
+        return 'contract-follow'
+      } else if (this.tabCurrentName === 'basicinfo') {
+        return 'c-r-m-base-info'
+      } else if (this.tabCurrentName === 'team') {
+        return 'relative-team'
+      } else if (this.tabCurrentName === 'contract') {
+        return 'relative-contract'
+      } else if (this.tabCurrentName === 'operationlog') {
+        return 'relative-handle'
+      } else if (this.tabCurrentName === 'product') {
+        return 'relative-product'
+      } else if (this.tabCurrentName === 'returnedmoney') {
+        return 'relative-return-money'
+      } else if (this.tabCurrentName === 'file') {
+        return 'relative-files'
+      }
+      return ''
+    },
+    tabnames () {
+      var tempsTabs = []
+      tempsTabs.push({ label: '跟进记录', name: 'followlog' })
+      if (this.crm.contract && this.crm.contract.read) {
+        tempsTabs.push({ label: '基本信息', name: 'basicinfo' })
+      }
+      if (this.crm.product && this.crm.product.index) {
+        tempsTabs.push({ label: '产品', name: 'product' })
+      }
+      if (this.crm.receivables && this.crm.receivables.index) {
+        tempsTabs.push({ label: '回款信息', name: 'returnedmoney' })
+      }
+      tempsTabs.push({ label: '相关团队', name: 'team' })
+      tempsTabs.push({ label: '附件', name: 'file' })
+      tempsTabs.push({ label: '操作记录', name: 'operationlog' })
+      return tempsTabs
+    }
+  },
+  mounted () {},
+  methods: {
+    getDetial () {
+      this.loading = true
+      // crmContractRead({
+      //   contractId: this.id
+      // })
+      //   .then(res => {
+      //     this.loading = false
+      //     this.detailData = res.data // 创建回款计划的时候使用
+
+      //     this.headDetails[0].value = res.data.num
+      //     this.headDetails[1].value = res.data.customerName
+      //     this.headDetails[2].value = this.moneyFormat(res.data.money)
+      //     this.headDetails[3].value = res.data.orderDate
+      //     this.headDetails[4].value = this.moneyFormat(res.data.receivablesMoney)
+      //     this.headDetails[5].value = res.data.ownerUserName
+      //   })
+      //   .catch(() => {
+      //     this.loading = false
+      //   })
+    },
+    //* * 点击关闭按钮隐藏视图 */
+    hideView () {
+      this.$emit('hide-view')
+    },
+    //* * tab标签点击 */
+    handleClick (tab, event) {},
+    editSaveSuccess () {
+      this.$emit('handle', { type: 'save-success' })
+      this.getDetial()
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../styles/crmdetail.scss';
+</style>
diff --git a/src/views/clients/sealContract/SealContractIndex.vue b/src/views/clients/sealContract/SealContractIndex.vue
new file mode 100644
index 0000000..fb9fe7f
--- /dev/null
+++ b/src/views/clients/sealContract/SealContractIndex.vue
@@ -0,0 +1,257 @@
+<template>
+  <div>
+    <c-r-m-list-head
+      ref="listHead"
+      title="合同管理"
+      main-title="人事管理"/>
+      <c-r-m-table-head
+        ref="crmTableHead"
+        :crm-type="crmType"
+        :fieldList='fieldList'
+        @filter="handleFilter"
+        @handle="handleHandle"
+        @on-handle="listHeadHandle"
+        @scene="handleScene"
+        @queryList='queryList'/>
+      <el-card class="el-card">
+        <el-table
+          v-loading="loading"
+          id="crm-table"
+          :data="list"
+          :height="tableHeight"
+          :cell-style="cellStyle"
+          class="n-table--border"
+          border
+          highlight-current-row
+          style="width: 100%"
+          @row-click="handleRowClick"
+          @sort-change="sortChange"
+          @header-dragend="handleHeaderDragend"
+          @selection-change="handleSelectionChange">
+          <!--<el-table-column
+            show-overflow-tooltip
+            type="selection"
+            align="left"
+            width="55"/>-->
+          <el-table-column
+            v-for="(item, index) in fieldList"
+            :key="index"
+            :prop="item.field"
+            :label="item.value"
+            :width="item.width"
+            :formatter="fieldFormatter"
+            sortable="custom"
+            show-overflow-tooltip>
+            <template
+              slot="header"
+              slot-scope="scope">
+              <div class="table-head-name">
+                  {{ scope.column.label }}
+                  <!--<c-r-m-table-filter
+                    :show="scope.column.label==='合同类型'"
+                    :tableType="scope.column.label"
+                    @queryList="queryList">
+                  </c-r-m-table-filter>-->
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column prop="BeforeSealFile" label="盖章前合同">
+            <template
+              slot="header"
+              slot-scope="scope">
+              <div class="table-head-name">{{ scope.column.label }}</div>
+            </template>
+            <template slot-scope="scope">
+              <span>{{scope.row.BeforeSealFile===''?'--':'点击下载'}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="SealFile" label="盖章后合同">
+            <template
+              slot="header"
+              slot-scope="scope">
+              <div class="table-head-name">{{ scope.column.label }}</div>
+            </template>
+            <template slot-scope="scope">
+              <span>{{scope.row.SealFile===''?'--':'点击下载'}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column
+            prop="operation"
+            width="150">
+            <template
+              slot="header"
+              slot-scope="scope">
+              <div class="table-head-name">操作</div>
+            </template>
+            <template slot-scope="scope">
+            <el-button type="text" size="small"  @click='editList(scope.row)'>上传盖章合同</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="p-contianer"  v-show='total>0'>
+          <el-pagination
+            :current-page="currentPage"
+            :page-sizes="pageSizes"
+            :page-size.sync="pageSize"
+            :total="total"
+            class="p-bar"
+            layout="total, sizes, prev, pager, next, jumper"
+            @size-change="handleSizeChange"
+            @current-change="handleCurrentChange"/>
+        </div>
+      </el-card>
+    <el-dialog title="上传盖章合同" :visible.sync="isCreate" :modal-append-to-body="false" width="30%">
+      <c-r-m-create-file-view
+        v-if="isCreate"
+        :id="rowID"
+        :action="createActionInfo"
+        crm-type="sealContract"
+        @save-success="createSaveSuccess"
+        @hiden-view="isCreate=false"/>
+    </el-dialog>
+    <!-- 相关详情页面 -->
+    <c-r-m-all-detail
+      :visible.sync="showDview"
+      :crm-type="rowType"
+      :id="rowID"
+      class="d-view"
+      @handle="handleHandle"/>
+    <fields-set
+      :crm-type="crmType"
+      :dialog-visible.sync="showFieldSet"
+      @set-success="setSave"/>
+  </div>
+</template>
+
+<script>
+import CRMAllDetail from '@/views/clients/components/CRMAllDetail'
+import table from '../mixins/table'
+import CRMTableFilter from '../components/CRMTableFilter'
+import CRMCreateFileView from '@/views/clients/components/CRMCreateFileView'
+import { DeleteAgreenment } from '@/api/customermanagement/contract'
+
+export default {
+  /** 客户管理 的 合同列表 */
+  name: 'SealContractIndex',
+  components: {
+    CRMAllDetail,
+    CRMTableFilter,
+    CRMCreateFileView
+  },
+  mixins: [table],
+  data () {
+    return {
+      crmType: 'sealContract',
+      isCreate: false,
+      // 创建的相关信息
+      createActionInfo: { type: 'update', crmType: 'sealContract', data: {} },
+      fieldList: [],
+      moneyData: null // 合同列表金额
+    }
+  },
+  computed: {
+    moneyPageData () {
+      // 未勾选展示合同总金额信息
+      if (this.selectionList.length === 0 && this.moneyData) {
+        return this.moneyData
+      } else {
+        let contractMoney = 0.0
+        let receivedMoney = 0.0
+        for (let index = 0; index < this.selectionList.length; index++) {
+          const element = this.selectionList[index]
+          // 2 审核通过的合同
+          if (element.checkStatus === 1) {
+            contractMoney += parseFloat(element.money)
+            receivedMoney += parseFloat(element.receivedMoney)
+          }
+        }
+        return {
+          contractMoney: contractMoney.toFixed(2),
+          receivedMoney: receivedMoney.toFixed(2)
+        }
+      }
+    }
+  },
+  mounted () {
+    this.getFieldList()
+  },
+  methods: {
+    getFieldList () {
+      this.fieldList.push(
+        { field: 'AgreeNumber', value: '合同编号' },
+        { field: 'AgreeName', value: '合同名称' },
+        // { field: 'Comment', value: '合同备注' },
+        { field: 'CustomerName', value: '客户名称' },
+        { field: 'SalesChanceName', value: '商机名称' },
+        // { field: 'AuditStatus', value: '是否审核', width: '100' },
+        { field: 'AuditUserName', value: '审核人' },
+        { field: 'SealTypeString', value: '合同类型' },
+        { field: 'IsSeal', value: '是否盖章', width: '100' },
+        { field: 'SealUserName', value: '盖章上传人' },
+        { field: 'CreateTime', value: '创建时间' },
+        { field: 'ExpressNumber', value: '快递单号' },
+        { field: 'ExpressComment', value: '快递备注信息' }
+        // { field: 'BeforeSealFile', value: '盖章前合同' },
+        // { field: 'SealFile', value: '盖章后合同' }
+      )
+    },
+    queryList (data) {
+      this.getList(data)
+    },
+    /** 编辑 */
+    editList (row) {
+      console.log(row)
+      this.createActionInfo.data = row
+      this.isCreate = true
+    },
+    deleteModule (id) {
+      this.$confirm('确定删除?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          DeleteAgreenment([{'Id': id}]).then(res => {
+            if (res.data.ErrorCode === 200) {
+              this.$message.success(res.data.Message)
+              this.getList()
+            } else {
+              this.$message.error(res.data.Message)
+            }
+          })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    },
+    createSaveSuccess () {
+      this.getList()
+      this.isCreate = false
+    },
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      if (column.property === 'BeforeSealFile' || column.property === 'SealFile' || column.property === 'SalesChanceName' ||
+        column.property === 'CustomerName') {
+        return { color: '#4D88FF', cursor: 'pointer' }
+      } else {
+        return { textAlign: 'left' }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../styles/table.scss';
+.money-bar {
+  color: #99a9bf;
+  line-height: 44px !important;
+  position: absolute;
+  left: 20px;
+  top: 0;
+}
+
+</style>
diff --git a/src/views/clients/sealOffers/SealOfferIndex.vue b/src/views/clients/sealOffers/SealOfferIndex.vue
new file mode 100644
index 0000000..92e72bb
--- /dev/null
+++ b/src/views/clients/sealOffers/SealOfferIndex.vue
@@ -0,0 +1,260 @@
+<template>
+  <div>
+    <c-r-m-list-head
+      ref="listHead"
+      title="报价/标书管理"
+      main-title="人事管理"/>
+      <c-r-m-table-head
+        ref="crmTableHead"
+        :crm-type="crmType"
+        :fieldList='fieldList'
+        @filter="handleFilter"
+        @handle="handleHandle"
+        @on-handle="listHeadHandle"
+        @scene="handleScene"
+        @queryList='queryList'/>
+      <el-card class="el-card">
+        <el-table
+          v-loading="loading"
+          id="crm-table"
+          :data="list"
+          :height="tableHeight"
+          :cell-style="cellStyle"
+          class="n-table--border"
+          border
+          highlight-current-row
+          style="width: 100%"
+          @row-click="handleRowClick"
+          @sort-change="sortChange"
+          @header-dragend="handleHeaderDragend"
+          @selection-change="handleSelectionChange">
+          <!--<el-table-column
+            show-overflow-tooltip
+            type="selection"
+            align="left"
+            width="55"/>-->
+          <el-table-column
+            v-for="(item, index) in fieldList"
+            :key="index"
+            :prop="item.field"
+            :label="item.value"
+            :width="item.width"
+            :formatter="fieldFormatter"
+            sortable="custom"
+            show-overflow-tooltip>
+            <template
+              slot="header"
+              slot-scope="scope">
+              <div class="table-head-name">
+                  {{ scope.column.label }}
+                  <c-r-m-table-filter
+                    :show="scope.column.label==='合同类型'"
+                    :tableType="scope.column.label"
+                    @queryList="queryList">
+                  </c-r-m-table-filter>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column prop="BeforeSealFile" label="盖章前文件">
+            <template
+              slot="header"
+              slot-scope="scope">
+              <div class="table-head-name">{{ scope.column.label }}</div>
+            </template>
+            <template slot-scope="scope">
+              <span>{{scope.row.BeforeSealFile===''?'--':'点击下载'}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="SealFile" label="盖章后文件">
+            <template
+              slot="header"
+              slot-scope="scope">
+              <div class="table-head-name">{{ scope.column.label }}</div>
+            </template>
+            <template slot-scope="scope">
+              <span>{{scope.row.SealFile===''?'--':'点击下载'}}</span>
+            </template>
+          </el-table-column>
+          <el-table-column
+            prop="operation"
+            width="150">
+            <template
+              slot="header"
+              slot-scope="scope">
+              <div class="table-head-name">操作</div>
+            </template>
+            <template slot-scope="scope">
+            <el-button type="text" size="small"  @click='editList(scope.row)'>上传报价单</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="p-contianer"  v-show='total>0'>
+          <el-pagination
+            :current-page="currentPage"
+            :page-sizes="pageSizes"
+            :page-size.sync="pageSize"
+            :total="total"
+            class="p-bar"
+            layout="total, sizes, prev, pager, next, jumper"
+            @size-change="handleSizeChange"
+            @current-change="handleCurrentChange"/>
+        </div>
+      </el-card>
+    <el-dialog title="上传盖章报价单" :visible.sync="isCreate" :modal-append-to-body="false" width="30%">
+      <c-r-m-create-file-view
+        v-if="isCreate"
+        :id="rowID"
+        :action="createActionInfo"
+        crm-type="sealOffers"
+        @save-success="createSaveSuccess"
+        @hiden-view="isCreate=false"/>
+    </el-dialog>
+    <!-- 相关详情页面 -->
+    <c-r-m-all-detail
+      :visible.sync="showDview"
+      :crm-type="rowType"
+      :id="rowID"
+      class="d-view"
+      @handle="handleHandle"/>
+    <fields-set
+      :crm-type="crmType"
+      :dialog-visible.sync="showFieldSet"
+      @set-success="setSave"/>
+  </div>
+</template>
+
+<script>
+import CRMAllDetail from '@/views/clients/components/CRMAllDetail'
+import table from '../mixins/table'
+import CRMTableFilter from '../components/CRMTableFilter'
+import CRMCreateFileView from '@/views/clients/components/CRMCreateFileView'
+import { DeleteQuotationSheet } from '@/api/customermanagement/offer'
+
+export default {
+  /** 客户管理 的 合同列表 */
+  name: 'SealOfferIndex',
+  components: {
+    CRMAllDetail,
+    CRMTableFilter,
+    CRMCreateFileView
+  },
+  mixins: [table],
+  data () {
+    return {
+      crmType: 'sealOffers',
+      isCreate: false,
+      // 创建的相关信息
+      createActionInfo: { type: 'update', crmType: 'sealOffers', data: {} },
+      fieldList: [],
+      moneyData: null // 合同列表金额
+    }
+  },
+  computed: {
+    moneyPageData () {
+      // 未勾选展示合同总金额信息
+      if (this.selectionList.length === 0 && this.moneyData) {
+        return this.moneyData
+      } else {
+        let contractMoney = 0.0
+        let receivedMoney = 0.0
+        for (let index = 0; index < this.selectionList.length; index++) {
+          const element = this.selectionList[index]
+          // 2 审核通过的合同
+          if (element.checkStatus === 1) {
+            contractMoney += parseFloat(element.money)
+            receivedMoney += parseFloat(element.receivedMoney)
+          }
+        }
+        return {
+          contractMoney: contractMoney.toFixed(2),
+          receivedMoney: receivedMoney.toFixed(2)
+        }
+      }
+    }
+  },
+  created () {
+    this.getFieldList()
+  },
+  methods: {
+    getFieldList () {
+      this.fieldList.push(
+        { field: 'QuotationNumber', value: '报价单编号' },
+        { field: 'QuotationName', value: '报价单名称' },
+        { field: 'CustomerName', value: '客户名称' },
+        { field: 'SalesChanceName', value: '商机名称' },
+        // { field: 'AuditStatus', value: '是否审批' },
+        { field: 'AuditUserName', value: '审批人' },
+        { field: 'IsSeal', value: '是否盖章' },
+        { field: 'SealUserName', value: '盖章上传人' },
+        { field: 'CreateTime', value: '创建时间' },
+        { field: 'Comment', value: '备注' }
+        // { field: 'BeforeSealFile', value: '盖章前文件' },
+        // { field: 'SealFile', value: '盖章后文件' }
+      )
+    },
+    queryList (data) {
+      this.getList(data)
+    },
+    /** 编辑 */
+    editList (row) {
+      this.createActionInfo.data = row
+      this.isCreate = true
+    },
+    deleteModule (id) {
+      this.$confirm('确定删除?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          DeleteQuotationSheet([{'Id': id}]).then(res => {
+            if (res.data.ErrorCode === 200) {
+              this.$message.success(res.data.Message)
+              this.getList()
+            } else {
+              this.$message.error(res.data.Message)
+            }
+          })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    },
+    createSaveSuccess () {
+      this.getList()
+      this.isCreate = false
+    },
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      if (column.property === 'BeforeSealFile' || column.property === 'SealFile' || column.property === 'SalesChanceName' ||
+        column.property === 'CustomerName') {
+        return { color: '#4D88FF', cursor: 'pointer' }
+      } else if (column.property === 'AuditStatus') {
+        if (row[column.property] === '审批中') {
+          return { color: '#FF8800' }
+        } else if (row[column.property] === '通过') {
+          return { color: '#2DB300' }
+        } else if (row[column.property] === '驳回') {
+          return { color: '#FF4D4D' }
+        }
+      } else {
+        return { textAlign: 'left' }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../styles/table.scss';
+.money-bar {
+  color: #99a9bf;
+  line-height: 44px !important;
+  position: absolute;
+  left: 20px;
+  top: 0;
+}
+</style>
diff --git a/src/views/clients/styles/crmdetail.scss b/src/views/clients/styles/crmdetail.scss
new file mode 100644
index 0000000..4db7123
--- /dev/null
+++ b/src/views/clients/styles/crmdetail.scss
@@ -0,0 +1,48 @@
+//客户相关详情 头部类似布局
+.el-tabs /deep/ .el-tabs__nav-wrap::after {
+  display: none !important;
+}
+
+.el-tabs /deep/ .el-tabs__header {
+  background-color: transparent;
+  padding: 0 40px;
+  margin: 0 !important;
+  // border-bottom: 1px solid #F1F1F1;
+}
+
+.el-tabs /deep/ .el-tabs__item {
+  font-size: 16px !important;
+  height: 40px !important;
+  line-height: 40px !important;
+  color: #666 !important;
+  // padding: 0 32px !important;
+}
+.el-tabs /deep/ .el-tabs__item.is-active{
+  color: #4D88FF !important;
+}
+.d-container {
+  position: relative;
+  height: 100%;
+  // padding: 24px 40px;
+}
+.tabs{
+  border-bottom: 1px solid #F1F1F1;
+  margin-bottom: 48px;
+}
+/** 让element 查询到的标签 */
+.t-loading-content {
+  position: relative;
+  overflow-y: scroll;
+  flex: 1;
+}
+
+/** 审核信息 */
+.examine-info {
+  padding: 0 17px 17px 17px;
+
+  .examine-info-border {
+    border: 1px solid #e6e6e6;
+    border-radius: 3px;
+    padding: 17px;
+  }
+}
diff --git a/src/views/clients/styles/detailview.scss b/src/views/clients/styles/detailview.scss
new file mode 100644
index 0000000..5ed31e0
--- /dev/null
+++ b/src/views/clients/styles/detailview.scss
@@ -0,0 +1,15 @@
+
+  /** 客户管理详情页面的 css 侧滑进入的详情 */
+  .d-view {
+    position: fixed;
+    // width: 950px;
+    // top: 0px;
+    width: 100%;
+    // top: 300px;
+    bottom: 0px;
+    right: 0px;
+    // background: #FFFFFF;
+    box-shadow: 0px -4px 12px 0px rgba(61, 121, 204, 0.2);
+    border-radius: 24px 24px 0px 0px;
+  }
+  
\ No newline at end of file
diff --git a/src/views/clients/styles/followcell.scss b/src/views/clients/styles/followcell.scss
new file mode 100644
index 0000000..bcc7ad2
--- /dev/null
+++ b/src/views/clients/styles/followcell.scss
@@ -0,0 +1,170 @@
+/** 跟进记录相关的 日志 审批任务 日程 项目 公共css */
+.fl-c {
+  background-color: white;
+  padding: 10px 20px;
+  position: relative;
+}
+
+/** 头部布局 名字 头像 */
+.fl-h {
+  .fl-h-img {
+    display: block;
+    width: 34px;
+    height: 34px;
+    border-radius: 17px;
+    margin-right: 8px;
+  }
+
+  .fl-h-b {
+    flex: 1;
+
+    .fl-h-name {
+      font-size: 13px;
+      color: #333;
+    }
+
+    .fl-h-time {
+      font-size: 12px;
+      color: #999;
+      margin-top: 3px;
+    }
+  }
+}
+
+/** 头部 右侧 布局*/
+.fl-h-handle {
+  width: auto;
+
+  .fl-h-handle-name {
+    font-size: 13px;
+    color: #333;
+    margin-right: 6px;
+  }
+}
+
+.fl-h-mark {
+  width: auto;
+
+  .fl-h-mark-img {
+    display: block;
+    width: 14px;
+    height: 14px;
+    margin-right: 8px;
+  }
+
+  .fl-h-mark-name {
+    font-size: 12px;
+    color: #333;
+  }
+}
+
+/** 内容区域 */
+.fl-b {
+  margin: 20px 0 0 40px;
+
+  .fl-b-content {
+    font-size: 13px;
+    color: #333;
+    margin-bottom: 10px;
+  }
+
+  .fl-b-images {
+    margin-top: 5px;
+    width: 310px;
+
+    .fl-b-img-item {
+      width: 98px;
+      height: 98px;
+      display: inline-block;
+      margin: 0 4px 4px 0;
+      background-size: contain;
+      background-repeat: no-repeat;
+      background-position: center;
+      position: relative;
+      cursor: pointer;
+    }
+  }
+
+  .fl-b-other {
+    margin: 8px 0;
+
+    .fl-b-other-name {
+      margin: 10px 0;
+      color: #666;
+      font-size: 13px;
+    }
+  }
+}
+
+.fl-c:before {
+  content: " ";
+  position: absolute;
+  top: 0;
+  right: 0;
+  height: 1px;
+  border-top: 1px solid #e5e5e5;
+  color: #e5e5e5;
+  -webkit-transform-origin: 0 0;
+  transform-origin: 0 0;
+  -webkit-transform: scaleY(0.5);
+  transform: scaleY(0.5);
+  left: 15px;
+  z-index: 2;
+}
+
+.fl-c:first-child:before {
+  display: none;
+}
+
+/** 附件 */
+.fl-b-files {
+  margin-top: 10px;
+}
+
+/** 关联附件 联系人 客户 行布局 */
+.cell {
+  padding: 8px;
+  background-color: #F5F7FA;
+  border-radius: 2px;
+  position: relative;
+
+  .cell-head {
+    display: block;
+    width: 15px;
+    height: 15px;
+    margin-right: 8px;
+  }
+
+  .cell-body {
+    flex: 1;
+    color: #333;
+    font-size: 12px;
+  }
+
+  .cell-foot {
+    display: block;
+    width: 20px;
+    padding: 0 4px;
+    margin-right: 8px;
+  }
+}
+
+.cell:before {
+  content: " ";
+  position: absolute;
+  top: 0;
+  right: 0;
+  height: 1px;
+  border-top: 1px solid #e5e5e5;
+  color: #e5e5e5;
+  -webkit-transform-origin: 0 0;
+  transform-origin: 0 0;
+  -webkit-transform: scaleY(0.5);
+  transform: scaleY(0.5);
+  left: 30px;
+  z-index: 2;
+}
+
+.cell:first-child:before {
+  display: none;
+}
diff --git a/src/views/clients/styles/followlog.scss b/src/views/clients/styles/followlog.scss
new file mode 100644
index 0000000..875b966
--- /dev/null
+++ b/src/views/clients/styles/followlog.scss
@@ -0,0 +1,122 @@
+// 跟进记录效果
+.f-container {
+  padding: 0 80px;
+}
+
+/** 发布行css  */
+.se-section {
+  position: relative;
+  margin: 12px;
+  height: 32px;
+  line-height: 32px;
+
+  .se-name {
+    font-size: 12px;
+    color: #333333;
+    margin-right: 5px;
+  }
+
+  .se-select {
+    // width: 118px;
+    height: 32px;
+    background: #FFFFFF;
+    border-radius: 4px;
+    border: 1px solid #D9D9D9;
+    font-size: 12px;
+    color: #333;
+    padding: 0 15px;
+    font-weight: 500;
+
+    .se-select-name {
+      margin-right: 20px;
+    }
+  }
+
+  .se-datepicker {
+    font-size: 12px;
+    width: 200px;
+    margin-right: 20px;
+  }
+
+  .se-send {
+    position: absolute;
+    right: 0;
+    padding: 5px 15px;
+  }
+}
+.se-collect {
+  position: absolute;
+  right: 85px;
+  padding: 5px 15px;
+  width: 58px;
+  height: 28px;
+  border-radius: 3px;
+  border: 1px solid #D9D9D9;
+  color: #666;
+  font-size: 12px;
+  &:hover{
+    border-color: #4D88FF;
+    color: #4D88FF;
+    background-color: #fff;
+  }
+  &:focus{
+    background-color: #fff;
+  }
+  &:active{
+    border-color: #4D88FF;
+    color: #4D88FF;
+    background-color: #fff;
+  }
+}
+.se-send {
+  position: absolute;
+  right: 12px;
+  padding: 5px 15px;
+  width: 58px;
+  height: 28px;
+  background: #4D88FF;
+  color: #fff;
+  font-size: 12px;
+  border-radius: 3px;
+}
+.el-date-editor /deep/ .el-input__inner {
+  height: 32px;
+  line-height: 32px;
+}
+
+.el-date-editor /deep/ .el-input__icon {
+  height: 25px;
+  line-height: 25px;
+}
+
+.el-checkbox /deep/ .el-checkbox__label {
+  font-size: 12px;
+  color: #333333;
+}
+
+.log-cont {
+  margin: 30px 0;
+  // border: 1px solid #e6e6e6;
+  // border-radius: 2px;
+
+  .log-tabs-item {
+    font-size: 13px;
+    padding: 8px 15px;
+    cursor: pointer;
+  }
+
+  .log-tabs-item:hover {
+    color: #F18C70 !important;
+  }
+
+  .log-tabs-line {
+    height: 10px;
+    background-color: #e6e6e6;
+    width: 2px;
+  }
+}
+
+.log-items {
+  min-height: 400px;
+  position: relative;
+}
diff --git a/src/views/clients/styles/relativecrm.scss b/src/views/clients/styles/relativecrm.scss
new file mode 100644
index 0000000..e169a80
--- /dev/null
+++ b/src/views/clients/styles/relativecrm.scss
@@ -0,0 +1,148 @@
+/**客户下相关信息 table 效果 */
+.rc-cont {
+    position: relative;
+    padding: 0 80px 20px;
+    .rc-head {
+        margin-bottom: 15px;
+        position: relative;
+        .rc-head-item {
+            font-size: 12px;
+            padding: 8px 5px;
+            border-radius: 2px;
+            margin-right: 20px;
+            margin-left: 0px;
+        }
+        .rc-head-item:first-child {
+            margin-right: 0;
+        }
+    }
+}
+
+.el-table{
+    border-top: 1px solid #e6e6e6;
+  }
+  
+  
+  .el-table th>.cell{
+    color: #333;
+    font-size: 14px;
+    font-weight: 500;
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+  }
+  .el-table /deep/ thead th {
+    background-color: #EBF1FF;
+    font-weight: 400;
+    // border-color: #E6E6E6;
+    color: #475059;
+  }
+  
+  .el-table /deep/ thead th, thead td {
+    padding:16px 0px;
+    border-right: 1px solid #F7FAFF;
+  }
+  // .el-table /deep/ thead th:first-child, thead td {
+  //   border-right: 0;
+  // }
+  .el-table /deep/ thead th:nth-last-child(2), thead td {
+    border-right: 0;
+    font-weight: 400;
+  }
+  .table-set {
+    width: 15px;
+    margin-top: 5px;
+    cursor: pointer;
+  }
+  
+  .table-head-name {
+    padding: 0;
+    color: #333;
+    font-size: 14px;
+    font-weight: 600;
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    display: flex;
+    align-items: flex-start;
+  }
+  
+  .el-table /deep/ thead .cell {
+    height: 23px;
+  }
+  
+  // .el-table /deep/ .el-table__row.current-row {
+  //   td:first-child::before {
+  //     content: ' ';
+  //     position: absolute;
+  //     top: 0;
+  //     left: 0;
+  //     bottom: 0;
+  //     width: 2px;
+  //     background-color: #5383ED;
+  //   }
+  // }
+  
+  .el-table /deep/ tbody tr td {
+    border-top-color: transparent;
+    border-left-color: transparent;
+    border-right-color: transparent;
+    border-bottom-color: #E6E6E6;
+    font-size: 14px;
+  }
+  .el-table {
+    /deep/.el-table--enable-row-hover .el-table__body tr:hover>td { 
+        background-color: #F7FAFF !important; 
+    }	
+  }
+  // .el-table /deep/ tbody tr td:nth-child(2) {
+  //   border-right: 1px solid #E6E6E6;
+  // }
+  
+  .n-table--border {
+    border-color: #E6E6E6;
+    border-left-color: transparent;
+    border-right-color: transparent;
+  }
+  
+  .n-table--border::after {
+    display: none;
+  }
+  
+  .p-contianer {
+    position: relative;
+    background-color: white;
+    height: 44px;
+  
+    .p-bar {
+      float: right;
+      margin: 5px 0 0 0;
+      font-size: 14px !important;
+    }
+  }
+  
+  // 列表状态
+  .status_button {
+    padding: 1px 6px;
+    border: 1px solid #e6e6e6;
+    border-radius: 4px;
+    display: inline-block;
+    font-size: 12px;
+    margin: 0 auto;
+  }
+  
+  .el-table /deep/ .sort-caret.ascending {
+    top: -6px;
+  }
+  .el-table /deep/ .caret-wrapper {
+    height: 24px;
+  }
+  .rc-head-item{
+    width: 78px;
+    height: 32px;
+    background: #FF8800;
+    border-color: #FF8800;
+    border-radius: 3px;
+    font-size: 12px;
+    color:#fff;
+  }
\ No newline at end of file
diff --git a/src/views/clients/styles/table.scss b/src/views/clients/styles/table.scss
new file mode 100644
index 0000000..70515ec
--- /dev/null
+++ b/src/views/clients/styles/table.scss
@@ -0,0 +1,146 @@
+@import './detailview.scss';
+
+.crm-container {
+  background-color: white;
+  border: 1px solid #E6E6E6;
+  border-radius: 2px;
+}
+
+/**
+  .el-table /deep/ thead th {
+    border-right: 1px solid #ebeef5;
+  }
+  
+  .el-table /deep/ tbody tr td:nth-child(2){
+    border-right: 1px solid #ebeef5;
+  }
+  
+  .b-bottom {
+    border-bottom: 1px solid #ebeef5;
+  }
+  */
+.el-table{
+  border-top: 1px solid #e6e6e6;
+}
+
+
+.el-table th>.cell{
+  color: #333;
+  font-size: 14px;
+  font-weight: 500;
+  overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+}
+.el-table /deep/ thead th {
+  background-color: #EBF1FF;
+  font-weight: 400;
+  // border-color: #E6E6E6;
+  color: #475059;
+}
+
+.el-table /deep/ thead th, thead td {
+  padding:16px 0px;
+  border-right: 1px solid #F7FAFF;
+}
+.el-table /deep/ thead th:first-child, thead td {
+  border-right: 0;
+}
+.el-table /deep/ thead th:nth-last-child(2), thead td {
+  border-right: 0;
+  font-weight: 400;
+}
+.table-set {
+  width: 15px;
+  margin-top: 5px;
+  cursor: pointer;
+}
+
+.table-head-name {
+  padding: 0;
+  color: #333;
+  font-size: 14px;
+  font-weight: 600;
+  overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  display: flex;
+  align-items: flex-start;
+}
+
+.el-table /deep/ thead .cell {
+  height: 23px;
+}
+
+// .el-table /deep/ .el-table__row.current-row {
+//   td:first-child::before {
+//     content: ' ';
+//     position: absolute;
+//     top: 0;
+//     left: 0;
+//     bottom: 0;
+//     width: 2px;
+//     background-color: #5383ED;
+//   }
+// }
+
+.el-table /deep/ tbody tr td {
+  border-top-color: transparent;
+  border-left-color: transparent;
+  border-right-color: transparent;
+  border-bottom-color: #E6E6E6;
+  font-size: 14px;
+}
+.el-table {
+  /deep/.el-table--enable-row-hover .el-table__body tr:hover>td { 
+      background-color: #F7FAFF !important; 
+  }	
+}
+.el-table::before{
+  height: 0;
+}
+.el-table__fixed::before{
+  height: 0;
+}
+// .el-table /deep/ tbody tr td:nth-child(2) {
+//   border-right: 1px solid #E6E6E6;
+// }
+
+.n-table--border {
+  border-color: #E6E6E6;
+  border-left-color: transparent;
+  border-right-color: transparent;
+}
+
+.n-table--border::after {
+  display: none;
+}
+
+.p-contianer {
+  position: relative;
+  background-color: white;
+  height: 44px;
+
+  .p-bar {
+    float: right;
+    margin: 10px 0 0 0;
+    font-size: 14px !important;
+  }
+}
+
+// 列表状态
+.status_button {
+  padding: 1px 6px;
+  border: 1px solid #e6e6e6;
+  border-radius: 4px;
+  display: inline-block;
+  font-size: 12px;
+  margin: 0 auto;
+}
+
+.el-table /deep/ .sort-caret.ascending {
+  top: -6px;
+}
+.el-table /deep/ .caret-wrapper {
+  height: 24px;
+}
\ No newline at end of file
diff --git a/src/views/company/ApartmentManage.vue b/src/views/company/ApartmentManage.vue
new file mode 100644
index 0000000..4ca22cd
--- /dev/null
+++ b/src/views/company/ApartmentManage.vue
@@ -0,0 +1,466 @@
+<!-- 菜单树 -->
+<template>
+  <div class="apartment-management">
+  <p class="title"> 部门管理 </p>
+
+  <el-card>
+      <el-row>
+        <el-button class="create-button"
+        type="primary" @click='createModule'>新增</el-button>
+        <el-button class="delete-button"
+        type="primary" @click='deleteModule' v-if='isDelete'>删除</el-button>
+      </el-row>
+      <el-table
+        ref="menusTable"
+        border
+        max-height="600px"
+        :row-style="showRow"
+        :data="menusTable"
+        @selection-change="handleSelectionChange"
+        v-bind="$attrs">
+        <el-table-column
+          show-overflow-tooltip
+          type="selection"
+          align="center"
+          width="55"/>
+        <el-table-column
+          prop="Name"
+          label="部门名称" width="400">
+          <template slot-scope="scope">
+            <span class='level'>
+              <div v-show="scope.row.Children&&scope.row.Children.length>0" @click="openToggle(scope.row)"
+                :class="[scope.row.open?'el-table__expand-icon el-table__expand-icon--expanded':'el-table__expand-icon']">
+                <i class='el-icon-arrow-right'></i>
+              </div>
+            </span>
+            {{scope.row.Name}}
+          </template>
+        </el-table-column>
+        <el-table-column
+          prop="Comment"
+          label="备注"  width="200">
+          <template slot-scope="scope">
+            <div>{{scope.row.Comment}}</div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          prop="IsEnabled"
+          label="状态">
+          <template slot-scope="scope">
+            <div>{{scope.row.IsEnabled ?'启用':'禁用'}}</div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          prop="Sort"
+          label="排序">
+          <template slot-scope="scope">
+            <div>{{scope.row.Sort}}</div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          prop="IsSectorArea"
+          label="是否是区域部门">
+          <template slot-scope="scope">
+            <div>{{scope.row.IsSectorArea ? '是' : '否'}}</div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          prop="operation"
+          label="操作">
+          <template slot-scope="scope">
+            <el-button type="text" size="small" @click='addApart(scope.row)'>添加子部门</el-button>
+            <!-- 判断下面是否有子菜单,有子菜单不能是有删除按钮 -->
+            <el-button v-if="!scope.row.children" type="text" size="small"  @click='deleteApart(scope.row.Id)'>删除</el-button>
+            <el-button type="text" size="small"  @click='editApart(scope.row)'>编辑</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+     </el-card>
+    <!-- 导航新增编辑弹出框 -->
+    <el-dialog
+      :visible.sync="depCreateDialog"
+      :title="navBtnTitle"
+      :before-close="cancelDialog"
+      width="40%">
+      <el-form
+        ref="apartForm"
+        :model="apartForm"
+        :rules="apartRules"
+        label-width="120px"
+        class="login-form"
+        auto-complete="on"
+        label-position="left">
+        <el-form-item label="上级部门" prop='fatherIntro'>
+            <el-cascader
+              ref="refApart"
+              placeholder="请选择上级部门"
+              :options="isCreate? selectOpts: rightsList"
+              :show-all-levels="false"
+              :props="{
+                children: 'Children',
+                label: 'Name',
+                value: 'Id'
+              }"
+              v-model="apartForm.fatherIntro"
+              style="width: 100%;"
+              @change='getFatherOpt'
+              change-on-select/>
+        </el-form-item>
+        <el-form-item label="部门名称"  prop='introName'>
+          <el-input
+            v-model="apartForm.introName"
+            placeholder="请输入部门名称"/>
+          </el-form-item>
+        <el-form-item label="部门状态"  prop='apartStatus'>
+          <el-switch v-model="apartForm.apartStatus"></el-switch>
+        </el-form-item>
+          <el-form-item label="是否是区域部门">
+            <el-switch v-model="apartForm.apartChosen"></el-switch>
+          </el-form-item>
+          <el-form-item label="部门类型" prop='apartInt'>
+           <el-select v-model="apartForm.apartInt" placeholder="请选择" style="width: 100%;">
+              <el-option
+                v-for="item in apartLists"
+                :key="item.id"
+                :label="item.value"
+                :value="item.id">
+              </el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="排序数字">
+            <el-input
+              class='numInp'
+              type='number'
+              v-model="apartForm.sortNum"
+              placeholder="请输入排序数字"/>
+          </el-form-item>
+          <el-form-item label="备注说明">
+            <el-input
+                type='textarea'
+                v-model="apartForm.info"
+                placeholder="请输入备注说明"/>
+          </el-form-item>
+          <el-form-item>
+            <el-button @click="cancelDialog">取 消</el-button>
+            <el-button
+              type="primary"
+              @click="submitDialog('apartForm')">确 定</el-button>
+          </el-form-item>
+      </el-form>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import Vue from 'vue'
+import { GetDepartmentList, AddDepartment, DeleteDepartment, UpdateDepartment } from '@/api/systemManagement/departmentManage'
+export default {
+  name: 'staffManage',
+  data () {
+    return {
+      defaultProps: {
+        children: 'children',
+        label: 'title'
+      },
+      // 菜单表格结构数据
+      menusTable: [],
+      depCreateDialog: false,
+      apartForm: {
+        fatherIntro: '', // 上级部门
+        introName: '', // 部门名称
+        apartStatus: true, // 部门状态
+        apartChosen: false, // 是否是区域部门
+        apartInt: '', // 是否是区域部门
+        sortNum: 1, // 排序数字
+        info: ''
+      },
+      apartRules: {
+        fatherIntro: [
+          { required: true, trigger: 'blur', message: '请选择上级部门' }
+        ],
+        introName: [{ required: true, trigger: 'blur', message: '请输入部门名称' }],
+        apartInt: [{ required: true, trigger: 'blur', message: '请选择部门类型' }]
+      },
+      navBtnTitle: '新建',
+      deleteIds: [],
+      isDelete: false,
+      parentId: '',
+      isCreate: false,
+      isSon: false,
+      apartLists: [{id: 1, value: '总经办'}, {id: 2, value: '人事部'}, {id: 3, value: '财务部'}, {id: 4, value: '商务部'}, {id: 5, value: '销售部'}, {id: 6, value: '技术部'}],
+      rightsList: [],
+      selectOpts: []
+    }
+  },
+  // 初始化函数,赋值,menusTree =>menusTable
+  created () {
+    this.getList()
+  },
+  methods: {
+    getList () {
+      GetDepartmentList().then(res => {
+        console.log(res)
+        if (res.data.ErrorCode === 200) {
+          this.menusTable = res.data.Result
+          this.rightsList = res.data.Result
+          this.selectOpts = JSON.parse(JSON.stringify(this.rightsList))
+          this.selectOpts.unshift({ Name: '无上级部门', Id: 0 })
+        }
+      })
+    },
+    createModule () {
+      this.navBtnTitle = '新增部门'
+      this.depCreateDialog = true
+      this.isCreate = true
+      this.isSon = false
+    },
+    addApart (row) {
+      this.isCreate = true
+      this.isSon = true
+      this.navBtnTitle = '添加子部门'
+      this.depCreateDialog = true
+      this.apartForm = {
+        fatherIntro: row.Id, // 上级部门
+        introName: '', // 部门名称
+        apartStatus: true, // 部门状态
+        apartChosen: false, // 是否是区域部门
+        apartInt: '', // 是否是区域部门
+        sortNum: Number(row.Sort) + 1, // 排序数字
+        info: ''
+      }
+    },
+    editApart (row) {
+      console.log(row)
+      this.isCreate = false
+      this.isSon = false
+      this.navBtnTitle = '编辑部门'
+      this.depCreateDialog = true
+      this.isCreate = false
+      this.isSon = false
+      this.apartForm = {
+        fatherIntro: row.Id, // 上级部门
+        introName: row.Name, // 部门名称
+        apartStatus: row.IsEnabled, // 部门状态
+        apartChosen: row.IsSectorArea, // 是否是区域部门
+        apartInt: row.DepartmentType, // 是否是区域部门
+        sortNum: row.Sort, // 排序数字
+        info: row.Comment
+      }
+      this.parentId = row.ParentModuleId
+    },
+    getFatherOpt () {
+      console.log(this.apartForm.fatherIntro)
+      const flag = Array.isArray(this.apartForm.fatherIntro)
+      if (flag) {
+        this.parentId = this.apartForm.fatherIntro.length > 1 ? this.apartForm.fatherIntro[0] : ''
+      }
+    },
+    handleSelectionChange (val) {
+      console.log(val)
+      if (val.length > 0) {
+        let deleteId = []
+        val.forEach(item => {
+          deleteId.push(item.Id)
+        })
+        this.isDelete = true
+        this.deleteIds = deleteId
+      } else {
+        this.isDelete = false
+      }
+    },
+    deleteApart (id) {
+      this.$confirm('确定删除?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          DeleteDepartment({'Id': id}).then(res => {
+            console.log(res)
+            if (res.data.ErrorCode === 200) {
+              this.$message.success(res.data.Message)
+              this.getList()
+            } else {
+              this.$message.error(res.data.Message)
+            }
+          })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    },
+    submitDialog (formName) {
+      this.$refs[formName].validate(valid => {
+        if (!valid) return
+        const isIntro = Array.isArray(this.apartForm.fatherIntro)
+        let params = {
+          'Name': this.apartForm.introName,
+          'ParentId': isIntro ? (this.apartForm.fatherIntro.length > 1 ? this.apartForm.fatherIntro[this.apartForm.fatherIntro.length - 1] : (this.apartForm.fatherIntro[0] === 0 ? '' : this.apartForm.fatherIntro[0])) : this.apartForm.fatherIntro,
+          'DepartmentType': this.apartForm.apartInt,
+          'IsEnabled': this.apartForm.apartStatus,
+          'Sort': this.apartForm.sortNum,
+          'Comment': this.apartForm.info,
+          // 'LeaderUserId': '',
+          'IsSectorArea': this.apartForm.apartChosen
+        }
+        if (this.isCreate) {
+          if (this.isSon) {
+            params.ParentModuleId = this.parentId
+          }
+          AddDepartment(params).then(res => {
+            console.log(res)
+            if (res.data.ErrorCode === 200) {
+              this.$message.success(res.data.Message)
+              this.getList()
+              this.depCreateDialog = false
+              this.$refs.apartForm.resetFields()
+              this.apartForm = {
+                fatherIntro: '', // 上级部门
+                introName: '', // 部门名称
+                apartStatus: true, // 部门状态
+                apartChosen: false, // 是否是区域部门
+                apartInt: '', // 是否是区域部门
+                sortNum: 1, // 排序数字
+                info: ''
+              }
+            } else {
+              this.$message.error(res.data.Message)
+            }
+          })
+        } else {
+          params.Id = isIntro ? (this.apartForm.fatherIntro.length > 1 ? this.apartForm.fatherIntro[this.apartForm.fatherIntro.length - 1] : this.apartForm.fatherIntro[0]) : this.apartForm.fatherIntro
+
+          params.ParentId = this.parentId
+
+          UpdateDepartment(params).then(res => {
+            console.log(res)
+            if (res.data.ErrorCode === 200) {
+              this.$message.success(res.data.Message)
+              this.getList()
+              this.depCreateDialog = false
+              this.$refs.apartForm.resetFields()
+              this.apartForm = {
+                fatherIntro: '', // 上级部门
+                introName: '', // 部门名称
+                apartStatus: true, // 部门状态
+                apartChosen: false, // 是否是区域部门
+                apartInt: '', // 是否是区域部门
+                sortNum: 1, // 排序数字
+                info: ''
+              }
+            } else {
+              this.$message.error(res.data.Message)
+            }
+          })
+        }
+      })
+    },
+    // 关闭新增或编辑
+    cancelDialog () {
+      this.$refs.apartForm.resetFields()
+      this.apartForm = {
+        fatherIntro: '', // 上级部门
+        introName: '', // 部门名称
+        apartStatus: true, // 部门状态
+        apartChosen: false, // 是否是区域部门
+        apartInt: '', // 是否是区域部门
+        sortNum: 1, // 排序数字
+        info: ''
+      }
+      this.depCreateDialog = false
+    },
+    showRow (row) {
+      const show = row.row.parent
+        ? row.row.parent._expanded && row.row.parent._show
+        : true
+      row.row._show = show
+      return show
+        ? 'animation:treeTableShow 1s;-webkit-animation:treeTableShow 1s;'
+        : 'display:none;'
+    },
+
+    // 树节点开关操作
+    openToggle (item) {
+      console.log(item)
+      // 这里只是展开和关闭样式的变换方法
+      Vue.set(item, 'open', !item.open)
+      // 展开的时候,显示子节点,关闭的时候隐藏子节点
+      // 遍历所有的子节点,加入到menuTable中
+      for (let j = 0; j < this.rightsList.length; j++) {
+        // 找到父节点的id,然后依次把子节点放到数组里面父节点后面
+        if (this.rightsList[j].Id !== item.Id) {
+          continue
+        }
+        if (item.open) { // open => close
+          console.log(item.Children)
+          let rightsList = this.rightsList
+          item.Children.forEach(function (child, index) {
+            rightsList.splice(j + index + 1, 0, child) // 添加子节点
+          })
+        } else {
+          this.rightsList.splice(j + 1, item.Children.length) // 删除子节点
+        }
+        break
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  .apartment-management{
+    height: 100%;
+    box-sizing: border-box;
+    display: flex;
+    flex-direction: column;
+  }
+  .nav-dialog-div {
+    margin-bottom: 20px;
+  }
+  .nav-dialog-div /deep/ .el-input {
+    width: auto;
+  }
+  .title {
+    font-size: 18px;
+    height: 40px;
+    line-height: 40px;
+    margin: 10px 0;
+    color: #333;
+    padding: 0 20px;
+  }
+  .level {
+    display: inline-block;
+    width: 20px;
+  }
+  .level1, .level2, .level3 {
+    display: inline-block;
+    width: 20px;
+  }
+
+  .level1 {
+    margin-left: 5px;
+  }
+
+  .level2 {
+    margin-left: 20px;
+  }
+
+  .level3 {
+    margin-left: 35px;
+  }
+  .create-button{
+    margin-bottom: 20px;
+    float: right;
+  }
+  .delete-button{
+    margin-bottom: 20px;
+    float: right;
+    margin-right: 20px;
+  }
+  .numInp{
+    width:40%;
+  }
+</style>
diff --git a/src/views/company/employeeManage/EmployeeManage.vue b/src/views/company/employeeManage/EmployeeManage.vue
new file mode 100644
index 0000000..83e20de
--- /dev/null
+++ b/src/views/company/employeeManage/EmployeeManage.vue
@@ -0,0 +1,1800 @@
+<template>
+  <div class="employee-dep-management">
+    <p class="title">员工与部门管理 </p>
+    <div class="system-content">
+      <!-- 左边导航栏 -->
+      <div
+        v-loading="depLoading"
+        class="system-view-nav">
+        <div class='system-nav-title'>
+          企业组织架构
+        </div>
+        <el-tree
+          ref="tree"
+          :data="treeData"
+          :expand-on-click-node="false"
+          node-key="DepartmentId"
+          :props="defaultProps"
+          default-expand-all
+          highlight-current
+          @node-click="changeDepClick">
+          <flexbox
+            slot-scope="{ node, data }"
+            class="node-data">
+            <img
+              v-if="node.expanded"
+              class="node-img"
+              src="@/assets/img/fold.png"
+              @click="handleExpand('close',node, data)">
+            <img
+              v-if="!node.expanded"
+              class="node-img"
+              src="@/assets/img/unfold.png"
+              @click="handleExpand('open',node, data)">
+            <div class="node-label">{{ data.Name }}</div>
+            <!-- <div class="node-label-set">
+              <el-button
+                v-if="strucSaveAuth"
+                type="text"
+                size="mini"
+                @click.stop="() => append(data)">
+                <i class="el-icon-plus"/>
+              </el-button>
+              <el-button
+                v-if="strucUpdateAuth"
+                type="text"
+                size="mini"
+                @click.stop="() => edit(node, data)">
+                <i class="el-icon-edit"/>
+              </el-button>
+              <el-button
+                v-if="strucDeleteAuth"
+                type="text"
+                size="mini"
+                @click.stop="() => remove(node, data)">
+                <i class="el-icon-close"/>
+              </el-button>
+            </div> -->
+          </flexbox>
+        </el-tree>
+      </div>
+      <!-- 右边内容 -->
+      <div class="system-view-table flex-index">
+        <div
+          class="table-top">
+          <div class='table-top__title'>{{tableTopName}}</div>
+          <div class="icon-search lt">
+            <el-input
+              v-model="searchName"
+              placeholder="请输入员工名称"
+              @keyup.enter.native="searchClick"/>
+            <i
+              class="el-icon-search"
+              @click="searchClick"/>
+          </div>
+          <div class="icon-search lt">
+            <el-input
+              v-model="searchPhone"
+              placeholder="请输入员工手机号"
+              @keyup.enter.native="searchClick"/>
+            <i
+              class="el-icon-search"
+              @click="searchClick"/>
+          </div>
+          <!--<div class="status">
+            <span>状态</span>
+            <el-select
+              v-model="selectModel"
+              :clearable="true"
+              placeholder="请选择"
+              @change="statusChange">
+              <el-option
+                v-for="item in statusOptions"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"/>
+            </el-select>
+          </div>
+          <el-button
+            v-if="selectionList.length > 0"
+            type="primary"
+            class="setMultiPosition"
+            @click="newBtn">新建员工</el-button>-->
+            <el-button
+            v-if="selectionList.length > 0"
+            type="primary"
+            class="setMultiPosition"
+            @click="isSetPosition = true">权限名称</el-button>
+        </div>
+        <!--<flexbox
+          v-if="selectionList.length > 0"
+          class="selection-bar">
+          <div class="selected—title">已选中<span class="selected—count">{{ selectionList.length }}</span>项</div>
+          <flexbox class="selection-items-box">
+            <flexbox
+              v-for="(item, index) in selectionInfo"
+              :key="index"
+              class="selection-item"
+              @click.native="selectionBarClick(item.type)">
+              <img
+                :src="item.icon"
+                class="selection-item-icon" >
+              <div class="selection-item-name">{{ item.name }}</div>
+            </flexbox>
+          </flexbox>
+        </flexbox>-->
+        <div class="flex-box">
+          <el-table
+            v-loading="loading"
+            id="crm-table"
+            :data="tableData"
+            :height="tableHeight"
+            :cell-style="cellStyle"
+            class="n-table--border"
+            border
+            highlight-current-row
+            style="width: 100%; z-index: 0;"
+            @header-dragend="handleHeaderDragend"
+            @selection-change="handleSelectionChange"
+            @row-click="rowClick">
+            <el-table-column
+              type="selection"
+              width="55"/>
+            <el-table-column
+              prop="Name"
+              width="200"
+              show-overflow-tooltip
+              label="姓名">
+              <template slot-scope="scope">
+                <div class="status-name">
+                  <div
+                    v-photo="scope.row.Avatar"
+                    v-lazy:background-image="$options.filters.filterUserLazyImg(scope.row.Avatar)"
+                    :key="scope.row.Avatar"
+                     class="user-img div-photo"/>
+
+                  <div :style="{'background-color' : getStatusColor(scope.row.Status)}"/>
+                  {{ scope.row.Name }}
+                </div>
+              </template>
+              <template
+                slot="header"
+                slot-scope="scope">
+                <div class="table-head-name">{{ scope.column.label }}</div>
+              </template>
+            </el-table-column>
+            <el-table-column
+              v-for="(item, index) in fieldList"
+              :key="index"
+              :width="item.width"
+              :prop="item.field"
+              :label="item.value"
+              :formatter="tableFormatter"
+              show-overflow-tooltip>
+              <template
+                slot="header"
+                slot-scope="scope">
+                <div class="table-head-name">{{ scope.column.label }}</div>
+              </template>
+            </el-table-column>
+            <!--<el-table-column label="排序" prop="SortNumber"></el-table-column>-->
+            <el-table-column
+              prop="operation"
+              width='200'
+              label="操作">
+              <template
+                slot="header"
+                slot-scope="scope">
+                <div class="table-head-name">操作</div>
+              </template>
+              <template slot-scope="scope">
+                <el-button type="text" size="small"  @click='setPosition(scope.row.Id)'>权限名称</el-button>
+                <el-button type="text" size="small"  @click='setArea(scope.row)'>销售区域</el-button>
+              </template>
+            </el-table-column>
+            <el-table-column/>
+          </el-table>
+          <div class="p-contianer" v-if='total>0'>
+            <el-pagination
+              :current-page="currentPage"
+              :page-sizes="pageSizes"
+              :page-size.sync="pageSize"
+              :total="total"
+              class="p-bar"
+              layout="total, sizes, prev, pager, next, jumper"
+              @size-change="handleSizeChange"
+              @current-change="handleCurrentChange"/>
+          </div>
+        </div>
+      </div>
+    </div>
+    <!-- 配置系统职务 -->
+    <el-dialog
+      title="配置权限名称"
+      :visible.sync="isSetPosition"
+      width="24%"
+      append-to-body
+      :before-close="handlePosClose">
+      <div class='pushBody'>
+        <div class='hintSelect'>
+          <span>权限名称:</span>
+          <el-select v-model="pushStatus" placeholder="请选择">
+            <el-option
+              v-for="item in pushOptions"
+              :key="item.Id"
+              :label="item.Name"
+              :value="item.Id">
+            </el-option>
+          </el-select>
+        </div>
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="handlePosClose" class='closePushBtn'>取 消</el-button>
+        <el-button type="primary" @click="savePos" class='surePushBtn'>提交</el-button>
+      </span>
+    </el-dialog>
+    <!-- 配置区域 -->
+    <el-dialog
+      title="销售区域"
+      :visible.sync="isSetArea"
+      width="24%"
+      append-to-body
+      :before-close="handleAreaClose">
+      <div class='pushBody'>
+        <div class='hintSelect'>
+          <span>销售区域:</span>
+          <el-select v-model="areaStatus" multiple placeholder="请选择">
+            <el-option
+              v-for="item in areaOptions"
+              :key="item.ID"
+              :label="item.ProvinceName"
+              :value="item.ProvinceName">
+            </el-option>
+          </el-select>
+        </div>
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="handleAreaClose" class='closePushBtn'>取 消</el-button>
+        <el-button type="primary" @click="saveArea" class='surePushBtn'>提交</el-button>
+      </span>
+    </el-dialog>
+    <!-- 导航新增编辑弹出框 -->
+    <el-dialog
+      :visible.sync="depCreateDialog"
+      :title="navBtnTitle"
+      :before-close="navHandleClose"
+      width="30%">
+      <div class="nav-dialog-div">
+        <label>{{ labelName }}:</label>
+        <el-input
+          v-model="treeInput"
+          placeholder="请输入内容"/>
+      </div>
+      <div
+        v-if="depSelect !== 0"
+        class="nav-dialog-div">
+        <label>上级部门:</label>
+        <el-select
+          v-model="depSelect"
+          :clearable="false"
+          placeholder="请选择">
+          <el-option
+            v-for="item in dialogOptions"
+            :key="item.id"
+            :label="item.name"
+            :value="item.id"/>
+        </el-select>
+      </div>
+      <span
+        slot="footer"
+        class="dialog-footer">
+        <el-button @click="depCreateDialog = false">取 消</el-button>
+        <el-button
+          type="primary"
+          @click="submitDialog">确 定</el-button>
+      </span>
+    </el-dialog>
+    <!-- 详情 -->
+    <employee-detail
+      v-if="employeeDetailDialog"
+      :data="dialogData"
+      @edit="editBtn"
+      @command="handleCommand"
+      @hide-view="employeeDetailDialog=false"/>
+    <!-- 重置密码 -->
+    <el-dialog
+      v-loading="loading"
+      :visible.sync="resetPasswordVisible"
+      :close-on-click-modal="false"
+      :modal-append-to-body="false"
+      :before-close="resetPasswordClose"
+      title="重置密码"
+      width="30%">
+      <div class="el-password">
+        <el-form
+          ref="passForm"
+          :model="passForm"
+          :rules="rules">
+          <el-form-item
+            label="密码"
+            prop="password">
+            <el-input
+              v-model="passForm.password"
+              type="password"/>
+          </el-form-item>
+        </el-form>
+      </div>
+      <span
+        slot="footer"
+        class="dialog-footer">
+        <el-button @click="resetPasswordClose">取 消</el-button>
+        <el-button
+          type="primary"
+          @click="passSubmit(passForm)">确 定</el-button>
+      </span>
+    </el-dialog>
+
+    <!-- 重置登录账号 -->
+    <el-dialog
+      v-loading="loading"
+      :visible.sync="resetUserNameVisible"
+      :close-on-click-modal="false"
+      :modal-append-to-body="false"
+      :before-close="()=>{resetUserNameVisible = false}"
+      title="重置登录账号"
+      width="30%">
+      <div class="el-password">
+        <el-form
+          ref="resetUserNameForm"
+          :model="resetUserNameForm"
+          :rules="dialogRules">
+          <el-form-item
+            label="新账号(手机号)"
+            prop="username">
+            <el-input v-model="resetUserNameForm.username"/>
+          </el-form-item>
+          <el-form-item
+            label="新密码"
+            prop="password">
+            <el-input
+              v-model="resetUserNameForm.password"
+              type="password"/>
+          </el-form-item>
+        </el-form>
+        <div
+          class="tips"
+          style="margin-top: 20px;">重置登录帐号后,员工需用新账号登录。请及时告知员工,确保正常使用</div>
+      </div>
+      <span
+        slot="footer"
+        class="dialog-footer">
+        <el-button @click="()=>{resetUserNameVisible = false}">取 消</el-button>
+        <el-button
+          type="primary"
+          @click="passUserNameSubmit(resetUserNameForm)">确 定</el-button>
+      </span>
+    </el-dialog>
+
+    <!-- 新建和编辑 -->
+    <el-dialog
+      v-loading="loading"
+      v-if="employeeCreateDialog"
+      :title="dialogTitle"
+      :visible.sync="employeeCreateDialog"
+      :close-on-click-modal="false"
+      :modal-append-to-body="true"
+      :append-to-body="true"
+      :before-close="newHandleClose"
+      width="60%">
+      <p class="new-dialog-title">基本信息</p>
+      <el-form
+        ref="dialogRef"
+        :inline="true"
+        :model="formInline"
+        :rules="dialogRules"
+        class="new-dialog-form"
+        label-width="80px"
+        label-position="top">
+        <el-form-item
+          v-for="(item, index) in tableList"
+          :label="item.value"
+          :prop="item.field"
+          :key="index">
+          <span slot="label">{{ item.value }}</span>
+          <el-tooltip
+            v-if="item.tips"
+            slot="label"
+            :content="item.tips"
+            effect="dark"
+            placement="top">
+            <i class="wukong wukong-help_tips"/>
+          </el-tooltip>
+          <template v-if="item.type === 'select'">
+            <el-select
+              v-model="formInline[item.field]"
+              filterable
+              placeholder="请选择"
+              @change='getPositionName'>
+              <el-option
+                v-for="optionItem in optionsList[item.field].list"
+                :key="optionItem.Id"
+                :label="optionItem.PositionName"
+                :value="optionItem.Id"/>
+            </el-select>
+          </template>
+          <template v-else-if="item.type === 'radio'">
+            <el-radio-group v-model="formInline[item.field]">
+              <el-radio :label="1">男</el-radio>
+              <el-radio :label="2">女</el-radio>
+            </el-radio-group>
+          </template>
+          <template v-else-if="item.type === 'switch'">
+            <el-switch v-model="formInline[item.field]"></el-switch>
+          </template>
+          <template v-else-if="item.type === 'cascader'">
+             <el-cascader
+              ref="refSubDepart"
+              placeholder="请选择上级部门"
+              :options="rightsList"
+              :show-all-levels="false"
+              :props="{
+                children: 'Children',
+                label: 'DepartmentName',
+                value: 'Id'
+              }"
+              v-model="formInline[item.field]"
+              style="width: 100%;"
+              @change='getFatherOpt'
+              change-on-select/>
+          </template>
+          <template v-else-if="item.type === 'selectCheckout'">
+            <el-select
+              v-model="formInline[item.field]"
+              :popper-append-to-body="false"
+              popper-class="select-popper-class"
+              filterable
+              placeholder="请选择">
+              <el-option
+                v-for="item in groupsList"
+                :key="item.Id"
+                :label="item.DepartmentName"
+                :value="item.Id"/>
+            </el-select>
+          </template>
+          <el-input
+            v-else
+            v-model="formInline[item.field]"
+            :disabled="dialogTitle === '编辑员工' && item.field === 'username'"/>
+        </el-form-item>
+      </el-form>
+      <span
+        slot="footer"
+        class="dialog-footer">
+        <el-button
+          type="primary"
+          @click="newDialogSubmit">保 存</el-button>
+        <el-button @click="newHandleClose">取 消</el-button>
+      </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { GetUserInfoDepartmentList, GetUserInfoPositionList, AddUserInfo, UpdateUserInfo, DeleteUserInfo, GetUserInfoList, UpdateUserPostion, BindUserSalesArea
+} from '@/api/systemManagement/employeeManage'
+import { GetProvincesList } from '@/api/common'
+// GetUserInfoPageList,
+import { GetDepartmentList, GetDepartmentAreaList } from '@/api/systemManagement/departmentManage'
+// import { usersList, depList } from '@/api/common' // 直属上级接口
+import EmployeeDetail from './components/employeeDetail'
+import { GetPositionList } from '@/api/systemManagement/officalAuthority'
+import { mapGetters } from 'vuex'
+
+var validateUsername = (rule, value, callback) => {
+  if (value && value === 'admin') {
+    callback()
+  } else if (value && /^1\d{10}$/.test(value)) {
+    callback()
+  } else {
+    callback(new Error('目前只支持中国大陆的手机号码或座机号'))
+  }
+}
+
+export default {
+  /** 系统管理 的 员工部门管理 */
+  name: 'EmployeeManage',
+  components: {
+    EmployeeDetail
+  },
+  data () {
+    return {
+      // 右边导航
+      navBtnTitle: '新建',
+      depCreateDialog: false, // 控制部门新增 编辑 数据
+      depSelect: '',
+      dialogOptions: [],
+      labelName: '',
+      treeData: [],
+      depLoading: false, // 左侧部门loading效果
+      // 列表
+      loading: false, // 表的加载动画
+      searchName: '', // 搜索
+      searchPhone: '',
+      statusOptions: [
+        { value: '1', label: '已激活' },
+        { value: '2', label: '已禁用' },
+        { value: '4', label: '未激活' },
+        { value: '5', label: '退出企业' }
+      ],
+      selectModel: '', // 状态值 用于筛选
+      /** 列表 */
+      fieldList: [
+        { field: 'IsLeader', value: '是否为上级' },
+        { field: 'MobilePhone', value: '手机号(登录名)' },
+        { field: 'Gender', value: '性别' },
+        { field: 'Email', value: '邮箱' },
+        { field: 'MainDepartmentName', value: '部门' },
+        { field: 'MasterSalesArea', value: '销售区域' },
+        { field: 'Status', value: '状态' },
+        { field: 'Position', value: '公司职务' },
+        { field: 'JobPosition', value: '权限名称' }
+      ],
+      selectionList: [], // 批量勾选数据
+      tableData: [],
+      tableHeight: document.documentElement.clientHeight - 360, // 表的高度
+      /** 分页逻辑 */
+      structureValue: '', // 左侧列表选中的值 用于筛选
+      currentPage: 1,
+      pageSize: 10,
+      pageSizes: [10, 20, 45, 60],
+      total: 0,
+      /** ** */
+      employeeDetailDialog: false,
+      dialogData: {},
+      // 新建和编辑
+      employeeCreateDialog: false,
+      dialogTitle: '新建员工',
+      formInline: {},
+      treeInput: '',
+      // 编辑部门时id
+      treeEditId: '',
+      optionsList: {
+        DepartmentId: {
+          field: 'DepartmentId',
+          list: []
+        },
+        PositionId: {
+          field: 'PositionId',
+          list: [{ Id: 0, PositionName: '请选择' }]
+        },
+        Sex: {
+          field: 'Sex',
+          list: [
+            { id: 0, name: '请选择' },
+            { id: 1, name: '男' },
+            { id: 2, name: '女' }
+          ]
+        }
+      },
+      groupsList: [{DepartmentName: '', Id: 0}],
+      // 重置密码
+      resetPasswordVisible: false,
+      rules: {
+        password: [
+          { required: true, message: '请输入密码', trigger: 'blur' },
+          { min: 6, max: 12, message: '长度在 6 到 12 个字符', trigger: 'blur' }
+        ],
+        username: [
+          { required: true, message: '手机号不能为空', trigger: 'blur' }
+        ]
+      },
+      passForm: {},
+      dialogRules: {
+        UserName: [
+          { required: true, message: '用户名不能为空', trigger: 'blur' }
+        ],
+        RealName: [
+          { required: true, message: '姓名不能为空', trigger: 'blur' }
+        ],
+        LoginPassword: [
+          { required: true, message: '请输入密码', trigger: 'blur' },
+          { min: 6, max: 12, message: '长度在 6 到 12 个字符', trigger: 'blur' }
+        ],
+        ConfirmPassword: [
+          { required: true, message: '请再次输入密码', trigger: 'blur' },
+          { min: 6, max: 12, message: '长度在 6 到 12 个字符', trigger: 'blur' }
+        ],
+        MobilePhone: [
+          { required: true, message: '手机号码不能为空', trigger: 'blur' },
+          {
+            validator: validateUsername,
+            trigger: 'blur'
+          }
+        ],
+        Email: [
+          {
+            // eslint-disable-next-line no-useless-escape
+            pattern: /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/,
+            message: '请输入正确的邮箱格式',
+            trigger: 'blur',
+            required: true
+          }
+        ],
+        DepartmentId: [
+          { required: true, message: '部门不能为空', trigger: 'change' }
+        ],
+        PositionId: [{ required: true, message: '职务不能为空', trigger: 'change' }]
+      },
+      // 重置登录账号
+      resetUserNameVisible: false,
+      resetUserNameForm: {
+        username: '',
+        password: ''
+      },
+      defaultProps: {
+        children: 'Children',
+        label: 'Name'
+      },
+      rightsList: [],
+      parentId: '',
+      positionName: '',
+      tableTopName: '全公司',
+      isSetPosition: false, // 职务配置
+      pushStatus: '',
+      pushOptions: [],
+      isSetArea: false, // 区域配置
+      areaId: '',
+      areaStatus: [],
+      areaOptions: []
+    }
+  },
+  computed: {
+    ...mapGetters(['manage']),
+    // 员工创建权限
+    userSaveAuth () {
+      // return this.manage && this.manage.users && this.manage.users.userSave
+      return true
+    },
+    // 员工编辑操作权限
+    userUpdateAuth () {
+      // return this.manage && this.manage.users && this.manage.users.userUpdate
+      return true
+    },
+    // 员工禁用启用权限
+    userEnablesAuth () {
+      // return this.manage && this.manage.users && this.manage.users.userEnables
+      return true
+    },
+    // 员工列表的勾选编辑
+    tableUpdateAuth () {
+      return this.userEnablesAuth && this.userUpdateAuth
+    },
+    // // 部门编辑权限
+    strucSaveAuth () {
+      // return this.manage && this.manage.users && this.manage.users.deptSave
+      return true
+    },
+    // 部门编辑权限
+    strucUpdateAuth () {
+      // return this.manage && this.manage.users && this.manage.users.deptUpdate
+      return true
+    },
+    // 部门编辑权限
+    strucDeleteAuth () {
+      // return this.manage && this.manage.users && this.manage.users.deptDelete
+      return true
+    },
+    selectionInfo: function () {
+      let temps = []
+      // if (this.userEnablesAuth) {
+      //   temps = [
+      //     {
+      //       name: '禁用',
+      //       type: 'lock',
+      //       icon: require('@/assets/img/selection_disable.png')
+      //     },
+      //     {
+      //       name: '激活',
+      //       type: 'unlock',
+      //       icon: require('@/assets/img/selection_start.png')
+      //     }
+      //   ]
+      // }
+      if (this.userUpdateAuth) {
+        if (this.selectionList.length === 1) {
+          temps = temps.concat([
+            {
+              name: '编辑',
+              type: 'edit',
+              icon: require('@/assets/img/selection_edit.png')
+            }
+            // ,
+            // {
+            //   name: '重置密码',
+            //   type: 'reset',
+            //   icon: require('@/assets/img/selection_reset.png')
+            // },
+            // {
+            //   name: '重置登录账号',
+            //   type: 'resetName',
+            //   icon: require('@/assets/img/section_reset_name.png')
+            // }
+          ])
+        } else {
+          // temps = temps.concat([
+          //   {
+          //     name: '重置密码',
+          //     type: 'reset',
+          //     icon: require('@/assets/img/selection_reset.png')
+          //   }
+          // ])
+        }
+      }
+
+      return temps
+    },
+    /** 添加列表 */
+    tableList: function () {
+      if (this.dialogTitle === '新建员工') {
+        return [
+          { field: 'UserName', value: '用户名(登录名)' },
+          { field: 'RealName', value: '姓名' },
+          { field: 'Sex', value: '性别', type: 'radio' },
+          { field: 'MobilePhone', value: '手机号' },
+          { field: 'Email', value: '邮箱' },
+          { field: 'OfficePhone', value: '办公电话' },
+          { field: 'QQNumber', value: 'QQ' },
+          { field: 'WeixinNumber', value: '微信' },
+          { field: 'IsEnabled', value: '状态', type: 'switch' },
+          { field: 'DepartmentId', value: '部门', type: 'cascader' },
+          { field: 'LoginPassword', value: '登录密码' },
+          { field: 'PositionId', value: '职务', type: 'select' },
+          { field: 'ConfirmPassword', value: '确认登录密码' }
+        ]
+      } else {
+        return [
+          { field: 'UserName', value: '用户名(登录名)' },
+          { field: 'RealName', value: '姓名' },
+          { field: 'Sex', value: '性别', type: 'radio' },
+          { field: 'MobilePhone', value: '手机号' },
+          { field: 'Email', value: '邮箱' },
+          { field: 'OfficePhone', value: '办公电话' },
+          { field: 'QQNumber', value: 'QQ' },
+          { field: 'WeixinNumber', value: '微信' },
+          { field: 'IsEnabled', value: '状态', type: 'switch' },
+          { field: 'DepartmentId', value: '部门', type: 'cascader' },
+          { field: 'PositionId', value: '职务', type: 'select' },
+          { field: 'LoginPassword', value: '登录密码' },
+          { field: 'ConfirmPassword', value: '确认登陆密码' }
+        ]
+      }
+    }
+  },
+  mounted () {
+    var self = this
+    /** 控制table的高度 */
+    window.onresize = function () {
+      self.tableHeight = document.documentElement.clientHeight - 260
+    }
+
+    // 部门树形列表
+    this.treeListFun()
+    this.getSelectUserList() // 直属上级列表
+    this.getDepList()
+    // 系统职务
+    this.getPositionList()
+    // 配置区域
+    this.getAreaList()
+    // 新增编辑下拉选项
+    // this.departListFun()
+    // this.positionListFun()
+    // this.departAreaFunc()
+    // document.getElementsByClassName('el-select-dropdown')[0].style.color = 'red'
+  },
+  methods: {
+    handleHeaderDragend (newWidth, oldWidth, column, event) {
+      if (column.property) {
+      }
+    },
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+    },
+    getArea (val) {
+      console.log(val)
+    },
+    // 改变部门
+    changeDepClick (data) {
+      console.log(data)
+      this.currentPage = 1
+      this.structureValue = data.DepartmentId
+      this.usersListFun()
+    },
+    /**
+     * 展开闭合操作
+     */
+    handleExpand (type, node, data) {
+      console.log(type, node, data)
+      if (type === 'close') {
+        if (data.Children) {
+          node.expanded = false
+        }
+      } else if (type === 'open') {
+        node.expanded = true
+      }
+    },
+    getPositionName (val) {
+      this.positionName = val ? this.optionsList['PositionId'].list.find(ele => ele.Id === val).PositionName : ''
+    },
+    getFatherOpt (val) {
+      console.log(this.$refs['refSubDepart'][0].getCheckedNodes()[0].label)
+      const flag = Array.isArray(this.formInline['DepartmentId'])
+      if (flag) {
+        this.parentId = this.formInline['DepartmentId'].length > 1 ? this.formInline['DepartmentId'][0] : ''
+      }
+      for (let j = 0; j < this.rightsList.length; j++) {
+        if (this.rightsList[j].Id === val[0]) {
+          if (this.rightsList[j].DepartmentType === 6) {
+            this.tableList.splice(11, 0, { field: 'UserDepartment', value: '区域部门关联', type: 'selectCheckout' })
+          } else {
+            if (this.tableList[11].field === 'UserDepartment') {
+              this.tableList.splice(11, 1)
+            }
+          }
+        }
+      }
+    },
+    handleClose () {
+      this.employeeDetailDialog = false
+    },
+    // 第一列点击事件
+    rowClick (row, column, event) {
+      this.dialogData = row
+      if (column.property === 'Name') {
+        this.employeeDetailDialog = true
+      }
+    },
+    // 新建和编辑
+    newHandleClose () {
+      this.employeeCreateDialog = false
+      this.$refs.dialogRef.resetFields()
+      if (this.tableList[11].field === 'UserDepartment') {
+        this.tableList.splice(11, 1)
+      }
+    },
+    // 新建用户
+    newBtn () {
+      this.employeeCreateDialog = true
+      this.dialogTitle = '新建员工'
+      this.formInline = {
+        Sex: 1,
+        IsEnabled: true
+      }
+    },
+    // 详情 -- 编辑用户
+    editBtn () {
+      this.dialogTitle = '编辑员工'
+      var detail = {}
+      for (let index = 0; index < this.tableList.length; index++) {
+        const element = this.tableList[index]
+        if (element.field !== 'LoginPassword') {
+          // if (element.field === 'PositionId') {
+          //   detail[element.field] = this.dialogData.PositionId
+          //     ? this.dialogData.PositionId
+          //       .split(',')
+          //       .map(function (item, index, array) {
+          //         return parseInt(item)
+          //       })
+          //     : []
+          // }
+          if (element.field === 'DepartmentId') {
+            detail.DepartmentId = this.dialogData.DepartmentId
+          } else {
+            detail[element.field] = this.dialogData[element.field]
+          }
+        }
+      }
+      detail['Id'] = this.dialogData.Id
+      this.formInline = detail
+      this.employeeCreateDialog = true
+    },
+    // 增加组织架构
+    // 部门非树形结构列表 用于部门添加
+    getDepList () {
+      // depList().then(response => {
+      //   this.optionsList['deptId'].list = response.data
+      // })
+    },
+    append (data) {
+      this.treeInput = ''
+      this.labelName = '新增部门'
+      this.navBtnTitle = '新增部门'
+      this.depSelect = data.id
+      this.getStructuresListBySuperior({ id: data.id, type: 'save' })
+      this.depCreateDialog = true
+    },
+    // 获取新增部门 上级部门信息
+    getStructuresListBySuperior (data) {
+      this.dialogOptions = []
+      // depList(data).then(response => {
+      //   this.dialogOptions = response.data
+      // })
+    },
+    // 配置系统职务
+    setPosition (id) {
+      this.selectionList = [{'Id': id}]
+      this.isSetPosition = true
+    },
+    handlePosClose () {
+      this.pushStatus = ''
+      this.isSetPosition = false
+    },
+    savePos () {
+      let params = {
+        'PositionId': this.pushStatus,
+        'UserInfos': this.selectionList
+      }
+      console.log(params)
+      UpdateUserPostion(params).then(res => {
+        console.log(res)
+        if (res.data.ErrorCode === 200) {
+          this.$message.success(res.data.Message)
+          this.isSetPosition = false
+          this.pushStatus = ''
+          this.usersListFun()
+        } else {
+          this.$message.error(res.data.Message)
+        }
+      })
+    },
+    // 勾选
+    handleSelectionChange (val) {
+      let Ids = []
+      for (let j in val) {
+        Ids.push({'Id': val[j].Id})
+      }
+      this.selectionList = Ids // 勾选的行
+      console.log(this.selectionList)
+    },
+    getPositionList () {
+      GetPositionList().then(res => {
+        console.log(res)
+        if (res.data.ErrorCode === 200 && res.data.Result) {
+          this.pushOptions = res.data.Result
+        } else {
+          this.$message.error(res.data.Message)
+        }
+      })
+    },
+    getAreaList () {
+      GetProvincesList().then(res => {
+        console.log(res)
+        if (res.data.ErrorCode === 200 && res.data.Result) {
+          this.areaOptions = res.data.Result
+        } else {
+          this.$message.error(res.data.Message)
+        }
+      })
+    },
+    // 区域配置
+    handleAreaClose () {
+      this.areaStatus = []
+      this.isSetArea = false
+    },
+    // 配置系统区域
+    setArea (row) {
+      this.areaId = [row.Id]
+      this.areaStatus = row.MasterSalesArea && row.MasterSalesArea.length > 0 ? row.MasterSalesArea.split(',') : []
+      this.isSetArea = true
+    },
+    saveArea () {
+      console.log(this.areaStatus)
+      let params = {
+        'Users': this.areaId,
+        'Areas': this.areaStatus
+      }
+      console.log(params)
+      BindUserSalesArea(params).then(res => {
+        console.log(res)
+        if (res.data.ErrorCode === 200) {
+          this.$message.success(res.data.Message)
+          this.isSetArea = false
+          this.areaStatus = []
+          this.usersListFun()
+        } else {
+          this.$message.error(res.data.Message)
+        }
+      })
+    },
+    // 编辑组织架构
+    edit (node, data) {
+      this.treeInput = data.label
+      this.treeEditId = data.id
+      this.depSelect = data.pid
+      this.navBtnTitle = '编辑部门'
+      this.labelName = '编辑部门'
+      this.getStructuresListBySuperior({ id: data.id, type: 'update' })
+      this.depCreateDialog = true
+    },
+    // 删除组织架构
+    remove (node, data) {
+      this.$confirm('此操作将永久删除, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          this.loading = true
+          // depDelete({ id: data.id })
+          //   .then(res => {
+          //     this.treeListFun()
+          //     this.$message.success('删除成功')
+          //     this.loading = false
+          //   })
+          //   .catch(() => {
+          //     this.loading = false
+          //   })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    },
+    // 关闭新增或编辑
+    navHandleClose () {
+      this.depCreateDialog = false
+    },
+    // 新增或编辑确定按钮
+    submitDialog () {
+      if (this.labelName === '新增部门') {
+        // depSave({ name: this.treeInput, pid: this.depSelect }).then(res => {
+        //   this.getDepList() // 增加了新部门 刷新数据
+        //   this.treeListFun()
+        //   this.navHandleClose()
+        // })
+      } else {
+        // depEdit({
+        //   name: this.treeInput,
+        //   deptId: this.treeEditId,
+        //   pid: this.depSelect
+        // }).then(res => {
+        //   this.$message.success('操作成功')
+        //   this.treeListFun()
+        //   this.navHandleClose()
+        // })
+      }
+    },
+    // 获取树形列表
+    treeListFun () {
+      this.depLoading = true
+      GetDepartmentList()
+        .then(response => {
+          this.treeData = response.data.Result
+          this.structureValue = response.data.Result[0].DepartmentId
+          this.tableTopName = response.data.Result[0].Name
+          this.usersListFun()
+          this.depLoading = false
+        })
+        .catch(() => {
+          this.depLoading = false
+        })
+    },
+    departListFun () {
+      GetUserInfoDepartmentList().then(response => {
+        if (response.data.Result) {
+          this.rightsList = response.data.Result
+        } else {
+          this.$message.error(response.data.Message)
+        }
+      })
+        .catch((err) => {
+          console.log(err)
+        })
+    },
+    positionListFun () {
+      GetUserInfoPositionList().then(response => {
+        if (response.data.Result) {
+          this.optionsList['PositionId'].list = response.data.Result
+        } else {
+          this.$message.error(response.data.Message)
+        }
+      })
+        .catch((err) => {
+          console.log(err)
+        })
+    },
+    departAreaFunc () {
+      GetDepartmentAreaList().then(response => {
+        if (response.data.Result) {
+          this.groupsList = response.data.Result
+        } else {
+          this.$message.error(response.data.Message)
+        }
+      })
+        .catch((err) => {
+          console.log(err)
+        })
+    },
+    // 搜索框
+    searchClick () {
+      this.currentPage = 1
+      this.structureValue = 0
+      this.usersListFun()
+    },
+    // 状态筛选
+    statusChange () {
+      this.currentPage = 1
+      this.usersListFun()
+    },
+    deleteSingleModule (id) {
+      this.$confirm('确定删除?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          DeleteUserInfo({'Id': id}).then(res => {
+            if (res.data.ErrorCode === 200) {
+              this.$message.success(res.data.Message)
+              this.usersListFun()
+              this.getSelectUserList()
+            } else {
+              this.$message.error(res.data.Message)
+            }
+          })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    },
+    // 用户新建
+    newDialogSubmit () {
+      this.$refs.dialogRef.validate(valid => {
+        if (valid) {
+          const isIntro = Array.isArray(this.formInline.DepartmentId)
+          this.formInline.DepartmentId = isIntro ? (this.formInline.DepartmentId.length > 1 ? this.formInline.DepartmentId[this.formInline.DepartmentId.length - 1] : (this.formInline.DepartmentId[0] === 0 ? '' : this.formInline.DepartmentId[0])) : this.formInline.DepartmentId
+          this.formInline.DepartmentName = this.$refs['refSubDepart'][0].getCheckedNodes()[0].label
+          this.formInline.PositionName = this.positionName
+          console.log(this.formInline)
+          if (this.dialogTitle === '新建员工') {
+            this.loading = true
+            // this.formInline.roleIds = this.formInline.roleId.join(',')
+            AddUserInfo(this.formInline)
+              .then(res => {
+                if (res.data.ErrorCode === 200 && res.data.Result !== 0) {
+                  this.$message.success('新增成功')
+                  this.employeeCreateDialog = false
+                  this.usersListFun()
+                  this.getSelectUserList()
+                  this.loading = false
+                } else {
+                  this.$message.error(res.data.Message)
+                  this.loading = false
+                }
+              })
+              .catch(() => {
+                this.loading = false
+              })
+          } else {
+            this.loading = true
+            // this.formInline.roleIds = this.formInline.roleId.join(',')
+            UpdateUserInfo(this.formInline)
+              .then(res => {
+                if (res.data.ErrorCode === 200 && res.data.Result !== 0) {
+                  if (this.employeeDetailDialog) {
+                    this.employeeDetailDialog = false
+                  }
+                  this.employeeCreateDialog = false
+                  this.$message.success('编辑成功')
+                  this.usersListFun()
+                  this.getSelectUserList()
+                  this.loading = false
+                } else {
+                  this.$message.error(res.data.Message)
+                  this.loading = false
+                }
+              })
+              .catch(() => {
+                this.loading = false
+              })
+          }
+        } else {
+          return false
+        }
+      })
+    },
+    // 详情里面点击事件
+    handleCommand (command) {
+      switch (command) {
+        case 'reset':
+          // 当前登录用户ID
+          this.passForm = {
+            password: ''
+          }
+          this.resetPasswordVisible = true
+          break
+        case 'status':
+          // usersEditStatus({
+          //   userIds: this.dialogData.userId,
+          //   status: this.dialogData.status === 0 ? 1 : 0
+          // }).then(res => {
+          //   this.employeeDetailDialog = false
+          //   this.$message.success('修改成功')
+          //   this.usersListFun()
+          // })
+          break
+      }
+    },
+    /** 操作 */
+    selectionBarClick (type) {
+      // var ids = this.selectionList
+      //   .map(function (item, index, array) {
+      //     return item.userId
+      //   })
+      // .join(',')
+      if (type === 'lock' || type === 'unlock') {
+        var message = type === 'lock' ? '禁用' : '激活'
+        this.$confirm('这些员工账号将被' + message + ', 是否继续?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+          .then(() => {
+            this.loading = true
+            // usersEditStatus({
+            //   userIds: ids,
+            //   status: type === 'unlock' ? 1 : 0
+            // })
+            //   .then(res => {
+            //     this.loading = false
+            //     this.$message.success('修改成功')
+            //     this.usersListFun()
+            //   })
+            //   .catch(() => {
+            //     this.loading = false
+            //   })
+          })
+          .catch(() => {
+            this.$message({
+              type: 'info',
+              message: '已取消删除'
+            })
+          })
+      } else if (type === 'reset') {
+        this.resetPasswordVisible = true
+      } else if (type === 'resetName') {
+        this.resetUserNameVisible = true
+      } else if (type === 'edit') {
+        this.dialogData = this.selectionList[0]
+
+        this.dialogTitle = '编辑员工'
+        var detail = {}
+        for (let index = 0; index < this.tableList.length; index++) {
+          const element = this.tableList[index]
+          if (element.field !== 'LoginPassword') {
+          // if (element.field === 'PositionId') {
+          //   detail[element.field] = this.dialogData.PositionId
+          //     ? this.dialogData.PositionId
+          //       .split(',')
+          //       .map(function (item, index, array) {
+          //         return parseInt(item)
+          //       })
+          //     : []
+          // }
+            if (element.field === 'DepartmentId') {
+              detail.DepartmentId = this.dialogData.DepartmentId
+            } else {
+              detail[element.field] = this.dialogData[element.field]
+            }
+          }
+        }
+        detail['Id'] = this.dialogData.Id
+        this.formInline = detail
+        this.employeeCreateDialog = true
+      }
+    },
+    // 重置密码 -- 关闭按钮
+    resetPasswordClose () {
+      this.resetPasswordVisible = false
+    },
+    // 重置密码 -- 确定按钮
+    passSubmit (val) {
+      this.$refs.passForm.validate(valid => {
+        if (valid) {
+          var ids = []
+          if (this.selectionList.length > 0) {
+            ids = this.selectionList
+              .map(function (item, index, array) {
+                return item.userId
+              })
+              .join(',')
+          } else {
+            ids = this.dialogData.userId
+          }
+          val.userIds = ids
+          this.loading = true
+          // adminUsersUpdatePwd(val)
+          //   .then(res => {
+          //     this.$message.success('重置成功')
+          //     this.resetPasswordClose()
+          //     this.loading = false
+          //   })
+          //   .catch(() => {
+          //     this.loading = false
+          //   })
+        } else {
+          return false
+        }
+      })
+    },
+    /**
+     * 重置登录账号
+     */
+    passUserNameSubmit (val) {
+      this.$refs.resetUserNameForm.validate(valid => {
+        if (valid) {
+          if (this.selectionList.length > 0) {
+            val.id = this.selectionList[0].userId
+            this.loading = true
+            // adminUsersUsernameEditAPI(val)
+            //   .then(res => {
+            //     this.$message.success('重置成功')
+            //     this.searchClick()
+            //     this.resetUserNameVisible = false
+            //     this.loading = false
+            //   })
+            //   .catch(() => {
+            //     this.loading = false
+            //   })
+          }
+        } else {
+          return false
+        }
+      })
+    },
+
+    // 更改每页展示数量
+    handleSizeChange (val) {
+      this.pageSize = val
+      this.usersListFun()
+    },
+    // 更改当前页数
+    handleCurrentChange (val) {
+      this.currentPage = val
+      this.usersListFun()
+    },
+    // 用户列表
+    usersListFun () {
+      this.loading = true
+      GetUserInfoList({
+        PageIndex: this.currentPage,
+        PageSize: this.pageSize,
+        RealName: this.searchName,
+        DepartmentId: this.structureValue,
+        MobilePhone: this.searchPhone
+      })
+        .then(res => {
+          this.tableData = res.data.Result.List
+          this.total = res.data.Result.Count
+          this.loading = false
+        })
+        .catch(() => {
+          this.loading = false
+        })
+    },
+    /** 获取选择直属上级列表 */
+    getSelectUserList () {
+      this.loading = true
+      // usersList({ pageType: 0 })
+      //   .then(res => {
+      //     this.optionsList['parentId'].list = []
+      //     for (const i of res.data) {
+      //       this.optionsList['parentId'].list.push({
+      //         id: i.userId,
+      //         name: i.realname
+      //       })
+      //     }
+      //     this.loading = false
+      //   })
+      //   .catch(() => {
+      //     this.loading = false
+      //   })
+    },
+    // 获取状态颜色 0 禁用 1 启用 2未激活
+    getStatusColor (status) {
+      if (status === 0) {
+        return '#FF6767'
+      } else if (status === 1) {
+        return '#4D88FF'
+      } else if (status === 2) {
+        return '#CCCCCC'
+      }
+    },
+    // 列表信息格式化
+    tableFormatter (row, column) {
+      if (column.property === 'IsLeader') {
+        return { true: '是', false: '否' }[row.IsLeader]
+      } else if (column.property === 'Gender') {
+        return { 1: '男', 2: '女' }[row.Gender]
+      } else if (column.property === 'Status') {
+        return { 1: '已激活',
+          2: '已禁用',
+          4: '未激活',
+          5: '退出企业'}[row.Status]
+      }
+      return row[column.property] || '--'
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.el-table /deep/ thead th:first-child, thead td {
+  border-right: 1px solid #F7FAFF !important;
+}
+.setMultiPosition{
+  margin-left: 30px;
+}
+.pushBody{
+  margin: 0 60px;
+  .hintWord{
+    margin-top: 10px;
+  }
+  .hintSelect{
+    margin-top: 20px;
+    .el-select{
+      width: 224px;
+    }
+  }
+}
+.closePushBtn{
+  margin-right: 16px;
+}
+.employee-dep-management {
+  /* padding: 0 20px 20px; */
+  height: 100%;
+  box-sizing: border-box;
+  display: flex;
+  flex-direction: column;
+}
+.system-content {
+  position: relative;
+  height: 100%;
+  flex: 1;
+  display: flex;
+  overflow: hidden;
+}
+.system-view-nav {
+  width: 240px;
+  height: 100%;
+  overflow: auto;
+  margin-right: 10px;
+  background: #fff;
+  border: 1px solid #e6e6e6;
+  .system-nav-title{
+      padding: 15px;
+      font-size: 16px;
+      font-weight: 600;
+      border-bottom: 1px solid #e6e6e6;
+    }
+}
+.title {
+  font-size: 18px;
+  height: 40px;
+  line-height: 40px;
+  margin: 10px 0;
+  color: #333;
+  padding: 0 20px;
+}
+.system-view-table {
+  background: #fff;
+  border: 1px solid #e6e6e6;
+  /* flex: 1; */
+  position: absolute;
+  top: 0;
+  left: 250px;
+  bottom: 0;
+  right: 0;
+}
+
+.table-top {
+    padding: 0 30px;
+    height: 50px;
+    display: flex;
+    align-items: center;
+  .table-top__title{
+    font-size: 16px;
+    color: #333;
+  }
+}
+
+.status {
+  display: inline-block;
+  margin-left: 50px;
+}
+.status > span {
+  margin-right: 10px;
+}
+
+.status-name {
+  .user-img {
+    width: 32px;
+    min-width: 32px;
+    min-height: 32px;
+    height: 32px;
+    margin-right: 8px;
+    border-radius: 50%;
+  }
+  div {
+    width: 6px;
+    height: 6px;
+    border-radius: 3px;
+  }
+  color:  #ff6a00;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  justify-content: left;
+}
+/* 详情 */
+.employee-dep-management /deep/ .el-dialog__wrapper {
+  margin-top: 60px !important;
+}
+// .employee-dep-management /deep/ .position-flxed-animation {
+//   left: 70%;
+//   height: 100%;
+//   color: red;
+//   margin: 0 !important;
+// }
+.dialog-top > img {
+  vertical-align: middle;
+  margin-right: 10px;
+  height: 36px;
+}
+.dialog-btn-group {
+  float: right;
+}
+.dialog-remark {
+  font-size: 14px;
+  color: #999;
+  margin-top: 10px;
+}
+.dialog-content {
+  margin-top: 20px;
+  padding-top: 20px;
+  border-top: 1px solid #e6e6e6;
+}
+.dialog-content > div {
+  padding: 10px 0;
+}
+.dialog-content > div > label {
+  color: #777;
+  width: 30%;
+  display: inline-block;
+}
+/* 新建和编辑 */
+.new-dialog-title {
+  padding-left: 10px;
+  margin-bottom: 3px;
+  border-left: 2px solid #4D88FF;
+}
+.new-dialog-form {
+  height: 47vh;
+  overflow-y: auto;
+  padding: 20px;
+}
+.new-dialog-form /deep/ .el-form-item {
+  width: 50%;
+  margin: 0;
+  padding-bottom: 10px;
+}
+.new-dialog-form /deep/ .el-form-item .el-form-item__label {
+  padding: 0;
+}
+.new-dialog-form /deep/ .el-form-item .el-form-item__content {
+  width: 70%;
+}
+.nav-dialog-div {
+  margin-bottom: 20px;
+}
+.nav-dialog-div /deep/ .el-input {
+  width: auto;
+}
+/** 树形结构 */
+.el-tree /deep/ .el-tree-node__expand-icon {
+  display: none;
+}
+.el-tree /deep/ .el-tree-node__content {
+  height: 30px;
+
+  .node-data {
+    .node-img {
+      width: 15px;
+      height: 15px;
+      display: block;
+      margin-right: 8px;
+      margin-left: 24px;
+    }
+    .node-label {
+      margin-right: 8px;
+    }
+    .node-label-set {
+      display: none;
+    }
+  }
+
+  .node-data:hover .node-label-set {
+    display: block;
+  }
+}
+.el-tree /deep/ .el-tree-node.is-current > .el-tree-node__content {
+  background-color: #ebf3ff;
+  border-right: 2px solid #4D88FF;
+  .node-label-set {
+    display: block;
+  }
+}
+.system-view-nav /deep/ .el-tree-node > .el-tree-node__children {
+  overflow: visible;
+}
+.system-view-nav /deep/ .el-tree > .el-tree-node {
+  min-width: 100%;
+  display: inline-block !important;
+}
+/* 搜索框图标按钮 */
+.icon-search .el-icon-search {
+  position: absolute;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  width: 40px;
+  line-height: 40px;
+  text-align: center;
+  cursor: pointer;
+  font-size: 20px;
+  color: #ccc;
+}
+/* 设置flex布局 */
+.flex-index {
+  display: flex;
+  flex-direction: column;
+}
+/* 设置占位 */
+.flex-box {
+  flex: 1;
+  border-bottom: 1px solid #e6e6e6;
+  padding: 24px 20px;
+}
+/* 搜索框 */
+.icon-search {
+  width: 280px;
+  position: relative;
+}
+.new-dialog-form /deep/ .el-select {
+  display: block;
+}
+
+/** 分页布局 */
+.p-contianer {
+  position: relative;
+  background-color: white;
+  height: 44px;
+  .p-bar {
+    float: right;
+    margin: 5px 0 0 0;
+    font-size: 14px !important;
+  }
+}
+
+/** 勾选操作 */
+.selection-bar {
+  font-size: 12px;
+  height: 54px;
+  min-height: 54px;
+  padding: 0 20px;
+  color: #777;
+
+  .selected—title {
+    flex-shrink: 0;
+    padding-right: 20px;
+    border-right: 1px solid #e6e6e6;
+    .selected—count {
+      color:  #ff6a00;
+    }
+  }
+}
+
+.selection-items-box {
+  .selection-item {
+    width: auto;
+    padding: 15px;
+    .selection-item-icon {
+      display: block;
+      margin-right: 5px;
+      width: 15px;
+      height: 15px;
+    }
+    .selection-item-name {
+      cursor: pointer;
+      color: #777;
+    }
+    .selection-item-name:hover {
+      color:  #ff6a00;
+    }
+  }
+}
+.new-dialog-form
+  /deep/
+  .el-form-item
+  .el-form-item__content
+  .el-select-group__wrap:not(:last-of-type)::after {
+  display: none;
+}
+.new-dialog-form /deep/ .el-form-item .el-form-item__content .el-select-group {
+  padding-left: 10px;
+}
+.new-dialog-form
+  /deep/
+  .el-form-item
+  .el-form-item__content
+  .el-select-group__title {
+  border-bottom: 1px solid #e4e7ed;
+  padding: 0 0 7px;
+  margin: 0 20px 5px;
+}
+
+.status-des {
+  font-size: 12px;
+  color: #777777;
+  margin: 0 5px;
+  position: absolute;
+  left: 0;
+  top: 7px;
+  .status-des-item {
+    margin: 8px;
+    display: inline-block;
+    div {
+      display: inline-block;
+      width: 6px;
+      height: 6px;
+      border-radius: 3px;
+      margin-right: 5px;
+    }
+  }
+}
+
+// 提示
+// 提示标志
+.wukong-help_tips {
+  color: #999;
+  font-size: 14px;
+  margin-left: 3px;
+  cursor: pointer;
+}
+
+.wukong-help_tips:hover {
+  color:  #ff6a00;
+}
+
+// 修改密码和修改登录名的样式
+.el-password {
+  .el-form-item {
+    margin-bottom: 5px;
+  }
+}
+
+.el-dialog__wrapper /deep/.el-dialog__body {
+  padding: 20px;
+}
+
+.tips {
+  font-size: 13px;
+  color: #999;
+}
+
+@import '../../clients/styles/table.scss';
+</style>
diff --git a/src/views/company/employeeManage/components/EmployeeDetail.vue b/src/views/company/employeeManage/components/EmployeeDetail.vue
new file mode 100644
index 0000000..6a59f38
--- /dev/null
+++ b/src/views/company/employeeManage/components/EmployeeDetail.vue
@@ -0,0 +1,231 @@
+<template>
+  <div>
+    <div class="bgColor" @click.self="hideView"></div>
+    <slide-view
+      :listener-ids="['manager-main-container']"
+      :no-listener-ids="['depTable']"
+      :body-style="{padding: '10px 30px', height: '100%'}"
+      class="d-view"
+      @side-close="hideView">
+      <flexbox
+        orient="vertical"
+        style="height: 100%;">
+        <flexbox class="detail-header">
+          <div class="header-name"/>
+          <img
+            class="header-close"
+            src="@/assets/img/task_close.png"
+            @click="hideView" >
+        </flexbox>
+        <div class="detail-body">
+          <div class="dialog-top">
+            <img
+              :src="data.Avatar"
+              alt="">
+            <span>{{ data.Name }}</span>
+            <!--<div class="dialog-btn-group">
+              <el-button
+                type="primary"
+                size="medium"
+                @click="editBtn"> 编 辑 </el-button>
+              <el-dropdown
+                v-if="userUpdateAuth || userEnablesAuth"
+                trigger="click"
+                @command="handleCommand">
+                <el-button size="medium">
+                  更 多<i class="el-icon-arrow-down el-icon--right"/>
+                </el-button>
+                <el-dropdown-menu slot="dropdown">
+                  <el-dropdown-item
+                    v-if="userUpdateAuth"
+                    command="reset">重置密码</el-dropdown-item>
+                  <el-dropdown-item
+                    v-if="userEnablesAuth"
+                    command="status">{{ data.status === 0 ? '激 活' : '禁 用' }}</el-dropdown-item>
+                </el-dropdown-menu>
+              </el-dropdown>
+            </div> -->
+            <div class="dialog-remark">
+              <p>账号状态:{{ {'1':'已激活', 2: '已禁用', 4: '未激活', 5: '退出企业' }[data.Status] }}</p>
+            </div>
+          </div>
+          <div class="dialog-content">
+            <flexbox
+              v-for="(item, index) in detailList"
+              :key="index"
+              class="content-items"
+              align="stretch">
+              <div class="content-items-name">{{ item.value }}</div>
+              <div class="content-items-value">{{ data|formatedInfo(item.field) }}</div>
+            </flexbox>
+          </div>
+        </div>
+      </flexbox>
+    </slide-view>
+  </div>
+</template>
+
+<script>
+import SlideView from '@/components/SlideView'
+import { mapGetters } from 'vuex'
+
+export default {
+  /** 审批详情 */
+  name: 'EmployeeDetail',
+  components: {
+    SlideView
+  },
+  filters: {
+    formatedInfo (data, field) {
+      console.log(data, field)
+      if (field === 'IsLeader') {
+        return { true: '是', false: '否' }[data.IsLeader]
+      } else if (field === 'Gender') {
+        return { 1: '男', 2: '女' }[data.Gender]
+      } else if (field === 'Status') {
+        return { 1: '已激活',
+          2: '已禁用',
+          4: '未激活',
+          5: '退出企业'}[data.Status]
+      }
+      return data[field] || '暂无'
+    }
+  },
+  props: {
+    // 详情信息
+    data: Object
+  },
+  data () {
+    return {
+      detailList: [
+        { field: 'IsLeader', value: '是否为上级' },
+        { field: 'MobilePhone', value: '手机号(登录名)' },
+        { field: 'Gender', value: '性别' },
+        { field: 'Email', value: '邮箱' },
+        { field: 'MainDepartmentName', value: '部门' },
+        { field: 'Position', value: '职务' },
+        { field: 'Address', value: '地址' }
+      ]
+    }
+  },
+  computed: {
+    ...mapGetters(['manage']),
+    // 员工编辑操作权限
+    userUpdateAuth () {
+      return this.manage && this.manage.users && this.manage.users.userUpdate
+    },
+    // 员工禁用启用权限
+    userEnablesAuth () {
+      return this.manage && this.manage.users && this.manage.users.userEnables
+    }
+  },
+  watch: {},
+  mounted () {},
+  methods: {
+    editBtn () {
+      this.$emit('edit')
+    },
+    handleCommand (command) {
+      this.$emit('command', command)
+    },
+    //* * 点击关闭按钮隐藏视图 */
+    hideView () {
+      this.$emit('hide-view')
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.detail-header {
+  position: relative;
+  min-height: 60px;
+  .header-name {
+    font-size: 14px;
+    color: #333333;
+    flex: 1;
+  }
+  .header-close {
+    display: block;
+    width: 40px;
+    height: 40px;
+    margin-left: 20px;
+    padding: 10px;
+    cursor: pointer;
+  }
+}
+
+.dialog-top > img {
+  vertical-align: middle;
+  margin-right: 10px;
+  height: 80px;
+}
+.dialog-btn-group {
+  float: right;
+}
+.dialog-remark {
+  font-size: 14px;
+  color: #999;
+  margin-top: 10px;
+  p + p {
+    margin-top: 5px;
+  }
+  .user-img {
+    width: 100px;
+    min-width: 32px;
+    min-height: 32px;
+    height: 100px;
+    margin-right: 8px;
+    border-radius: 50%;
+  }
+}
+.dialog-content {
+  margin-top: 20px;
+  padding-top: 20px;
+  border-top: 1px solid #e6e6e6;
+  .content-items {
+    padding: 10px 0;
+    .content-items-name {
+      width: 132px;
+      color: #777;
+      flex-shrink: 0;
+    }
+    .content-items-value {
+      flex: 1;
+    }
+  }
+}
+
+.detail-body {
+  flex: 1;
+  overflow-y: auto;
+  width: 100%;
+}
+
+.d-view {
+  position: fixed;
+  width: 1200px;
+  top: 0px;
+  // width: 100%;
+  // top: 500px;
+  bottom: 0px;
+  right: 0px;
+  // background: #FFFFFF;
+  box-shadow: 0px -4px 12px 0px rgba(61, 121, 204, 0.2);
+  border-radius: 24px 0px 0px 0px;
+}
+.bgColor {
+  width: 100%;
+  height: 100%;
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  overflow: hidden;
+  outline: 0;
+  filter: alpha(opacity=60);
+  background-color: rgba(51, 51, 51, 0.2);
+  z-index: 100;
+}
+</style>
diff --git a/src/views/company/offcialAuthority.vue b/src/views/company/offcialAuthority.vue
new file mode 100644
index 0000000..d1877a0
--- /dev/null
+++ b/src/views/company/offcialAuthority.vue
@@ -0,0 +1,418 @@
+<template>
+  <div class='offical-authority'>
+    <p class="title"> 职务管理 </p>
+
+    <el-card>
+      <el-row>
+        <el-button class="create-button"
+        type="primary" @click='createAuthority'>新增职务</el-button>
+      </el-row>
+      <el-table :data="rightsList" border stripe max-height="600px">
+        <el-table-column label="权限名称" prop="Name"></el-table-column>
+        <el-table-column label="备注" prop="Comment">
+          <template slot-scope="scope">
+            <div>{{scope.row.Comment ?scope.row.Comment:'--'}}</div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          prop="IsEnabled"
+          label="状态">
+          <template slot-scope="scope">
+            <div>{{scope.row.IsEnabled ?'启用':'禁用'}}</div>
+          </template>
+        </el-table-column>
+         <el-table-column
+          prop="operation"
+          label="操作">
+          <template slot-scope="scope">
+            <el-button type="text" size="small" @click='addAuthority(scope.row.Id)'>配置权限</el-button>
+            <el-button type="text" size="small"  @click='editAuthority(scope.row)'>编辑职务</el-button>
+            <el-button type="text" size="small"  @click='deleteAuthority(scope.row.Id)'>删除职务</el-button>
+        </template>
+      </el-table-column>
+      </el-table>
+    </el-card>
+    <!-- 导航新增编辑弹出框 -->
+    <el-dialog
+      :visible.sync="authorityDialog"
+      :title="addTitle"
+      :before-close="cancelDialog"
+      width="40%">
+      <el-form
+        ref="authForm"
+        :model="authForm"
+        :rules="authRules"
+        label-width="80px"
+        class="login-form"
+        auto-complete="on"
+        label-position="left">
+        <el-form-item label="职务名称"  prop='Name'>
+          <el-input
+            v-model="authForm.Name"
+            placeholder="请输入职务名称"/>
+        </el-form-item>
+        <el-form-item label="职务类型"  prop='PositionType'>
+          <el-select v-model="authForm.PositionType" placeholder="请选择职务类型">
+              <el-option
+                v-for="item in positionOption"
+                :key="item.id"
+                :label="item.name"
+                :value="item.id"/>
+            </el-select>
+        </el-form-item>
+        <el-form-item label="备注" prop='Comment'>
+          <el-input
+              type='textarea'
+              v-model="authForm.Comment"
+              placeholder="请输入备注"/>
+        </el-form-item>
+        <el-form-item label="启用状态" prop='IsEnabled'>
+          <el-switch v-model="authForm.IsEnabled"></el-switch>
+        </el-form-item>
+        <el-form-item>
+          <el-button @click="cancelDialog">取 消</el-button>
+          <el-button
+            type="primary"
+            @click="submitDialog('authForm')">确 定</el-button>
+        </el-form-item>
+      </el-form>
+    </el-dialog>
+    <!-- 设置权限弹出框 -->
+    <el-dialog
+      :visible.sync="setAuthorityDialog"
+      :title="addTitle"
+      :before-close="cancelSetDialog"
+      width="50%">
+      <el-form
+        ref="setForm"
+        :model="setForm"
+        :rules="setRules"
+        class="set-form"
+        auto-complete="on"
+        label-position="left">
+        <el-form-item
+          v-for="(item, index) in setList"
+          :key="index"
+          :prop="item.ModuleName"
+          class="setFormItem">
+          <div
+            slot="label"
+            style="display: inline-block;">
+            <div style="margin:5px 0;font-size:16px;word-wrap:break-word;word-break:break-all;font-weight: 600;">
+              {{ item.ModuleName }}
+            </div>
+          </div>
+          <template>
+            <el-checkbox :indeterminate="item.isIndeterminate" v-model="item.isCheck" @change="handleCheckTitle(item.isCheck, index)" class='allChecked' :disabled="item.Children.length === 0">全选</el-checkbox>
+            <el-checkbox-group v-model="item.checkedData" @change="checkItem(item.checkedData, index)">
+              <el-checkbox v-for="(cu, index) in item.Children" :label="cu.Id" :key="index">{{cu.ModuleName}}</el-checkbox>
+            </el-checkbox-group>
+          </template>
+        </el-form-item>
+      </el-form>
+      <div class="handle-bar">
+        <el-button @click="cancelSetDialog" class="handle-button">取 消</el-button>
+        <el-button
+          type="primary"
+          @click="submitDialog('setForm')" class="handle-button">确 定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { GetPositionList, AddPosition, DeletePosition, UpdatePosition, GetPositionModules, UpdatePositionModules } from '@/api/systemManagement/officalAuthority'
+// import { GetSysModuleList } from '@/api/moduleManage/moduleManage'
+export default {
+  name: 'offcialAuthority',
+  data () {
+    return {
+      rightsList: [],
+      authorityDialog: false,
+      isCreate: false,
+      authForm: {
+        Name: '',
+        PositionType: 2,
+        Comment: '',
+        IsEnabled: true
+      },
+      positionOption: [
+        {id: 1, name: '总经理'},
+        {id: 2, name: '人事'},
+        {id: 3, name: '财务'},
+        {id: 4, name: '商务'},
+        {id: 5, name: '销售'},
+        {id: 6, name: '技术'},
+        {id: 7, name: '管理员'}
+      ],
+      authRules: {
+        Name: [
+          { required: true, trigger: 'blur', message: '请输入职务名称' }
+        ],
+        PositionType: [
+          { required: true, trigger: 'blur', message: '请选择职务类型' }
+        ]
+      },
+      addTitle: '新增',
+      setAuthorityDialog: false,
+      setForm: {},
+      setRules: {},
+      setList: [],
+      positionId: ''
+    }
+  },
+  created () {
+    this.getRightsList()
+  },
+  methods: {
+    getSetsList (id) {
+      // GetSysModuleList()
+      GetPositionModules({Id: id}).then(res => {
+        if (res.data.ErrorCode === 200 && res.data.Result) {
+          this.setList = res.data.Result.Modules
+          let checkedModule = res.data.Result.PositionModules
+          for (let i in this.setList) {
+            this.setList[i]['isIndeterminate'] = false
+            this.setList[i]['isCheck'] = false
+            this.setList[i]['checkedData'] = []
+            if (checkedModule && checkedModule.length > 0) {
+              for (let h in checkedModule) {
+                if (this.setList[i].Id === checkedModule[h].Id) {
+                  // 已选中的数组
+                  let checkedArr = checkedModule[h].PositionModuleOperations
+                  if (checkedArr && checkedArr.length > 0) {
+                    this.setList[i]['isIndeterminate'] = checkedArr.length > 0 && checkedArr.length < this.setList[i].Children.length
+
+                    this.setList[i]['isCheck'] = checkedArr.length === this.setList[i].Children.length
+                    let arr = []
+                    for (let j = 0; j < checkedArr.length; j++) {
+                      arr[j] = checkedArr[j]['Id']
+                    }
+                    this.setList[i]['checkedData'] = arr
+                  }
+                }
+              }
+            }
+          }
+
+          console.log(this.setList)
+        } else {
+          this.$message.error(res.data.Message)
+        }
+      })
+    },
+    checkItem (val, index) {
+      console.log(val, index)
+      let checkedCount = val.length
+      this.setList[index].isCheck =
+        checkedCount === this.setList[index].Children.length
+
+      this.setList[index].isIndeterminate =
+        checkedCount > 0 && checkedCount < this.setList[index].Children.length
+      this.$forceUpdate()
+    },
+    handleCheckTitle (val, index) {
+      console.log(val, index)
+      let arr = []
+      const re = this.setList[index].Children
+      // 全选
+      if (val) {
+        for (let i = 0; i < re.length; i++) {
+          arr[i] = re[i]['Id']
+        }
+      }
+      this.setList[index].checkedData = arr
+      this.setList[index].isIndeterminate = false
+      this.$forceUpdate()
+    },
+    createAuthority () {
+      this.isCreate = true
+      this.addTitle = '添加职务'
+      this.authorityDialog = true
+    },
+    addAuthority (id) {
+      this.isCreate = false
+      this.addTitle = '配置权限'
+      this.setAuthorityDialog = true
+      this.positionId = id
+      this.getSetsList(id)
+    },
+    deleteAuthority (id) {
+      this.$confirm('确定删除?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          DeletePosition({'Id': id}).then(res => {
+            console.log(res)
+            if (res.data.ErrorCode === 200) {
+              this.$message.success(res.data.Message)
+              this.getRightsList()
+            } else {
+              this.$message.error(res.data.Message)
+            }
+          })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    },
+    editAuthority (row) {
+      this.isCreate = false
+      this.authForm = {
+        'Id': row.Id,
+        'Name': row.Name,
+        'PositionType': row.PositionType,
+        'Comment': row.Comment,
+        'IsEnabled': row.IsEnabled
+      }
+      this.authorityDialog = true
+    },
+    submitDialog (formName) {
+      this.$refs[formName].validate(valid => {
+        if (!valid) return
+        if (formName === 'authForm') {
+          console.log(this.authForm)
+          if (this.isCreate) {
+            AddPosition(this.authForm).then(res => {
+              console.log(res)
+              if (res.data.ErrorCode === 200) {
+                this.$message.success(res.data.Message)
+                this.getRightsList()
+                this.authorityDialog = false
+              } else {
+                this.$message.error(res.data.Message)
+              }
+            })
+          } else {
+            UpdatePosition(this.authForm).then(res => {
+              console.log(res)
+              if (res.data.ErrorCode === 200) {
+                this.$message.success(res.data.Message)
+                this.getRightsList()
+                this.authorityDialog = false
+              } else {
+                this.$message.error(res.data.Message)
+              }
+            })
+          }
+        }
+        if (formName === 'setForm') {
+          let params = {}
+          params.PositionId = this.positionId
+          let checkedArray = []
+          for (let i in this.setList) {
+            if (this.setList[i].checkedData.length > 0) {
+              let arr = this.setList[i].checkedData
+              let Ids = []
+              for (let j in arr) {
+                Ids.push({'Id': arr[j]})
+              }
+              checkedArray.push({'Id': this.setList[i].Id, 'ModuleOperations': Ids})
+              // checkedArray.push({'Id': this.setList[i].Id, 'ModuleOperations': this.setList[i].checkedData})
+            }
+          }
+          console.log(checkedArray)
+          params.ModifyModules = checkedArray
+          UpdatePositionModules(params)
+            .then(res => {
+              this.getRightsList()
+              this.$message.success('编辑成功')
+              this.setAuthorityDialog = false
+            })
+            .catch(() => {
+            })
+        }
+      })
+    },
+    // 关闭新增或编辑
+    cancelDialog () {
+      this.$refs.authForm.resetFields()
+      this.authForm = {
+        Name: '',
+        PositionType: 2,
+        Comment: '',
+        IsEnabled: true
+      }
+      this.authorityDialog = false
+    },
+    cancelSetDialog () {
+      this.setAuthorityDialog = false
+    },
+    getRightsList () {
+      this.rightsList = [{authName: 'abc', path: '', level: '0'}]
+      GetPositionList().then(res => {
+        console.log(res)
+        if (res.data.ErrorCode === 200 && res.data.Result) {
+          this.rightsList = res.data.Result
+        } else {
+          this.$message.error(res.data.Message)
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style lang='scss' scoped>
+  .offical-authority{}
+
+  .title {
+    font-size: 18px;
+    height: 40px;
+    line-height: 40px;
+    margin: 10px 0;
+    color: #333;
+    padding: 0 20px;
+  }
+  .nav-dialog-div {
+    margin-bottom: 12px;
+  }
+  .checkedBox{
+    display:flex;
+    flex-direction:row;
+  }
+  .allChecked{
+    margin-right:20px;
+  }
+  .dialogLabel{
+    font-size: 16px;
+  }
+  .create-button{
+    margin-bottom: 20px;
+    float: right;
+  }
+  .set-form{
+    height: 550px;
+    overflow: auto;
+    position: relative;
+    .setFormItem{
+      display: flex;
+      flex-direction: column;
+      margin-left: 20px;
+    }
+  }
+  .setFormItem.el-form-item /deep/ .el-form-item__content{
+    display: flex;
+  }
+  .setFormItem.el-form-item /deep/ .el-form-item{
+    margin-bottom: 0;
+  }
+  .setFormItem.el-form-item /deep/ .el-checkbox__label{
+    font-size: 14px;
+  }
+  .handle-bar{
+    padding-top: 20px;
+    padding-left: 40%;
+    width: 100%;
+    height: 40px;
+    .handle-button {
+      padding: 8px 12px;
+      border-radius: 3px;
+    }
+  }
+</style>
diff --git a/src/views/company/staffLog.vue b/src/views/company/staffLog.vue
new file mode 100644
index 0000000..2cdd03a
--- /dev/null
+++ b/src/views/company/staffLog.vue
@@ -0,0 +1,254 @@
+<template>
+  <div class='staff-log'>
+    <el-menu :default-active="activeIndex" class="el-menu-demo" mode="horizontal" @select="handleSelect">
+      <el-menu-item index="1">员工操作日志</el-menu-item>
+      <el-menu-item index="2">登录日志</el-menu-item>
+    </el-menu>
+    <el-form :inline="true" :model="logCheck" class="selectInline">
+      <el-form-item>
+          <el-date-picker
+            v-model="logCheck.dateValue"
+            style="width: 100%;"
+            type="daterange"
+            class='datePicker'
+            align='center'
+            value-format="yyyy-MM-dd"
+            range-separator="至"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期">
+          </el-date-picker>
+        </el-form-item>
+      <el-form-item>
+        <el-input v-model="logCheck.user" placeholder="请输入用户名"></el-input>
+      </el-form-item>
+      <el-form-item v-if="selectIndex === '1'">
+        <el-select v-model="logCheck.region" placeholder="请选择">
+          <el-option
+              v-for="(value, index) in operationList"
+              :key="index"
+              :label="value"
+              :value="index"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" @click="onSubmit">查询</el-button>
+        <el-button @click="onSubmit('reset')">重置</el-button>
+      </el-form-item>
+    </el-form>
+     <el-table
+        ref="logTable"
+        v-loading="loading"
+        id="crm-table"
+        :data="tableData"
+        :height="tableHeight"
+        :cell-style="cellStyle"
+        class="n-table--border"
+        border
+        highlight-current-row
+        style="width: 100%">
+      <el-table-column
+        v-for="(item, index) in fieldList"
+        :key="index"
+        :width="item.width"
+        :prop="item.field"
+        :label="item.value"
+        :formatter="tableFormatter"
+        show-overflow-tooltip>
+        <template
+          slot="header"
+          slot-scope="scope">
+          <div class="table-head-name">{{ scope.column.label }}</div>
+        </template>
+      </el-table-column>
+    </el-table>
+    <div class="p-contianer" v-show='total>0'>
+        <el-pagination
+          :current-page="currentPage"
+          :page-sizes="pageSizes"
+          :page-size.sync="pageSize"
+          :total="total"
+          class="p-bar"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"/>
+      </div>
+  </div>
+</template>
+
+<script>
+import { GetOperationLogList, GetLoginRecordList } from '@/api/systemManagement/log'
+export default {
+  name: 'staffLog',
+  computed: {
+    fieldList: function () {
+      if (this.selectIndex === '1') {
+        return [
+          { field: 'RealName', value: '用户姓名' },
+          // { field: 'UserId', value: '用户ID' },
+          { field: 'Content', value: '操作内容' },
+          { field: 'OperationTime', value: '操作时间' },
+          { field: 'BusinessOperationType', value: '业务操作类型' },
+          { field: 'OperationType', value: '操作类型' }
+        ]
+      } else {
+        return [
+          { field: 'RealName', value: '用户姓名' },
+          // { field: 'UserId', value: '用户ID' },
+          { field: 'LoginTime', value: '登录时间' },
+          { field: 'LoginIpLocation', value: '登录IP地址' },
+          { field: 'LoginIp', value: '登录IP' }
+        ]
+      }
+    }
+  },
+  data () {
+    return {
+      operationList: ['默认其他', '客户', '联系人', '商机', '合同管理', '工单', '报价单', '合同', '日程', '开票', '回款'],
+      tableHeight: document.documentElement.clientHeight - 360, // 表的高度
+      tableData: [],
+      total: 0,
+      currentPage: 1,
+      pageSize: 10,
+      pageSizes: [10, 30, 60, 100],
+      logCheck: {
+        user: '',
+        region: 0,
+        dateValue: ''
+      },
+      activeIndex: '1',
+      selectIndex: '1',
+      loading: false // 表的加载动画
+    }
+  },
+  mounted () {
+    var self = this
+    /** 控制table的高度 */
+    window.onresize = function () {
+      self.tableHeight = document.documentElement.clientHeight - 260
+    }
+    this.getTableList()
+  },
+  methods: {
+    /** 通过回调控制style */
+    cellStyle ({ row, column, rowIndex, columnIndex }) {
+      if (
+        column.property === 'CustomerName' ||
+        column.property === 'businessCheck'
+      ) {
+        return { color: '#4D88FF', cursor: 'pointer' }
+      } else {
+        return ''
+      }
+    },
+    // 列表信息格式化
+    tableFormatter (row, column) {
+      if (column.property === 'BusinessOperationType') {
+        return {0: '默认其他',
+          1: '客户',
+          2: '联系人',
+          3: '商机',
+          4: '合同管理',
+          5: '工单',
+          6: '报价单',
+          7: '合同',
+          8: '日程',
+          9: '开票',
+          10: '回款',
+          11: '回款'}[row.BusinessOperationType]
+      } else if (column.property === 'OperationType') {
+        return { 1: '添加', 2: '修改', 3: '删除' }[row.OperationType]
+      } else if (column.property === 'Status') {
+        return { 1: '已激活',
+          2: '已禁用',
+          4: '未激活',
+          5: '退出企业'}[row.Status]
+      }
+      return row[column.property]
+    },
+    onSubmit (val) {
+      console.log(this.logCheck)
+      if (val === 'reset') {
+        this.logCheck = {
+          user: '',
+          region: 0,
+          dateValue: ''
+        }
+        this.getTableList()
+      } else {
+        this.getTableList()
+      }
+    },
+    getTableList () {
+      let request
+      const params = {
+        'PageIndex': this.currentPage,
+        'PageSize': this.pageSize,
+        'StartTime': this.logCheck.dateValue ? this.logCheck.dateValue[0] : '',
+        'EndTime': this.logCheck.dateValue ? this.logCheck.dateValue[1] : '',
+        'RealName': this.logCheck.user
+      }
+      if (this.selectIndex === '1') {
+        params['BusinessOperationType'] = this.logCheck.region
+        request = GetOperationLogList
+      } else {
+        request = GetLoginRecordList
+      }
+      this.loading = true
+      request(params).then(res => {
+        this.loading = false
+        this.tableData = res.data.Result.List
+        this.total = res.data.Result.Count
+      })
+        .catch(data => {
+          this.loading = false
+        })
+    },
+    handleSizeChange (val) {
+      console.log(`每页 ${val} 条`)
+      this.pageSize = val
+      this.getTableList()
+    },
+    handleCurrentChange (val) {
+      console.log(`当前页: ${val}`)
+      this.currentPage = val
+      this.getTableList()
+    },
+    handleSelect (key, keyPath) {
+      this.selectIndex = key
+      this.getTableList()
+    }
+  }
+}
+</script>
+
+<style lang='scss' scoped>
+  .title {
+    font-size: 18px;
+    height: 40px;
+    line-height: 40px;
+    margin: 10px 0;
+    color: #333;
+    padding: 0 20px;
+  }
+  .selectInline{
+    background: #fff;
+    padding:20px 20px 0;
+  }
+  .datePicker{
+    margin-top:3px;
+    .el-date-editor .el-range__icon{
+      line-height: 28px;
+    }
+  }
+  /** 分页布局 */
+  .p-contianer {
+    position: relative;
+    background-color: white;
+    height: 44px;
+    .p-bar {
+      float: right;
+      margin: 5px 0 0 0;
+      font-size: 14px !important;
+    }
+  }
+</style>
diff --git a/src/views/company/systemSetting.vue b/src/views/company/systemSetting.vue
new file mode 100644
index 0000000..13544fc
--- /dev/null
+++ b/src/views/company/systemSetting.vue
@@ -0,0 +1,196 @@
+<template>
+  <div class='system-setting'>
+    <p class="title"> 系统设置 </p>
+      <!--导航选择事件-->
+    <div class='tabChosen'>
+      <el-tabs tab-position="top" style="height: 500px;">
+        <el-tab-pane label="基础设置">
+          <el-form :model="basicRuleForm" :rules="basicRules" ref="basicRuleForm" label-width="100px" class="basicForm">
+            <el-form-item label="网站名称" prop="name">
+              <el-input v-model="basicRuleForm.name"></el-input>
+            </el-form-item>
+            <el-form-item label="网站域名" prop="webName">
+             <el-input v-model="basicRuleForm.webName"></el-input>
+            </el-form-item>
+            <el-form-item label="网站关键词">
+              <el-input type="textarea" v-model="basicRuleForm.keyWords"></el-input>
+            </el-form-item>
+            <el-form-item label="网站描述" prop="descripe">
+              <el-input type="textarea" v-model="basicRuleForm.descripe"></el-input>
+            </el-form-item>
+            <el-form-item label="公司名称" prop="companyName">
+              <el-input v-model="basicRuleForm.companyName"></el-input>
+            </el-form-item>
+            <el-form-item label="公司地址" prop="companyAddress">
+              <el-input v-model="basicRuleForm.companyAddress"></el-input>
+            </el-form-item>
+            <el-form-item label="版本信息" prop="versionInfo">
+              <el-input type="textarea" v-model="basicRuleForm.versionInfo"></el-input>
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" @click="submitForm('basicRuleForm')">立即创建</el-button>
+              <el-button @click="resetForm('basicRuleForm')">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-tab-pane>
+        <el-tab-pane label="邮件设置">
+          <el-form :model="mailForm" :rules="mailRules" ref="mailForm" label-width="100px" class="basicForm">
+            <el-form-item label="SMTP服务器" prop="web">
+              <el-input v-model="mailForm.web"></el-input>
+            </el-form-item>
+            <el-form-item label="SSL加密连接" prop="connect">
+               <el-radio-group v-model="mailForm.connect">
+                <el-radio label="是"></el-radio>
+                <el-radio label="否"></el-radio>
+              </el-radio-group>
+            </el-form-item>
+            <el-form-item label="SMTP端口" required>
+               <el-input v-model="mailForm.port" type='number'></el-input>
+            </el-form-item>
+            <el-form-item label="发件人地址" prop="sendAddress">
+              <el-input v-model="mailForm.sendAddress"></el-input>
+            </el-form-item>
+            <el-form-item label="邮箱账号" prop="mailDress" required>
+              <el-input v-model="mailForm.mailDress"></el-input>
+            </el-form-item>
+            <el-form-item label="邮箱密码" prop="mailPsd" required>
+              <el-input v-model="mailForm.mailPsd"></el-input>
+            </el-form-item>
+            <el-form-item label="发件人昵称" prop="sendName" required>
+              <el-input v-model="mailForm.sendName"></el-input>
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" @click="submitForm('mailForm')">立即创建</el-button>
+              <el-button @click="resetForm('mailForm')">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-tab-pane>
+        <el-tab-pane label="提醒设置">
+           <el-form :model="alarmForm" ref="alarmForm" label-width="100px" class="basicForm">
+            <el-form-item label="是否开启通知" prop="isAlarm">
+               <el-radio-group v-model="alarmForm.isAlarm">
+                <el-radio label="是"></el-radio>
+                <el-radio label="否"></el-radio>
+              </el-radio-group>
+            </el-form-item>
+            <el-form-item label="通知方式"  prop="alarmWay">
+              <el-radio-group v-model="alarmForm.alarmWay">
+                <el-radio :label='1'>站内信</el-radio>
+                <el-radio :label='2'>站内信+邮件</el-radio>
+                <el-radio :label='3'>站内信+短信</el-radio>
+                <el-radio :label='4'>站内信+邮件+短信</el-radio>
+              </el-radio-group>
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" @click="submitForm('alarmForm')">立即创建</el-button>
+              <el-button @click="resetForm('alarmForm')">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-tab-pane>
+      </el-tabs>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'systemSetting',
+  data () {
+    return {
+      basicRuleForm: {
+        name: '',
+        webName: '',
+        keyWords: '',
+        date1: '',
+        date2: '',
+        descripe: '',
+        companyName: '',
+        companyAddress: '',
+        versionInfo: ''
+      },
+      basicRules: {
+        name: [
+          { required: true, message: '请输入网站名称', trigger: 'blur' },
+          { min: 3, max: 10, message: '长度在 3 到 10 个字符', trigger: 'blur' }
+        ],
+        webName: [
+          { required: true, message: '请输入网站域名', trigger: 'blur' },
+          { min: 3, max: 10, message: '长度在 3 到 10 个字符', trigger: 'blur' }
+        ]
+      },
+      mailForm: {
+        web: '',
+        connect: '是',
+        port: '',
+        sendAddress: '',
+        mailDress: '',
+        mailPsd: '',
+        sendName: ''
+      },
+      mailRules: {
+        web: [
+          { required: true, message: '请输入SMTP服务器', trigger: 'blur' },
+          { min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur' }
+        ],
+        port: [
+          { required: true, message: '请输入SMTP端口', trigger: 'blur' }
+        ],
+        mailDress: [
+          { required: true, message: '请输入邮箱账号', trigger: 'blur' }
+        ],
+        mailPsd: [
+          { required: true, message: '请输入邮箱密码', trigger: 'blur' }
+        ],
+        sendName: [
+          { required: true, message: '请输入发件人昵称', trigger: 'blur' }
+        ]
+      },
+      alarmForm: {
+        isAlarm: '是',
+        alarmWay: 1
+      }
+    }
+  },
+  methods: {
+    submitForm (formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          alert('submit!')
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    },
+    resetForm (formName) {
+      this.$refs[formName].resetFields()
+    }
+  },
+  mounted () {
+  }
+}
+</script>
+
+<style lang='scss' scoped>
+.system-setting{
+  width:100%;
+  .title {
+    font-size: 18px;
+    height: 40px;
+    line-height: 40px;
+    margin: 10px 0;
+    color: #333;
+    padding: 0 20px;
+  }
+  .tabChosen{
+    background-color: #fff;
+    height: 600px;
+    padding:20px;
+  }
+  .basicForm{
+    margin-left: 0;
+    width: 60%;
+  }
+}
+
+</style>
diff --git a/src/views/home/Home.vue b/src/views/home/Home.vue
new file mode 100644
index 0000000..eb878dc
--- /dev/null
+++ b/src/views/home/Home.vue
@@ -0,0 +1,518 @@
+<template>
+  <el-container class="home_container">
+
+    <el-header class="home_header">
+      <div class="header_title">
+        <img src="../../assets/img/login/logo.png" alt="">
+        <span>北京友联华宇科技有限公司CRM</span>
+      </div>
+      <div class='header_right'>
+        <!--<el-badge :value='0' class="alarmList">
+          <i class='el-icon-message-solid wk-bell'  @click='alarmDrawer=true'></i>
+        </el-badge> -->
+
+        <!--<el-popover
+          :visible-arrow="false"
+          placement="bottom"
+          popper-class="no-padding-popover"
+          width="200"
+          trigger="click">
+          <div class="handel-items">
+            <div
+              class="handel-item"
+              @click="handleClick('person')"><i class="wukong wukong-personcenter"/>个人中心</div>
+            <div
+              class="handel-item"
+              @click="handleClick('goout')"><i class="wukong wukong-goout"/>退出登录</div>
+            <div
+              :style="{'margin-bottom': manage ? '15px' : '0'}"
+              class="handel-item hr-top"
+              style="pointer-events: none;"><i class="wukong wukong-versions"/>版本 V9.2.3.191220</div>
+            <div
+              v-if="manage"
+              class="handel-box">
+              <el-button
+                type="primary"
+                class="handel-button"
+                @click="enterSystemSet()">进入企业管理后台</el-button>
+            </div>
+          </div> slot="reference"-->
+          <div class="user-container">
+              <div
+                v-photo="userInfo"
+                v-lazy:background-image="$options.filters.filterUserLazyImg(userInfo.Avatar)"
+                :key="userInfo.Avatar"
+                class="user-img div-photo"/>
+                <div class="user-name">{{userInfo.RealName}}</div>
+                <div><img class="goout" src="@/assets/img/goOut.png" @click="handleClick('goout')"/></div>
+              <!--<i class="el-icon-caret-bottom mark"/>-->
+            </div>
+        <!--</el-popover>-->
+      </div>
+
+    </el-header>
+    <el-drawer
+      title="最新消息"
+      :visible.sync="alarmDrawer"
+     >
+      <div style="height:600px;">
+        <el-scrollbar style="height:100%">
+            <div style="width:100%;height:700px;padding:0px 20px;" >
+               <ul>
+                  <li v-for="item in 100" :key="item">{{item}}</li>
+              </ul>
+            </div>
+        </el-scrollbar>
+      </div>
+    </el-drawer>
+    <el-container>
+      <el-aside :width="isCollapse ? '80px' : '220px'" class="home_aside">
+        <div
+          style='background-color: #transparent;'
+          class="sidebar-bottom">
+          <div class="sidebar-container">
+            <img
+              v-if='isCollapse'
+              :style="{ 'right': isCollapse ? '13px' : '0' }"
+              class="collapse-button"
+              src="@/assets/img/collapse_right.png"
+              alt=""
+              @click="toggleCollapse">
+              <img
+              v-if='!isCollapse'
+              :style="{ 'right': isCollapse ? '3px' : '0' }"
+              class="collapse-button"
+              src="@/assets/img/collapse_white.png"
+              alt=""
+              @click="toggleCollapse">
+          </div>
+        </div>
+        <el-menu class="aside_menu"
+                 background-color="#fff"
+                 text-color="#666666"
+                 active-text-color="#4D88FF"
+                 unique-opened
+                 :collapse="isCollapse"
+                 :collapse-transition="false"
+                 :router="true" :default-active="activePath">
+          <el-submenu :index="item.Id + ''" v-for="item in moduleBlock" :key="item.Id">
+            <template slot="title">
+              <i :class="item.IconPath" style='width:20px;height:25px;margin-top:12px;margin-right:12px;'></i>
+              <span>{{item.Name}}</span>
+            </template>
+            <el-menu-item :index="'/' + subItem.LinkUrl"
+                          :disabled="subItem.LinkUrl === ''"
+                          v-for="subItem in item.Children"
+                          :key="subItem.Id" @click="saveNavState(subItem.LinkUrl)">
+              <template slot="title">
+                <i class="el-icon-menu"></i>
+                <span>{{subItem.Name}}</span>
+              </template>
+            </el-menu-item>
+          </el-submenu>
+        </el-menu>
+
+      </el-aside>
+
+      <el-main class="home_main">
+        <router-view></router-view>
+      </el-main>
+
+    </el-container>
+
+  </el-container>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+import Lockr from 'lockr'
+import { Loading } from 'element-ui'
+export default {
+  name: 'Home',
+  data () {
+    return {
+      menuList: [],
+      iconsObj: {
+        125: 'el-icon-s-custom',
+        103: 'el-icon-lock',
+        101: 'el-icon-s-goods',
+        102: 'el-icon-shopping-bag-1',
+        145: 'el-icon-data-analysis'
+      },
+      isCollapse: false,
+      activePath: '',
+      alarmDrawer: false,
+      userInfo: []
+    }
+  },
+  computed: {
+    ...mapGetters(['moduleBlock'])
+  },
+  watch: {
+    moduleBlock: function (newFlag, oldFlag) {
+      // 需要执行的代码
+      return newFlag
+    }
+  },
+  created () {
+    this.activePath = window.sessionStorage.getItem('activePath')
+    console.log(this.activePath, this.moduleBlock, Lockr.get('authList'))
+    if (Object.keys(this.moduleBlock).length === 0) {
+      this.$store.commit('SET_MODULE', Lockr.get('authList'))
+    }
+    this.userInfo = Lockr.get('User-Info')
+  },
+  methods: {
+    logout () {
+      window.sessionStorage.clear()
+      localStorage.clear()
+      this.$router.replace('/login')
+    },
+    handleClick (type) {
+      if (type === 'goout') {
+        this.$confirm('退出登录?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+          .then(() => {
+            let loading = Loading.service({
+              target: document.getElementById('#app')
+            })
+            window.sessionStorage.clear()
+            localStorage.clear()
+            this.$router.replace('/login')
+            loading.close()
+            // this.$store
+            //   .dispatch('LogOut')
+            //   .then(() => {
+            //     location.reload()
+            //     loading.close()
+            //   })
+            //   .catch(() => {
+            //     location.reload()
+            //     loading.close()
+            //   })
+          })
+          .catch(() => {})
+      } else if (type === 'person') {
+        this.$router.push({
+          name: ''
+        })
+      }
+    },
+    getMenuList () {
+      // this.menuList = {...this.moduleBlock}
+      //  [{Id: 1, ModuleName: '客户管理', children: [{Id: 11, ModuleName: '客户管理', LinkUrl: 'clientsManage'}, {Id: 12, ModuleName: '商机', LinkUrl: 'saleChance'}, {Id: 13, ModuleName: '联系人', LinkUrl: 'ContactsIndex'}, {Id: 14, ModuleName: '商机(审批)', LinkUrl: 'BusinessIndex'}, {Id: 15, ModuleName: '合同管理', LinkUrl: 'ContractIndex'}]}, {Id: 2, ModuleName: '企业管理', children: [{Id: 21, ModuleName: '部门管理', LinkUrl: 'ApartmentManage'}, {Id: 22, ModuleName: '职务权限管理', LinkUrl: 'offcialAuthority'}, {Id: 23, ModuleName: '员工管理', LinkUrl: 'EmployeeManage'}, {Id: 24, ModuleName: '系统设置', LinkUrl: 'systemSetting'}, {Id: 25, ModuleName: '员工日志', LinkUrl: 'staffLog'}]}, {Id: 3, ModuleName: '系统管理', children: [{Id: 31, ModuleName: '模块设置', LinkUrl: 'ModuleManage'}]}]
+    },
+
+    toggleCollapse () {
+      this.isCollapse = !this.isCollapse
+    },
+
+    saveNavState (activePath) {
+      console.log(activePath)
+      window.sessionStorage.setItem('activePath', '/' + activePath)
+      this.activePath = '/' + activePath
+    },
+    getInfoList () {
+      console.log('111')
+    }
+  }
+
+}
+</script>
+
+<style lang="less" scoped>
+  .home_container{
+    height: 100%;
+    background: #F5F6FA;
+    .home_header{
+      height: 64px; /*no*/
+      background: #4D88FF;
+      display: flex;
+      justify-content: space-between;
+      padding-left: 0px;
+      align-items: center;
+      color: #ffffff;
+      font-size: 20px; /*no*/
+      margin-bottom:10px;
+    }
+    .header_title{
+      display: flex;
+      align-items: center;
+    }
+    .header_title img{
+      width: 220px; /*no*/
+      height: 100%;
+    }
+    .header_title span{
+      font-size: 18px; /*no*/
+      font-weight: 400;
+      color: #FFFFFF;
+      margin-left: 40px;
+    }
+    .header_right{
+      display: flex;
+      justify-content: flex-end;
+      align-items: center;
+    }
+    .alarmList{
+      margin-right: 32px;
+    }
+    .home_aside{
+      background-color: #fff;
+      position: relative;
+      box-shadow: 0px 4px 12px 0px #EDEFF2;
+    }
+    .sidebar-bottom {
+      position: absolute;
+      bottom: 50px;
+      left: 0;
+      right: 0;
+      height: 48px;
+
+      .sidebar-container {
+        position: relative;
+        height: 48px;
+      }
+    }
+
+    .collapse-button {
+      position: absolute;
+      top: 0;
+      padding: 18px 20px;
+      // background: #4D88FF;
+    }
+    .home_aside.el-aside /deep/ .el-menu--collapse{
+      width: 80px; /*no*/
+    }
+    .el-aside /deep/ .el-submenu__title:hover{
+      color: #4D88FF !important;
+      background-color: #EBF1FF !important;
+      i{
+        color: #4D88FF !important;
+      }
+      i.icon-customer{
+        background: url('../../assets/aside/customer_active.png') no-repeat;
+        background-size: 20px 20px;
+        background-position: 0px 5px;
+      }
+      i.icon-financial{
+        background: url('../../assets/aside/financial_active.png') no-repeat;
+        background-size: 20px 20px;
+        background-position: 0px 5px;
+      }
+      i.icon-company{
+        background: url('../../assets/aside/company_active.png') no-repeat;
+        background-size: 20px 20px;
+        background-position: 0px 5px;
+      }
+      i.icon-order{
+        background: url('../../assets/aside/order_active.png') no-repeat;
+        background-size: 20px 20px;
+        background-position: 0px 5px;
+      }
+      i.icon-product{
+        background: url('../../assets/aside/product_active.png') no-repeat;
+        background-size: 20px 20px;
+        background-position: 0px 5px;
+      }
+      i.icon-system{
+        background: url('../../assets/aside/system_active.png') no-repeat;
+        background-size: 20px 20px;
+        background-position: 0px 5px;
+      }
+      i.icon-total{
+        background: url('../../assets/aside/total_active.png') no-repeat;
+        background-size: 20px 20px;
+        background-position: 0px 5px;
+      }
+      i.icon-workbench{
+        background: url('../../assets/aside/workbench_active.png') no-repeat;
+        background-size: 20px 20px;
+        background-position: 0px 5px;
+      }
+      i.icon-business{
+        background: url('../../assets/aside/business_active.png') no-repeat;
+        background-size: 20px 20px;
+        background-position: 0px 5px;
+      }
+      i.icon-personnel{
+        background: url('../../assets/aside/personnel_active.png') no-repeat;
+        background-size: 20px 20px;
+        background-position: 0px 5px;
+      }
+    }
+    .el-aside /deep/ .el-menu-item:hover, .el-menu-item:focus{
+      color: #4D88FF !important;
+      background-color: #EBF1FF !important;
+      i{
+        color: #4D88FF !important;
+      }
+    }
+    .el-menu--vertical /deep/ .el-menu-item:focus{
+      background-color: #EBF1FF !important;
+    }
+    .aside_menu{
+      border-right: none;
+      /deep/ .el-menu-item{
+        height: 40px;
+        line-height: 40px;
+        background: #F8F8F8 !important;
+      }
+      /deep/ .el-submenu__title{
+        display: flex;
+        font-size: 16px;
+        span{
+          flex: 1;
+        }
+      }
+      /deep/ .el-submenu.is-active .el-submenu__title{
+         color: #4D88FF !important;
+         font-size: 16px;
+         i{
+           color: #4D88FF !important;
+         }
+         i.icon-customer{
+            background: url('../../assets/aside/customer_active.png') no-repeat;
+            background-size: 20px 20px;
+            background-position: 0px 5px;
+         }
+         i.icon-financial{
+            background: url('../../assets/aside/financial_active.png') no-repeat;
+            background-size: 20px 20px;
+            background-position: 0px 5px;
+         }
+         i.icon-company{
+            background: url('../../assets/aside/company_active.png') no-repeat;
+            background-size: 20px 20px;
+            background-position: 0px 5px;
+         }
+         i.icon-order{
+            background: url('../../assets/aside/order_active.png') no-repeat;
+            background-size: 20px 20px;
+            background-position: 0px 5px;
+         }
+         i.icon-product{
+            background: url('../../assets/aside/product_active.png') no-repeat;
+            background-size: 20px 20px;
+            background-position: 0px 5px;
+         }
+         i.icon-system{
+            background: url('../../assets/aside/system_active.png') no-repeat;
+            background-size: 20px 20px;
+            background-position: 0px 5px;
+         }
+         i.icon-total{
+            background: url('../../assets/aside/total_active.png') no-repeat;
+            background-size: 20px 20px;
+            background-position: 0px 5px;
+         }
+         i.icon-workbench{
+            background: url('../../assets/aside/workbench_active.png') no-repeat;
+            background-size: 20px 20px;
+            background-position: 0px 5px;
+         }
+         i.icon-business{
+            background: url('../../assets/aside/business_active.png') no-repeat;
+            background-size: 20px 20px;
+            background-position: 0px 5px;
+          }
+         i.icon-personnel{
+            background: url('../../assets/aside/personnel_active.png') no-repeat;
+            background-size: 20px 20px;
+            background-position: 0px 5px;
+          }
+      }
+      /deep/ .el-menu-item:hover{
+        background-color: #EBF1FF !important;
+      }
+      /deep/ .el-menu-item.is-active{
+         background-color: #EBF1FF !important;
+         position: relation;
+         &:after{
+            content: '|';
+            width: 2px;
+            height: 40px;
+            background: #4D88FF;
+            position: absolute;
+            left: 0px;
+         }
+      }
+    }
+
+    .home_main{
+      background-color: #F5F6FA;
+      padding: 16px;
+    }
+    .wk-bell{
+      cursor: pointer;
+      font-size: 20px;
+      &:hover{
+        color: #2362fb;
+      }
+    }
+    .user-container {
+      display: flex;
+      align-items: center;
+      flex-shrink: 0;
+      cursor: pointer;
+      .user-img {
+        display: block;
+        width: 32px; /*no*/
+        min-width: 32px;
+        min-height: 32px;
+        height: 32px; /*no*/
+        border-radius: 50%;
+      }
+      .user-name{
+        font-size: 14px; /*no*/
+        font-weight: 400;
+        color: #FFFFFF;
+        margin-left: 12px;
+        margin-right:40px;
+      }
+      .goout{
+        width: 20px; /*no*/
+        height: 20px; /*no*/
+      }
+      .mark {
+        font-size: 15px;
+        color: #aaaaaa;
+      }
+    }
+
+    .user-container:hover {
+      .mark {
+        color: #2486e4;
+      }
+    }
+  }
+  .handel-items {
+      padding: 10px 0 18px 0;
+      .handel-item {
+        padding: 5px 20px;
+        font-size: 14px;
+        color: #aaa;
+        cursor: pointer;
+        i {
+          margin-right: 8px;
+          font-size: 15px;
+        }
+      }
+      .handel-item:hover {
+        background-color: #f7f8fa;
+        color: #4D88FF;
+      }
+      .handel-box {
+        padding: 0 15px;
+        .handel-button {
+          width: 100%;
+          border-radius: 4px;
+          border-color: #009df0;
+          background-color: #009df0;
+        }
+      }
+    }
+</style>
diff --git a/src/views/login/index.vue b/src/views/login/index.vue
new file mode 100644
index 0000000..990923f
--- /dev/null
+++ b/src/views/login/index.vue
@@ -0,0 +1,733 @@
+<template>
+  <div class="login_container">
+    <img class='login_bg' src='../../assets/img/login/login_bg.png' />
+    <div class='center_container'>
+      <div class="left">
+        <img class="left-pic" src='../../assets/img/login/login.png' />
+      </div>
+      <div class="right">
+        <div id="wx_qrcode" class='wx_qrcode'></div>
+        <!--<el-form
+          ref="loginForm"
+          v-if="loginProgress ==1"
+          :model="loginForm"
+          :rules="loginRules"
+          class="login-form"
+          auto-complete="on"
+          label-position="left">
+          <div class="title">北京友联华宇科技有限公司</div>
+          <el-form-item prop="LoginName">
+            <el-input
+              ref="name"
+              v-model="loginForm.LoginName"
+              autofocus="autofocus"
+              name="LoginName"
+              type="text"
+              auto-complete="on"
+              placeholder="请输入用户名"
+              @keyup.enter.native="handleLogin" />
+          </el-form-item>
+          <el-form-item prop="LoginPassword">
+            <el-input
+              v-model="loginForm.LoginPassword"
+              type="password"
+              name="LoginPassword"
+              auto-complete="on"
+              placeholder="请输入密码"
+              @keyup.enter.native="handleLogin" />
+          </el-form-item>
+          <el-form-item prop="VerifyCode">
+            <el-row :span="24">
+              <el-col :span="16">
+                <el-input v-model="loginForm.VerifyCode" auto-complete="off" placeholder="请输入验证码" @keyup.enter.native="handleLogin('loginForm')"/>
+              </el-col>
+              <el-col :span="8">
+                <div class="login-code" @click="refreshCode">
+                  <img :src='loginImg' class='loginImg' />
+                </div>
+              </el-col>
+            </el-row>
+          </el-form-item>
+          <el-form-item>
+            <el-button
+              :loading="loading"
+              class="submit-btn"
+              @click.native.prevent="handleLogin">
+              登录
+            </el-button>
+            <div class='getPsd' @click='getPsd'>找回密码</div>
+          </el-form-item>
+        </el-form>-->
+
+        <el-form
+          ref="vertifyForm"
+          v-if="loginProgress ==2"
+          :model="vertifyForm"
+          :rules="vertifyRules"
+          class="login-form"
+          auto-complete="on"
+          label-position="left">
+          <el-form-item prop="ResetName" v-if="loginProgress ==2">
+            <el-input
+              ref="ResetName"
+              v-model="vertifyForm.ResetName"
+              autofocus="autofocus"
+              name="ResetName"
+              type="text"
+              auto-complete="on"
+              placeholder="请输入邮箱/手机号"
+              @blur.prevent="handleVertify" />
+          </el-form-item>
+          <el-form-item prop="ResetCode" v-if="loginProgress ==2">
+            <el-row :span="24">
+              <el-col :span="16">
+                <el-input
+                  ref="ResetCode"
+                  v-model="vertifyForm.ResetCode"
+                  autofocus="autofocus"
+                  name="ResetCode"
+                  type="text"
+                  auto-complete="on"
+                  placeholder="请输入验证码"
+                  @keyup.enter.native="handleVertify" />
+              </el-col>
+              <el-col :span="6">
+                <el-button
+                  :disabled="codeDisabled"
+                  class="codeBtn"
+                  @click.native.prevent="getResetCode">
+                  {{codeMsg}}
+                </el-button>
+              </el-col>
+            </el-row>
+
+          </el-form-item>
+          <el-form-item v-if="loginProgress ==2">
+            <el-button
+              :loading="vertifyloading"
+              class="submit-btn"
+              @click.native.prevent="handleVertify">
+              验证
+            </el-button>
+            <div class='getPsd' @click='backToLogin'>返回登录</div>
+          </el-form-item>
+        </el-form>
+        <el-form
+          ref="resetForm"
+          v-if="loginProgress ==3"
+          :model="resetForm"
+          :rules="resetRules"
+          class="login-form"
+          auto-complete="on"
+          label-position="left">
+          <el-form-item prop="newPsd" label="新密码" v-if="loginProgress ==3">
+            <el-input
+              ref="newPsd"
+              v-model="resetForm.newPsd"
+              autofocus="autofocus"
+              name="newPsd"
+              type="text"
+              auto-complete="on"
+              placeholder="请输入新密码"
+              @keyup.enter.native="handleConfirmChange" />
+          </el-form-item>
+          <el-form-item prop="newPsdSceond" label="确认新密码" v-if="loginProgress ==3">
+            <el-input
+              ref="newPsdSceond"
+              v-model="resetForm.newPsdSceond"
+              autofocus="autofocus"
+              name="newPsdSceond"
+              type="text"
+              auto-complete="on"
+              placeholder="请确认新密码"
+              @keyup.enter.native="handleNewCode" />
+          </el-form-item>
+          <el-form-item v-if="loginProgress ==3">
+            <el-button
+              :loading="resetloading"
+              class="submit-btn"
+              @click.native.prevent="handleConfirmChange">
+              确定
+            </el-button>
+          </el-form-item>
+        </el-form>
+        <!--<div class="copyright">
+          北京友联华宇科技有限公司CRM受国家计算机软件著作权保护,未经授权不得进行商业行为,违者必究。<br>
+          <a
+            target="_blank"
+            href="http://www.urlink.com.cn/">©2021 北京友联华宇科技有限公司</a>
+        </div>-->
+      </div>
+    </div>
+    <!--<img
+      src="../../assets/img/logo_bg.png"
+      class="logo" > -->
+  </div>
+</template>
+
+<script>
+import SIdentify from '@/components/common/SIdentify'
+// FindPassword FindPasswordStep2 FindPasswordStep3 CreateVerifyCode, requestLogin,
+import { WxLogin, CheckLogin } from '@/api/login'
+import Lockr from 'lockr'
+import {
+  addAuth
+} from '@/utils/auth'
+export default {
+  name: 'Login',
+  components: { SIdentify },
+  data () {
+    const validateLoginName = (rule, value, callback) => {
+      if (value.length === 0) {
+        callback(new Error('请输入账号'))
+      } else {
+        callback()
+      }
+    }
+    const validatePass = (rule, value, callback) => {
+      let psd = /^[A-Za-z0-9]{6,20}$/
+      if (value === '') {
+        callback(new Error('请输入密码'))
+      } else if (!psd.test(value)) {
+        callback(new Error('请输入至少包含 数字和英文,长度6-20的密码'))
+      } else {
+        callback()
+      }
+    }
+    const validateCode = (rule, value, callback) => {
+      if (value === '') {
+        callback(new Error('请输入验证码'))
+      } else {
+        callback()
+      }
+    }
+    const validateResetName = (rule, value, callback) => {
+      let phone = /^1(3|4|5|6|7|8|9)\d{9}$/
+      let mail = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/
+      if (value.length === 0) {
+        callback(new Error('请输入邮箱/手机号'))
+      } else if (!phone.test(value) && !mail.test(value)) {
+        callback(new Error('请输入正确的手机号/邮箱地址'))
+      } else {
+        this.codeDisabled = false
+        console.log(this.codeDisabled)
+        callback()
+      }
+    }
+    const validateresetCode = (rule, value, callback) => {
+      if (value === '') {
+        callback(new Error('请输入验证码'))
+      } else {
+        if (value !== this.identifyCode) {
+          callback(new Error('请输入正确的验证码'))
+        }
+        callback()
+      }
+    }
+    const validatenewPsd = (rule, value, callback) => {
+      let psd = /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,20}$/
+      if (value === '') {
+        callback(new Error('请输入新密码'))
+      } else if (!psd.test(value)) {
+        callback(new Error('请输入至少包含 数字和英文,长度6-20的密码'))
+      } else {
+        callback()
+      }
+    }
+    const validatenewPsdTrue = (rule, value, callback) => {
+      if (value === '') {
+        callback(new Error('请再次输入新密码'))
+      } else if (value !== this.resetForm.newPsd) {
+        callback(new Error('请输入相同的新密码'))
+      } else {
+        callback()
+      }
+    }
+    return {
+      loginProgress: '1', // 1 登录  2 重置密码验证  3 重置密码
+      loginForm: {
+        LoginName: '',
+        LoginPassword: '',
+        VerifyCode: ''
+      },
+      vertifyForm: {
+        ResetName: '',
+        ResetCode: ''
+      },
+      vertifyRules: {
+        ResetName: [
+          { required: true, trigger: 'blur', validator: validateResetName }
+        ],
+        ResetCode: [{ required: true, trigger: 'blur', validator: validateresetCode }]
+      },
+      resetForm: {
+        newPsd: '',
+        newPsdSceond: ''
+      },
+      resetRules: {
+        newPsd: [
+          { required: true, trigger: 'blur', validator: validatenewPsd }
+        ],
+        newPsdSceond: [{ required: true, trigger: 'blur', validator: validatenewPsdTrue }]
+      },
+      loginRules: {
+        LoginName: [
+          { required: true, trigger: 'blur', validator: validateLoginName }
+        ],
+        LoginPassword: [{ required: true, trigger: 'blur', validator: validatePass }],
+        VerifyCode: [
+          { required: true, trigger: 'blur', validator: validateCode }
+        ]
+      },
+      loading: false,
+      vertifyloading: false, // 验证
+      resetloading: false, // 重置
+      redirect: undefined,
+      remember: false,
+      identifyCodes: [1, 2, 3, 4],
+      identifyCode: '3333',
+      codeMsg: '获取验证码',
+      countdown: 60,
+      timer: null,
+      codeDisabled: true,
+      loginImg: '',
+      loginToken: ''
+    }
+  },
+  watch: {
+    $route: {
+      handler: function (route) {
+        console.log(sessionStorage.getItem('code'))
+        const query = route.query
+        if (query) {
+          let queryCode = sessionStorage.getItem('code')
+          if (queryCode) {
+            // this.userWxLogin(queryCode)
+            // 成功后删除不必要的参数(state,code,appid 在其他页面并不需要),保证路由是干净的
+            // delete this.otherQuery.code
+            // delete this.otherQuery.state
+            // delete this.otherQuery.appid
+          }
+        }
+      },
+      immediate: true
+    }
+  },
+  mounted () {
+    console.log('localStorage' + '-----' + window.localStorage.getItem('token'))
+    console.log('sessionStorage' + '-----' + window.sessionStorage.getItem('token'))
+    console.log(Lockr.get('Admin-Token'))
+    if (window.localStorage.getItem('token')) {
+      this.setToken(window.localStorage.getItem('token'))
+    } else if (Lockr.get('Admin-Token')) {
+      this.setToken(Lockr.get('Admin-Token'))
+    } else {
+      window.WwLogin({
+        'id': 'wx_qrcode',
+        'appid': 'wwcb2217872225e05b',
+        'agentid': '1000004',
+        'redirect_uri': encodeURIComponent('http://crm.urlink.com.cn/#/logining'),
+        'state': '',
+        'href': ''
+      })
+    }
+
+    // this.loginToken = Lockr.get('Login-Cache')
+    // this.getTextCode()
+  },
+  methods: {
+    // getTextCode () {
+    //   CreateVerifyCode(this.loginToken).then(res => {
+    //     console.log(res)
+    //     return (
+    //       'data:image/png;base64,' +
+    //         btoa(
+    //           new Uint8Array(res.data).reduce(
+    //             (data, byte) => data + String.fromCharCode(byte),
+    //             ''
+    //           )
+    //         )
+    //     )
+    //   })
+    //     .then(data => {
+    //       this.loginImg = data
+    //     })
+    // },
+    // onKeyUp (type) {
+    //   this[type] = this[type].replace(/./g, '*')
+    // },
+    // 找回密码 1
+    // getPsd () {
+    //   this.loginProgress = 2
+    // },
+    // 忘记密码 重置 2
+    // backToLogin () {
+    //   this.loginProgress = 1
+    // },
+    // 重置- 获取验证码 2
+    // resetVertifyForm () {
+    //   this.$refs.vertifyForm.resetFields()
+    // },
+    // 验证- 获取验证码
+    // handleVertify () {
+    //   this.$refs.vertifyForm.validate(valid => {
+    //     if (valid) {
+    //       // let params = {
+    //       //   'Token': '',
+    //       //   'ValiteCode': ''
+    //       // }
+    //       // FindPasswordStep2(params).then(res => {
+
+    //       // })
+    //       this.loginProgress = 3
+    //       clearInterval(this.timer)
+    //       this.codeMsg = '获取短信验证码'
+    //       this.countdown = 60
+    //       this.timer = null
+    //       this.codeDisabled = false
+    //       this.resetVertifyForm()
+    //     }
+    //   })
+    // },
+    // 重置- 获取验证码 2
+    // getResetCode () {
+    //   console.log('11111')
+    //   if (this.vertifyForm.ResetName !== '') {
+    //     this.codeDisabled = true
+    //     // let data = {
+    //     //   Account: this.ResetName
+    //     // }
+    //     // FindPassword(data).then(res=>{
+    //     // if(res.code === 200){
+    //     if (!this.timer) {
+    //       console.log(this.countdown)
+    //       this.timer = setInterval(() => {
+    //         if (this.countdown > 0 && this.countdown <= 60) {
+    //           this.countdown--
+    //           if (this.countdown !== 0) {
+    //             this.codeDisabled = true
+    //             this.codeMsg = '重新发送(' + this.countdown + ')'
+    //           } else {
+    //             clearInterval(this.timer)
+    //             this.codeMsg = '获取短信验证码'
+    //             this.countdown = 60
+    //             this.timer = null
+    //             this.codeDisabled = false
+    //           }
+    //         }
+    //       }, 1000)
+    //     }
+    // }else{
+    // this.message({
+    //   message:res.message,
+    //   type:'error'
+    // })
+    // this.codeDisabled  = false;
+    // }
+    // })
+    //   }
+    // },
+    // 确认新密码 3
+    // resetConfirmForm () {
+    //   this.$refs.resetForm.resetFields()
+    // },
+    // 确认新密码 3
+    // handleConfirmChange () {
+    //   this.$refs.resetForm.validate(valid => {
+    //     if (valid) {
+    //       // let params = {
+    //       //   'NewPassword': this.resetForm.newPsd,
+    //       //   'ConfirmPassword': this.resetForm.newPsdSceond,
+    //       //   'Token': ''
+    //       // }
+    //       // FindPasswordStep3(params).then(res => {
+
+    //       // })
+    //       this.loginProgress = 1
+    //       this.resetConfirmForm()
+    //     }
+    //   })
+    // },
+    // 登录 1
+    // resetLoginForm () {
+    //   this.$refs.loginForm.resetFields()
+    // },
+    userWxLogin (code) {
+      WxLogin(code).then(res => {
+        console.log(res)
+        if (res.data.ErrorCode !== 200) {
+          this.$message.error('登录失败!')
+          this.loading = false
+        } else {
+          if (res.data.ErrorCode === 500) {
+            this.$message.error(res.data.Message)
+            this.loading = false
+          } else {
+            this.loading = false
+            this.$message.success('登录成功!')
+            addAuth(res.data.Result.Token)
+            Lockr.set('Admin-Token', res.data.Result.Token)
+            Lockr.set('User-Info', res.data.Result.LoginUserInfo)
+            this.$store.commit('SET_USERINFO', res.data.Result.LoginUserInfo)
+            window.localStorage.setItem('token', res.data.Result.Token)
+            this.$store.dispatch('getAuth')
+            this.$router.replace('/home')
+          }
+        }
+      })
+    },
+    setToken (token) {
+      CheckLogin({'Token': token}).then(res => {
+        if (res.data.ErrorCode === 200) {
+          this.$message.success('登录成功!')
+          addAuth(res.data.Result.Token)
+          Lockr.set('Admin-Token', res.data.Result.Token)
+          Lockr.set('User-Info', res.data.Result.LoginUserInfo)
+          this.$store.commit('SET_USERINFO', res.data.Result.LoginUserInfo)
+          window.localStorage.setItem('token', res.data.Result.Token)
+          this.$store.dispatch('getAuth')
+          this.$router.replace('/home')
+        } else {
+          window.WwLogin({
+            'id': 'wx_qrcode',
+            'appid': 'wwcb2217872225e05b',
+            'agentid': '1000004',
+            'redirect_uri': encodeURIComponent('http://crm.urlink.com.cn/#/logining'),
+            'state': '',
+            'href': ''
+          })
+        }
+      })
+        .catch(res => {
+          window.WwLogin({
+            'id': 'wx_qrcode',
+            'appid': 'wwcb2217872225e05b',
+            'agentid': '1000004',
+            'redirect_uri': encodeURIComponent('http://crm.urlink.com.cn/#/logining'),
+            'state': '',
+            'href': ''
+          })
+        })
+    }
+    // 登录 1
+    // handleLogin () {
+    //   this.$refs.loginForm.validate(valid => {
+    //     console.log(valid)
+    //     if (!valid) return
+    //     this.loading = true
+    //     // this.$message.success('登录成功!')
+    //     // window.sessionStorage.setItem('token', this.loginForm.LoginPassword)
+    //     // this.loading = false
+    //     // this.$router.replace('/home')
+    //     let params = {
+    //       LoginName: this.loginForm.LoginName,
+    //       LoginPassword: this.loginForm.LoginPassword,
+    //       VerifyCode: this.loginForm.VerifyCode,
+    //       Verify: this.loginToken
+    //     }
+    //     requestLogin(params).then(res => {
+    //       console.log(res)
+    //       if (res.data.ErrorCode !== 200) {
+    //         this.resetLoginForm()
+    //         this.$message.error('登录失败!')
+    //         this.loading = false
+    //       } else {
+    //         if (res.data.ErrorCode === 500) {
+    //           this.$message.error(res.data.Message)
+    //           this.loading = false
+    //         } else {
+    //           this.loading = false
+    //           this.$message.success('登录成功!')
+    //           addAuth(res.data.Result.Token)
+    //           Lockr.set('Admin-Token', res.data.Result.Token)
+    //           Lockr.set('User-Info', res.data.Result.LoginUserInfo)
+    //           window.localStorage.setItem('token', res.data.Result.Token)
+    //           this.$store.dispatch('getAuth')
+    //           this.$router.replace('/home')
+    //         }
+    //       }
+    //     })
+    //   })
+    // },
+    // randomNum (min, max) {
+    //   return Math.floor(Math.random() * (max - min) + min)
+    // },
+    // refreshCode () {
+    //   console.log('111')
+    //   this.getTextCode()
+    //   // this.identifyCode = ''
+    //   // this.makeCode(this.identifyCodes, 4)
+    // },
+    // makeCode (o, l) {
+    //   for (let i = 0; i < l; i++) {
+    //     // eslint-disable-next-line standard/computed-property-even-spacing
+    //     this.identifyCode += this.identifyCodes[
+    //       this.randomNum(0, this.identifyCodes.length)
+    //     ]
+    //   }
+    // }
+  }
+}
+</script>
+
+<style lang='less' scoped>
+@media screen and (max-width:1366px) and (min-width:300px){
+    .login_bg{
+      width: 100%;
+      height:470px;
+      position: absolute;
+      content: '1366';
+      left: 0;
+      bottom: 0;
+    }
+}
+@media screen and (max-width:1440px) and (min-width:1367px){
+    .login_bg{
+      width: 100%;
+      height:536px;
+      position: absolute;
+      content: '1440';
+      left: 0;
+      bottom: 0;
+    }
+}
+@media screen and (max-width:1920px) and (min-width:1441px){
+    .login_bg{
+      width: 100%;
+      height:500px;
+      position: absolute;
+      left: 0;
+      bottom: 0;
+    }
+}
+  .login_container{
+    position: relative;
+    width: 100%;
+    height: 100%;
+    background: #F0F1F5;
+    min-width: 1300px;
+    display: flex;
+    align-items: center;
+    .center_container{
+      position: absolute;
+      left:50%;
+      transform:translateX(-50%);
+      width: 1000px;
+      height: 680px;
+      background: #FFFFFF;
+      box-shadow: 0px 2px 4px 0px rgba(15, 27, 51, 0.05);
+      border-radius: 4px;
+      display: flex;
+      .left {
+        width: 440px;
+        .left-pic {
+          height: 100%;
+          background-color:#f0f8ff;
+        }
+      }
+      .right {
+        position: relative;
+        width: 560px;
+        background-color: #fff;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        flex-direction: column;
+        .el-form {
+          width: 70%;
+          .title {
+            font-size: 26px;
+            color: #333;
+            margin: 0 auto 50px;
+            text-align: center;
+          }
+          .submit-btn {
+            width: 100%;
+            line-height: 2;
+            font-size: 16px;
+            color: white;
+            border-radius: 3px;
+            background-color: #ff7d00;
+            display: block;
+          }
+          .codeBtn{
+            width: 124px;
+            height: 40px;
+            line-height: 1;
+            font-size: 14px;
+            color: white;
+            border-radius: 3px;
+            background-color: #ff7d00;
+            display: block;
+            margin-left: 20px;
+          }
+          .getPsd{
+            color: #333;
+            font-size: 14px;
+            cursor:pointer;
+            float:right;
+            &:hover{
+              color:#ff7d00;
+            }
+          }
+          .el-button {
+            border: 0 none;
+          }
+          .action-control {
+            color: #999;
+            /deep/ .el-checkbox {
+              .el-checkbox__label {
+                color: #999;
+              }
+              .el-checkbox__input.is-checked .el-checkbox__inner {
+                background-color: #ff7d00;
+                border-color: #ff7d00;
+              }
+            }
+
+            .forget {
+              cursor: pointer;
+              float: right;
+            }
+          }
+        }
+
+        .register {
+          width: 70%;
+          padding-top: 30px;
+          color: #333;
+          border-top: 1px solid #e6e6e6;
+          text-align: center;
+          margin-top: 28px;
+          .register-btn {
+            color: #ff7d00;
+            cursor: pointer;
+          }
+        }
+
+        .copyright {
+          width: 92%;
+          position: absolute;
+          bottom: 5%;
+          color: #d0d0d0;
+          font-size: 12px;
+          text-align: center;
+          line-height: 1.5;
+        }
+      }
+    }
+
+    .logo {
+      position: absolute;
+      left: 60px;
+      top: 0px;
+      width: 200px;
+      height: 200px;
+      z-index: 200;
+    }
+    .loginImg{
+      width: 124px;
+      margin-left: 20px;
+    }
+  }
+</style>
diff --git a/src/views/login/logining.vue b/src/views/login/logining.vue
new file mode 100644
index 0000000..327aa50
--- /dev/null
+++ b/src/views/login/logining.vue
@@ -0,0 +1,67 @@
+<template>
+  <div>正在登录...</div>
+</template>
+
+<script>
+import Lockr from 'lockr'
+import { WxLogin, CheckLogin } from '@/api/login'
+import {
+  addAuth
+} from '@/utils/auth'
+export default {
+  name: 'logining',
+  watch: {
+    $route: {
+      handler: function (route) {
+        console.log(sessionStorage.getItem('code'))
+        const query = route.query
+        if (query) {
+          let queryCode = sessionStorage.getItem('code')
+          if (queryCode) {
+            this.userWxLogin(queryCode)
+          }
+        }
+      },
+      immediate: true
+    }
+  },
+  methods: {
+    userWxLogin (code) {
+      console.log(process.env.BASE_API)
+      WxLogin(code).then(res => {
+        console.log(res)
+        if (res.data.ErrorCode !== 200) {
+          this.$message.error('登录失败!')
+          this.loading = false
+        } else {
+          if (res.data.ErrorCode === 500) {
+            this.$message.error(res.data.Message)
+            this.loading = false
+            this.$router.replace('/login')
+          } else {
+            this.loading = false
+            this.$message.success('登录成功!')
+            addAuth(res.data.Result.Token)
+            Lockr.set('Admin-Token', res.data.Result.Token)
+            Lockr.set('User-Info', res.data.Result.LoginUserInfo)
+            this.$store.commit('SET_USERINFO', res.data.Result.LoginUserInfo)
+            window.localStorage.setItem('token', res.data.Result.Token)
+            window.sessionStorage.setItem('token', res.data.Result.Token)
+            this.$store.dispatch('getAuth')
+            this.setToken(res.data.Result.Token)
+          }
+        }
+      })
+    },
+    setToken (token) {
+      CheckLogin({'Token': token}).then(res => {
+        if (res.data.ErrorCode === 200) {
+          this.$router.replace('/home')
+        } else {
+          this.$router.replace('/login')
+        }
+      })
+    }
+  }
+}
+</script>
diff --git a/src/views/module/ModuleManage.vue b/src/views/module/ModuleManage.vue
new file mode 100644
index 0000000..c7bd1e6
--- /dev/null
+++ b/src/views/module/ModuleManage.vue
@@ -0,0 +1,484 @@
+<template>
+  <div class='offical-authority'>
+    <p class="title"> 后台模块管理 </p>
+
+    <el-card>
+      <el-row>
+        <el-button class="create-button"
+        type="primary" @click='createModule'>新增</el-button>
+        <el-button class="delete-button"
+        type="primary" @click='deleteModule' v-if='isDelete'>删除</el-button>
+      </el-row>
+      <el-table
+        ref="moduleTable"
+        :data="rightsList"
+        border
+        max-height="600px"
+        @selection-change="handleSelectionChange"
+        v-bind="$attrs"
+        :row-style="showRow">
+        <el-table-column
+          show-overflow-tooltip
+          type="selection"
+          align="center"
+          width="55"/>
+        <el-table-column label="图标" prop="IconPath" width="100">
+          <template slot-scope="scope">
+            <div :class='scope.row.IconPath' style='margin-left:5px; width: 20px;height: 25px;'></div>
+          </template>
+        </el-table-column>
+        <el-table-column label="标题" prop="ModuleName" width="400">
+          <template slot-scope="scope">
+            <span class='level'>
+              <div v-if="scope.row.Children&&scope.row.Children.length>0" @click="openToggle(scope.row)"
+                :class="[scope.row.open?'el-table__expand-icon el-table__expand-icon--expanded':'el-table__expand-icon']">
+                <i class='el-icon-arrow-right'></i>
+              </div>
+            </span>
+            {{scope.row.ModuleName}}
+            <span>
+            <el-tooltip :content="scope.row.Description" placement="bottom" effect="light" v-show='scope.row.Description'>
+              <i class='el-icon-warning-outline'></i>
+            </el-tooltip>
+            </span>
+          </template>
+        </el-table-column>
+        <el-table-column label="地址" prop="LinkUrl"  width="400"></el-table-column>
+        <el-table-column label="显示" prop="IsShow">
+          <template slot-scope="scope">
+           <img :class="scope.row.IsShow?'el-icon-success':'el-icon-error'" />
+          </template>
+        </el-table-column>
+        <el-table-column label="排序" prop="SortNumber"></el-table-column>
+         <el-table-column
+          prop="operation"
+          label="操作">
+          <template slot-scope="scope">
+            <el-button type="text" size="small" @click='addModule(scope.row)'>添加子级</el-button>
+            <el-button type="text" size="small"  @click='editModule(scope.row)'>编辑模块</el-button>
+            <el-button type="text" size="small"  @click='deleteSingleModule(scope.row.Id)'>删除模块</el-button>
+        </template>
+      </el-table-column>
+      </el-table>
+    </el-card>
+    <!-- 导航新增编辑弹出框 -->
+    <el-dialog
+      :visible.sync="moduleDialog"
+      :title='addTitle'
+      :before-close="cancelDialog"
+      width="40%">
+      <el-form
+        ref="createForm"
+        :model="createForm"
+        :rules="createRules"
+        label-width="80px"
+        class="login-form"
+        auto-complete="on"
+        label-position="left">
+        <el-form-item label="上级导航" prop='fatherIntro'>
+           <el-cascader
+              ref="refSubCat"
+              placeholder="请选择上级导航"
+              :options="isCreate? selectOpts: rightsList"
+              :show-all-levels="false"
+              :props="{
+                children: 'Children',
+                label: 'ModuleName',
+                value: 'Id'
+              }"
+              v-model="createForm.fatherIntro"
+              style="width: 100%;"
+              @change='getFatherOpt'
+              change-on-select/>
+        </el-form-item>
+        <el-form-item label="导航标题"  prop='introName'>
+          <el-input
+            v-model="createForm.introName"
+            placeholder="请输入导航标题"/>
+          </el-form-item>
+          <el-form-item label="是否显示">
+            <el-switch v-model="createForm.isShow"></el-switch>
+          </el-form-item>
+          <el-form-item label="排序数字">
+            <el-input
+              class='numInp'
+              type='number'
+              v-model="createForm.sortNum"
+              placeholder="请输入排序数字"/>
+          </el-form-item>
+          <el-form-item label="自定义图标">
+            <el-select v-model="createForm.img" placeholder="请选择图标">
+              <el-option
+                v-for="(item, index) in iconOption"
+                class='iconList'
+                :class='item.name'
+                :key="index"
+                :label="item.name"
+                :value="item.name"/>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="链接地址">
+            <el-input
+              v-model="createForm.address"
+              placeholder="请输入链接地址"/>
+          </el-form-item>
+          <el-form-item label="备注说明">
+            <el-input
+                type='textarea'
+                v-model="createForm.info"
+                placeholder="请输入备注说明"/>
+          </el-form-item>
+          <el-form-item>
+            <el-button @click="cancelDialog">取 消</el-button>
+            <el-button
+              type="primary"
+              @click="submitDialog('createForm')">确 定</el-button>
+          </el-form-item>
+      </el-form>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import Vue from 'vue'
+import Lockr from 'lockr'
+import { GetSysModuleList, DeleteSysModule, AddSysModule, UpdateSysModule, GetCurrentUserModules } from '@/api/moduleManage/moduleManage'
+import { mapGetters } from 'vuex'
+export default {
+  name: 'ModuleManage',
+  data () {
+    return {
+      rightsList: [],
+      selectOpts: [],
+      defaultProps: {
+        children: 'children',
+        label: 'title'
+      },
+      moduleDialog: false,
+      createForm: {
+        fatherIntro: '',
+        introName: '',
+        isShow: true,
+        sortNum: 1,
+        img: '',
+        address: '',
+        info: ''
+      },
+      createRules: {
+        fatherIntro: [
+          { required: true, trigger: 'blur', message: '请选择上级导航' }
+        ],
+        introName: [{ required: true, trigger: 'blur', message: '请输入导航标题' }]
+      },
+      iconOption: [{id: '1', name: 'icon-financial'}, {id: '2', name: 'icon-company'}, {id: '3', name: 'icon-customer'}, {id: '4', name: 'icon-order'}, {id: '5', name: 'icon-product'}, {id: '6', name: 'icon-system'}, {id: '7', name: 'icon-total'}, {id: '8', name: 'icon-workbench'}, {id: '7', name: 'icon-business'}, {id: '8', name: 'icon-personnel'}],
+      authName: '',
+      isCreate: false,
+      isSon: false,
+      addTitle: '',
+      isDelete: false,
+      deleteIds: [],
+      parentId: ''
+    }
+  },
+  computed: {
+    ...mapGetters(['moduleBlock'])
+  },
+  created () {
+    this.getRightsList()
+  },
+  methods: {
+    // 树节点开关操作
+    openToggle (item) {
+      console.log(item)
+      // 这里只是展开和关闭样式的变换方法
+      Vue.set(item, 'open', !item.open)
+      // 展开的时候,显示子节点,关闭的时候隐藏子节点
+      // 遍历所有的子节点,加入到menuTable中
+      for (let j = 0; j < this.rightsList.length; j++) {
+        // 找到父节点的id,然后依次把子节点放到数组里面父节点后面
+        if (this.rightsList[j].Id !== item.Id) {
+          continue
+        }
+        if (item.open) { // open => close
+          console.log(item.Children)
+          let rightsList = this.rightsList
+          item.Children.forEach(function (child, index) {
+            rightsList.splice(j + index + 1, 0, child) // 添加子节点
+          })
+        } else {
+          this.rightsList.splice(j + 1, item.Children.length) // 删除子节点
+        }
+        break
+      }
+    },
+    showRow (row) {
+      const show = row.row.parent
+        ? row.row.parent._expanded && row.row.parent._show
+        : true
+      row.row._show = show
+      return show
+        ? 'animation:treeTableShow 1s;-webkit-animation:treeTableShow 1s;'
+        : 'display:none;'
+    },
+    handleSelectionChange (val) {
+      console.log(val)
+      if (val.length > 0) {
+        let deleteId = []
+        val.forEach(item => {
+          deleteId.push(item.Id)
+        })
+        this.isDelete = true
+        this.deleteIds = deleteId
+      } else {
+        this.isDelete = false
+      }
+    },
+    createModule () {
+      this.isCreate = true
+      this.isSon = false
+      this.moduleDialog = true
+      this.addTitle = '新增模块'
+    },
+    deleteModule () {
+      DeleteSysModule({'Id': this.deleteIds}).then(res => {
+        console.log(res)
+        if (res.data.ErrorCode === 200) {
+          this.$message.success(res.data.Message)
+          this.getRightsList()
+          this.getCurrentUser()
+        } else {
+          this.$message.error(res.data.Message)
+        }
+      })
+    },
+    addModule (row) {
+      console.log(row)
+      this.isCreate = true
+      this.isSon = true
+      this.addTitle = '添加子级'
+      this.moduleDialog = true
+      this.createForm = {
+        fatherIntro: row.Id,
+        introName: '',
+        isShow: row.IsShow,
+        sortNum: Number(row.SortNumber) + 1,
+        img: '',
+        address: '',
+        info: ''
+      }
+      this.parentId = row.Id
+    },
+    deleteSingleModule (id) {
+      this.$confirm('确定删除?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          DeleteSysModule([{'Id': id}]).then(res => {
+            console.log(res)
+            if (res.data.ErrorCode === 200) {
+              this.$message.success(res.data.Message)
+              this.getRightsList()
+              this.getCurrentUser()
+            } else {
+              this.$message.error(res.data.Message)
+            }
+          })
+        })
+        .catch(() => {
+          this.$message({
+            type: 'info',
+            message: '已取消删除'
+          })
+        })
+    },
+    editModule (row) {
+      this.isCreate = false
+      this.isSon = false
+      this.addTitle = '编辑模块'
+      this.moduleDialog = true
+      this.createForm = {
+        fatherIntro: row.Id,
+        introName: row.ModuleName,
+        isShow: row.IsShow,
+        sortNum: row.SortNumber,
+        img: row.IconPath,
+        address: row.LinkUrl,
+        info: row.Description
+      }
+      this.parentId = row.ParentModuleId
+    },
+    submitDialog (formName) {
+      this.$refs[formName].validate(valid => {
+        if (!valid) return
+        const isIntro = Array.isArray(this.createForm.fatherIntro)
+        let params = {
+          'ModuleName': this.createForm.introName,
+          'ParentModuleId': isIntro ? (this.createForm.fatherIntro.length > 1 ? this.createForm.fatherIntro[this.createForm.fatherIntro.length - 1] : (this.createForm.fatherIntro[0] === 100001 ? '' : this.createForm.fatherIntro[0])) : this.createForm.fatherIntro,
+          'ParentModuleName': this.createForm.fatherIntro[0] === '' ? '' : this.$refs['refSubCat'].getCheckedNodes()[0].label,
+          'LinkUrl': this.createForm.address,
+          'IconPath': this.createForm.img,
+          'IsShow': this.createForm.isShow,
+          'SortNumber': Number(this.createForm.sortNum),
+          'Description': this.createForm.info
+        }
+        if (this.isCreate) {
+          if (this.isSon) {
+            params.ParentModuleId = this.parentId
+          }
+          AddSysModule(params).then(res => {
+            console.log(res)
+            if (res.data.ErrorCode === 200) {
+              this.$message.success(res.data.Message)
+              this.getRightsList()
+              this.getCurrentUser()
+              this.moduleDialog = false
+              this.$refs.createForm.resetFields()
+              this.createForm = {
+                fatherIntro: '',
+                introName: '',
+                isShow: true,
+                sortNum: 1,
+                img: '',
+                address: '',
+                info: ''
+              }
+            } else {
+              this.$message.error(res.data.Message)
+            }
+          })
+        } else {
+          params.Id = isIntro ? (this.createForm.fatherIntro.length > 1 ? this.createForm.fatherIntro[this.createForm.fatherIntro.length - 1] : this.createForm.fatherIntro[0]) : this.createForm.fatherIntro
+
+          params.ParentModuleId = this.parentId
+
+          UpdateSysModule(params).then(res => {
+            console.log(res)
+            if (res.data.ErrorCode === 200) {
+              this.$message.success(res.data.Message)
+              this.getRightsList()
+              this.getCurrentUser()
+              this.moduleDialog = false
+              this.$refs.createForm.resetFields()
+              this.createForm = {
+                fatherIntro: '',
+                introName: '',
+                isShow: true,
+                sortNum: 1,
+                img: '',
+                address: '',
+                info: ''
+              }
+            } else {
+              this.$message.error(res.data.Message)
+            }
+          })
+        }
+      })
+    },
+    cancelDialog () {
+      this.$refs.createForm.resetFields()
+      this.createForm = {
+        fatherIntro: '',
+        introName: '',
+        isShow: true,
+        sortNum: 1,
+        img: '',
+        address: '',
+        info: ''
+      }
+      this.moduleDialog = false
+    },
+    getFatherOpt () {
+      console.log(this.createForm.fatherIntro[0])
+      const flag = Array.isArray(this.createForm.fatherIntro)
+      if (flag) {
+        this.parentId = this.createForm.fatherIntro.length > 1 ? this.createForm.fatherIntro[0] : ''
+      }
+    },
+    getRightsList () {
+      GetSysModuleList().then(res => {
+        if (res.data.ErrorCode === 200 && res.data.Result) {
+          this.rightsList = res.data.Result
+          this.selectOpts = JSON.parse(JSON.stringify(this.rightsList))
+          this.selectOpts.unshift({ ModuleName: '无上级导航', Id: 100001 })
+          // this.$store.commit('SET_MODULE', res.data.Result)
+          // Lockr.set('authList', res.data.Result)
+          // console.log(this.moduleBlock)
+        } else {
+          this.$message.error(res.data.Message)
+        }
+      })
+    },
+    getCurrentUser () {
+      GetCurrentUserModules().then(res => {
+        if (res.data.ErrorCode === 200 && res.data.Result) {
+          this.$store.commit('SET_MODULE', res.data.Result)
+          Lockr.set('authList', res.data.Result)
+          console.log(this.moduleBlock)
+        } else {
+          this.$message.error(res.data.Message)
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style lang='scss' scoped>
+
+  .offical-authority{}
+
+  .title {
+    font-size: 18px;
+    height: 40px;
+    line-height: 40px;
+    margin: 10px 0;
+    color: #333;
+    padding: 0 20px;
+  }
+  .nav-dialog-div {
+    margin-bottom: 12px;
+  }
+  .checkedBox{
+    display:flex;
+    flex-direction:row;
+  }
+  .allChecked{
+    margin-right:20px;
+  }
+  .dialogLabel{
+    font-size: 16px;
+    float:right;
+    margin-right: 20px;
+  }
+  .create-button{
+    margin-bottom: 20px;
+    float: right;
+  }
+  .delete-button{
+    margin-bottom: 20px;
+    float: right;
+    margin-right: 20px;
+  }
+  .level {
+    display: inline-block;
+    width: 20px;
+  }
+
+  .level1 {
+    margin-left: 5px;
+  }
+
+  .level2 {
+    margin-left: 20px;
+  }
+
+  .level3 {
+    margin-left: 35px;
+  }
+  .numInp{
+    width:40%;
+  }
+</style>
diff --git a/src/views/welcome/Welcome.vue b/src/views/welcome/Welcome.vue
new file mode 100644
index 0000000..629a818
--- /dev/null
+++ b/src/views/welcome/Welcome.vue
@@ -0,0 +1,13 @@
+<template>
+  <div>Welcome</div>
+</template>
+
+<script>
+export default {
+  name: 'Welcome'
+}
+</script>
+
+<style scoped>
+
+</style>
diff --git a/static/.gitkeep b/static/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/static/.gitkeep
diff --git a/static/client.js b/static/client.js
new file mode 100644
index 0000000..4b77859
--- /dev/null
+++ b/static/client.js
@@ -0,0 +1,62 @@
+/* eslint-disable no-eval */
+/* eslint-disable no-unused-expressions */
+!(function () {
+  var Sys = {}
+  var ua = navigator.userAgent.toLowerCase()
+
+  var regMap = {
+    msie: '/msie ([\\d.]+)/',
+    firefox: '/firefox\\/([\\d.]+)/',
+    chrome: '/chrome\\/([\\d.]+)/',
+    opera: '/opera.([\\d.]+)/',
+    safari: '/version\\/([\\d.]+).*safari/'
+  }
+
+  var o
+  if (ua.match(eval(regMap.msie))) {
+    o = ua.match(eval(regMap.msie))
+    Sys = {
+      appName: 'IE',
+      version: o[1]
+    }
+  } else if (ua.match(eval(regMap.firefox))) {
+    o = ua.match(eval(regMap.firefox))
+    Sys = {
+      appName: 'Firefox',
+      version: o[1]
+    }
+  } else if (ua.match(eval(regMap.chrome))) {
+    o = ua.match(eval(regMap.chrome))
+    Sys = {
+      appName: 'Chrome',
+      version: o[1]
+    }
+  } else if (ua.match(eval(regMap.opera))) {
+    o = ua.match(eval(regMap.opera))
+    Sys = {
+      appName: 'Opera',
+      version: o[1]
+    }
+  } else if (ua.match(eval(regMap.safari))) {
+    o = ua.match(eval(regMap.safari))
+    Sys = {
+      appName: 'Safari',
+      version: o[1]
+    }
+  } else if (ua.indexOf('edge')) {
+    Sys = {
+      appName: 'Edge'
+    }
+  } else {
+    if (navigator.appName === 'Microsoft Internet Explorer') {
+      Sys = {
+        appName: 'IE',
+        version: '6.0'
+      }
+    }
+  }
+
+  if (Sys.appName === 'IE' && Number(Sys.version) < 10) {
+    window.location.href = './static/index.html'
+  }
+})()
diff --git a/webpack-dev-server b/webpack-dev-server
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/webpack-dev-server

--
Gitblit v1.9.3