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"></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"></span> + <div class="name">show-password </div> + <div class="code-name">&#xea3f;</div> + </li> + + <li class="dib"> + <span class="icon iconfont"></span> + <div class="name">user</div> + <div class="code-name">&#xe830;</div> + </li> + + <li class="dib"> + <span class="icon iconfont">
</span> + <div class="name">users</div> + <div class="code-name">&#xa;</div> + </li> + + <li class="dib"> + <span class="icon iconfont"></span> + <div class="name">225默认头像</div> + <div class="code-name">&#xe8c9;</div> + </li> + + <li class="dib"> + <span class="icon iconfont"></span> + <div class="name">406报表</div> + <div class="code-name">&#xe902;</div> + </li> + + <li class="dib"> + <span class="icon iconfont"></span> + <div class="name">password</div> + <div class="code-name">&#xe734;</div> + </li> + + <li class="dib"> + <span class="icon iconfont"></span> + <div class="name">lock-fill</div> + <div class="code-name">&#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" +><span class="iconfont">&#x33;</span> +</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"><link rel="stylesheet" href="./iconfont.css"> +</code></pre> + <h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3> +<pre><code class="language-html"><span class="iconfont icon-xxx"></span> +</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"><script src="./iconfont.js"></script> +</code></pre> + <h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3> +<pre><code class="language-html"><style> +.icon { + width: 1em; + height: 1em; + vertical-align: -0.15em; + fill: currentColor; + overflow: hidden; +} +</style> +</code></pre> + <h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3> +<pre><code class="language-html"><svg class="icon" aria-hidden="true"> + <use xlink:href="#icon-xxx"></use> +</svg> +</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="" 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="" 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=" " 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="" 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="" 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="" 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="" 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}} + </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}} + </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 }} + </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> 种 总金额:<span class="info-yellow">{{ totalInfo.money }}</span> 元</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 +' “' + item.value[0] + '-' + item.value[1] + '”' }}</span> + <span v-else-if="item.formType === 'datetime'">{{ item.name +' “' + item.value[0] + '-' + item.value[1] + '”' }}</span> + <span v-else-if="item.formType === 'business_type'">{{ item.name +' “' + 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 +' “' + optionsNames[item.condition]+ '”'+' '+ getCheckName(item) }}</span> + <span v-else-if="item.formType === 'user'">{{ item.name +' ' + optionsNames[item.condition] + '“' + item.value[0].realname + '”' }}</span> + <span v-else-if="item.formType === 'category' && item.value.length > 0">{{ item.name +' “' + item.valueContent + '”' }}</span> + <span v-else>{{ item.name + ' ' + 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"> </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"> </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"> </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"> </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"> </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"> </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