├── .gitignore ├── LICENSE ├── README.md ├── configFile └── nginx.conf ├── frontEnd ├── mobile │ ├── README.md │ ├── auto-imports.d.ts │ ├── env.d.ts │ ├── eslint.config.ts │ ├── index.html │ ├── package.json │ ├── public │ │ └── static │ │ │ ├── LOGO_DARK.png │ │ │ └── config.js │ ├── src │ │ ├── App.vue │ │ ├── api │ │ │ └── common.ts │ │ ├── assets │ │ │ ├── base.css │ │ │ ├── icons │ │ │ │ └── svg │ │ │ │ │ └── custom │ │ │ │ │ └── ai.svg │ │ │ ├── logo.svg │ │ │ └── main.css │ │ ├── components │ │ │ ├── Empty.vue │ │ │ ├── PullRefreshScrollLoadList.vue │ │ │ ├── SvgIcon.vue │ │ │ ├── TagEllipsis.vue │ │ │ └── Upload.vue │ │ ├── config.js │ │ ├── main.ts │ │ ├── router │ │ │ ├── index.js │ │ │ ├── permission.js │ │ │ └── routes.js │ │ ├── stores │ │ │ ├── counter.ts │ │ │ └── index.js │ │ ├── styles │ │ │ ├── base.css │ │ │ ├── index.scss │ │ │ ├── vant.css │ │ │ └── var.css │ │ ├── utils │ │ │ ├── index.js │ │ │ ├── request.js │ │ │ └── sdk.ts │ │ └── views │ │ │ ├── Home.vue │ │ │ └── customerComplaint │ │ │ ├── List.vue │ │ │ ├── api.js │ │ │ ├── detail.vue │ │ │ ├── form.vue │ │ │ └── index.vue │ ├── sys.config.js │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts └── pc │ ├── .vite │ └── deps_temp_2831f31c │ │ └── package.json │ ├── README.md │ ├── auto-imports.d.ts │ ├── env.d.ts │ ├── index.html │ ├── package.json │ ├── public │ ├── favicon.ico │ └── static │ │ └── logo.png │ ├── src │ ├── App.vue │ ├── api │ │ └── common.js │ ├── assets │ │ └── icons │ │ │ └── svg │ │ │ ├── code.svg │ │ │ ├── conversation.svg │ │ │ ├── customer.svg │ │ │ ├── customerService.svg │ │ │ ├── excel.svg │ │ │ ├── eye-open.svg │ │ │ ├── eye.svg │ │ │ ├── gitee.svg │ │ │ ├── marketing.svg │ │ │ ├── password.svg │ │ │ ├── pdf.svg │ │ │ ├── ppt.svg │ │ │ ├── system.svg │ │ │ ├── toker.svg │ │ │ ├── user.svg │ │ │ └── word.svg │ ├── components │ │ ├── CacheElTabs.vue │ │ ├── CardGroup.vue │ │ ├── ChartBar.vue │ │ ├── ChartLine.vue │ │ ├── CommonTopRight.vue │ │ ├── Editor │ │ │ └── index.vue │ │ ├── IconBtn.vue │ │ ├── IconSelect │ │ │ └── index.vue │ │ ├── MessageContentForm.vue │ │ ├── Pagination.vue │ │ ├── PhoneChatList.vue │ │ ├── PhoneInterface.vue │ │ ├── RequestChartTable.vue │ │ ├── SearchResetButton.vue │ │ ├── SelectEmoji.vue │ │ ├── SelectGroup.vue │ │ ├── SelectStaff.vue │ │ ├── SelectStaffQrCode.vue │ │ ├── SvgIcon │ │ │ └── index.vue │ │ ├── TableOperateBtn.vue │ │ ├── TagEllipsis.vue │ │ ├── TextareaExtend.vue │ │ ├── TimeButtonGroup.vue │ │ ├── Upload.vue │ │ ├── WelcomeForm.vue │ │ ├── addAttachment.vue │ │ └── base │ │ │ └── BaseDialog.vue │ ├── config.js │ ├── layout │ │ ├── components │ │ │ ├── AppMain.vue │ │ │ ├── Breadcrumb.vue │ │ │ ├── Sidebar │ │ │ │ ├── FixiOSBug.js │ │ │ │ ├── Link.vue │ │ │ │ ├── SidebarItem.vue │ │ │ │ ├── image.png │ │ │ │ └── index.vue │ │ │ └── TopBar │ │ │ │ ├── Logo.vue │ │ │ │ ├── TopMenu.vue │ │ │ │ └── index.vue │ │ ├── index.vue │ │ └── visitor.vue │ ├── main.ts │ ├── router │ │ ├── index.ts │ │ ├── permission.js │ │ └── routes.js │ ├── stores │ │ ├── getters.js │ │ ├── index.js │ │ └── modules │ │ │ ├── app.js │ │ │ └── user.js │ ├── styles │ │ ├── base.css │ │ ├── common.css │ │ ├── element-ui.scss │ │ ├── index.scss │ │ ├── var.css │ │ └── varOld.css │ ├── utils │ │ ├── auth.js │ │ ├── common.js │ │ ├── index.js │ │ ├── request.js │ │ ├── sdk.ts │ │ └── validate.js │ └── views │ │ ├── KBM │ │ ├── api.ts │ │ └── index.vue │ │ ├── chat │ │ ├── aev.vue │ │ ├── api.js │ │ ├── apiLink.js │ │ ├── index.vue │ │ └── synch.vue │ │ ├── complaintManage │ │ ├── api.ts │ │ ├── index.vue │ │ ├── list.vue │ │ └── statistics.vue │ │ ├── config │ │ ├── agent.vue │ │ ├── api.js │ │ ├── index.vue │ │ └── welcome.vue │ │ ├── customerServiceManage │ │ ├── api.ts │ │ ├── index.vue │ │ ├── list.vue │ │ └── statistics.vue │ │ ├── groupChat │ │ ├── api.js │ │ └── index.vue │ │ ├── groupCode │ │ ├── aev.vue │ │ ├── api.js │ │ └── index.vue │ │ ├── hotWordManage │ │ ├── SelectHotWord.vue │ │ ├── api.ts │ │ ├── apiCategory.ts │ │ ├── index.vue │ │ ├── statistics.vue │ │ └── synch.vue │ │ ├── inquiryCustomer │ │ ├── aev.vue │ │ ├── api.js │ │ ├── apiLink.js │ │ ├── index.vue │ │ └── synch.vue │ │ ├── inquiryKqChat │ │ ├── aev.vue │ │ ├── api.js │ │ ├── apiLink.js │ │ ├── index.vue │ │ └── synch.vue │ │ ├── intentionCustomer │ │ ├── aev.vue │ │ ├── api.js │ │ ├── apiLink.js │ │ ├── index.vue │ │ └── synch.vue │ │ ├── intentionGroupFriend │ │ ├── aev.vue │ │ ├── api.js │ │ ├── apiLink.js │ │ ├── index.vue │ │ └── synch.vue │ │ ├── kqchat │ │ ├── aev.vue │ │ ├── api.js │ │ ├── apiLink.js │ │ ├── index.vue │ │ └── synch.vue │ │ ├── liveCode │ │ ├── aev.vue │ │ ├── api.js │ │ ├── apiLink.js │ │ └── index.vue │ │ ├── massMarketing │ │ ├── api.ts │ │ ├── index.vue │ │ ├── list.vue │ │ └── statistics.vue │ │ ├── serviceRecord │ │ ├── api.ts │ │ └── index.vue │ │ ├── system │ │ ├── error │ │ │ ├── 401.vue │ │ │ ├── 404.vue │ │ │ └── assets │ │ │ │ ├── 401.gif │ │ │ │ ├── 404.png │ │ │ │ └── 404_cloud.png │ │ ├── login │ │ │ ├── api.js │ │ │ ├── authRedirect.vue │ │ │ ├── bg.svg │ │ │ └── index.vue │ │ ├── register │ │ │ └── index.vue │ │ └── user │ │ │ └── api.js │ │ ├── tag │ │ └── api.js │ │ └── user │ │ ├── api.js │ │ └── index.vue │ ├── sys.config.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── img ├── config.png ├── image.png ├── img_1.png ├── img_2.png ├── img_3.png ├── j-1.jpg ├── j-10.png ├── j-11.png ├── j-12.png ├── j-13.png ├── j-14.png ├── j-2.jpg ├── j-3.jpg ├── j-4.png ├── j-5.png ├── j-6.png ├── j-7.png ├── j-8.png └── j-9.png ├── pic ├── 1.png ├── 111111.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png ├── contactus.png ├── tab_logo.png └── tab_logo2.png ├── pom.xml ├── src └── main │ ├── java │ └── cn │ │ └── iyque │ │ ├── IyQueApplication.java │ │ ├── annotation │ │ └── RateLimit.java │ │ ├── aop │ │ └── RateLimitAspect.java │ │ ├── chain │ │ ├── loader │ │ │ ├── PdfFileLoader.java │ │ │ ├── ResourceLoader.java │ │ │ ├── ResourceLoaderFactory.java │ │ │ ├── TextFileLoader.java │ │ │ └── WordLoader.java │ │ ├── split │ │ │ ├── CharacterTextSplitter.java │ │ │ └── TextSplitter.java │ │ ├── vectorizer │ │ │ ├── OpenAiVectorization.java │ │ │ └── Vectorization.java │ │ └── vectorstore │ │ │ ├── IYqueVectorStore.java │ │ │ └── MilvusVectorStore.java │ │ ├── config │ │ ├── AsyncConfig.java │ │ ├── CORSConfig.java │ │ ├── IYqueParamConfig.java │ │ ├── JacksonConfig.java │ │ ├── JwtConfig.java │ │ └── SimpleRedisValidator.java │ │ ├── constant │ │ ├── CodeStateConstant.java │ │ ├── FileType.java │ │ ├── HttpStatus.java │ │ ├── IYqueContant.java │ │ ├── IYqueWxCpConsts.java │ │ └── WxFileType.java │ │ ├── controller │ │ ├── FileController.java │ │ ├── IYQueComplaintController.java │ │ ├── IYcallbackController.java │ │ ├── IYqueAnalysisHotWordController.java │ │ ├── IYqueCategoryController.java │ │ ├── IYqueChatCodeController.java │ │ ├── IYqueChatController.java │ │ ├── IYqueCommonController.java │ │ ├── IYqueConfigController.java │ │ ├── IYqueDefaultMsgController.java │ │ ├── IYqueGroupMsgController.java │ │ ├── IYqueHotWordController.java │ │ ├── IYqueKfController.java │ │ ├── IYqueKnowledgeController.java │ │ ├── IYqueLoginController.java │ │ ├── IYqueShortLinkController.java │ │ ├── IYqueTagController.java │ │ ├── IYqueThreeLoginController.java │ │ ├── IYqueUserCodeController.java │ │ ├── IYqueUserController.java │ │ └── IYqueWeMsgAuditController.java │ │ ├── converter │ │ ├── AttachmentConverter.java │ │ ├── AttachmentConverterFactory.java │ │ ├── FileAttachmentConverter.java │ │ ├── ImageAttachmentConverter.java │ │ ├── LinkAttachmentConverter.java │ │ ├── MiniprogramAttachmentConverter.java │ │ └── VideoAttachmentConverter.java │ │ ├── dao │ │ ├── IYQueComplaintAnnexDao.java │ │ ├── IYQueComplaintDao.java │ │ ├── IYQueComplaintTipDao.java │ │ ├── IYQueCustomerInfoDao.java │ │ ├── IYqueAiAnalysisMsgAuditDao.java │ │ ├── IYqueAiTokenRecordDao.java │ │ ├── IYqueAnalysisHotWordDao.java │ │ ├── IYqueAnnexPeriodDao.java │ │ ├── IYqueCategoryDao.java │ │ ├── IYqueChatCodeDao.java │ │ ├── IYqueChatDao.java │ │ ├── IYqueConfigDao.java │ │ ├── IYqueDefaultMsgDao.java │ │ ├── IYqueGroupMsgDao.java │ │ ├── IYqueGroupMsgSubDao.java │ │ ├── IYqueHotWordDao.java │ │ ├── IYqueKfDao.java │ │ ├── IYqueKfMsgDao.java │ │ ├── IYqueKfMsgSubDao.java │ │ ├── IYqueKnowledgeAttachDao.java │ │ ├── IYqueKnowledgeFragmentDao.java │ │ ├── IYqueKnowledgeInfoDao.java │ │ ├── IYqueMsgAnnexDao.java │ │ ├── IYqueMsgAuditDao.java │ │ ├── IYqueMsgRuleDao.java │ │ ├── IYquePeriodMsgAnnexDao.java │ │ ├── IYqueShortLinkDao.java │ │ ├── IYqueUserCodeDao.java │ │ └── IYqueUserDao.java │ │ ├── domain │ │ ├── CustomerChatGroup.java │ │ ├── DateCount.java │ │ ├── EmployeeChatGroup.java │ │ ├── GiteeTokenResponse.java │ │ ├── IYQueAuthInfo.java │ │ ├── IYQueCallback.java │ │ ├── IYQueCallbackQuery.java │ │ ├── IYQueCountQuery.java │ │ ├── IYQueCustomerInfo.java │ │ ├── IYQueTrendCount.java │ │ ├── IYqueAnalysisHotWordTabVo.java │ │ ├── IYqueAnalysisHotWordVo.java │ │ ├── IYqueCallBackBaseMsg.java │ │ ├── IYqueComplaintCountVo.java │ │ ├── IYqueKvalStrVo.java │ │ ├── IYqueKvalVo.java │ │ ├── IYqueUserCodeCountVo.java │ │ ├── JwtResponse.java │ │ ├── KnowledgeInfoUploadRequest.java │ │ ├── NewContactWay.java │ │ ├── PageDomain.java │ │ ├── ResponseResult.java │ │ ├── ThreeLoginInfo.java │ │ └── fileType │ │ │ ├── File.java │ │ │ ├── Image.java │ │ │ ├── Link.java │ │ │ ├── Miniprogram.java │ │ │ └── Video.java │ │ ├── entity │ │ ├── BaseEntity.java │ │ ├── IYQueComplain.java │ │ ├── IYQueComplaintTip.java │ │ ├── IYqueAiAnalysisMsgAudit.java │ │ ├── IYqueAiTokenRecord.java │ │ ├── IYqueAnalysisHotWord.java │ │ ├── IYqueAnnexPeriod.java │ │ ├── IYqueCategory.java │ │ ├── IYqueChat.java │ │ ├── IYqueChatCode.java │ │ ├── IYqueComplainAnnex.java │ │ ├── IYqueConfig.java │ │ ├── IYqueDefaultMsg.java │ │ ├── IYqueDept.java │ │ ├── IYqueGroupMsg.java │ │ ├── IYqueGroupMsgSub.java │ │ ├── IYqueHotWord.java │ │ ├── IYqueKf.java │ │ ├── IYqueKfMsg.java │ │ ├── IYqueKfMsgSub.java │ │ ├── IYqueKnowledgeAttach.java │ │ ├── IYqueKnowledgeFragment.java │ │ ├── IYqueKnowledgeInfo.java │ │ ├── IYqueMsgAnnex.java │ │ ├── IYqueMsgAudit.java │ │ ├── IYqueMsgRule.java │ │ ├── IYquePeriodMsgAnnex.java │ │ ├── IYqueShortLink.java │ │ ├── IYqueUser.java │ │ └── IYqueUserCode.java │ │ ├── enums │ │ ├── ComplaintAnnexType.java │ │ ├── ComplaintContent.java │ │ ├── CustomerStatusType.java │ │ ├── GroupMsgSendStatus.java │ │ ├── KfServiceState.java │ │ ├── MsgDefaultRule.java │ │ └── RemarksType.java │ │ ├── exception │ │ ├── IYAesException.java │ │ └── IYqueException.java │ │ ├── handler │ │ └── GlobalExceptionHandler.java │ │ ├── interceptor │ │ ├── JwtInterceptor.java │ │ └── ReadOnlyInterceptor.java │ │ ├── mass │ │ ├── MassSenderFactoryService.java │ │ ├── dto │ │ │ └── IYqueGroupMsgDto.java │ │ └── sender │ │ │ ├── AbstractMassSender.java │ │ │ └── GroupMassSender.java │ │ ├── service │ │ ├── IYQueComplaintService.java │ │ ├── IYqueAiService.java │ │ ├── IYqueAiTokenRecordService.java │ │ ├── IYqueAnalysisHotWordService.java │ │ ├── IYqueAnnexPeriodService.java │ │ ├── IYqueCategoryService.java │ │ ├── IYqueChatCodeService.java │ │ ├── IYqueChatService.java │ │ ├── IYqueConfigService.java │ │ ├── IYqueCustomerInfoService.java │ │ ├── IYqueDefaultMsgService.java │ │ ├── IYqueEmbeddingService.java │ │ ├── IYqueGiteeOAuthService.java │ │ ├── IYqueGroupMsgService.java │ │ ├── IYqueGroupMsgSubService.java │ │ ├── IYqueHotWordService.java │ │ ├── IYqueKfMsgService.java │ │ ├── IYqueKfService.java │ │ ├── IYqueKnowledgeAttachService.java │ │ ├── IYqueKnowledgeFragmentService.java │ │ ├── IYqueKnowledgeInfoService.java │ │ ├── IYqueMsgAnnexService.java │ │ ├── IYqueMsgAuditService.java │ │ ├── IYqueMsgRuleService.java │ │ ├── IYquePeriodMsgAnnexService.java │ │ ├── IYqueShortLinkService.java │ │ ├── IYqueTagService.java │ │ ├── IYqueUserCodeService.java │ │ ├── IYqueUserService.java │ │ └── impl │ │ │ ├── IYQueComplaintServiceImpl.java │ │ │ ├── IYqueAiServiceImpl.java │ │ │ ├── IYqueAiTokenRecordServiceImpl.java │ │ │ ├── IYqueAnalysisHotWordServiceImpl.java │ │ │ ├── IYqueAnnexPeriodServiceImpl.java │ │ │ ├── IYqueCategoryServiceImpl.java │ │ │ ├── IYqueChatCodeServiceImpl.java │ │ │ ├── IYqueChatServiceImpl.java │ │ │ ├── IYqueConfigServiceImpl.java │ │ │ ├── IYqueCustomerInfoServiceImpl.java │ │ │ ├── IYqueDefaultMsgImpl.java │ │ │ ├── IYqueEmbeddingServiceImpl.java │ │ │ ├── IYqueGiteeOAuthServiceImpl.java │ │ │ ├── IYqueGroupMsgServiceImpl.java │ │ │ ├── IYqueGroupMsgSubServiceImpl.java │ │ │ ├── IYqueHotWordServiceImpl.java │ │ │ ├── IYqueKfMsgServiceImpl.java │ │ │ ├── IYqueKfServiceImpl.java │ │ │ ├── IYqueKnowledgeAttachServiceImpl.java │ │ │ ├── IYqueKnowledgeFragmentServiceImpl.java │ │ │ ├── IYqueKnowledgeInfoServiceImpl.java │ │ │ ├── IYqueMsgAnnexServiceImpl.java │ │ │ ├── IYqueMsgAuditServiceImpl.java │ │ │ ├── IYqueMsgRuleServiceImpl.java │ │ │ ├── IYquePeriodMsgAnnexServiceImpl.java │ │ │ ├── IYqueShortLinkServiceImpl.java │ │ │ ├── IYqueTagServiceImpl.java │ │ │ ├── IYqueUserCodeServiceImpl.java │ │ │ ├── IYqueUserServiceImpl.java │ │ │ └── WxCpServiceFactory.java │ │ ├── strategy │ │ └── callback │ │ │ ├── ActionContext.java │ │ │ ├── ActionStrategy.java │ │ │ ├── MakeTagCustomerStrategy.java │ │ │ ├── RemarkCustomerStrategy.java │ │ │ ├── SaveCustomerStrategy.java │ │ │ ├── SendPeriodWelcomeMsgStrategy.java │ │ │ └── SendWelcomeMsgStrategy.java │ │ └── utils │ │ ├── ByteGroupUtils.java │ │ ├── DateUtils.java │ │ ├── FileUtils.java │ │ ├── IYqueCryptUtil.java │ │ ├── JwtUtils.java │ │ ├── MapUtils.java │ │ ├── PKCS7EncoderUtils.java │ │ ├── SHA1Utils.java │ │ ├── SecurityUtils.java │ │ ├── ServletUtils.java │ │ ├── SnowFlakeUtils.java │ │ ├── SpringUtils.java │ │ └── TableSupport.java │ └── resources │ ├── application.yml │ └── banner.txt └── upload ├── 074824b7-255a-47c5-aa62-48529dacb6b5.jpg ├── 09681c07-81a3-49da-ac30-4defb391dae7.jpg ├── 1916739531953016832.png ├── 1916740883139661824.png ├── 1916741426302029824.png ├── 1916748808138657792.png ├── 511ed115-66c1-4faa-881d-0be43b6be9cb.jpg ├── 64f1e239-0cca-485a-b4ae-0f0e57776a62.jpg ├── 8265c6c6-8438-45ee-b537-52498d3d4f88.jpg ├── 8768e0ac-0481-4af6-a321-49f60fac3385.jpg ├── 8f353a71-e5a1-4bcd-b540-1344a33f5f9c.jpg ├── 99e0ddb7-51da-4a03-9261-359e84893ab1.jpg ├── 9f7fe11f-ede5-42c9-b660-1f64cd66d277.jpg ├── c052be96-7dd1-4d9d-abb3-9cd67e0d9091.jpg ├── ef928e04-ffc8-4bcb-8e3d-79c496d252a7.jpg └── f0f0337b-9074-43ba-a3fc-4e5537eed403.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | node_modules 25 | dist 26 | icode-ui/deploy/ 27 | frontEnd/mobile/deploy/deploy.config.mjs 28 | frontEnd/pc/deploy/deploy.config.mjs 29 | -------------------------------------------------------------------------------- /frontEnd/mobile/README.md: -------------------------------------------------------------------------------- 1 | # 1 2 | 3 | This template should help get you started developing with Vue 3 in Vite. 4 | 5 | ## Recommended IDE Setup 6 | 7 | [VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). 8 | 9 | ## Type Support for `.vue` Imports in TS 10 | 11 | TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. 12 | 13 | ## Customize configuration 14 | 15 | See [Vite Configuration Reference](https://vite.dev/config/). 16 | 17 | ## Project Setup 18 | 19 | ```sh 20 | npm install 21 | ``` 22 | 23 | ### Compile and Hot-Reload for Development 24 | 25 | ```sh 26 | npm run dev 27 | ``` 28 | 29 | ### Type-Check, Compile and Minify for Production 30 | 31 | ```sh 32 | npm run build 33 | ``` 34 | 35 | ### Lint with [ESLint](https://eslint.org/) 36 | 37 | ```sh 38 | npm run lint 39 | ``` 40 | -------------------------------------------------------------------------------- /frontEnd/mobile/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /frontEnd/mobile/eslint.config.ts: -------------------------------------------------------------------------------- 1 | import pluginVue from 'eslint-plugin-vue' 2 | import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript' 3 | import skipFormatting from '@vue/eslint-config-prettier/skip-formatting' 4 | 5 | // To allow more languages other than `ts` in `.vue` files, uncomment the following lines: 6 | // import { configureVueProject } from '@vue/eslint-config-typescript' 7 | // configureVueProject({ scriptLangs: ['ts', 'tsx'] }) 8 | // More info at https://github.com/vuejs/eslint-config-typescript/#advanced-setup 9 | 10 | export default defineConfigWithVueTs( 11 | { 12 | name: 'app/files-to-lint', 13 | files: ['**/*.{ts,mts,tsx,vue}'], 14 | }, 15 | 16 | { 17 | name: 'app/files-to-ignore', 18 | ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'], 19 | }, 20 | 21 | pluginVue.configs['flat/essential'], 22 | vueTsConfigs.recommended, 23 | skipFormatting, 24 | ) 25 | -------------------------------------------------------------------------------- /frontEnd/mobile/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | %VITE_APP_TITLE% 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /frontEnd/mobile/public/static/LOGO_DARK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/frontEnd/mobile/public/static/LOGO_DARK.png -------------------------------------------------------------------------------- /frontEnd/mobile/public/static/config.js: -------------------------------------------------------------------------------- 1 | // 用于无打包配置,会覆盖系统相关配置 2 | window.sysConfig = {} 3 | -------------------------------------------------------------------------------- /frontEnd/mobile/src/App.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 14 | -------------------------------------------------------------------------------- /frontEnd/mobile/src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /frontEnd/mobile/src/assets/main.css: -------------------------------------------------------------------------------- 1 | @import './base.css'; 2 | 3 | #app { 4 | max-width: 1280px; 5 | margin: 0 auto; 6 | padding: 2rem; 7 | font-weight: normal; 8 | } 9 | 10 | a, 11 | .green { 12 | text-decoration: none; 13 | color: hsla(160, 100%, 37%, 1); 14 | transition: 0.4s; 15 | padding: 3px; 16 | } 17 | 18 | @media (hover: hover) { 19 | a:hover { 20 | background-color: hsla(160, 100%, 37%, 0.2); 21 | } 22 | } 23 | 24 | @media (min-width: 1024px) { 25 | body { 26 | display: flex; 27 | place-items: center; 28 | } 29 | 30 | #app { 31 | display: grid; 32 | grid-template-columns: 1fr 1fr; 33 | padding: 0 2rem; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /frontEnd/mobile/src/components/Empty.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 20 | 21 | 45 | -------------------------------------------------------------------------------- /frontEnd/mobile/src/components/SvgIcon.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 18 | 19 | 28 | -------------------------------------------------------------------------------- /frontEnd/mobile/src/config.js: -------------------------------------------------------------------------------- 1 | import { config } from '../sys.config' 2 | const BASE_URL = import.meta.env.BASE_URL 3 | 4 | // 系统常量 5 | window.sysConfig = { 6 | ...config, 7 | ...(globalThis.sysConfig || {}), 8 | 9 | BASE_URL, 10 | RUN_ENV: config.RUN_ENV, 11 | TOKEN: '', // 本地开发调试用的token,仅本地开发环境生效 12 | 13 | services: { 14 | wecom: '/open', 15 | weChat: '/wx-api', 16 | ai: '/ai', 17 | }, 18 | 19 | // 以下仅用于系统信息展示,不作为项目变量使用,请勿在代码中使用 20 | _packDateTime: __PACK_DATETIME__, // 打包时间 21 | _mode: import.meta.env.MODE, // 前端打包模式 22 | } 23 | -------------------------------------------------------------------------------- /frontEnd/mobile/src/router/index.js: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router' 2 | import routes from './routes' 3 | import permission from './permission' 4 | 5 | const router = createRouter({ 6 | history: createWebHistory(import.meta.env.BASE_URL), 7 | routes, 8 | }) 9 | permission(router) 10 | 11 | export default router 12 | -------------------------------------------------------------------------------- /frontEnd/mobile/src/stores/counter.ts: -------------------------------------------------------------------------------- 1 | import { ref, computed } from 'vue' 2 | import { defineStore } from 'pinia' 3 | 4 | export const useCounterStore = defineStore('counter', () => { 5 | const count = ref(0) 6 | const doubleCount = computed(() => count.value * 2) 7 | function increment() { 8 | count.value++ 9 | } 10 | 11 | return { count, doubleCount, increment } 12 | }) 13 | -------------------------------------------------------------------------------- /frontEnd/mobile/src/utils/sdk.ts: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | import Vant, { setToastDefaultOptions, setDialogDefaultOptions, showToast, showDialog } from 'vant' 4 | // $sdk 公共方法,挂在到全局 window 和 vue app.config.globalProperties 5 | export class SDK { 6 | ruleRequiredBlur = { required: true, message: '必填项', trigger: 'blur' } 7 | ruleRequiredChange = { required: true, message: '必选项', trigger: 'change' } 8 | 9 | request = request 10 | 11 | msgSuccess(message = '操作成功') { 12 | showToast({ message, type: 'success' }) 13 | } 14 | msgError(message = '操作失败') { 15 | showToast({ message, type: 'fail' }) 16 | } 17 | msgInfo(message) { 18 | showToast(message) 19 | } 20 | 21 | loading(message = '加载中...') { 22 | showToast({ message, type: 'loading', loadingType: 'spinner' }) 23 | } 24 | confirm(message = '是否确认删除?', title = '提示', options) { 25 | return showDialog({ title, message, showCancelButton: true, ...options }) 26 | } 27 | 28 | /** 通用删除 29 | * @param {*} removeApi 删除接口 30 | * @param {*} callback 成功回调 31 | */ 32 | delConfirm(remove: Function, callback?: Function) { 33 | this.confirm() 34 | .then(() => { 35 | return remove() 36 | }) 37 | .then(() => { 38 | callback && callback() 39 | // this.getList && this.getList() 40 | this.msgSuccess() 41 | }) 42 | .catch((error: Error) => { 43 | console.error(error) 44 | }) 45 | } 46 | } 47 | export const $sdk: SDK = new SDK() 48 | declare global { 49 | var $sdk: SDK 50 | } 51 | window.$sdk = $sdk 52 | // 下面定义非全局公共方法等 53 | -------------------------------------------------------------------------------- /frontEnd/mobile/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 35 | 36 | 56 | -------------------------------------------------------------------------------- /frontEnd/mobile/src/views/customerComplaint/List.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 32 | 33 | 58 | -------------------------------------------------------------------------------- /frontEnd/mobile/src/views/customerComplaint/api.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | const { get, post, put, del: _del } = request 3 | const serve = '/iYqueComplaint' 4 | 5 | /** 6 | * 列表 7 | * @param {*} data 8 | { 9 | page: 10 | size: 11 | handleState:1 处理状态(1:未处理;2:已处理) 12 | } 13 | */ 14 | export function getList(data) { 15 | return get(`${serve}/findComplaintByPage`, data) 16 | } 17 | 18 | export const getDetail = (id) => get(`${serve}/findIYQueComplainById/${id}`) 19 | 20 | /** 21 | * 处理投诉意见 22 | * @param {*} data 23 | { 24 | "id": "string", 25 | "handleContent": "string", 26 | "complainAnnexList": [ 27 | { 28 | "annexUrl": "附件地址" 29 | } 30 | ] 31 | } 32 | * @returns 33 | */ 34 | export function handleComplaint(data) { 35 | return post(`${serve}/handleComplaint`, data) 36 | } 37 | 38 | export function addComplaint(data) { 39 | return post(`${serve}/addComplaint`, data) 40 | } 41 | 42 | // 获取投诉类型列表 43 | export function findComplaint(data) { 44 | return get(`${serve}/findComplaint`) 45 | } 46 | -------------------------------------------------------------------------------- /frontEnd/mobile/src/views/customerComplaint/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /frontEnd/mobile/sys.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 环境变量 3 | */ 4 | const envs = { 5 | development: { 6 | DOMAIN: 'https://iyque.cn', // 站点域名,会根据此处域名判断应用环境 7 | BASE_URL: '/openmobile/', // 路由基础路径 8 | BASE_API: 'https://iyque.cn/iyque', // 接口基础路径 9 | }, 10 | production: { 11 | DOMAIN: 'https://iyque.cn', 12 | BASE_URL: '/openmobile/', 13 | BASE_API: 'https://iyque.cn/iyque', 14 | }, 15 | } 16 | 17 | const packMode = globalThis.MODE || import.meta.env.MODE 18 | const mode = 19 | process.env.NODE_ENV == 'development' || !globalThis.document 20 | ? packMode // 本地开发和vite中使用 21 | : Object.keys(envs).find((e) => envs[e].DOMAIN === window?.location.origin) || 'diy' // 打包后,根据访问域名动态判断环境 22 | 23 | const BASE_URL = envs[packMode].BASE_URL 24 | const env = envs[mode] || {} 25 | 26 | // 配置项 27 | export const config = { 28 | ...env, 29 | SYSTEM_NAME: '源雀', // 系统简称 30 | } 31 | Object.assign(config, { BASE_URL, RUN_ENV: mode }) 32 | -------------------------------------------------------------------------------- /frontEnd/mobile/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@vue/tsconfig/tsconfig.dom.json", 3 | "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], 4 | "exclude": ["src/**/__tests__/*"], 5 | "compilerOptions": { 6 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 7 | 8 | "paths": { 9 | "@/*": ["./src/*"] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /frontEnd/mobile/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { 5 | "path": "./tsconfig.node.json" 6 | }, 7 | { 8 | "path": "./tsconfig.app.json" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /frontEnd/mobile/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/node22/tsconfig.json", 3 | "include": [ 4 | "vite.config.*", 5 | "vitest.config.*", 6 | "cypress.config.*", 7 | "nightwatch.conf.*", 8 | "playwright.config.*", 9 | "eslint.config.*" 10 | ], 11 | "compilerOptions": { 12 | "noEmit": true, 13 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 14 | 15 | "module": "ESNext", 16 | "moduleResolution": "Bundler", 17 | "types": ["node"] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /frontEnd/pc/.vite/deps_temp_2831f31c/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module" 3 | } 4 | -------------------------------------------------------------------------------- /frontEnd/pc/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /frontEnd/pc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yq", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build-check": "run-p type-check \"build-only {@}\" --", 9 | "preview": "vite preview", 10 | "build": "vite build", 11 | "deploy": "deploy prod", 12 | "type-check": "vue-tsc --build --force" 13 | }, 14 | "dependencies": { 15 | "@element-plus/icons-vue": "^2.3.1", 16 | "@tailwindcss/vite": "^4.1.3", 17 | "@vueuse/core": "^13.0.0", 18 | "axios": "^1.8.3", 19 | "echarts": "^5.6.0", 20 | "element-plus": "^2.9.7", 21 | "js-cookie": "^3.0.5", 22 | "lodash.merge": "^4.6.2", 23 | "normalize.css": "^8.0.1", 24 | "nprogress": "^0.2.0", 25 | "path-browserify": "^1.0.1", 26 | "pinia": "^3.0.1", 27 | "sass": "^1.86.3", 28 | "tailwindcss": "^4.1.3", 29 | "vue": "^3.5.13", 30 | "vue-router": "^4.5.0", 31 | "vue3-count-to": "^1.1.2" 32 | }, 33 | "devDependencies": { 34 | "@tsconfig/node20": "^20.1.4", 35 | "@types/node": "^22.13.16", 36 | "@vitejs/plugin-vue": "^5.0.4", 37 | "@vitejs/plugin-vue-jsx": "^3.1.0", 38 | "@vue/tsconfig": "^0.5.1", 39 | "npm-run-all2": "^6.1.2", 40 | "rollup-plugin-visualizer": "^5.12.0", 41 | "sharp": "^0.33.4", 42 | "terser": "^5.31.0", 43 | "typescript": "~5.4.0", 44 | "unplugin-auto-import": "^0.17.6", 45 | "vite": "^6.2.5", 46 | "vite-plugin-compression": "^0.5.1", 47 | "vite-plugin-image-optimizer": "^1.1.8", 48 | "vite-plugin-svg-icons": "^2.0.1", 49 | "vue-tsc": "^2.0.11" 50 | } 51 | } -------------------------------------------------------------------------------- /frontEnd/pc/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/frontEnd/pc/public/favicon.ico -------------------------------------------------------------------------------- /frontEnd/pc/public/static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/frontEnd/pc/public/static/logo.png -------------------------------------------------------------------------------- /frontEnd/pc/src/App.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /frontEnd/pc/src/api/common.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | const { get, post, put, delt } = request 3 | 4 | export const upload = (data) => post(`/file/upload`, data) 5 | 6 | export const getUserList = (data) => 7 | get(`/iYqueUser/findIYqueUser`, data).then((res) => { 8 | if (res.code == 200) { 9 | res.data?.forEach((element) => { 10 | element.id = element.userId 11 | }) 12 | } 13 | return res 14 | }) 15 | 16 | export const getTagList = (data) => get(`/iYqueTag/findIYqueTag`, data) 17 | 18 | export function getRemarkList() { 19 | return request({ 20 | url: '/iYqueCommon/findRemarksType', 21 | }) 22 | } 23 | -------------------------------------------------------------------------------- /frontEnd/pc/src/assets/icons/svg/eye-open.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontEnd/pc/src/assets/icons/svg/eye.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontEnd/pc/src/assets/icons/svg/gitee.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | -------------------------------------------------------------------------------- /frontEnd/pc/src/assets/icons/svg/user.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontEnd/pc/src/components/CommonTopRight.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 17 | -------------------------------------------------------------------------------- /frontEnd/pc/src/components/IconBtn.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 41 | 42 | 58 | 65 | -------------------------------------------------------------------------------- /frontEnd/pc/src/components/SearchResetButton.vue: -------------------------------------------------------------------------------- 1 | 2 | 28 | 29 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /frontEnd/pc/src/components/SelectGroup.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /frontEnd/pc/src/components/SelectStaff.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /frontEnd/pc/src/components/SvgIcon/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 32 | 33 | 42 | -------------------------------------------------------------------------------- /frontEnd/pc/src/config.js: -------------------------------------------------------------------------------- 1 | import { getToken } from '@/utils/auth' 2 | import { env, common } from '../sys.config' 3 | 4 | let config = { 5 | get headers() { 6 | return { Authorization: 'Bearer ' + getToken() } 7 | }, 8 | _packDateTime: __PACK_DATETIME__, // 打包时间 9 | } 10 | 11 | window.sysConfig = Object.assign(config, env, common) 12 | 13 | // 主题回显 14 | const [h, s, l] = localStorage.hsl?.split(',')?.map((e) => e.trim()) || [] 15 | if (h) { 16 | const style = document.documentElement.style 17 | style.setProperty('--h', h) 18 | style.setProperty('--s', s) 19 | style.setProperty('--l', l) 20 | } 21 | 22 | // 阻止表单默认提交行为 23 | document.addEventListener('submit', (event) => { 24 | event.preventDefault() 25 | }) 26 | 27 | // 统一为img的src不是绝对地址的拼接接口地址 28 | document.addEventListener( 29 | 'error', 30 | function (e) { 31 | let target = e.target 32 | let src = target.attributes.getNamedItem('src').value 33 | if (target.tagName.toUpperCase() === 'IMG' && src && !src.includes('http')) { 34 | target.src = window.sysConfig.BASE_API + '/file/fileView/' + src 35 | e.stopPropagation() 36 | } 37 | }, 38 | true, 39 | ) 40 | -------------------------------------------------------------------------------- /frontEnd/pc/src/layout/components/Sidebar/FixiOSBug.js: -------------------------------------------------------------------------------- 1 | export default { 2 | computed: { 3 | device() { 4 | return this.$store.app.device 5 | }, 6 | }, 7 | mounted() { 8 | // In order to fix the click on menu on the ios device will trigger the mouseleave bug 9 | this.fixBugIniOS() 10 | }, 11 | methods: { 12 | fixBugIniOS() { 13 | const $subMenu = this.$refs.subMenu 14 | if ($subMenu) { 15 | const handleMouseleave = $subMenu.handleMouseleave 16 | $subMenu.handleMouseleave = (e) => { 17 | if (this.device === 'mobile') { 18 | return 19 | } 20 | handleMouseleave(e) 21 | } 22 | } 23 | }, 24 | }, 25 | } 26 | -------------------------------------------------------------------------------- /frontEnd/pc/src/layout/components/Sidebar/Link.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 44 | -------------------------------------------------------------------------------- /frontEnd/pc/src/layout/components/Sidebar/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/frontEnd/pc/src/layout/components/Sidebar/image.png -------------------------------------------------------------------------------- /frontEnd/pc/src/layout/visitor.vue: -------------------------------------------------------------------------------- 1 | 4 | 18 | 19 | 29 | 30 | 75 | -------------------------------------------------------------------------------- /frontEnd/pc/src/router/index.ts: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router' 2 | import { constantRoutes } from '@/router/routes' 3 | import permission from './permission' 4 | 5 | const router = createRouter({ 6 | history: createWebHistory(import.meta.env.BASE_URL), 7 | routes: constantRoutes, 8 | }) 9 | permission(router) 10 | 11 | export default router 12 | -------------------------------------------------------------------------------- /frontEnd/pc/src/router/permission.js: -------------------------------------------------------------------------------- 1 | import NProgress from 'nprogress' 2 | import 'nprogress/nprogress.css' 3 | import { getToken } from '@/utils/auth' 4 | 5 | NProgress.configure({ showSpinner: true }) 6 | 7 | const whiteList = ['/bind', '/test', '/404', '/401'] // 不管有没有token都可直接进入的页面路径 8 | const noLoginList = ['/authRedirect', '/login', '/register'] // 没有token才能进入的页面 9 | 10 | export default function permission(router) { 11 | router.beforeEach((to, from, next) => { 12 | NProgress.start() 13 | // 无需检测token的, 不管有没有token都可直接进入 14 | if (whiteList.includes(to.path) || to.meta.isNoLogin) { 15 | next() 16 | } else if (getToken()) { 17 | /* has token*/ 18 | if (noLoginList.includes(to.path)) { 19 | next({ path: '/' }) 20 | } else { 21 | next() 22 | } 23 | } else if (noLoginList.includes(to.path)) { 24 | // 没有token才能进入的页面 25 | next() 26 | } else { 27 | next(`/login?redirect=${encodeURIComponent(to.fullPath)}`) // 否则全部重定向到登录页 28 | // NProgress.done() 29 | } 30 | }) 31 | 32 | router.afterEach(() => { 33 | NProgress.done() 34 | document.getElementById('loader-wrapper').className = 'loaded' 35 | }) 36 | } 37 | -------------------------------------------------------------------------------- /frontEnd/pc/src/stores/getters.js: -------------------------------------------------------------------------------- 1 | const getters = { 2 | sidebar: (state) => state.app.sidebar, 3 | avatar: (state) => state.user.avatar, 4 | name: (state) => state.user.name, 5 | sidebarRouters: (state) => state.app.sidebarRouters, 6 | } 7 | export default getters 8 | -------------------------------------------------------------------------------- /frontEnd/pc/src/stores/index.js: -------------------------------------------------------------------------------- 1 | import { createPinia, defineStore } from 'pinia' 2 | import app from './modules/app' 3 | import user from './modules/user' 4 | import getters from './getters' 5 | 6 | export const store = createPinia() 7 | 8 | export default defineStore('app', { 9 | state: () => ({ 10 | loading: false, // 页面loading 11 | app: { ...app.state }, 12 | user: { ...user.state }, 13 | }), 14 | actions: { 15 | ...app.actions, 16 | ...user.actions, 17 | }, 18 | getters, 19 | }) 20 | -------------------------------------------------------------------------------- /frontEnd/pc/src/stores/modules/app.js: -------------------------------------------------------------------------------- 1 | import Cookies from 'js-cookie' 2 | import { useDark, useToggle } from '@vueuse/core' 3 | import { constantRoutes } from '@/router/routes' 4 | 5 | const state = { 6 | sidebar: { 7 | opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true, 8 | withoutAnimation: false, 9 | }, 10 | topbarRouters: [], 11 | sidebarRouters: [], 12 | // isDark: useDark(), 13 | showMenuIndex: 0, 14 | currentMenuIndex: 0, 15 | } 16 | 17 | const actions = { 18 | toggleSideBar() { 19 | this.app.sidebar.opened = !this.app.sidebar.opened 20 | this.app.sidebar.withoutAnimation = false 21 | if (this.app.sidebar.opened) { 22 | Cookies.set('sidebarStatus', 1) 23 | } else { 24 | Cookies.set('sidebarStatus', 0) 25 | } 26 | }, 27 | closeSideBar({ withoutAnimation }) { 28 | Cookies.set('sidebarStatus', 0) 29 | this.app.sidebar.opened = false 30 | this.app.sidebar.withoutAnimation = withoutAnimation 31 | }, 32 | setBusininessDesc(busininessDesc) { 33 | this.app.busininessDesc = busininessDesc 34 | }, 35 | } 36 | 37 | export default { 38 | state, 39 | actions, 40 | } 41 | -------------------------------------------------------------------------------- /frontEnd/pc/src/stores/modules/user.js: -------------------------------------------------------------------------------- 1 | // import { getInfo } from '@/views/system/login/api' 2 | import { removeToken } from '@/utils/auth' 3 | 4 | const user = { 5 | state: { 6 | name: '', 7 | avatar: new URL('@/assets/image/profile.jpg', import.meta.url).href, 8 | }, 9 | 10 | actions: { 11 | // 退出系统 12 | LogOut() { 13 | return new Promise((resolve, reject) => { 14 | removeToken() 15 | resolve() 16 | // logout(state.token) 17 | // .then(() => { 18 | // removeToken() 19 | // resolve() 20 | // }) 21 | // .catch((error) => { 22 | // reject(error) 23 | // }) 24 | location.href = window.sysConfig.BASE_URL 25 | }) 26 | }, 27 | }, 28 | } 29 | 30 | export default user 31 | -------------------------------------------------------------------------------- /frontEnd/pc/src/utils/auth.js: -------------------------------------------------------------------------------- 1 | import Cookies from 'js-cookie' 2 | const TokenKey = 'Admin-Token' 3 | 4 | export function getToken() { 5 | return Cookies.get(TokenKey) 6 | } 7 | 8 | export function setToken(token) { 9 | return Cookies.set(TokenKey, token) 10 | } 11 | 12 | export function removeToken() { 13 | return Cookies.remove(TokenKey) 14 | } 15 | 16 | // import { getQueryValue } from './index' 17 | // export async function authRedirect() { 18 | // let auth_code = getQueryValue('auth_code') 19 | // if (!auth_code) { 20 | // return false 21 | // } 22 | // try { 23 | // let { wxQrLogin } = await import('@/api/login') 24 | // let { data } = await wxQrLogin(auth_code) 25 | // setToken(data.access_token) 26 | // history.pushState({}, 'page 2', window.sysConfig.BASE_URL) 27 | // this.$router.replace(window.sysConfig.BASE_URL) 28 | // } catch (error) { 29 | // console.log(error) 30 | // } 31 | // } 32 | -------------------------------------------------------------------------------- /frontEnd/pc/src/utils/index.js: -------------------------------------------------------------------------------- 1 | export const dictMsgType = Object.freeze({ 2 | image: { name: '图片', type: 'image' }, 3 | link: { name: '链接', type: 'link' }, 4 | miniprogram: { name: '小程序', type: 'miniprogram' }, 5 | video: { name: '视频', type: 'video' }, 6 | file: { name: '文件', type: 'file' }, 7 | }) 8 | export const echartColors = [ 9 | '#0F68FF', 10 | '#34D7C3', 11 | '#FFBF49', 12 | '#FF5954', 13 | '#52DDFF', 14 | '#34D781', 15 | '#FFE85F', 16 | '#7F47FF', 17 | '#A47D79', 18 | '#7796D7', 19 | '#89C369', 20 | '#B595D4', 21 | '#E4CBCB', 22 | '#7D889B', 23 | '#AAAFB7', 24 | '#DCD7B0', 25 | '#749E84', 26 | '#B0BBDC', 27 | ] 28 | /** 29 | * 获取query请求参数中name对应的值 30 | * @param string name 31 | */ 32 | export function getQueryValue(name) { 33 | let url = window.location.href 34 | 35 | let reg = new RegExp('(^|&|\\?)' + name + '=([^&#]*)(&|#|$)') 36 | let r = url.match(reg) 37 | if (r != null) { 38 | return decodeURIComponent(r[2]) 39 | } 40 | return '' 41 | } 42 | -------------------------------------------------------------------------------- /frontEnd/pc/src/views/KBM/api.ts: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | const { get, post, put, delt: _del } = request 3 | 4 | const service = '/knowledge' 5 | 6 | /** 列表 7 | * @param {*} params 8 | kname,string,false,,,知识库名称 9 | */ 10 | export const getList = (data) => get(`${service}/findKnowledgeByPage`, data) 11 | 12 | /** 13 | * 14 | * @returns 获取所有知识库 15 | */ 16 | 17 | export const getKnowledgeAll = () => get(`${service}/findAll`) 18 | 19 | /** 删除 20 | * @param {*} ids 21 | */ 22 | export const del = (ids) => _del(`${service}/remove/${ids}`) 23 | 24 | /** 新增 25 | { 26 | "kname": "string", 27 | "description": "string", 28 | "knowledgeSeparator": "string", 29 | "questionSeparator": "string", 30 | "overlapChar": "string", 31 | "retrieveLimit": "string", 32 | "textBlockSize": "string" 33 | } 34 | * @returns 35 | */ 36 | export const save = (data) => post(`${service}/save`, data) 37 | 38 | export const upload = (data) => post(`${service}/attach/upload`, data) 39 | 40 | /** 查询知识附件信息列表 41 | * @param {*} params 42 | kid,string,知识库主键id 43 | */ 44 | export const getListDetail = (data) => get(`${service}/detail/${data.kid}`, data) 45 | 46 | /** 删除知识库附件 47 | * @param {*} docId 知识库附件主键id 48 | */ 49 | export const delAttach = (docId) => _del(`${service}/attach/remove/${docId}`) 50 | 51 | /** 查询知识附件片段 52 | * @param {*} params 53 | docId string 知识库附件文档id 54 | */ 55 | export const getListFragment = (data) => get(`${service}/fragment/list/${data.docId}`, data) 56 | -------------------------------------------------------------------------------- /frontEnd/pc/src/views/chat/api.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | const { get, post, put, delt } = request 3 | const serve = '/msg' 4 | 5 | /** 6 | * 列表 7 | * @param {*} data 8 | { 9 | pageNum: 10 | pageSize: 11 | type:'' 12 | } 13 | */ 14 | export const getList = (data) => get(`${serve}/findMsgAuditByPage`, data) 15 | 16 | 17 | /** 18 | * AI预审列表 19 | * @param {*} data 20 | * @returns 21 | */ 22 | export const findAiAnalysisMsgAudits = (data) => get(`${serve}/findAiAnalysisMsgAudits`, data) 23 | 24 | 25 | /** 26 | * AI预审规则列表 27 | * @param {*} data 28 | * @returns 29 | */ 30 | export const findIYqueMsgRules = (data) => get(`${serve}/findIYqueMsgRules`, data) 31 | 32 | 33 | 34 | /** 35 | * 新增或编辑ai预审规则 36 | * @param {*} data 37 | * @returns 38 | */ 39 | 40 | export const saveOrUpdateMsgRule = (data) => post(`${serve}/saveOrUpdateMsgRule`, data) 41 | 42 | 43 | /** 44 | * 会话同步 45 | * @returns 46 | */ 47 | export const synchMsg = () => get(`${serve}/synchMsg`) 48 | 49 | 50 | 51 | /** 52 | * 53 | * @returns ai会话预审 54 | */ 55 | export const buildAISessionWarning = (data) => get(`${serve}/buildAISessionWarning`,data) 56 | 57 | 58 | 59 | // 删除 60 | export const del = (ids) => delt(`${serve}/${ids}`) 61 | 62 | 63 | //启用或停用 64 | 65 | export const batchStartOrStop = (ids) => post(`${serve}/${ids}`) -------------------------------------------------------------------------------- /frontEnd/pc/src/views/chat/apiLink.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | const { get, post, put, delt } = request 3 | const serve = '/iyQue/shortLink' 4 | 5 | /** 6 | * 列表 7 | * @param {*} data 8 | { 9 | pageNum: 10 | pageSize: 11 | type:'' 12 | } 13 | */ 14 | export const getList = (data) => get(`${serve}/findIYqueShortLink`, data) 15 | 16 | // 详情 17 | export const getDetail = (id) => get(`${serve}/findIYqueUserCode/${id}`) 18 | 19 | // 删除 20 | export const del = (ids) => delt(`${serve}/${ids}`) 21 | 22 | /** 23 | * 新增 24 | * @param {*} data 25 | * id integer 主键为id且自增 26 | codeName string 名称 27 | userId string 员工id,多个使用逗号隔开 28 | userName string 员工名称,多个使用逗号隔开 29 | skipVerify boolean 是否免验证:true:免验证 false:需验证 30 | isExclusive boolean 是否可重复添加: true:可重复添加 false:不可重复添加 31 | tagId string 标签id,多个使用逗号隔开 32 | tagName string 标签名,多个使用逗号隔开 33 | weclomeMsg string 欢迎语 34 | codeState string 渠道标识 35 | codeUrl string 活码地址 36 | configId string 联系方式的配置id 37 | createTime string 创建时间 38 | updateTime string 更新时间 39 | delFlag integer 是否删除标识 40 | * @returns 41 | */ 42 | export const add = (data) => post(`${serve}/save`, data) 43 | 44 | // 修改 45 | export function update(data) { 46 | return put(`${serve}/update`, data) 47 | } 48 | 49 | export const findIYqueMsgAnnexByMsgId = (id) => get(`${serve}/findIYqueMsgAnnexByMsgId/${id}`) 50 | export const findIYqueMsgPeriodAnnexByMsgId = (id) => get(`${serve}/findIYqueMsgPeriodAnnexByMsgId/${id}`) 51 | 52 | //获取所有活码id与name 53 | export const findIYqueUserCodeKvs = () => get(`${serve}/findIYqueUserCodeKvs`) 54 | 55 | export const countTotalTab = (data) => get(`${serve}/countTotalTab`, data) 56 | 57 | export const countTrend = (data) => get(`${serve}/countTrend`, data) 58 | -------------------------------------------------------------------------------- /frontEnd/pc/src/views/complaintManage/api.ts: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | const { get, post, put, delt: _del } = request 3 | 4 | const service = '/iYqueComplaint' 5 | 6 | /** 列表 7 | * @param {*} params 8 | tplName,string,true,,false,模版名称 9 | status,string,true,,false,状态(1:启用;0:停用) 10 | */ 11 | export const getList = (data) => get(`${service}/findComplaintByPage`, data) 12 | 13 | /** 通知 14 | * @param {*} params 15 | */ 16 | export const distributeHandle = (id) => get(`${service}/distributeHandle/${id}`) 17 | 18 | /** 设置通知人 19 | * @param {Object} data 20 | [ 21 | { 22 | "userId": "string" 23 | } 24 | ] 25 | */ 26 | export const setIYQueComplaintTip = (data) => { 27 | return post(`${service}/setIYQueComplaintTip`, data) 28 | } 29 | 30 | /** 31 | * 获取投诉通知人 32 | * @returns 33 | */ 34 | export const findIYQueComplaintTips = () => get(`${service}/findIYQueComplaintTips`) 35 | 36 | /** 删除 37 | * @param {*} ids 38 | */ 39 | export const del = (ids) => _del(`${service}/${ids}`) 40 | 41 | /** 启用或者停用 42 | { 43 | "svipGroupIds": "", //一客一群模版id,多个使用逗号隔开 44 | "status": 0, //状态(1:启用;0:停用) 45 | "chatId": "", //群id 46 | "weUserId": "", //成员id 47 | "externalUserid": "" //客户id 48 | } 49 | * @returns 50 | */ 51 | export const updateStatus = (data) => post(`${service}/updateStatus`, data) 52 | 53 | // 建群统计-头部tab 54 | export const getStatistic = (svipGroupId) => get(`${service}/countTotalTab`, { svipGroupId }) 55 | 56 | // 建群统计-折线图 57 | export const getDataTrend = (data) => get(`${service}/countTrend`, data) 58 | -------------------------------------------------------------------------------- /frontEnd/pc/src/views/complaintManage/index.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /frontEnd/pc/src/views/config/api.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | const { get, post, put, delt } = request 3 | const serve = '/iYqueConfig' 4 | 5 | export const getDetail = (id) => get(`${serve}/findIYqueConfig`) 6 | 7 | export const addOrUpdate = (data) => post(`${serve}/saveOrUpdate`, data) 8 | 9 | const serveWel = '/iYqueDefaultMsg' 10 | export const getDetailWel = (id) => get(`${serveWel}/findDefaultMsg`) 11 | 12 | /** 13 | * 14 | * @param {*} data 15 | * { 16 | "defaultContent": "string", 17 | "annexLists": [ 18 | { 19 | "msgtype": "string", 当前分为四种类型:image(图片);like(链接);miniprogram(小程序);video(视频);file(文件)。 根据当前类型的不同传入的对象不同,比如当前类型为image则传image对象。其附件返回也是一样 20 | "image": { 21 | "picUrl": "string" 22 | }, 23 | "link": { 24 | "title": "string", 25 | "picurl": "string", 26 | "desc": "string", 27 | "url": "string" 28 | }, 29 | "miniprogram": { 30 | "title": "string", 31 | "picurl": "string", 32 | "appid": "string", 33 | "page": "string" 34 | }, 35 | "video": { 36 | "videoUrl": "string" 37 | }, 38 | "file": { 39 | "fileUrl": "string" 40 | } 41 | } 42 | ] 43 | } 44 | * @returns 45 | */ 46 | export const addOrUpdateWel = (data) => post(`${serveWel}/saveOrUpdate`, data) 47 | -------------------------------------------------------------------------------- /frontEnd/pc/src/views/config/index.vue: -------------------------------------------------------------------------------- 1 | 16 | 58 | 59 | 65 | -------------------------------------------------------------------------------- /frontEnd/pc/src/views/config/welcome.vue: -------------------------------------------------------------------------------- 1 | 47 | 55 | 56 | 61 | -------------------------------------------------------------------------------- /frontEnd/pc/src/views/customerServiceManage/api.ts: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | const { get, post, put, delt: _del } = request 3 | 4 | const service = '/kf' 5 | 6 | /** 列表 7 | * @param {*} params 8 | kfName,string,false,,,知识库名称 9 | */ 10 | export const getList = (data) => get(`${service}/findAll`, data) 11 | 12 | /** 删除 13 | * @param {*} ids 14 | */ 15 | export const del = (ids) => _del(`${service}/${ids}`) 16 | 17 | /** 启用或者停用 18 | { 19 | "svipGroupIds": "", //一客一群模版id,多个使用逗号隔开 20 | "status": 0, //状态(1:启用;0:停用) 21 | "chatId": "", //群id 22 | "weUserId": "", //成员id 23 | "externalUserid": "" //客户id 24 | } 25 | * @returns 26 | */ 27 | export const save = (data) => post(`${service}/saveOrUpdateKf`, data) 28 | 29 | // 建群统计-头部tab 30 | export const getStatistic = (svipGroupId) => get(`${service}/countTotalTab`, { svipGroupId }) 31 | 32 | // 建群统计-折线图 33 | export const getDataTrend = (data) => get(`${service}/countTrend`, data) 34 | -------------------------------------------------------------------------------- /frontEnd/pc/src/views/customerServiceManage/index.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /frontEnd/pc/src/views/groupChat/api.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | const { get, post, put, delt } = request 3 | const serve = '/iYqueChat' 4 | 5 | /** 6 | * 列表 7 | * @param {*} data 8 | { 9 | pageNum: 10 | pageSize: 11 | type:'' 12 | } 13 | */ 14 | export const getList = (data) => get(`${serve}/findIYqueChatPage`, data) 15 | 16 | 17 | 18 | /** 19 | * 客群同步 20 | * @returns 21 | */ 22 | export const synchIyqueChat = () => post(`${serve}/synchIyqueChat`) 23 | 24 | -------------------------------------------------------------------------------- /frontEnd/pc/src/views/groupCode/api.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | const { get, post, put, delt } = request 3 | const serve = '/iychatCode' 4 | 5 | /** 6 | * 列表 7 | * @param {*} data 8 | { 9 | pageNum: 10 | pageSize: 11 | type:'' 12 | } 13 | */ 14 | export const getList = (data) => get(`${serve}/findIYqueChatCode`, data) 15 | 16 | // 详情 17 | // export const getDetail = (id) => get(`${serve}/findIYqueUserCode/${id}`) 18 | 19 | // // 删除 20 | export const del = (ids) => delt(`${serve}/${ids}`) 21 | 22 | /** 23 | * 新增 24 | * @param {*} data 25 | id integer 26 | chatCodeName string 群码名称 27 | chatCodeUrl string 群码url 28 | chatCodeState string 群码渠道标识 29 | configId string 群码config 30 | remark string 联系方式的备注信息,用于助记,超过30个字符将被截断 31 | autoCreateRoom integer 当群满了后,是否自动新建群。0-否;1-是。 默认为1 32 | roomBaseName string 自动建群的群名前缀,当auto_create_room为1时有效。最长40个utf8字符 33 | roomBaseId integer 自动建群的群起始序号,当auto_create_room为1时有效 34 | chatIds string 使用该配置的客户群ID列表,最多支持5个 35 | createTime string 36 | updateTime string 更新时间 37 | delFlag integer 是否删除标识 38 | * @returns 39 | */ 40 | export const add = (data) => post(`${serve}/save`, data) 41 | 42 | // 修改 43 | export function update(data) { 44 | return put(`${serve}/update`, data) 45 | } 46 | 47 | //获取企业微信群 48 | export const getGroupList = () => get(`${serve}/findIYqueChat`) 49 | -------------------------------------------------------------------------------- /frontEnd/pc/src/views/hotWordManage/SelectHotWord.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /frontEnd/pc/src/views/hotWordManage/apiCategory.ts: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | const { get, post, put, delt: _del } = request 3 | 4 | const service = '/category' 5 | 6 | /** 列表 7 | */ 8 | export const getList = (data) => get(`${service}/findIYqueCategory`, data) 9 | 10 | /** 详情 11 | * @param {*} params 12 | */ 13 | export const getDetail = (id) => get(`${service}/findSvipGroupTplById/${id}`) 14 | 15 | /** 新增或更新 16 | * @param {Object} data 17 | { 18 | "id": "string", 19 | "name": "string", 20 | "mediaType": 0 // 默认传7 21 | } 22 | */ 23 | export const save = (data) => post(`${service}/saveOrUpdate`, data) 24 | 25 | /** 删除 26 | * @param {*} ids 27 | */ 28 | export const del = (ids) => _del(`${service}/${ids}`) 29 | -------------------------------------------------------------------------------- /frontEnd/pc/src/views/inquiryCustomer/api.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | const { get, post, put, delt } = request 3 | const serve = '/msg' 4 | 5 | /** 6 | * 列表 7 | * @param {*} data 8 | { 9 | pageNum: 10 | pageSize: 11 | type:'' 12 | } 13 | */ 14 | export const getList = (data) => get(`${serve}/findMsgAuditByPage`, data) 15 | 16 | 17 | /** 18 | * AI预审列表 19 | * @param {*} data 20 | * @returns 21 | */ 22 | export const findAiAnalysisMsgAudits = (data) => get(`${serve}/findAiAnalysisMsgAudits`, data) 23 | 24 | 25 | /** 26 | * AI预审规则列表 27 | * @param {*} data 28 | * @returns 29 | */ 30 | export const findIYqueMsgRules = (data) => get(`${serve}/findIYqueMsgRules`, data) 31 | 32 | 33 | 34 | /** 35 | * 新增或编辑ai预审规则 36 | * @param {*} data 37 | * @returns 38 | */ 39 | 40 | export const saveOrUpdateMsgRule = (data) => post(`${serve}/saveOrUpdateMsgRule`, data) 41 | 42 | 43 | /** 44 | * 会话同步 45 | * @returns 46 | */ 47 | export const synchMsg = () => get(`${serve}/synchMsg`) 48 | 49 | 50 | 51 | /** 52 | * 53 | * @returns ai会话预审 54 | */ 55 | export const buildAISessionWarning = (data) => get(`${serve}/buildAISessionWarning`,data) 56 | 57 | 58 | 59 | // 删除 60 | export const del = (ids) => delt(`${serve}/${ids}`) 61 | 62 | 63 | //启用或停用 64 | 65 | export const batchStartOrStop = (ids) => post(`${serve}/${ids}`) -------------------------------------------------------------------------------- /frontEnd/pc/src/views/inquiryKqChat/api.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | const { get, post, put, delt } = request 3 | const serve = '/msg' 4 | 5 | /** 6 | * 列表 7 | * @param {*} data 8 | { 9 | pageNum: 10 | pageSize: 11 | type:'' 12 | } 13 | */ 14 | export const getList = (data) => get(`${serve}/findMsgAuditByPage`, data) 15 | 16 | 17 | /** 18 | * AI预审列表 19 | * @param {*} data 20 | * @returns 21 | */ 22 | export const findAiAnalysisMsgAudits = (data) => get(`${serve}/findAiAnalysisMsgAudits`, data) 23 | 24 | 25 | /** 26 | * AI预审规则列表 27 | * @param {*} data 28 | * @returns 29 | */ 30 | export const findIYqueMsgRules = (data) => get(`${serve}/findIYqueMsgRules`, data) 31 | 32 | 33 | 34 | /** 35 | * 新增或编辑ai预审规则 36 | * @param {*} data 37 | * @returns 38 | */ 39 | 40 | export const saveOrUpdateMsgRule = (data) => post(`${serve}/saveOrUpdateMsgRule`, data) 41 | 42 | 43 | /** 44 | * 会话同步 45 | * @returns 46 | */ 47 | export const synchMsg = () => get(`${serve}/synchMsg`) 48 | 49 | 50 | 51 | /** 52 | * 53 | * @returns ai会话预审 54 | */ 55 | export const buildAISessionWarning = (data) => get(`${serve}/buildAISessionWarning`,data) 56 | 57 | 58 | 59 | // 删除 60 | export const del = (ids) => delt(`${serve}/${ids}`) 61 | 62 | 63 | //启用或停用 64 | 65 | export const batchStartOrStop = (ids) => post(`${serve}/${ids}`) -------------------------------------------------------------------------------- /frontEnd/pc/src/views/intentionCustomer/api.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | const { get, post, put, delt } = request 3 | const serve = '/msg' 4 | 5 | /** 6 | * 列表 7 | * @param {*} data 8 | { 9 | pageNum: 10 | pageSize: 11 | type:'' 12 | } 13 | */ 14 | export const getList = (data) => get(`${serve}/findMsgAuditByPage`, data) 15 | 16 | 17 | /** 18 | * AI预审列表 19 | * @param {*} data 20 | * @returns 21 | */ 22 | export const findAiAnalysisMsgAudits = (data) => get(`${serve}/findAiAnalysisMsgAudits`, data) 23 | 24 | 25 | /** 26 | * AI预审规则列表 27 | * @param {*} data 28 | * @returns 29 | */ 30 | export const findIYqueMsgRules = (data) => get(`${serve}/findIYqueMsgRules`, data) 31 | 32 | 33 | 34 | /** 35 | * 新增或编辑ai预审规则 36 | * @param {*} data 37 | * @returns 38 | */ 39 | 40 | export const saveOrUpdateMsgRule = (data) => post(`${serve}/saveOrUpdateMsgRule`, data) 41 | 42 | 43 | /** 44 | * 会话同步 45 | * @returns 46 | */ 47 | export const synchMsg = () => get(`${serve}/synchMsg`) 48 | 49 | 50 | 51 | /** 52 | * 53 | * @returns ai意向分析 54 | */ 55 | export const buildAISessionWarning = (data) => get(`${serve}/aiIntentionAssay`,data) 56 | 57 | 58 | 59 | // 删除 60 | export const del = (ids) => delt(`${serve}/${ids}`) 61 | 62 | 63 | //启用或停用 64 | 65 | export const batchStartOrStop = (ids) => post(`${serve}/${ids}`) -------------------------------------------------------------------------------- /frontEnd/pc/src/views/intentionGroupFriend/api.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | const { get, post, put, delt } = request 3 | const serve = '/msg' 4 | 5 | /** 6 | * 列表 7 | * @param {*} data 8 | { 9 | pageNum: 10 | pageSize: 11 | type:'' 12 | } 13 | */ 14 | export const getList = (data) => get(`${serve}/findMsgAuditByPage`, data) 15 | 16 | 17 | /** 18 | * AI预审列表 19 | * @param {*} data 20 | * @returns 21 | */ 22 | export const findAiAnalysisMsgAudits = (data) => get(`${serve}/findAiAnalysisMsgAudits`, data) 23 | 24 | 25 | /** 26 | * AI预审规则列表 27 | * @param {*} data 28 | * @returns 29 | */ 30 | export const findIYqueMsgRules = (data) => get(`${serve}/findIYqueMsgRules`, data) 31 | 32 | 33 | 34 | /** 35 | * 新增或编辑ai预审规则 36 | * @param {*} data 37 | * @returns 38 | */ 39 | 40 | export const saveOrUpdateMsgRule = (data) => post(`${serve}/saveOrUpdateMsgRule`, data) 41 | 42 | 43 | /** 44 | * 会话同步 45 | * @returns 46 | */ 47 | export const synchMsg = () => get(`${serve}/synchMsg`) 48 | 49 | 50 | 51 | /** 52 | * 53 | * @returns ai意向分析 54 | */ 55 | export const buildAISessionWarning = (data) => get(`${serve}/aiIntentionAssay`,data) 56 | 57 | 58 | 59 | // 删除 60 | export const del = (ids) => delt(`${serve}/${ids}`) 61 | 62 | 63 | //启用或停用 64 | 65 | export const batchStartOrStop = (ids) => post(`${serve}/${ids}`) -------------------------------------------------------------------------------- /frontEnd/pc/src/views/kqchat/api.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | const { get, post, put, delt } = request 3 | const serve = '/msg' 4 | 5 | /** 6 | * 列表 7 | * @param {*} data 8 | { 9 | pageNum: 10 | pageSize: 11 | type:'' 12 | } 13 | */ 14 | export const getList = (data) => get(`${serve}/findMsgAuditByPage`, data) 15 | 16 | 17 | /** 18 | * AI预审列表 19 | * @param {*} data 20 | * @returns 21 | */ 22 | export const findAiAnalysisMsgAudits = (data) => get(`${serve}/findAiAnalysisMsgAudits`, data) 23 | 24 | 25 | /** 26 | * AI预审规则列表 27 | * @param {*} data 28 | * @returns 29 | */ 30 | export const findIYqueMsgRules = (data) => get(`${serve}/findIYqueMsgRules`, data) 31 | 32 | 33 | 34 | /** 35 | * 新增或编辑ai预审规则 36 | * @param {*} data 37 | * @returns 38 | */ 39 | 40 | export const saveOrUpdateMsgRule = (data) => post(`${serve}/saveOrUpdateMsgRule`, data) 41 | 42 | 43 | /** 44 | * 会话同步 45 | * @returns 46 | */ 47 | export const synchMsg = () => get(`${serve}/synchMsg`) 48 | 49 | 50 | 51 | /** 52 | * 53 | * @returns ai会话预审 54 | */ 55 | export const buildAISessionWarning = (data) => get(`${serve}/buildAISessionWarning`,data) 56 | 57 | 58 | 59 | // 删除 60 | export const del = (ids) => delt(`${serve}/${ids}`) 61 | 62 | 63 | //启用或停用 64 | 65 | export const batchStartOrStop = (ids) => post(`${serve}/${ids}`) -------------------------------------------------------------------------------- /frontEnd/pc/src/views/massMarketing/api.ts: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | const { get, post, put, delt: _del } = request 3 | 4 | const service = '/groupMsg' 5 | 6 | /** 列表 7 | * @param {*} params 8 | tplName,string,true,,false,模版名称 9 | status,string,true,,false,状态(1:启用;0:停用) 10 | */ 11 | export const getList = (data) => get(`${service}/findIYqueGroupMsgPage`, data) 12 | 13 | /** 详情 14 | * @param {*} params 15 | */ 16 | export const getDetail = (id) => get(`${service}/findIYqueGroupMsgById/${id}`) 17 | 18 | /** 删除 19 | * @param {*} ids 20 | */ 21 | export const del = (ids) => _del(`${service}/${ids}`) 22 | 23 | /** save 24 | * @returns 25 | */ 26 | export const save = (data) => post(`${service}/buildGroupMsg`, data) 27 | 28 | // 建群统计-头部tab 29 | export const getStatistic = (svipGroupId) => get(`${service}/countTotalTab`, { svipGroupId }) 30 | 31 | // 建群统计-折线图 32 | export const getDataTrend = (data) => get(`${service}/countTrend`, data) 33 | -------------------------------------------------------------------------------- /frontEnd/pc/src/views/massMarketing/index.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /frontEnd/pc/src/views/serviceRecord/api.ts: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | const { get, post, put, delt: _del } = request 3 | 4 | const service = '/kf' 5 | 6 | /** 列表 7 | * @param {*} params 8 | kfName,string,false,客服名 9 | nickname,string,false,客户名 10 | */ 11 | export const getList = (data) => get(`${service}/findKfMsgAll`, data) 12 | -------------------------------------------------------------------------------- /frontEnd/pc/src/views/system/error/assets/401.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/frontEnd/pc/src/views/system/error/assets/401.gif -------------------------------------------------------------------------------- /frontEnd/pc/src/views/system/error/assets/404.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/frontEnd/pc/src/views/system/error/assets/404.png -------------------------------------------------------------------------------- /frontEnd/pc/src/views/system/error/assets/404_cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/frontEnd/pc/src/views/system/error/assets/404_cloud.png -------------------------------------------------------------------------------- /frontEnd/pc/src/views/system/login/api.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | const { get, post, put, del: _del } = request 3 | const serve = '/iYqueSys' 4 | 5 | export const login = (data) => post(`${serve}/login`, data) 6 | /** 7 | * 获取gitee登录地址 8 | */ 9 | export const findThreeLoginInfo = () => get(`${serve}/threeLogin/findThreeLoginInfo`) 10 | 11 | export const giteeLogin = (code) => get(`${serve}/threeLogin/giteeLogin/${code}`) 12 | 13 | // 详情 14 | export const getDetail = (id) => get(`${serve}/getKeyWordGroupBaseInfo/${id}`) 15 | 16 | // 删除 17 | export const remove = (ids) => _del(`${serve}/batchRemoveKeyWordGroup/${ids}`) 18 | 19 | /** 20 | * 新增 21 | * @param {*} data 22 | * id integer 主键为id且自增 23 | codeName string 名称 24 | userId string 员工id,多个使用逗号隔开 25 | userName string 员工名称,多个使用逗号隔开 26 | skipVerify boolean 是否免验证:true:免验证 false:需验证 27 | isExclusive boolean 是否可重复添加: true:可重复添加 false:不可重复添加 28 | tagId string 标签id,多个使用逗号隔开 29 | tagName string 标签名,多个使用逗号隔开 30 | weclomeMsg string 欢迎语 31 | codeState string 渠道标识 32 | codeUrl string 活码地址 33 | configId string 联系方式的配置id 34 | createTime string 创建时间 35 | updateTime string 更新时间 36 | delFlag integer 是否删除标识 37 | * @returns 38 | */ 39 | 40 | // 修改 41 | export function update(data) { 42 | return put(`${serve}/update`, data) 43 | } 44 | -------------------------------------------------------------------------------- /frontEnd/pc/src/views/system/login/authRedirect.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 32 | -------------------------------------------------------------------------------- /frontEnd/pc/src/views/tag/api.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | const { get, post, put, delt } = request 3 | const serve = '/iYqueTag' 4 | 5 | /** 6 | * 列表 7 | * @param {*} data 8 | { 9 | pageNum: 10 | pageSize: 11 | type:'' 12 | } 13 | */ 14 | export const getList = (data) => get(`${serve}/findIYqueTag`, data) 15 | 16 | // 详情 17 | export const getDetail = (id) => get(`${serve}/getKeyWordGroupBaseInfo/${id}`) 18 | 19 | // 删除 20 | export const del = (ids) => delt(`${serve}/${ids}`) 21 | 22 | /** 23 | * 新增 24 | * @param {*} data 25 | * id integer 主键为id且自增 26 | codeName string 名称 27 | userId string 员工id,多个使用逗号隔开 28 | userName string 员工名称,多个使用逗号隔开 29 | skipVerify boolean 是否免验证:true:免验证 false:需验证 30 | isExclusive boolean 是否可重复添加: true:可重复添加 false:不可重复添加 31 | tagId string 标签id,多个使用逗号隔开 32 | tagName string 标签名,多个使用逗号隔开 33 | weclomeMsg string 欢迎语 34 | codeState string 渠道标识 35 | codeUrl string 活码地址 36 | configId string 联系方式的配置id 37 | createTime string 创建时间 38 | updateTime string 更新时间 39 | delFlag integer 是否删除标识 40 | * @returns 41 | */ 42 | export const add = (data) => post(`${serve}/save`, data) 43 | 44 | // 修改 45 | export function update(data) { 46 | return put(`${serve}/update`, data) 47 | } 48 | -------------------------------------------------------------------------------- /frontEnd/pc/src/views/user/api.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | const { get, post, put, delt } = request 3 | const serve = '/iYqueUser' 4 | 5 | /** 6 | * 列表 7 | * @param {*} data 8 | { 9 | pageNum: 10 | pageSize: 11 | type:'' 12 | } 13 | */ 14 | export const getList = (data) => get(`${serve}/findIYqueUserPage`, data) 15 | 16 | 17 | 18 | /** 19 | * 成员同步 20 | * @returns 21 | */ 22 | export const synchIyqueUser = () => post(`${serve}/synchIyqueUser`) 23 | 24 | -------------------------------------------------------------------------------- /frontEnd/pc/sys.config.ts: -------------------------------------------------------------------------------- 1 | // 环境变量 2 | const envs = { 3 | development: { 4 | DOMAIN: 'http://127.0.0.1:8085', 5 | BASE_URL: '/tools/', 6 | BASE_API: 'http://127.0.0.1:8085', 7 | }, 8 | production: { 9 | DOMAIN: 'https://iyque.cn', 10 | BASE_URL: '/tools/', 11 | BASE_API: 'https://iyque.cn/iyque', 12 | }, 13 | } 14 | 15 | let mode = 16 | process.env.NODE_ENV == 'development' || !globalThis.document 17 | ? process.env.VUE_APP_ENV 18 | : Object.keys(envs).find((e) => envs[e].DOMAIN === window?.location.origin) 19 | 20 | export const env = { ...envs[mode], ENV: mode } 21 | 22 | // 系统常量配置 23 | export const common = { 24 | SYSTEM_NAME: '源雀', // 系统简称 25 | SYSTEM_SLOGAN: 26 | '源雀Scrm-是基于Java源码交付的企微SCRM,帮助企业构建高度自由安全的私域平台. ', // 系统标语 27 | COPYRIGHT: 'Copyright © 2022-2025 源雀 All Rights Reserved.', // 版权信息 28 | LOGO: env.BASE_URL + 'static/logo.png', // 深色logo 29 | } 30 | -------------------------------------------------------------------------------- /frontEnd/pc/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@vue/tsconfig/tsconfig.dom.json", 3 | "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], 4 | "exclude": ["src/**/__tests__/*"], 5 | "compilerOptions": { 6 | "composite": true, 7 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 8 | 9 | "baseUrl": ".", 10 | "paths": { 11 | "@/*": ["./src/*"] 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontEnd/pc/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "types": ["node"], 4 | "allowJs": true 5 | }, 6 | "files": [], 7 | "references": [ 8 | { 9 | "path": "./tsconfig.node.json" 10 | }, 11 | { 12 | "path": "./tsconfig.app.json" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /frontEnd/pc/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/node20/tsconfig.json", 3 | "include": [ 4 | "vite.config.*", 5 | "vitest.config.*", 6 | "cypress.config.*", 7 | "nightwatch.conf.*", 8 | "playwright.config.*" 9 | ], 10 | "compilerOptions": { 11 | "composite": true, 12 | "noEmit": true, 13 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 14 | 15 | "module": "ESNext", 16 | "moduleResolution": "Bundler", 17 | "types": ["node"] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /img/config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/img/config.png -------------------------------------------------------------------------------- /img/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/img/image.png -------------------------------------------------------------------------------- /img/img_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/img/img_1.png -------------------------------------------------------------------------------- /img/img_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/img/img_2.png -------------------------------------------------------------------------------- /img/img_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/img/img_3.png -------------------------------------------------------------------------------- /img/j-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/img/j-1.jpg -------------------------------------------------------------------------------- /img/j-10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/img/j-10.png -------------------------------------------------------------------------------- /img/j-11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/img/j-11.png -------------------------------------------------------------------------------- /img/j-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/img/j-12.png -------------------------------------------------------------------------------- /img/j-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/img/j-13.png -------------------------------------------------------------------------------- /img/j-14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/img/j-14.png -------------------------------------------------------------------------------- /img/j-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/img/j-2.jpg -------------------------------------------------------------------------------- /img/j-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/img/j-3.jpg -------------------------------------------------------------------------------- /img/j-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/img/j-4.png -------------------------------------------------------------------------------- /img/j-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/img/j-5.png -------------------------------------------------------------------------------- /img/j-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/img/j-6.png -------------------------------------------------------------------------------- /img/j-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/img/j-7.png -------------------------------------------------------------------------------- /img/j-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/img/j-8.png -------------------------------------------------------------------------------- /img/j-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/img/j-9.png -------------------------------------------------------------------------------- /pic/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/pic/1.png -------------------------------------------------------------------------------- /pic/111111.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/pic/111111.png -------------------------------------------------------------------------------- /pic/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/pic/2.png -------------------------------------------------------------------------------- /pic/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/pic/3.png -------------------------------------------------------------------------------- /pic/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/pic/4.png -------------------------------------------------------------------------------- /pic/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/pic/5.png -------------------------------------------------------------------------------- /pic/contactus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/pic/contactus.png -------------------------------------------------------------------------------- /pic/tab_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/pic/tab_logo.png -------------------------------------------------------------------------------- /pic/tab_logo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/pic/tab_logo2.png -------------------------------------------------------------------------------- /src/main/java/cn/iyque/IyQueApplication.java: -------------------------------------------------------------------------------- 1 | package cn.iyque; 2 | 3 | 4 | import org.h2.tools.Server; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.boot.builder.SpringApplicationBuilder; 7 | 8 | import java.sql.SQLException; 9 | 10 | @SpringBootApplication 11 | public class IyQueApplication { 12 | public static void main(String[] args) throws SQLException { 13 | Server.createTcpServer("-tcp", "-tcpAllowOthers", "-tcpPort", "9092").start(); 14 | new SpringApplicationBuilder(IyQueApplication.class) 15 | .build().run(args); 16 | System.out.println("(♥◠‿◠)ノ゙ 源雀SCRM【开源版】启动成功。官方文档地址【https://iyque.cn】ლ(´ڡ`ლ)゙"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/annotation/RateLimit.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.annotation; 2 | 3 | 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | @Target(ElementType.METHOD) 10 | @Retention(RetentionPolicy.RUNTIME) 11 | public @interface RateLimit { 12 | int attempts() default 5; // 默认允许5次尝试 13 | long lockTime() default 300; // 锁定时间(秒),默认5分钟 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/chain/loader/PdfFileLoader.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.chain.loader; 2 | 3 | import cn.iyque.chain.split.TextSplitter; 4 | import lombok.AllArgsConstructor; 5 | import org.apache.pdfbox.pdmodel.PDDocument; 6 | import org.apache.pdfbox.text.PDFTextStripper; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | import java.util.List; 12 | 13 | @Component 14 | @AllArgsConstructor 15 | public class PdfFileLoader implements ResourceLoader{ 16 | private final TextSplitter characterTextSplitter; 17 | @Override 18 | public String getContent(InputStream inputStream) { 19 | PDDocument document = null; 20 | try { 21 | document = PDDocument.load(inputStream); 22 | PDFTextStripper textStripper = new PDFTextStripper(); 23 | String content = textStripper.getText(document); 24 | return content; 25 | } catch (IOException e) { 26 | throw new RuntimeException(e); 27 | } 28 | } 29 | 30 | @Override 31 | public List getChunkList(String content) { 32 | return characterTextSplitter.split(content); 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/chain/loader/ResourceLoader.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.chain.loader; 2 | 3 | import java.io.InputStream; 4 | import java.util.List; 5 | 6 | /** 7 | * 资源载入 8 | */ 9 | public interface ResourceLoader { 10 | 11 | String getContent(InputStream inputStream); 12 | 13 | List getChunkList(String content); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/chain/loader/ResourceLoaderFactory.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.chain.loader; 2 | 3 | import cn.iyque.chain.split.CharacterTextSplitter; 4 | import cn.iyque.constant.FileType; 5 | import lombok.AllArgsConstructor; 6 | import org.springframework.stereotype.Component; 7 | 8 | @AllArgsConstructor 9 | @Component 10 | public class ResourceLoaderFactory { 11 | private final CharacterTextSplitter characterTextSplitter; 12 | 13 | public ResourceLoader getLoaderByFileType(String fileType){ 14 | if (FileType.isTextFile(fileType)){ 15 | return new TextFileLoader(characterTextSplitter); 16 | } else if (FileType.isWord(fileType)) { 17 | return new WordLoader(characterTextSplitter); 18 | } else if (FileType.isPdf(fileType)) { 19 | return new PdfFileLoader(characterTextSplitter); 20 | }else { 21 | return new TextFileLoader(characterTextSplitter); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/main/java/cn/iyque/chain/loader/TextFileLoader.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.chain.loader; 2 | 3 | import cn.iyque.chain.split.TextSplitter; 4 | import lombok.AllArgsConstructor; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.stereotype.Component; 7 | 8 | import java.io.BufferedReader; 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | import java.io.InputStreamReader; 12 | import java.util.List; 13 | 14 | @Component 15 | @AllArgsConstructor 16 | @Slf4j 17 | public class TextFileLoader implements ResourceLoader{ 18 | private final TextSplitter textSplitter; 19 | @Override 20 | public String getContent(InputStream inputStream) { 21 | StringBuffer stringBuffer = new StringBuffer(); 22 | try (InputStreamReader reader = new InputStreamReader(inputStream, "UTF-8"); 23 | BufferedReader bufferedReader = new BufferedReader(reader)){ 24 | String line; 25 | while ((line = bufferedReader.readLine()) != null) { 26 | stringBuffer.append(line).append("\n"); 27 | } 28 | } catch (IOException e) { 29 | e.printStackTrace(); 30 | } 31 | return stringBuffer.toString(); 32 | } 33 | @Override 34 | public List getChunkList(String content){ 35 | return textSplitter.split(content); 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/java/cn/iyque/chain/loader/WordLoader.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.chain.loader; 2 | 3 | import cn.iyque.chain.split.TextSplitter; 4 | import lombok.AllArgsConstructor; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.apache.poi.xwpf.extractor.XWPFWordExtractor; 7 | import org.apache.poi.xwpf.usermodel.XWPFDocument; 8 | import org.springframework.stereotype.Component; 9 | 10 | import java.io.IOException; 11 | import java.io.InputStream; 12 | import java.util.List; 13 | 14 | @Component 15 | @AllArgsConstructor 16 | @Slf4j 17 | public class WordLoader implements ResourceLoader{ 18 | private final TextSplitter textSplitter; 19 | @Override 20 | public String getContent(InputStream inputStream) { 21 | XWPFDocument document = null; 22 | try { 23 | document = new XWPFDocument(inputStream); 24 | XWPFWordExtractor extractor = new XWPFWordExtractor(document); 25 | String content = extractor.getText(); 26 | return content; 27 | } catch (IOException e) { 28 | throw new RuntimeException(e); 29 | } 30 | } 31 | 32 | @Override 33 | public List getChunkList(String content) { 34 | return textSplitter.split(content); 35 | } 36 | 37 | } 38 | 39 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/chain/split/CharacterTextSplitter.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.chain.split; 2 | 3 | 4 | import cn.iyque.config.IYqueParamConfig; 5 | import io.github.lnyocly.ai4j.utils.RecursiveCharacterTextSplitter; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.context.annotation.Primary; 9 | import org.springframework.stereotype.Component; 10 | import java.util.List; 11 | 12 | @Component 13 | @Slf4j 14 | @Primary 15 | public class CharacterTextSplitter implements TextSplitter { 16 | 17 | @Autowired 18 | private IYqueParamConfig iYqueParamConfig; 19 | 20 | 21 | 22 | @Override 23 | public List split(String content) { 24 | 25 | RecursiveCharacterTextSplitter recursiveCharacterTextSplitter = new RecursiveCharacterTextSplitter(iYqueParamConfig.getVector().getChunkSize(), 26 | iYqueParamConfig.getVector().getChunkOverlap()); 27 | return recursiveCharacterTextSplitter.splitText(content); 28 | 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/chain/split/TextSplitter.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.chain.split; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * 文本切分 7 | */ 8 | public interface TextSplitter { 9 | 10 | /** 11 | * 文本切分 12 | * 13 | * @param content 文本内容 14 | * @return 切分后的文本列表 15 | */ 16 | List split(String content); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/chain/vectorizer/Vectorization.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.chain.vectorizer; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * 向量化 7 | */ 8 | public interface Vectorization { 9 | 10 | 11 | /** 12 | * 多向量 13 | * @param chunkList 14 | * @param kid 15 | * @return 16 | */ 17 | List> batchVectorization(List chunkList, String kid); 18 | 19 | 20 | /** 21 | * 单一向量 22 | * @param chunk 23 | * @param kid 24 | * @return 25 | */ 26 | List singleVectorization(String chunk, String kid); 27 | } -------------------------------------------------------------------------------- /src/main/java/cn/iyque/chain/vectorstore/IYqueVectorStore.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.chain.vectorstore; 2 | 3 | import java.util.List; 4 | 5 | 6 | /** 7 | * 向量存储 8 | */ 9 | public interface IYqueVectorStore { 10 | 11 | /** 12 | * 向量存储 13 | * @param chunkList 14 | * @param vectorList 15 | * @param kid 16 | * @param docId 17 | * @param fidList 18 | */ 19 | void storeEmbeddings(List chunkList, List> vectorList, String kid, String docId, List fidList); 20 | 21 | 22 | /** 23 | * 根据id删除指定向量数据 24 | * @param kid 25 | */ 26 | void removeByKid(String kid); 27 | 28 | /** 29 | * 查询向量相似数据 30 | * @param queryVector 31 | * @param kid 32 | * @return 33 | */ 34 | List nearest(List queryVector, String kid); 35 | 36 | 37 | /** 38 | * 创建向量表 39 | * @param kid 40 | */ 41 | void newSchema(String kid); 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/config/AsyncConfig.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.scheduling.annotation.EnableAsync; 5 | 6 | @Configuration 7 | @EnableAsync 8 | public class AsyncConfig { 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/config/CORSConfig.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.config; 2 | 3 | import cn.iyque.interceptor.ReadOnlyInterceptor; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.web.servlet.config.annotation.CorsRegistry; 7 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 8 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 9 | 10 | @Configuration 11 | public class CORSConfig implements WebMvcConfigurer { 12 | 13 | @Autowired 14 | private ReadOnlyInterceptor readOnlyInterceptor; 15 | 16 | @Override 17 | public void addCorsMappings(CorsRegistry registry) { 18 | registry.addMapping("/**") // 允许跨域的路径 19 | .allowedOriginPatterns("*") // 允许跨域请求的域名 20 | .allowedMethods("GET", "POST", "PUT", "DELETE") // 允许的请求方法 21 | .allowedHeaders("*") // 允许的请求头 22 | .allowCredentials(true); // 是否允许证书(cookies) 23 | } 24 | 25 | @Override 26 | public void addInterceptors(InterceptorRegistry registry) { 27 | registry.addInterceptor(readOnlyInterceptor) 28 | .addPathPatterns("/**") 29 | .excludePathPatterns("/error"); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/config/JacksonConfig.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.config; 2 | 3 | import com.fasterxml.jackson.databind.MapperFeature; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import com.fasterxml.jackson.databind.PropertyNamingStrategy; 6 | import com.fasterxml.jackson.databind.module.SimpleModule; 7 | import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; 11 | import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; 12 | 13 | 14 | 15 | @Configuration 16 | public class JacksonConfig { 17 | @SuppressWarnings("deprecation") 18 | @Bean 19 | public MappingJackson2HttpMessageConverter jackson2HttpMessageConverter() { 20 | final Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); 21 | /** 22 | * 序列化时,将 null 值不输出 23 | * builder.serializationInclusion(JsonInclude.Include.NON_NULL); 24 | */ 25 | final ObjectMapper objectMapper = builder.build(); 26 | SimpleModule simpleModule = new SimpleModule(); 27 | // Long 转为 String 防止 js 丢失精度 28 | simpleModule.addSerializer(Long.class, ToStringSerializer.instance); 29 | objectMapper.registerModule(simpleModule); 30 | // 忽略 transient 关键词属性 31 | objectMapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true); 32 | return new MappingJackson2HttpMessageConverter(objectMapper); 33 | } 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/config/JwtConfig.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.config; 2 | 3 | 4 | import cn.iyque.interceptor.JwtInterceptor; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.web.servlet.config.annotation.CorsRegistry; 8 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 9 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 10 | 11 | @Configuration 12 | public class JwtConfig implements WebMvcConfigurer { 13 | 14 | @Autowired 15 | private JwtInterceptor jwtInterceptor; 16 | 17 | @Override 18 | public void addInterceptors(InterceptorRegistry registry) { 19 | registry.addInterceptor(jwtInterceptor) 20 | .addPathPatterns("/**") 21 | .excludePathPatterns("/iYqueSys/login","/iycallback/handle/**","/file/fileView/**","/iYqueComplaint/findComplaint" 22 | ,"/iYqueComplaint/addComplaint","/iYqueSys/weComRedirect","/file/openUpload","/iYqueSys/weComLogin","/iYqueSys/threeLogin/findThreeLoginInfo","/iYqueSys/threeLogin/giteeLogin/**","/iYqueSys/threeLogin/giteeLoginRedirectUri"); 23 | } 24 | 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/config/SimpleRedisValidator.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.context.annotation.DependsOn; 6 | import org.springframework.data.redis.connection.RedisConnection; 7 | import org.springframework.data.redis.connection.RedisConnectionFactory; 8 | 9 | @Configuration 10 | public class SimpleRedisValidator { 11 | 12 | @Bean 13 | @DependsOn("redisConnectionFactory") 14 | public String mustHaveRedis(RedisConnectionFactory factory) { 15 | // 简单粗暴的验证方式 16 | try (RedisConnection connection = factory.getConnection()) { 17 | if (!"PONG".equals(connection.ping())) { 18 | throw new IllegalStateException("Redis 连接测试失败"); 19 | } 20 | return "Redis验证通过"; // 随便返回一个非空值 21 | } catch (Exception e) { 22 | throw new IllegalStateException("Redis 服务不可用", e); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/constant/CodeStateConstant.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.constant; 2 | 3 | public class CodeStateConstant { 4 | 5 | //活码渠道前缀 6 | public static final String USER_CODE_STATE="iyQue_"; 7 | 8 | //获客链接渠道前缀 9 | public static final String LINK_CODE_STATE="iyLink_"; 10 | 11 | //群活码渠道前缀 12 | public static final String CHAT_CODE_STATE="iyChat_"; 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/constant/HttpStatus.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.constant; 2 | 3 | /** 4 | * 返回状态码 5 | * 6 | * @author ruoyi 7 | */ 8 | public class HttpStatus 9 | { 10 | /** 11 | * 操作成功 12 | */ 13 | public static final int SUCCESS = 200; 14 | 15 | 16 | /** 17 | * 系统内部错误 18 | */ 19 | public static final int ERROR = 500; 20 | 21 | /** 22 | * 重新登录 23 | */ 24 | public static final int RE_LOGIN = 401; 25 | 26 | 27 | /** 28 | * 获取企微数据失败 29 | */ 30 | public static final int WE_ERROR = 301; 31 | 32 | 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/constant/IYqueContant.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.constant; 2 | 3 | import java.util.Date; 4 | 5 | public class IYqueContant { 6 | 7 | //正常状态 8 | public static final Integer COMMON_STATE=0; 9 | 10 | //删除状态 11 | public static final Integer DEL_STATE=1; 12 | 13 | //用户昵称模版 14 | public static final String USER_NICKNAME_TPL="$客户昵称$"; 15 | 16 | 17 | 18 | //企微api成功返回状态码 19 | public static final Integer WECHAT_API_SUCCESS=0; 20 | 21 | 22 | 23 | //投诉通知模版 24 | public static final String complaintTipTpl= "
%s
投诉类型:%s,联系方式:%s
有客户投诉,建议核实情况,尽快处理。
"; 25 | 26 | 27 | public static void main(String[] args) { 28 | 29 | System.out.println( 30 | String.format(complaintTipTpl,new Date(),"诈骗","18158873850") 31 | ); 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/constant/IYqueWxCpConsts.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.constant; 2 | 3 | 4 | import lombok.Data; 5 | 6 | @Data 7 | public class IYqueWxCpConsts { 8 | 9 | 10 | public static final class KfChangeType { 11 | 12 | public static final String KF_MSG_OR_EVENT = "kf_msg_or_event"; 13 | 14 | 15 | } 16 | 17 | 18 | 19 | 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/constant/WxFileType.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.constant; 2 | 3 | public class WxFileType { 4 | 5 | //图片 6 | public static String IMAGE="image"; 7 | 8 | //语音 9 | public static String VOICE="voice"; 10 | 11 | //视频 12 | public static String VIDEO="video"; 13 | 14 | //普通文件 15 | public static String FILE="file"; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/controller/IYqueCommonController.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.controller; 2 | 3 | import cn.iyque.domain.IYqueKvalVo; 4 | import cn.iyque.domain.ResponseResult; 5 | import cn.iyque.enums.RemarksType; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | import java.util.ArrayList; 11 | import java.util.Arrays; 12 | import java.util.List; 13 | 14 | @RestController 15 | @RequestMapping("/iYqueCommon") 16 | public class IYqueCommonController { 17 | 18 | 19 | /** 20 | * 获取备注相关类型 21 | * @return 22 | */ 23 | @GetMapping("/findRemarksType") 24 | public ResponseResult findRemarksType(){ 25 | List yqueKvalVoList=new ArrayList<>(); 26 | Arrays.stream(RemarksType.values()).forEach(k->{ 27 | yqueKvalVoList.add( 28 | IYqueKvalVo.builder() 29 | .key(k.getCode()) 30 | .val(k.getInfo()) 31 | .build() 32 | ); 33 | }); 34 | 35 | return new ResponseResult(yqueKvalVoList); 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/controller/IYqueConfigController.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.controller; 2 | 3 | 4 | import cn.iyque.config.IYqueParamConfig; 5 | import cn.iyque.constant.HttpStatus; 6 | import cn.iyque.entity.IYqueConfig; 7 | import cn.iyque.domain.ResponseResult; 8 | import cn.iyque.service.IYqueConfigService; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.web.bind.annotation.*; 11 | 12 | 13 | /** 14 | * 系统配置相关 15 | */ 16 | @RestController 17 | @RequestMapping("/iYqueConfig") 18 | public class IYqueConfigController { 19 | 20 | @Autowired 21 | private IYqueConfigService iYqueConfigService; 22 | 23 | 24 | 25 | 26 | /** 27 | * 获取配置 28 | * @return 29 | */ 30 | @GetMapping("/findIYqueConfig") 31 | public ResponseResult findIYqueConfig(){ 32 | return new ResponseResult<>( 33 | iYqueConfigService.findIYqueConfig() 34 | ); 35 | } 36 | 37 | 38 | /** 39 | * 保存或更新配置 40 | * @param iYqueConfig 41 | * @return 42 | */ 43 | @PostMapping("/saveOrUpdate") 44 | public ResponseResult saveOrUpdate(@RequestBody IYqueConfig iYqueConfig){ 45 | 46 | 47 | iYqueConfigService.saveOrUpdate(iYqueConfig); 48 | 49 | return new ResponseResult(); 50 | } 51 | 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/controller/IYqueDefaultMsgController.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.controller; 2 | 3 | 4 | import cn.iyque.entity.IYqueDefaultMsg; 5 | import cn.iyque.domain.ResponseResult; 6 | import cn.iyque.service.IYqueDefaultMsgService; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.web.bind.annotation.*; 9 | 10 | 11 | /** 12 | * 系统默认欢迎语相关 13 | */ 14 | @RestController 15 | @RequestMapping("/iYqueDefaultMsg") 16 | public class IYqueDefaultMsgController { 17 | 18 | @Autowired 19 | private IYqueDefaultMsgService iYqueDefaultMsgService; 20 | 21 | /** 22 | * 获取默认欢迎语 23 | * @return 24 | */ 25 | @GetMapping("/findDefaultMsg") 26 | public ResponseResult findDefaultMsg(){ 27 | return new ResponseResult<>( 28 | iYqueDefaultMsgService.findDefaultMsg() 29 | ); 30 | } 31 | 32 | 33 | /** 34 | * 保存或更新默认欢迎语 35 | * @param iYqueDefaultMsg 36 | * @return 37 | */ 38 | @PostMapping("/saveOrUpdate") 39 | public ResponseResult saveOrUpdate(@RequestBody IYqueDefaultMsg iYqueDefaultMsg){ 40 | iYqueDefaultMsgService.saveOrUpdate(iYqueDefaultMsg); 41 | 42 | return new ResponseResult(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/controller/IYqueTagController.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.controller; 2 | 3 | 4 | import cn.hutool.core.collection.CollectionUtil; 5 | import cn.iyque.constant.HttpStatus; 6 | import cn.iyque.domain.ResponseResult; 7 | import cn.iyque.service.impl.IYqueTagServiceImpl; 8 | import me.chanjar.weixin.cp.bean.WxCpTag; 9 | import me.chanjar.weixin.cp.bean.external.WxCpUserExternalTagGroupInfo; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.web.bind.annotation.GetMapping; 12 | import org.springframework.web.bind.annotation.RequestMapping; 13 | import org.springframework.web.bind.annotation.RestController; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | 19 | /** 20 | * 企微标签 21 | */ 22 | @RestController 23 | @RequestMapping("/iYqueTag") 24 | public class IYqueTagController { 25 | 26 | 27 | 28 | 29 | @Autowired 30 | private IYqueTagServiceImpl iYqueWxCptTagService; 31 | 32 | 33 | /** 34 | * 获取标签 35 | * @return 36 | */ 37 | @GetMapping("/findIYqueTag") 38 | public ResponseResult findIYqueTag(){ 39 | List wxCpTags=new ArrayList<>(); 40 | try { 41 | List wxCpTagList = iYqueWxCptTagService.listAll(); 42 | if(CollectionUtil.isNotEmpty(wxCpTagList)){ 43 | wxCpTags.addAll(wxCpTagList); 44 | } 45 | }catch (Exception e){ 46 | return new ResponseResult(HttpStatus.WE_ERROR,e.getMessage(),null); 47 | } 48 | 49 | 50 | return new ResponseResult(wxCpTags); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/converter/AttachmentConverter.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.converter; 2 | 3 | import cn.iyque.entity.IYqueMsgAnnex; 4 | import me.chanjar.weixin.cp.bean.external.msg.Attachment; 5 | 6 | public interface AttachmentConverter { 7 | Attachment convert(IYqueMsgAnnex annex); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/converter/AttachmentConverterFactory.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.converter; 2 | 3 | import cn.iyque.entity.IYqueMsgAnnex; 4 | 5 | public class AttachmentConverterFactory { 6 | public static AttachmentConverter getConverter(String msgType) { 7 | switch (msgType) { 8 | case IYqueMsgAnnex.MsgType.MSG_TYPE_IMAGE: 9 | return new ImageAttachmentConverter(); 10 | case IYqueMsgAnnex.MsgType.MSG_TYPE_LINK: 11 | return new LinkAttachmentConverter(); 12 | case IYqueMsgAnnex.MsgType.MSG_TYPE_MINIPROGRAM: 13 | return new MiniprogramAttachmentConverter(); 14 | case IYqueMsgAnnex.MsgType.MSG_TYPE_VIDES: 15 | return new VideoAttachmentConverter(); 16 | case IYqueMsgAnnex.MsgType.MSG_TYPE_FILE: 17 | return new FileAttachmentConverter(); 18 | default: 19 | throw new IllegalArgumentException("Unknown message type: " + msgType); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/converter/FileAttachmentConverter.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.converter; 2 | 3 | import cn.hutool.core.util.StrUtil; 4 | import cn.iyque.entity.IYqueMsgAnnex; 5 | import cn.iyque.service.IYqueConfigService; 6 | import cn.iyque.utils.FileUtils; 7 | import cn.iyque.utils.SpringUtils; 8 | import lombok.extern.slf4j.Slf4j; 9 | import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; 10 | import me.chanjar.weixin.cp.bean.external.msg.Attachment; 11 | 12 | import java.io.File; 13 | 14 | 15 | /** 16 | * 文件转换器 17 | */ 18 | @Slf4j 19 | public class FileAttachmentConverter implements AttachmentConverter { 20 | @Override 21 | public Attachment convert(IYqueMsgAnnex annex) { 22 | File file = FileUtils.downloadImage(annex.getFile().getFileUrl()); 23 | if (null != file) { 24 | 25 | try { 26 | WxMediaUploadResult uploadResult = 27 | SpringUtils.getBean(IYqueConfigService.class).findWxcpservice().getMediaService().upload(annex.getMsgtype(), file); 28 | if (null != uploadResult && StrUtil.isNotEmpty(uploadResult.getMediaId())) { 29 | Attachment attachment = new Attachment(); 30 | me.chanjar.weixin.cp.bean.external.msg.File wfile = new me.chanjar.weixin.cp.bean.external.msg.File(); 31 | wfile.setMediaId(uploadResult.getMediaId()); 32 | attachment.setFile(wfile); 33 | return attachment; 34 | } 35 | }catch (Exception e){ 36 | log.error("文件转换器异常:"+e.getMessage()); 37 | } 38 | 39 | } 40 | return null; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/converter/ImageAttachmentConverter.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.converter; 2 | 3 | import cn.hutool.core.util.StrUtil; 4 | import cn.iyque.entity.IYqueMsgAnnex; 5 | import cn.iyque.service.IYqueConfigService; 6 | import cn.iyque.utils.FileUtils; 7 | import cn.iyque.utils.SpringUtils; 8 | import lombok.extern.slf4j.Slf4j; 9 | import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; 10 | import me.chanjar.weixin.cp.bean.external.msg.Attachment; 11 | import me.chanjar.weixin.cp.bean.external.msg.Image; 12 | 13 | import java.io.File; 14 | 15 | /** 16 | * 图片转换器 17 | */ 18 | @Slf4j 19 | public class ImageAttachmentConverter implements AttachmentConverter { 20 | 21 | @Override 22 | public Attachment convert(IYqueMsgAnnex annex) { 23 | File file = FileUtils.downloadImage(annex.getImage().getPicUrl()); 24 | if (null != file) { 25 | 26 | try { 27 | WxMediaUploadResult uploadResult = 28 | SpringUtils.getBean(IYqueConfigService.class).findWxcpservice().getMediaService().upload(annex.getMsgtype(), file); 29 | if (null != uploadResult && StrUtil.isNotEmpty(uploadResult.getMediaId())) { 30 | Attachment attachment = new Attachment(); 31 | Image image = new Image(); 32 | image.setMediaId(uploadResult.getMediaId()); 33 | attachment.setImage(image); 34 | return attachment; 35 | } 36 | }catch (Exception e){ 37 | log.error("图片转换器异常:"+e.getMessage()); 38 | } 39 | 40 | } 41 | return null; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/converter/LinkAttachmentConverter.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.converter; 2 | 3 | import cn.hutool.core.util.StrUtil; 4 | import cn.hutool.extra.spring.SpringUtil; 5 | import cn.iyque.config.IYqueParamConfig; 6 | import cn.iyque.entity.IYqueMsgAnnex; 7 | import lombok.extern.slf4j.Slf4j; 8 | import me.chanjar.weixin.cp.bean.external.msg.Attachment; 9 | import me.chanjar.weixin.cp.bean.external.msg.Link; 10 | 11 | 12 | /** 13 | * 图文转化器 14 | */ 15 | @Slf4j 16 | public class LinkAttachmentConverter implements AttachmentConverter { 17 | @Override 18 | public Attachment convert(IYqueMsgAnnex annex) { 19 | cn.iyque.domain.fileType.Link link = annex.getLink(); 20 | if(null != link && StrUtil.isNotEmpty(link.getTitle()) 21 | && StrUtil.isNotEmpty(link.getUrl())){ 22 | Attachment attachment=new Attachment(); 23 | Link wLink=new Link(); 24 | wLink.setTitle(link.getTitle()); 25 | wLink.setDesc(link.getDesc()); 26 | if(StrUtil.isNotEmpty(link.getPicUrl())){ 27 | if (link.getPicUrl().startsWith("http://") || link.getPicUrl().startsWith("https://")){ 28 | wLink.setPicUrl(link.getPicUrl()); 29 | }else{ 30 | wLink.setPicUrl( SpringUtil.getBean(IYqueParamConfig.class).getFileViewUrl()+link.getPicUrl()); 31 | } 32 | } 33 | wLink.setUrl(link.getUrl()); 34 | attachment.setLink(wLink); 35 | return attachment; 36 | }else{ 37 | log.error("图文消息标题或链接不可为空"); 38 | } 39 | return null; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/converter/VideoAttachmentConverter.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.converter; 2 | 3 | import cn.hutool.core.util.StrUtil; 4 | import cn.hutool.json.JSONUtil; 5 | import cn.iyque.entity.IYqueMsgAnnex; 6 | import cn.iyque.service.IYqueConfigService; 7 | import cn.iyque.utils.FileUtils; 8 | import cn.iyque.utils.SpringUtils; 9 | import lombok.extern.slf4j.Slf4j; 10 | import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; 11 | import me.chanjar.weixin.cp.bean.external.msg.Attachment; 12 | import me.chanjar.weixin.cp.bean.external.msg.Video; 13 | 14 | import java.io.File; 15 | 16 | 17 | /** 18 | * 视频转换器 19 | */ 20 | @Slf4j 21 | public class VideoAttachmentConverter implements AttachmentConverter { 22 | @Override 23 | public Attachment convert(IYqueMsgAnnex annex) { 24 | File file = FileUtils.downloadImage(annex.getVideo().getVideoUrl()); 25 | if (null != file) { 26 | 27 | try { 28 | WxMediaUploadResult uploadResult = 29 | SpringUtils.getBean(IYqueConfigService.class).findWxcpservice().getMediaService().upload(annex.getMsgtype(), file); 30 | if (null != uploadResult && StrUtil.isNotEmpty(uploadResult.getMediaId())) { 31 | Attachment attachment = new Attachment(); 32 | Video video=new Video(); 33 | video.setMediaId(uploadResult.getMediaId()); 34 | attachment.setVideo(video); 35 | return attachment; 36 | } 37 | }catch (Exception e){ 38 | log.error("视频转换器异常:"+e.getMessage()); 39 | } 40 | 41 | } 42 | return null; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYQueComplaintAnnexDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYqueComplainAnnex; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | import java.util.List; 7 | 8 | public interface IYQueComplaintAnnexDao extends JpaRepository { 9 | 10 | List findByComplainId(Long complainId); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYQueComplaintDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYQueComplain; 4 | import cn.iyque.entity.IYqueChatCode; 5 | import cn.iyque.entity.IYqueUser; 6 | import org.springframework.data.domain.Page; 7 | import org.springframework.data.domain.Pageable; 8 | import org.springframework.data.jpa.domain.Specification; 9 | import org.springframework.data.jpa.repository.JpaRepository; 10 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 11 | 12 | public interface IYQueComplaintDao extends JpaRepository , JpaSpecificationExecutor { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYQueComplaintTipDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYQueComplaintTip; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | import java.util.List; 7 | 8 | public interface IYQueComplaintTipDao extends JpaRepository { 9 | 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYQueCustomerInfoDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.domain.IYQueCustomerInfo; 4 | import cn.iyque.domain.IYqueUserCodeCountVo; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | 7 | import java.util.List; 8 | 9 | public interface IYQueCustomerInfoDao extends JpaRepository { 10 | IYQueCustomerInfo findByExternalUseridAndUserId(String externalUserid, String userId); 11 | 12 | 13 | List findByExternalUserid(String externalUserid); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYqueAiAnalysisMsgAuditDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYqueAiAnalysisMsgAudit; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 6 | import org.springframework.data.jpa.repository.Modifying; 7 | import org.springframework.data.jpa.repository.Query; 8 | import org.springframework.data.repository.query.Param; 9 | 10 | import javax.transaction.Transactional; 11 | import java.util.Date; 12 | 13 | public interface IYqueAiAnalysisMsgAuditDao extends JpaRepository , JpaSpecificationExecutor { 14 | 15 | @Modifying 16 | @Transactional 17 | @Query("DELETE FROM iyque_ai_analysis_msg_audit a WHERE a.createTime BETWEEN :startOfDay AND :endOfDay") 18 | void deleteByCreateTimeToday(@Param("startOfDay") Date startOfDay, @Param("endOfDay") Date endOfDay); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYqueAiTokenRecordDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYqueAiTokenRecord; 4 | import cn.iyque.entity.IYqueAnnexPeriod; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 7 | 8 | public interface IYqueAiTokenRecordDao extends JpaRepository , JpaSpecificationExecutor { 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYqueAnalysisHotWordDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYqueAnalysisHotWord; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 6 | import org.springframework.data.jpa.repository.Modifying; 7 | import org.springframework.data.jpa.repository.Query; 8 | import org.springframework.data.repository.query.Param; 9 | 10 | import javax.transaction.Transactional; 11 | import java.util.Date; 12 | import java.util.List; 13 | 14 | public interface IYqueAnalysisHotWordDao extends JpaRepository, JpaSpecificationExecutor { 15 | 16 | 17 | /** 18 | * 根据多个 msgId 删除对应的记录 19 | * @param msgIds 要删除的 msgId 列表 20 | */ 21 | @Modifying 22 | @Transactional 23 | @Query("DELETE FROM iyque_analysis_hot_word y WHERE y.msgId IN :msgIds") 24 | void deleteByMsgIds(@Param("msgIds") List msgIds); 25 | 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYqueAnnexPeriodDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYqueAnnexPeriod; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | import java.util.List; 7 | 8 | public interface IYqueAnnexPeriodDao extends JpaRepository { 9 | List findIYqueAnnexPeriodByMsgId(Long msgId); 10 | 11 | void deleteIYqueAnnexPeriodByMsgId(Long msgId); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYqueCategoryDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYqueCategory; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 6 | 7 | public interface IYqueCategoryDao extends JpaRepository, JpaSpecificationExecutor { 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYqueChatCodeDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYqueChatCode; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface IYqueChatCodeDao extends JpaRepository { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYqueChatDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYqueChat; 4 | import cn.iyque.entity.IYqueUser; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 7 | 8 | import java.util.List; 9 | 10 | public interface IYqueChatDao extends JpaRepository , JpaSpecificationExecutor { 11 | 12 | /** 13 | * 根据群id获取群 14 | * @param chatId 15 | * @return 16 | */ 17 | List findIYqueChatByChatId(String chatId); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYqueConfigDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYqueConfig; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface IYqueConfigDao extends JpaRepository { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYqueDefaultMsgDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYqueDefaultMsg; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface IYqueDefaultMsgDao extends JpaRepository { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYqueGroupMsgDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYqueGroupMsg; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 6 | 7 | public interface IYqueGroupMsgDao extends JpaRepository, JpaSpecificationExecutor { 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYqueGroupMsgSubDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYqueGroupMsgSub; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 6 | 7 | import java.util.List; 8 | 9 | public interface IYqueGroupMsgSubDao extends JpaRepository, JpaSpecificationExecutor { 10 | 11 | List findByGroupMsgId(Long groupMsgId); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYqueHotWordDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYqueHotWord; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 6 | 7 | public interface IYqueHotWordDao extends JpaRepository, JpaSpecificationExecutor { 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYqueKfDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYqueKf; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 6 | 7 | public interface IYqueKfDao extends JpaRepository, JpaSpecificationExecutor { 8 | 9 | IYqueKf findByOpenKfid(String openKfid); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYqueKfMsgDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYqueDefaultMsg; 4 | import cn.iyque.entity.IYqueKfMsg; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | 7 | public interface IYqueKfMsgDao extends JpaRepository { 8 | 9 | IYqueKfMsg findTopByOpenKfidOrderByPullTimeDesc(String openKfid); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYqueKfMsgSubDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYqueKfMsgSub; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 6 | 7 | public interface IYqueKfMsgSubDao extends JpaRepository, JpaSpecificationExecutor { 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYqueKnowledgeAttachDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYqueKnowledgeAttach; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 6 | 7 | public interface IYqueKnowledgeAttachDao extends JpaRepository, JpaSpecificationExecutor { 8 | void deleteByKid(Long kid); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYqueKnowledgeFragmentDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYqueKnowledgeFragment; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 6 | 7 | public interface IYqueKnowledgeFragmentDao extends JpaRepository, JpaSpecificationExecutor { 8 | 9 | 10 | void deleteByKid(Long kid); 11 | 12 | 13 | void deleteByDocId(Long docId); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYqueKnowledgeInfoDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYqueKnowledgeInfo; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 6 | 7 | public interface IYqueKnowledgeInfoDao extends JpaRepository, JpaSpecificationExecutor { 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYqueMsgAnnexDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYqueMsgAnnex; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | import java.util.List; 7 | 8 | public interface IYqueMsgAnnexDao extends JpaRepository { 9 | List findIYqueMsgAnnexByMsgId(Long msgId); 10 | void deleteIYqueMsgAnnexByMsgId(Long msgId); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYqueMsgAuditDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYQueComplain; 4 | import cn.iyque.entity.IYqueMsgAudit; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 7 | 8 | import java.util.Date; 9 | import java.util.List; 10 | 11 | public interface IYqueMsgAuditDao extends JpaRepository , JpaSpecificationExecutor { 12 | 13 | /** 14 | * 获取最新的分页下标 15 | * @return 16 | */ 17 | IYqueMsgAudit findTopByOrderByDataSeqDesc(); 18 | 19 | 20 | /** 21 | * 查询当天凌晨到当前时间的数据 22 | * @param startTime 开始时间 23 | * @param endTime 结束时间 24 | * @param acceptType 25 | * @return 符合条件的消息列表 26 | */ 27 | List findByMsgTimeBetweenAndAcceptType(Date startTime, Date endTime,Integer acceptType); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYqueMsgRuleDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYqueMsgAudit; 4 | import cn.iyque.entity.IYqueMsgRule; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 7 | 8 | import java.util.List; 9 | 10 | public interface IYqueMsgRuleDao extends JpaRepository, JpaSpecificationExecutor { 11 | 12 | /** 13 | * 获取启用或者停用的列表数据 14 | * @param ruleStatus 15 | * @return 16 | */ 17 | List findByRuleStatusAndRuleType(boolean ruleStatus,Integer ruleType); 18 | 19 | 20 | /** 21 | * 22 | * @param ruleType 23 | * @param defaultRule 24 | * @return 25 | */ 26 | long countByRuleTypeAndDefaultRule(Integer ruleType,Boolean defaultRule); 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYquePeriodMsgAnnexDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYquePeriodMsgAnnex; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | import java.util.List; 7 | 8 | public interface IYquePeriodMsgAnnexDao extends JpaRepository { 9 | 10 | List findIYquePeriodMsgAnnexByAnnexPeroidId(Long annexPeroidId); 11 | 12 | 13 | void deleteAllByAnnexPeroidIdIn(List annexPeroidIds); 14 | 15 | 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYqueShortLinkDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYqueShortLink; 4 | import cn.iyque.entity.IYqueUserCode; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | 7 | public interface IYqueShortLinkDao extends JpaRepository { 8 | 9 | IYqueShortLink findByCodeState(String codeState); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYqueUserCodeDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYqueUserCode; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface IYqueUserCodeDao extends JpaRepository { 7 | IYqueUserCode findByCodeState(String codeState); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/dao/IYqueUserDao.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.dao; 2 | 3 | import cn.iyque.entity.IYqueUser; 4 | import org.springframework.data.domain.Page; 5 | import org.springframework.data.domain.Pageable; 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 8 | 9 | import java.util.List; 10 | 11 | public interface IYqueUserDao extends JpaRepository ,JpaSpecificationExecutor { 12 | 13 | 14 | List findIYqueUserByUserId(String userId); 15 | 16 | 17 | List findByUserId(String userId); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/domain/CustomerChatGroup.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.domain; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.List; 6 | 7 | 8 | @Data 9 | public class CustomerChatGroup { 10 | private String customerId; // 客户 ID 11 | private String customerName; // 客户名称 12 | private List contents; // 聊天内容列表 13 | // 构造方法、Getter 和 Setter 14 | public CustomerChatGroup(String customerId, String customerName, List contents) { 15 | this.customerId = customerId; 16 | this.customerName = customerName; 17 | this.contents = contents; 18 | } 19 | 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/domain/DateCount.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.domain; 2 | 3 | import lombok.Data; 4 | import java.util.Date; 5 | 6 | 7 | @Data 8 | public class DateCount { 9 | 10 | private Date date; 11 | private int count; 12 | 13 | public DateCount(Date date, int count) { 14 | this.date = date; 15 | this.count = count; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/domain/EmployeeChatGroup.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.domain; 2 | 3 | 4 | import lombok.Data; 5 | 6 | import java.util.List; 7 | 8 | @Data 9 | public class EmployeeChatGroup { 10 | private String employeeId; // 员工 ID 11 | private String employeeName; // 员工名称 12 | private List customerChatGroups; // 客户分组列表 13 | 14 | // 构造方法、Getter 和 Setter 15 | public EmployeeChatGroup(String employeeId, String employeeName, List customerChatGroups) { 16 | this.employeeId = employeeId; 17 | this.employeeName = employeeName; 18 | this.customerChatGroups = customerChatGroups; 19 | } 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/domain/GiteeTokenResponse.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.domain; 2 | 3 | 4 | import cn.hutool.core.annotation.Alias; 5 | import lombok.Data; 6 | 7 | @Data 8 | public class GiteeTokenResponse { 9 | @Alias("access_token") 10 | private String accessToken; 11 | 12 | @Alias("token_type") 13 | private String tokenType; 14 | 15 | @Alias("expires_in") 16 | private Integer expiresIn; 17 | 18 | @Alias("refresh_token") 19 | private String refreshToken; 20 | 21 | @Alias("scope") 22 | private String scope; 23 | 24 | @Alias("created_at") 25 | private Long createdAt; 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/domain/IYQueAuthInfo.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.domain; 2 | 3 | 4 | import lombok.Data; 5 | 6 | @Data 7 | public class IYQueAuthInfo { 8 | private String username; 9 | private String password; 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/domain/IYQueCallback.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.domain; 2 | 3 | 4 | import lombok.Data; 5 | 6 | @Data 7 | public class IYQueCallback { 8 | private String corpId; 9 | private String msg_signature; 10 | private String timestamp; 11 | private String nonce; 12 | private String echostr; 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/domain/IYQueCallbackQuery.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.domain; 2 | 3 | import lombok.Data; 4 | import org.hibernate.annotations.ColumnDefault; 5 | 6 | @Data 7 | public class IYQueCallbackQuery { 8 | 9 | 10 | //业务id,渠道活码id或者获客短链id 11 | private Long businessId; 12 | 13 | //标签id,多个使用逗号隔开 14 | private String tagId; 15 | 16 | 17 | //标签名 18 | private String tagName; 19 | 20 | 21 | //是否开启时段欢迎语 true:开启时段欢迎语; false:关闭时段欢迎语; 22 | private boolean startPeriodAnnex; 23 | 24 | 25 | //未开启时段欢迎语的附件,如果:startPeriodAnnex 为true 当前字段值为空。 26 | private String weclomeMsg; 27 | 28 | 29 | 30 | //备注名字 31 | private String remarkName; 32 | 33 | 34 | //客户备注类型cn.iyque.enums.RemarksType 35 | private Integer remarkType; 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/domain/IYQueCountQuery.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.domain; 2 | 3 | import lombok.Data; 4 | import org.springframework.format.annotation.DateTimeFormat; 5 | 6 | import java.util.Date; 7 | 8 | 9 | /** 10 | * 统计查询条件 11 | */ 12 | @Data 13 | public class IYQueCountQuery { 14 | private Long userCodeId; 15 | @DateTimeFormat(pattern = "yyyy-MM-dd") 16 | private Date startTime; 17 | @DateTimeFormat(pattern = "yyyy-MM-dd") 18 | private Date endTime; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/domain/IYQueCustomerInfo.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.domain; 2 | 3 | 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | import javax.persistence.Entity; 9 | import javax.persistence.GeneratedValue; 10 | import javax.persistence.GenerationType; 11 | import javax.persistence.Id; 12 | import java.util.Date; 13 | 14 | @Entity(name = "iyque_customer_info") 15 | @Data 16 | @AllArgsConstructor 17 | @NoArgsConstructor 18 | @Builder 19 | public class IYQueCustomerInfo { 20 | //主键为 externalUserid+"&"+userId 21 | @Id 22 | private String eId; 23 | 24 | //客户名称 25 | private String customerName; 26 | 27 | //客户id 28 | private String externalUserid; 29 | 30 | 31 | //添加人id 32 | private String userId; 33 | 34 | 35 | //添加的渠道标识 36 | private String state; 37 | 38 | //添加时间 39 | private Date addTime; 40 | 41 | 42 | // 0正常;1:客户流失;2:员工删除客户 43 | private Integer status; 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/domain/IYQueTrendCount.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.domain; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.List; 6 | 7 | @Data 8 | public class IYQueTrendCount { 9 | private List xData; 10 | private List> series; 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/domain/IYqueAnalysisHotWordTabVo.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.domain; 2 | 3 | 4 | import lombok.Data; 5 | 6 | @Data 7 | public class IYqueAnalysisHotWordTabVo { 8 | 9 | /** 10 | * 讨论总数 11 | */ 12 | private long discussTotalNumber; 13 | 14 | 15 | /** 16 | * 昨日讨论总数 17 | */ 18 | private long ydDiscussTotalNumber; 19 | 20 | 21 | /** 22 | * 昨日客户焦点热词 23 | */ 24 | private String ydHotWord; 25 | 26 | 27 | /** 28 | * 昨日客户焦点类别 29 | */ 30 | private String ydHotWordCategory; 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/domain/IYqueAnalysisHotWordVo.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.domain; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Data 9 | @Builder 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | public class IYqueAnalysisHotWordVo { 13 | //热词 14 | private String hotWord; 15 | 16 | //热词讨论数量 17 | private long hotWordDiscussNumber; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/domain/IYqueCallBackBaseMsg.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.domain; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class IYqueCallBackBaseMsg { 7 | 8 | //企业微信CorpID 9 | private String ToUserName; 10 | 11 | //此事件该值固定为sys 12 | private String FromUserName; 13 | 14 | //消息创建时间 (整型) 15 | private Long CreateTime; 16 | 17 | //消息的类型,此时固定为event 18 | private String MsgType; 19 | 20 | //事件的类型 21 | private String Event; 22 | 23 | //变更类型 24 | private String ChangeType; 25 | 26 | //token 27 | private String Token; 28 | 29 | //应用ID 30 | private String AgentID; 31 | 32 | //企业服务人员的UserID 33 | private String UserID; 34 | 35 | //外部联系人的userid,注意不是企业成员的帐号 36 | private String ExternalUserID; 37 | 38 | //添加此用户的「联系我」方式配置的state参数,可用于识别添加此用户的渠道 39 | private String State; 40 | 41 | 42 | //删除客户的操作来源,DELETE_BY_TRANSFER表示此客户是因在职继承自动被转接成员删除 43 | private String Source; 44 | 45 | //接替失败的原因, customer_refused-客户拒绝, customer_limit_exceed-接替成员的客户数达到上限 46 | private String FailReason; 47 | 48 | 49 | 50 | //有新消息的客服账号。可通过sync_msg接口指定open_kfid获取此客服账号的消息 51 | private String OpenKfId; 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/domain/IYqueKvalStrVo.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.domain; 2 | 3 | 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | @Data 10 | @Builder 11 | @AllArgsConstructor 12 | @NoArgsConstructor 13 | public class IYqueKvalStrVo { 14 | private String key; 15 | private String val; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/domain/IYqueKvalVo.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.domain; 2 | 3 | 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | @Data 10 | @Builder 11 | @AllArgsConstructor 12 | @NoArgsConstructor 13 | public class IYqueKvalVo { 14 | private Integer key; 15 | private String val; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/domain/JwtResponse.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.domain; 2 | 3 | 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | import org.checkerframework.checker.units.qual.N; 9 | 10 | @Data 11 | @Builder 12 | @AllArgsConstructor 13 | @NoArgsConstructor 14 | public class JwtResponse { 15 | 16 | private String token; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/domain/KnowledgeInfoUploadRequest.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.domain; 2 | 3 | import lombok.Data; 4 | import org.springframework.web.multipart.MultipartFile; 5 | 6 | 7 | @Data 8 | public class KnowledgeInfoUploadRequest { 9 | 10 | private Long kid; 11 | 12 | private MultipartFile file; 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/domain/NewContactWay.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.domain; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | import lombok.Data; 5 | import me.chanjar.weixin.cp.bean.external.WxCpContactWayInfo; 6 | 7 | @Data 8 | public class NewContactWay extends WxCpContactWayInfo.ContactWay{ 9 | @SerializedName("is_exclusive") 10 | private Boolean isExclusive; 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/domain/PageDomain.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.domain; 2 | 3 | 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.NoArgsConstructor; 7 | 8 | /** 9 | * 分页数据 10 | * 11 | * @author ruoyi 12 | */ 13 | @Builder 14 | @AllArgsConstructor 15 | @NoArgsConstructor 16 | public class PageDomain { 17 | /** 当前记录起始索引 */ 18 | private Integer pageNum; 19 | 20 | /** 每页显示记录数 */ 21 | private Integer pageSize; 22 | 23 | 24 | 25 | public Integer getPageNum() 26 | { 27 | return pageNum; 28 | } 29 | 30 | public void setPageNum(Integer pageNum) 31 | { 32 | this.pageNum = pageNum; 33 | } 34 | 35 | public Integer getPageSize() 36 | { 37 | return pageSize; 38 | } 39 | 40 | public void setPageSize(Integer pageSize) 41 | { 42 | this.pageSize = pageSize; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/domain/ResponseResult.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.domain; 2 | 3 | import cn.iyque.constant.HttpStatus; 4 | import com.fasterxml.jackson.annotation.JsonInclude; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Builder; 7 | import lombok.Data; 8 | 9 | import java.io.Serializable; 10 | 11 | @JsonInclude(JsonInclude.Include.NON_NULL) 12 | @Data 13 | @Builder 14 | @AllArgsConstructor 15 | public class ResponseResult implements Serializable { 16 | private int code; 17 | private String msg; 18 | private T data; 19 | 20 | private long count; 21 | 22 | public ResponseResult(T data,long count) { 23 | this.code = HttpStatus.SUCCESS; 24 | this.data = data; 25 | this.msg=""; 26 | this.count=count; 27 | } 28 | public ResponseResult(int code, String message, T data) { 29 | this.code = code; 30 | this.msg = message; 31 | this.data = data; 32 | } 33 | 34 | public ResponseResult(T data) { 35 | this.code = HttpStatus.SUCCESS; 36 | this.data = data; 37 | } 38 | 39 | public ResponseResult(String message) { 40 | this.code = HttpStatus.SUCCESS; 41 | this.msg=message; 42 | } 43 | 44 | public ResponseResult(){ 45 | this.code= HttpStatus.SUCCESS; 46 | } 47 | 48 | 49 | 50 | } -------------------------------------------------------------------------------- /src/main/java/cn/iyque/domain/ThreeLoginInfo.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.domain; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Data 9 | @Builder 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | public class ThreeLoginInfo { 13 | //是否启动三方登录,默认是不启动 14 | private boolean startThreeLogin; 15 | 16 | //三方登录地址 17 | private String threeLoginUrl; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/domain/fileType/File.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.domain.fileType; 2 | 3 | import lombok.Data; 4 | 5 | //文件 6 | @Data 7 | public class File{ 8 | //文件地址 9 | private String fileUrl; 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/domain/fileType/Image.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.domain.fileType; 2 | 3 | import lombok.Data; 4 | 5 | //图片 6 | @Data 7 | public class Image { 8 | //图片地址 9 | private String picUrl; 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/domain/fileType/Link.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.domain.fileType; 2 | 3 | import lombok.Data; 4 | 5 | //链接 6 | @Data 7 | public class Link{ 8 | //链接标题 9 | private String title; 10 | //链接封面 11 | private String picUrl; 12 | //链接描述 13 | private String desc; 14 | //链接跳转地址 15 | private String url; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/domain/fileType/Miniprogram.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.domain.fileType; 2 | 3 | import lombok.Data; 4 | 5 | //小程序 6 | @Data 7 | public class Miniprogram{ 8 | //小程序标题 9 | private String title; 10 | //小程序封面地址 11 | private String picUrl; 12 | //小程序id 13 | private String appid; 14 | //小程序页面 15 | private String page; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/domain/fileType/Video.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.domain.fileType; 2 | 3 | import lombok.Data; 4 | 5 | //视频 6 | @Data 7 | public class Video{ 8 | //视频地址 9 | private String videoUrl; 10 | } -------------------------------------------------------------------------------- /src/main/java/cn/iyque/entity/BaseEntity.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.entity; 2 | 3 | 4 | import lombok.Data; 5 | import org.springframework.format.annotation.DateTimeFormat; 6 | import javax.persistence.Transient; 7 | import java.util.Date; 8 | 9 | @Data 10 | public class BaseEntity { 11 | 12 | @Transient 13 | @DateTimeFormat(pattern = "yyyy-MM-dd") 14 | private Date startTime; 15 | 16 | @Transient 17 | @DateTimeFormat(pattern = "yyyy-MM-dd") 18 | private Date endTime; 19 | 20 | //规则类型1:客户规则;2:客群规则 3:意向客户分析 4:意向群友分析 21 | @Transient 22 | private Integer msgAuditType; 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/entity/IYQueComplaintTip.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.entity; 2 | 3 | 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | import org.hibernate.annotations.GenericGenerator; 9 | 10 | import javax.persistence.Entity; 11 | import javax.persistence.GeneratedValue; 12 | import javax.persistence.Id; 13 | import javax.persistence.Transient; 14 | 15 | @Entity(name = "iyque_complain_tip") 16 | @Data 17 | @AllArgsConstructor 18 | @NoArgsConstructor 19 | @Builder 20 | public class IYQueComplaintTip { 21 | @Id 22 | @GeneratedValue(generator = "snowflakeIdGenerator") 23 | @GenericGenerator( 24 | name = "snowflakeIdGenerator", 25 | strategy = "cn.iyque.utils.SnowFlakeUtils" 26 | ) 27 | private Long id; 28 | 29 | //通知的员工id 30 | private String userId; 31 | 32 | //通知员工名称 33 | @Transient 34 | private String userName; 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/entity/IYqueAnnexPeriod.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.entity; 2 | 3 | 4 | import cn.iyque.entity.IYquePeriodMsgAnnex; 5 | import com.fasterxml.jackson.annotation.JsonIgnore; 6 | import lombok.AllArgsConstructor; 7 | import lombok.Builder; 8 | import lombok.Data; 9 | import lombok.NoArgsConstructor; 10 | import org.hibernate.annotations.GenericGenerator; 11 | 12 | import javax.persistence.Entity; 13 | import javax.persistence.GeneratedValue; 14 | import javax.persistence.Id; 15 | import javax.persistence.Transient; 16 | import java.util.List; 17 | 18 | 19 | /** 20 | * 时段欢迎语时段 21 | */ 22 | @Entity(name = "iyque_annex_period") 23 | @Data 24 | @AllArgsConstructor 25 | @NoArgsConstructor 26 | @Builder 27 | public class IYqueAnnexPeriod { 28 | 29 | @Id 30 | @GeneratedValue(generator = "snowflakeIdGenerator") 31 | @GenericGenerator( 32 | name = "snowflakeIdGenerator", 33 | strategy = "cn.iyque.utils.SnowFlakeUtils" 34 | ) 35 | @JsonIgnore 36 | private Long id; 37 | 38 | //欢迎语id 39 | private Long msgId; 40 | 41 | 42 | //周期(1-7,代表周一到周日),多个使用逗号隔开 43 | private String workCycle; 44 | 45 | 46 | //开始时间 47 | private String beginTime; 48 | 49 | //结束时间 50 | private String endTime; 51 | 52 | //欢迎语 53 | private String weclomeMsg; 54 | 55 | //时段附件 56 | @Transient 57 | private List periodMsgAnnexList; 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/entity/IYqueChat.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.entity; 2 | 3 | 4 | import com.fasterxml.jackson.annotation.JsonFormat; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Builder; 7 | import lombok.Data; 8 | import lombok.NoArgsConstructor; 9 | import org.hibernate.annotations.GenericGenerator; 10 | import org.hibernate.annotations.Where; 11 | 12 | import javax.persistence.*; 13 | import java.util.Date; 14 | 15 | @Entity(name = "iyque_chat") 16 | @Data 17 | @AllArgsConstructor 18 | @NoArgsConstructor 19 | @Builder 20 | public class IYqueChat { 21 | 22 | 23 | @Id 24 | @GeneratedValue(generator = "snowflakeIdGenerator") 25 | @GenericGenerator( 26 | name = "snowflakeIdGenerator", 27 | strategy = "cn.iyque.utils.SnowFlakeUtils" 28 | ) 29 | private Long id; 30 | 31 | //群id 32 | private String chatId; 33 | 34 | 35 | //群名 36 | private String chatName; 37 | 38 | 39 | //群主id 40 | private String owner; 41 | 42 | 43 | //群主名称 44 | @Transient 45 | private String ownerName; 46 | 47 | 48 | //群创建时间 49 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") 50 | private Date createTime; 51 | 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/entity/IYqueComplainAnnex.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.entity; 2 | 3 | 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | import org.hibernate.annotations.GenericGenerator; 9 | import org.hibernate.annotations.Where; 10 | 11 | import javax.persistence.Entity; 12 | import javax.persistence.GeneratedValue; 13 | import javax.persistence.Id; 14 | 15 | @Entity(name = "iyque_complain_annex") 16 | @Data 17 | @AllArgsConstructor 18 | @NoArgsConstructor 19 | @Builder 20 | public class IYqueComplainAnnex { 21 | 22 | @Id 23 | @GeneratedValue(generator = "snowflakeIdGenerator") 24 | @GenericGenerator( 25 | name = "snowflakeIdGenerator", 26 | strategy = "cn.iyque.utils.SnowFlakeUtils" 27 | ) 28 | private Long id; 29 | 30 | 31 | //投诉id 32 | private Long complainId; 33 | 34 | //附件类型(1:投诉人;2:处理人) 35 | private Integer annexType; 36 | 37 | //附件地址 38 | private String annexUrl; 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/entity/IYqueConfig.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.entity; 2 | 3 | 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | import org.hibernate.annotations.GenericGenerator; 9 | 10 | import javax.persistence.*; 11 | 12 | @Entity(name = "iyque_config") 13 | @Data 14 | @AllArgsConstructor 15 | @NoArgsConstructor 16 | @Builder 17 | public class IYqueConfig { 18 | @Id 19 | @GeneratedValue(generator = "snowflakeIdGenerator") 20 | @GenericGenerator( 21 | name = "snowflakeIdGenerator", 22 | strategy = "cn.iyque.utils.SnowFlakeUtils" 23 | ) 24 | private Long id; 25 | 26 | private String corpId; 27 | 28 | private String agentId; 29 | 30 | private String agentSecert; 31 | 32 | private String token; 33 | 34 | private String encodingAESKey; 35 | 36 | 37 | 38 | //会话存档sdk路径 39 | private String msgAuditLibPath; 40 | 41 | //消息加密私钥 42 | @Lob 43 | private String msgAuditPriKey; 44 | 45 | 46 | //会话存档Secret 47 | private String msgAuditSecret; 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/entity/IYqueDefaultMsg.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.entity; 2 | 3 | 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | import org.hibernate.annotations.ColumnDefault; 9 | import org.hibernate.annotations.GenericGenerator; 10 | 11 | import javax.persistence.*; 12 | import java.util.List; 13 | 14 | 15 | /** 16 | * 默认欢迎语 17 | */ 18 | @Entity(name = "iyque_default_msg") 19 | @Data 20 | @AllArgsConstructor 21 | @NoArgsConstructor 22 | @Builder 23 | public class IYqueDefaultMsg { 24 | 25 | @Id 26 | @GeneratedValue(generator = "snowflakeIdGenerator") 27 | @GenericGenerator( 28 | name = "snowflakeIdGenerator", 29 | strategy = "cn.iyque.utils.SnowFlakeUtils" 30 | ) 31 | private Long id; 32 | 33 | //是否开启时段欢迎语 true:开启时段欢迎语; false:关闭时段欢迎语; 34 | @ColumnDefault("false") 35 | private boolean startPeriodAnnex; 36 | 37 | 38 | //时段欢迎语的附件 startPeriodAnnex为true则该字段传值 39 | @Transient 40 | private List periodAnnexLists; 41 | 42 | //默认欢迎语 startPeriodAnnex:false 43 | private String defaultContent; 44 | 45 | //欢迎语附件 startPeriodAnnex:false 46 | @Transient 47 | private List annexLists; 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/entity/IYqueDept.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.entity; 2 | 3 | 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | import org.hibernate.annotations.GenericGenerator; 9 | 10 | import javax.persistence.Entity; 11 | import javax.persistence.GeneratedValue; 12 | import javax.persistence.Id; 13 | 14 | @Entity(name = "iyque_dept") 15 | @Data 16 | @AllArgsConstructor 17 | @NoArgsConstructor 18 | @Builder 19 | public class IYqueDept { 20 | @Id 21 | @GeneratedValue(generator = "snowflakeIdGenerator") 22 | @GenericGenerator( 23 | name = "snowflakeIdGenerator", 24 | strategy = "cn.iyque.utils.SnowFlakeUtils" 25 | ) 26 | private Long id; 27 | 28 | 29 | //企微返回的部门id 30 | private String deptWeId; 31 | 32 | 33 | //部门名称 34 | private String deptName; 35 | 36 | 37 | 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/entity/IYqueKfMsg.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.entity; 2 | 3 | 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | import org.hibernate.annotations.GenericGenerator; 9 | 10 | import javax.persistence.Entity; 11 | import javax.persistence.GeneratedValue; 12 | import javax.persistence.Id; 13 | import java.util.Date; 14 | 15 | 16 | /** 17 | * 客服信息拉取记录表 18 | */ 19 | @Entity(name = "iyque_kf_msg") 20 | @Data 21 | @AllArgsConstructor 22 | @NoArgsConstructor 23 | @Builder 24 | public class IYqueKfMsg { 25 | @Id 26 | @GeneratedValue(generator = "snowflakeIdGenerator") 27 | @GenericGenerator( 28 | name = "snowflakeIdGenerator", 29 | strategy = "cn.iyque.utils.SnowFlakeUtils" 30 | ) 31 | private Long id; 32 | 33 | //上一次调用时返回的next_cursor,第一次拉取可以不填。若不填,从3天内最早的消息开始返回 34 | private String cursor; 35 | 36 | 37 | //指定拉取某个客服账号的消息 38 | private String openKfid; 39 | 40 | 41 | 42 | //拉取时间 43 | private Date pullTime; 44 | 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/entity/IYqueKnowledgeAttach.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.entity; 2 | 3 | 4 | import com.fasterxml.jackson.annotation.JsonFormat; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Builder; 7 | import lombok.Data; 8 | import lombok.NoArgsConstructor; 9 | import org.hibernate.annotations.GenericGenerator; 10 | import org.hibernate.annotations.Where; 11 | 12 | import javax.persistence.*; 13 | import java.util.Date; 14 | 15 | 16 | /** 17 | * 知识文档 18 | */ 19 | @Entity(name = "iyque_knowledge_attach") 20 | @Data 21 | @AllArgsConstructor 22 | @NoArgsConstructor 23 | @Builder 24 | @Where(clause = "delFlag = 0") 25 | public class IYqueKnowledgeAttach { 26 | @Id 27 | @GeneratedValue(generator = "snowflakeIdGenerator") 28 | @GenericGenerator( 29 | name = "snowflakeIdGenerator", 30 | strategy = "cn.iyque.utils.SnowFlakeUtils" 31 | ) 32 | private Long id; 33 | 34 | 35 | /** 36 | * 知识库ID 37 | */ 38 | private Long kid; 39 | 40 | 41 | /** 42 | * 文档名称 43 | */ 44 | private String docName; 45 | 46 | /** 47 | * 文档类型 48 | */ 49 | private String docType; 50 | 51 | 52 | 53 | 54 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") 55 | private Date createTime; 56 | 57 | //是否删除标识 58 | private Integer delFlag; 59 | 60 | 61 | @PrePersist 62 | @PreUpdate 63 | private void setDefaultDelFlag() { 64 | if (this.delFlag == null) { 65 | this.delFlag = 0; 66 | } 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/entity/IYqueMsgAudit.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.entity; 2 | 3 | 4 | import com.fasterxml.jackson.annotation.JsonFormat; 5 | import com.fasterxml.jackson.annotation.JsonIgnore; 6 | import lombok.AllArgsConstructor; 7 | import lombok.Builder; 8 | import lombok.Data; 9 | import lombok.NoArgsConstructor; 10 | import org.hibernate.annotations.GenericGenerator; 11 | 12 | import javax.persistence.Entity; 13 | import javax.persistence.GeneratedValue; 14 | import javax.persistence.Id; 15 | import java.util.Date; 16 | 17 | @Entity(name = "iyque_msg_audit") 18 | @Data 19 | @AllArgsConstructor 20 | @NoArgsConstructor 21 | @Builder 22 | public class IYqueMsgAudit extends BaseEntity{ 23 | 24 | 25 | 26 | //对应的消息id 27 | @Id 28 | private String msgId; 29 | 30 | 31 | //消息发送人id 32 | private String fromId; 33 | 34 | //消息发送人名称 35 | private String fromName; 36 | 37 | //消息接收人id 38 | private String acceptId; 39 | 40 | //消息的接受类型:1:客户或成员;2:客群 41 | private Integer acceptType; 42 | 43 | //消息接收人名称 44 | private String acceptName; 45 | 46 | 47 | 48 | //消息类型 49 | private String msgType; 50 | 51 | //消息内容 52 | private String content; 53 | 54 | //当前数据对应的下标 55 | private long dataSeq; 56 | 57 | //消息的发送时间 58 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") 59 | private Date msgTime; 60 | 61 | //当前数据入库创建时间 62 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") 63 | private Date createTime; 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/entity/IYqueUser.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.entity; 2 | 3 | 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | import org.hibernate.annotations.GenericGenerator; 9 | 10 | import javax.persistence.Entity; 11 | import javax.persistence.GeneratedValue; 12 | import javax.persistence.Id; 13 | import javax.persistence.Transient; 14 | 15 | @Entity(name = "iyque_user") 16 | @Data 17 | @AllArgsConstructor 18 | @NoArgsConstructor 19 | @Builder 20 | public class IYqueUser { 21 | 22 | @Id 23 | @GeneratedValue(generator = "snowflakeIdGenerator") 24 | @GenericGenerator( 25 | name = "snowflakeIdGenerator", 26 | strategy = "cn.iyque.utils.SnowFlakeUtils" 27 | ) 28 | private Long id; 29 | 30 | 31 | //员工名称 32 | private String name; 33 | 34 | 35 | //员工对应企微id 36 | private String userId; 37 | 38 | 39 | 40 | //职务 41 | private String position; 42 | 43 | //员工状态:1=已激活,2=已禁用,4=未激活,5=退出企业。 44 | private Integer status; 45 | 46 | 47 | @Transient 48 | private boolean avg=true; 49 | 50 | 51 | 52 | 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/enums/ComplaintAnnexType.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.enums; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public enum ComplaintAnnexType { 7 | 8 | ONE_TYPE(1,"投诉人"), 9 | TWO_TYPE(2,"处理人"); 10 | 11 | 12 | private Integer code; 13 | private String val; 14 | 15 | ComplaintAnnexType(Integer code, String val){ 16 | this.code=code; 17 | this.val=val; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/enums/CustomerStatusType.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.enums; 2 | 3 | /** 4 | * 客户状态 5 | */ 6 | public enum CustomerStatusType { 7 | CUSTOMER_STATUS_TYPE_COMMON(0,"正常"), 8 | CUSTOMER_STATUS_TYPE_LS(1,"客户流失"), 9 | CUSTOMER_STATUS_TYPE_DEL(2,"员工删除客户"); 10 | private final Integer code; 11 | private final String info; 12 | 13 | CustomerStatusType(Integer code, String info) 14 | { 15 | this.code = code; 16 | this.info = info; 17 | } 18 | public Integer getCode() { 19 | return code; 20 | } 21 | 22 | public String getInfo() { 23 | return info; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/enums/GroupMsgSendStatus.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.enums; 2 | 3 | 4 | import lombok.Getter; 5 | 6 | @Getter 7 | public enum GroupMsgSendStatus { 8 | 9 | 10 | 11 | GROUP_MSG_TYPE_WFS(0,0,"未发送"), 12 | GROUP_MSG_TYPE_YFS(1,1,"已发送"), 13 | GROUP_MSG_TYPE_NHY(2,2,"因客户不是好友导致发送失败"), //失败 14 | GROUP_MSG_TYPE_JSSX(2,3,"因客户已经收到其他群发消息导致发送失败"), //失败 15 | GROUP_MSG_TYPE_WX(3,4,"无效或无法发送的external_userid或chatid列表"), //无效 16 | GROUP_MSG_TYPE_FAIL(2,5,"任务构建失败,未返回信息id");//失败 17 | 18 | 19 | 20 | 21 | 22 | private Integer status; 23 | 24 | private Integer statusSub; 25 | 26 | 27 | private String msg; 28 | 29 | 30 | GroupMsgSendStatus(Integer status, Integer statusSub, String msg){ 31 | this.status=status; 32 | this.statusSub=statusSub; 33 | this.msg=msg; 34 | } 35 | 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/enums/KfServiceState.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.enums; 2 | 3 | 4 | import lombok.Data; 5 | import lombok.Getter; 6 | 7 | @Getter 8 | public enum KfServiceState { 9 | 10 | 11 | KF_SERVICE_STATE_WCL(0,"未处理"), 12 | KF_SERVICE_STATE_RGZNJD(1,"由智能助手接待"), 13 | KF_SERVICE_STATE_PDZ(2,"待接入池排队中"), 14 | KF_SERVICE_STATE_RGJD(3,"由人工接待"), 15 | KF_SERVICE_STATE_JJS(4,"已结束/未开始"); 16 | 17 | private Integer state; 18 | private String val; 19 | 20 | KfServiceState(Integer state,String val){ 21 | this.state=state; 22 | this.val=val; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/enums/RemarksType.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.enums; 2 | 3 | 4 | 5 | import java.util.stream.Stream; 6 | 7 | /** 8 | * 客户备注类型 9 | */ 10 | public enum RemarksType { 11 | 12 | REMARKS_TYPE_STATENAME(1,"渠道名"), 13 | REMARKS_TYPE_TAGS(2,"新客标签"), 14 | REMARKS_TYPE_ADDTIME(3,"添加时间"); 15 | 16 | private final Integer code; 17 | private final String info; 18 | 19 | RemarksType(Integer code, String info) 20 | { 21 | this.code = code; 22 | this.info = info; 23 | } 24 | public Integer getCode() { 25 | return code; 26 | } 27 | 28 | public String getInfo() { 29 | return info; 30 | } 31 | 32 | public static RemarksType of(Integer type){ 33 | return Stream.of(values()).filter(s->s.getCode().equals(type)).findFirst().orElseGet(null); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/exception/IYqueException.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.exception; 2 | 3 | 4 | import lombok.Data; 5 | 6 | @Data 7 | public class IYqueException extends RuntimeException { 8 | 9 | private static final long serialVersionUID = 1L; 10 | 11 | protected String msg; 12 | 13 | private Integer code = -1; 14 | 15 | public IYqueException(String msg) 16 | { 17 | this.msg = msg; 18 | } 19 | 20 | public IYqueException(Integer code,String msg) 21 | { 22 | this.code=code; 23 | this.msg = msg; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/handler/GlobalExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.handler; 2 | 3 | import cn.iyque.domain.ResponseResult; 4 | import org.springframework.web.bind.annotation.ExceptionHandler; 5 | import org.springframework.web.bind.annotation.RestControllerAdvice; 6 | 7 | @RestControllerAdvice 8 | public class GlobalExceptionHandler { 9 | 10 | @ExceptionHandler(RuntimeException.class) 11 | public ResponseResult handleRateLimitException(RuntimeException e) { 12 | if (e.getMessage().contains("请求过于频繁") || e.getMessage().contains("IP已被临时锁定")) { 13 | return new ResponseResult(429,e.getMessage(),null); 14 | } 15 | 16 | 17 | return new ResponseResult(500,"登录异常:"+e.getMessage(),null); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/mass/MassSenderFactoryService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.mass; 2 | 3 | import cn.iyque.mass.sender.AbstractMassSender; 4 | import cn.iyque.mass.sender.GroupMassSender; 5 | import org.springframework.stereotype.Component; 6 | 7 | 8 | @Component 9 | public class MassSenderFactoryService { 10 | public AbstractMassSender createSender(String chatType) { 11 | switch (chatType) { 12 | case "group"://客群群发 13 | return new GroupMassSender(); 14 | default: 15 | throw new IllegalArgumentException("不支持的群发类型"); 16 | } 17 | 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/mass/dto/IYqueGroupMsgDto.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.mass.dto; 2 | 3 | 4 | import cn.iyque.entity.IYqueGroupMsg; 5 | import lombok.Data; 6 | import me.chanjar.weixin.cp.bean.external.WxCpMsgTemplate; 7 | 8 | import java.util.List; 9 | 10 | @Data 11 | public class IYqueGroupMsgDto { 12 | //群发基础信息 13 | private IYqueGroupMsg iYqueGroupMsg; 14 | 15 | //群发任务模版 16 | private List wxCpMsgTemplate; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYqueAiService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | import cn.iyque.exception.IYqueException; 4 | import io.github.lnyocly.ai4j.platform.openai.embedding.entity.Embedding; 5 | import io.github.lnyocly.ai4j.platform.openai.embedding.entity.EmbeddingResponse; 6 | 7 | import java.util.List; 8 | 9 | public interface IYqueAiService { 10 | 11 | /** 12 | * 调用ai同步处理通用内容 (单条会话) 13 | * @param content 14 | * @return 15 | */ 16 | String aiHandleCommonContent(String content) throws IYqueException; 17 | 18 | 19 | 20 | 21 | 22 | 23 | /** 24 | * 向量值计算 25 | * @param embedding 26 | * @return 27 | */ 28 | EmbeddingResponse embedding(Embedding embedding); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYqueAiTokenRecordService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | import cn.iyque.entity.IYqueAiTokenRecord; 4 | 5 | public interface IYqueAiTokenRecordService { 6 | 7 | Long getTotalTokensToday(); 8 | 9 | 10 | void save(IYqueAiTokenRecord tokenRecord); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYqueAnalysisHotWordService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | import cn.iyque.domain.IYqueAnalysisHotWordTabVo; 4 | import cn.iyque.domain.IYqueAnalysisHotWordVo; 5 | import cn.iyque.entity.IYqueAnalysisHotWord; 6 | import cn.iyque.entity.IYqueHotWord; 7 | import org.springframework.data.domain.Page; 8 | import org.springframework.data.domain.Pageable; 9 | 10 | import java.util.List; 11 | 12 | public interface IYqueAnalysisHotWordService { 13 | 14 | 15 | /** 16 | * 热词讨论明细 17 | * @param iYqueAnalysisHotWord 18 | * @param pageable 19 | * @return 20 | */ 21 | Page findAll(IYqueAnalysisHotWord iYqueAnalysisHotWord, Pageable pageable); 22 | 23 | 24 | /** 25 | * 热词Top5 26 | * @param iYqueAnalysisHotWord 27 | * @return 28 | */ 29 | List hotWordTop5(IYqueAnalysisHotWord iYqueAnalysisHotWord); 30 | 31 | 32 | /** 33 | * 热词分类top5 34 | * @param iYqueAnalysisHotWord 35 | * @return 36 | */ 37 | List hotWordCategoryTop5(IYqueAnalysisHotWord iYqueAnalysisHotWord); 38 | 39 | 40 | /** 41 | * 获取头部统计tab 42 | * @return 43 | */ 44 | IYqueAnalysisHotWordTabVo findHotWordTab(); 45 | 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYqueAnnexPeriodService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | 4 | 5 | import cn.iyque.entity.IYqueAnnexPeriod; 6 | 7 | import java.util.List; 8 | 9 | public interface IYqueAnnexPeriodService { 10 | void saveAll( List annexLists); 11 | 12 | List findIYqueAnnexPeriodByMsgId(Long msgId); 13 | 14 | 15 | void deleteIYqueAnnexPeriodByMsgId(Long msgId); 16 | 17 | 18 | 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYqueCategoryService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | import cn.iyque.entity.IYqueCategory; 4 | import cn.iyque.entity.IYqueUserCode; 5 | import org.springframework.data.domain.Page; 6 | import org.springframework.data.domain.Pageable; 7 | 8 | import java.util.List; 9 | 10 | public interface IYqueCategoryService { 11 | 12 | 13 | /** 14 | * 获取分类列表 15 | * @return 16 | */ 17 | List findAll(); 18 | 19 | 20 | /** 21 | * 新增或编辑分类 22 | * @param iYqueCategory 23 | */ 24 | void saveOrUpdate(IYqueCategory iYqueCategory); 25 | 26 | 27 | /** 28 | * 删除分类 29 | * @param ids 30 | */ 31 | void batchDelete(Long[] ids); 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYqueChatCodeService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | 4 | import cn.iyque.entity.IYqueChat; 5 | import cn.iyque.entity.IYqueChatCode; 6 | import cn.iyque.entity.IYqueUserCode; 7 | import org.springframework.data.domain.Page; 8 | import org.springframework.data.domain.Pageable; 9 | import org.springframework.web.bind.annotation.PathVariable; 10 | 11 | import java.util.List; 12 | 13 | public interface IYqueChatCodeService { 14 | 15 | 16 | /** 17 | * 群活码列表 18 | * @param pageable 19 | * @return 20 | */ 21 | Page findAll(Pageable pageable); 22 | 23 | 24 | 25 | /** 26 | * 创建群活码 27 | * @param iYqueChatCode 28 | */ 29 | void createChatCode(IYqueChatCode iYqueChatCode) throws Exception; 30 | 31 | 32 | /** 33 | * 更新群活码 34 | * @param iYqueChatCode 35 | * @throws Exception 36 | */ 37 | void updateChatCode(IYqueChatCode iYqueChatCode) throws Exception; 38 | 39 | 40 | 41 | /** 42 | * 删除群活码 43 | * @param ids 44 | */ 45 | void batchDelete(Long[] ids); 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYqueChatService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | import cn.iyque.entity.IYqueChat; 4 | import cn.iyque.entity.IYqueChatCode; 5 | import cn.iyque.entity.IYqueUser; 6 | import org.springframework.data.domain.Page; 7 | import org.springframework.data.domain.Pageable; 8 | 9 | import java.util.List; 10 | 11 | public interface IYqueChatService { 12 | 13 | 14 | 15 | /** 16 | * 获取分页群数据 17 | * @param pageable 18 | * @return 19 | */ 20 | Page findAll(String name, Pageable pageable); 21 | 22 | 23 | /** 24 | * 获取所有群数据 25 | * @return 26 | */ 27 | List findAllIYqueChat(); 28 | 29 | 30 | /** 31 | * 同步客群 32 | */ 33 | void synchIyqueChat(); 34 | 35 | 36 | /** 37 | * 根据群id获取群明细,如果不存在则从企微拉取 38 | * @param chatId 39 | * @return 40 | */ 41 | IYqueChat findOrSaveChat(String chatId); 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYqueConfigService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | import cn.iyque.entity.IYqueConfig; 4 | import cn.iyque.exception.IYqueException; 5 | import me.chanjar.weixin.cp.api.WxCpService; 6 | 7 | public interface IYqueConfigService { 8 | 9 | IYqueConfig findIYqueConfig(); 10 | 11 | void saveOrUpdate(IYqueConfig iYqueConfig); 12 | 13 | WxCpService findWxcpservice() throws Exception; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYqueCustomerInfoService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | import cn.iyque.domain.*; 4 | 5 | import java.util.List; 6 | 7 | public interface IYqueCustomerInfoService { 8 | void addCustomerCallBackAction( IYqueCallBackBaseMsg callBackBaseMsg); 9 | void updateCustomerInfoStatus(String externalUserid,String userId,Integer status); 10 | 11 | IYqueUserCodeCountVo countTotalTab(IYQueCountQuery queCountQuery,boolean codeOrLink); 12 | 13 | IYQueTrendCount countTrend(IYQueCountQuery queCountQuery,boolean codeOrLink); 14 | 15 | List saveCustomer(String externalUserid); 16 | 17 | 18 | IYQueCustomerInfo findCustomerInfoByExternalUserId(String externalUserid); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYqueDefaultMsgService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | import cn.iyque.entity.IYqueDefaultMsg; 4 | import me.chanjar.weixin.cp.bean.external.WxCpWelcomeMsg; 5 | import me.chanjar.weixin.cp.bean.external.msg.Text; 6 | 7 | public interface IYqueDefaultMsgService { 8 | 9 | IYqueDefaultMsg findDefaultMsg(); 10 | 11 | 12 | 13 | void saveOrUpdate(IYqueDefaultMsg iYqueDefaultMsg); 14 | 15 | 16 | 17 | //设置默认欢迎语 18 | void setDefaultMsg(WxCpWelcomeMsg wxCpWelcomeMsg, Text text); 19 | 20 | 21 | 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYqueEmbeddingService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | import java.util.List; 4 | 5 | public interface IYqueEmbeddingService { 6 | 7 | 8 | /** 9 | * 构建向量schema 10 | * @param kid 11 | */ 12 | void createSchema(Long kid); 13 | 14 | 15 | /** 16 | * 保存向量数据库 17 | * @param chunkList 文档按行切分的片段 18 | * @param kid 知识库ID 19 | * @param docId 文档ID 20 | * @param fidList 21 | */ 22 | void storeEmbeddings(List chunkList, String kid, String docId, List fidList); 23 | 24 | 25 | /** 26 | * 删除知识库 27 | * @param kid 28 | */ 29 | void removeByKid(String kid); 30 | 31 | 32 | /** 33 | * 根据内容检索对应的知识库相关数据向量值 34 | * @param query 35 | * @param kid 36 | * @return 37 | */ 38 | List getQueryVector(String query, String kid); 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYqueGiteeOAuthService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | import cn.iyque.domain.GiteeTokenResponse; 4 | 5 | public interface IYqueGiteeOAuthService { 6 | 7 | /** 8 | * 获取请求token 9 | * 10 | * @param code 11 | * @return 12 | */ 13 | GiteeTokenResponse getAccessToken(String code,String redirectUri); 14 | 15 | 16 | /** 17 | * 获取登录token 18 | * 19 | * @param code 20 | * @return 21 | */ 22 | String getIYqueLoginToken(String code,String redirectUri); 23 | 24 | 25 | /** 26 | * 判断指定仓库是否进行了star 27 | * @return 28 | */ 29 | boolean isRepoStarred(String accessToken); 30 | 31 | 32 | /** 33 | * star仓库 34 | * @param accessToken 35 | * @return 36 | */ 37 | boolean starRepository(String accessToken); 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYqueGroupMsgService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | import cn.iyque.entity.IYqueGroupMsg; 4 | import cn.iyque.entity.IYqueUser; 5 | import cn.iyque.exception.IYqueException; 6 | import org.springframework.data.domain.Page; 7 | import org.springframework.data.domain.Pageable; 8 | 9 | public interface IYqueGroupMsgService { 10 | 11 | 12 | /** 13 | * 群发列表 14 | * @param iYqueGroupMsg 15 | * @param pageable 16 | * @return 17 | */ 18 | Page findIYqueGroupMsgPage(IYqueGroupMsg iYqueGroupMsg, Pageable pageable); 19 | 20 | 21 | /** 22 | * 获取群发详情 23 | * @param id 24 | * @return 25 | */ 26 | IYqueGroupMsg findIYqueGroupMsgById(Long id); 27 | 28 | 29 | /** 30 | * 群发构建 31 | * @param iYqueGroupMsg 32 | */ 33 | void buildGroupMsg(IYqueGroupMsg iYqueGroupMsg) throws IYqueException; 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYqueGroupMsgSubService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | public interface IYqueGroupMsgSubService { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYqueHotWordService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | import cn.iyque.entity.BaseEntity; 4 | import cn.iyque.entity.IYqueHotWord; 5 | import org.springframework.data.domain.Page; 6 | import org.springframework.data.domain.Pageable; 7 | 8 | import java.util.List; 9 | 10 | 11 | public interface IYqueHotWordService { 12 | /** 13 | * 获取热词列表 14 | * @return 15 | */ 16 | Page findAll(IYqueHotWord iYqueHotWord, Pageable pageable); 17 | 18 | 19 | /** 20 | * 新增或编辑分类 21 | * @param iYqueHotWord 22 | */ 23 | void saveOrUpdate(IYqueHotWord iYqueHotWord); 24 | 25 | /** 26 | * 获取所有热词 27 | * @return 28 | */ 29 | List findAll(); 30 | 31 | 32 | /** 33 | * 删除分类 34 | * @param ids 35 | */ 36 | void batchDelete(Long[] ids); 37 | 38 | 39 | /** 40 | * ai热词分析 41 | * @param iYqueHotWords 42 | * @param baseEntity 43 | */ 44 | String aiHotWordAnalysis( List iYqueHotWords,BaseEntity baseEntity); 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYqueKfMsgService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | import cn.iyque.entity.IYqueKf; 4 | import cn.iyque.entity.IYqueKfMsgSub; 5 | import cn.iyque.entity.IYqueKnowledgeInfo; 6 | import me.chanjar.weixin.cp.bean.kf.WxCpKfMsgListResp; 7 | import org.springframework.data.domain.Page; 8 | import org.springframework.data.domain.Pageable; 9 | 10 | public interface IYqueKfMsgService { 11 | 12 | /** 13 | * 客户与客服会话信息入库 14 | * @param iyqueKf 15 | * @param item 16 | * @param isArtificial 是否人工 17 | */ 18 | void saveIYqueKfMsg(IYqueKf iyqueKf,WxCpKfMsgListResp.WxCpKfMsgItem item,boolean isArtificial); 19 | 20 | 21 | 22 | 23 | /** 24 | * 客户与客服会话列表 25 | * @param iYqueKfMsgSub 26 | * @param pageable 27 | * @return 28 | */ 29 | Page findAll(IYqueKfMsgSub iYqueKfMsgSub, Pageable pageable); 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYqueKfService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | import cn.iyque.domain.IYqueCallBackBaseMsg; 4 | import cn.iyque.entity.IYqueKf; 5 | import cn.iyque.exception.IYqueException; 6 | import org.springframework.data.domain.Page; 7 | import org.springframework.data.domain.Pageable; 8 | import java.util.List; 9 | 10 | public interface IYqueKfService { 11 | 12 | 13 | 14 | /** 15 | * 获取客服列表 16 | * @param iYqueKf 17 | * @param pageable 18 | * @return 19 | */ 20 | Page findAll(IYqueKf iYqueKf, Pageable pageable); 21 | 22 | 23 | /** 24 | * 处理回调的客服信息 25 | * @param callBackBaseMsg 26 | */ 27 | void handleKfMsg( IYqueCallBackBaseMsg callBackBaseMsg) throws Exception; 28 | 29 | 30 | /** 31 | * 新建或更新客服 32 | * @param iYqueKf 33 | */ 34 | void saveOrUpdateKf(IYqueKf iYqueKf) throws IYqueException; 35 | 36 | 37 | /** 38 | * 删除客服 39 | * @param ids 40 | */ 41 | void batchDelete(List ids); 42 | 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYqueKnowledgeAttachService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | import cn.iyque.entity.IYqueKnowledgeAttach; 4 | import cn.iyque.entity.IYqueKnowledgeInfo; 5 | import org.springframework.data.domain.Page; 6 | import org.springframework.data.domain.Pageable; 7 | 8 | public interface IYqueKnowledgeAttachService { 9 | 10 | /** 11 | * 删除知识附件 12 | */ 13 | void removeKnowledgeAttach(Long docId); 14 | 15 | 16 | 17 | /** 18 | * 获取知识库附件列表 19 | * @param iYqueKnowledgeInfo 20 | * @param pageable 21 | * @return 22 | */ 23 | Page findAll(IYqueKnowledgeAttach iYqueKnowledgeInfo, Pageable pageable); 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYqueKnowledgeFragmentService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | import cn.iyque.entity.IYqueKnowledgeAttach; 4 | import cn.iyque.entity.IYqueKnowledgeFragment; 5 | import org.springframework.data.domain.Page; 6 | import org.springframework.data.domain.Pageable; 7 | 8 | import java.util.List; 9 | 10 | public interface IYqueKnowledgeFragmentService { 11 | 12 | /** 13 | * 获取知识库附件片段列表 14 | * @param iYqueKnowledgeInfo 15 | * @param pageable 16 | * @return 17 | */ 18 | Page findAll(IYqueKnowledgeFragment iYqueKnowledgeInfo, Pageable pageable); 19 | 20 | 21 | /** 22 | * 通过计算向量获取相近的数据 23 | * @param content 问题内容 24 | * @param kid 知识库id 25 | * @return 26 | */ 27 | List nearest(String content,String kid); 28 | 29 | 30 | /** 31 | * 根据主键批量获取存储片段 32 | * @param ids 33 | * @return 34 | */ 35 | 36 | List findAllByIds(List ids); 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYqueKnowledgeInfoService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | import cn.iyque.domain.KnowledgeInfoUploadRequest; 4 | import cn.iyque.entity.IYqueKnowledgeInfo; 5 | import cn.iyque.entity.IYqueMsgAudit; 6 | import org.springframework.data.domain.Page; 7 | import org.springframework.data.domain.Pageable; 8 | 9 | import java.util.List; 10 | 11 | public interface IYqueKnowledgeInfoService { 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | /** 20 | * 获取知识库列表 21 | * @param iYqueKnowledgeInfo 22 | * @param pageable 23 | * @return 24 | */ 25 | Page findAll(IYqueKnowledgeInfo iYqueKnowledgeInfo, Pageable pageable); 26 | 27 | 28 | /** 29 | * 获取所有知识库 30 | * @return 31 | */ 32 | List findAll(); 33 | 34 | 35 | /** 36 | * 新增知识库 37 | * @param iYqueKnowledgeInfo 38 | */ 39 | void saveOrUpdate(IYqueKnowledgeInfo iYqueKnowledgeInfo); 40 | 41 | 42 | /** 43 | * 根据主键获取对应的知识库信息 44 | * @param id 45 | * @return 46 | */ 47 | IYqueKnowledgeInfo findKnowledgeInfoById(Long id); 48 | 49 | 50 | 51 | /** 52 | * 上传附件 53 | */ 54 | void upload(KnowledgeInfoUploadRequest request); 55 | 56 | 57 | /** 58 | * 删除知识库 59 | */ 60 | void removeKnowledge(Long id); 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYqueMsgAnnexService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | import cn.iyque.entity.IYqueMsgAnnex; 4 | import me.chanjar.weixin.cp.bean.external.msg.Attachment; 5 | 6 | import java.util.List; 7 | 8 | public interface IYqueMsgAnnexService { 9 | 10 | List findIYqueMsgAnnexByMsgId(Long msgId); 11 | 12 | void deleteIYqueMsgAnnexByMsgId(Long msgId); 13 | 14 | void saveAll( List annexLists); 15 | List msgAnnexToAttachment(List annexList); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYqueMsgRuleService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | import cn.iyque.entity.IYqueMsgRule; 4 | import org.springframework.data.domain.Page; 5 | import org.springframework.data.domain.Pageable; 6 | 7 | import java.util.List; 8 | 9 | public interface IYqueMsgRuleService { 10 | 11 | /** 12 | * 分页查询规则列表 13 | * @param iYqueMsgRule 14 | * @param pageable 15 | * @return 16 | */ 17 | Page findAll(IYqueMsgRule iYqueMsgRule, Pageable pageable); 18 | 19 | 20 | /** 21 | * 新增或编辑预审规则 22 | * @param iYqueMsgRule 23 | */ 24 | void saveOrUpdateMsgRule(IYqueMsgRule iYqueMsgRule); 25 | 26 | 27 | /** 28 | * 批量删除预审规则 29 | * @param ids 30 | */ 31 | void batchDeleteAiMsgRule(Long[] ids); 32 | 33 | 34 | /** 35 | * 批量启用或停用预审规则 36 | * @param ids 37 | */ 38 | void batchStartOrStop(Long[] ids); 39 | 40 | 41 | /** 42 | * 获取启用或者停用的列表数据 43 | * @param startOrStop 44 | * @return 45 | */ 46 | List findByStartOrStop(boolean startOrStop,Integer ruleType); 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYquePeriodMsgAnnexService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | 4 | import cn.iyque.entity.IYqueMsgAnnex; 5 | import cn.iyque.entity.IYquePeriodMsgAnnex; 6 | import me.chanjar.weixin.cp.bean.external.msg.Attachment; 7 | 8 | import java.util.List; 9 | 10 | public interface IYquePeriodMsgAnnexService { 11 | void saveAll( List annexLists); 12 | 13 | void deleteAllByAnnexPeroidIdIn(List annexPeroidIds); 14 | 15 | /** 16 | * 附件转化为企业微信api所需的附件 17 | * @param annexList 18 | * @return 19 | */ 20 | List msgAnnexToAttachment(List annexList); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYqueShortLinkService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | import cn.iyque.domain.IYqueKvalStrVo; 4 | import cn.iyque.entity.IYqueShortLink; 5 | import cn.iyque.entity.IYqueUserCode; 6 | import org.springframework.data.domain.Page; 7 | import org.springframework.data.domain.Pageable; 8 | 9 | import java.util.List; 10 | 11 | public interface IYqueShortLinkService { 12 | 13 | 14 | Page findAll(Pageable pageable); 15 | 16 | void save(IYqueShortLink shortLink) throws Exception; 17 | 18 | 19 | List findIYqueShorkLinkKvs(); 20 | 21 | 22 | void update(IYqueShortLink shortLink) throws Exception; 23 | 24 | IYqueShortLink findIYqueShortLinkById(Long id); 25 | 26 | void batchDelete(Long[] ids); 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYqueTagService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | import me.chanjar.weixin.common.error.WxErrorException; 4 | import me.chanjar.weixin.cp.bean.WxCpTag; 5 | import me.chanjar.weixin.cp.bean.external.WxCpUserExternalTagGroupInfo; 6 | 7 | import java.util.List; 8 | 9 | public interface IYqueTagService { 10 | 11 | List listAll() throws Exception; 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYqueUserCodeService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | import cn.iyque.domain.IYqueKvalStrVo; 4 | import cn.iyque.domain.IYqueKvalVo; 5 | import cn.iyque.entity.IYqueUserCode; 6 | import me.chanjar.weixin.common.error.WxErrorException; 7 | import org.springframework.data.domain.Page; 8 | import org.springframework.data.domain.Pageable; 9 | 10 | import java.util.List; 11 | 12 | public interface IYqueUserCodeService { 13 | 14 | Page findAll(Pageable pageable); 15 | 16 | void save(IYqueUserCode product) throws Exception; 17 | 18 | List findIYqueUserCodeKvs(); 19 | 20 | void update(IYqueUserCode iYqueUserCode) throws Exception; 21 | 22 | IYqueUserCode findIYqueUserCodeById(Long id); 23 | 24 | void batchDelete(Long[] ids); 25 | 26 | void distributeUserCode(Long id) throws Exception; 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/IYqueUserService.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service; 2 | 3 | import cn.iyque.entity.IYqueUser; 4 | import org.springframework.data.domain.Page; 5 | import org.springframework.data.domain.Pageable; 6 | import java.util.List; 7 | 8 | public interface IYqueUserService { 9 | 10 | /** 11 | * 同步组织架构可见范围的员工 12 | */ 13 | void synchIyqueUser(); 14 | 15 | 16 | /** 17 | * 获取所有成员 18 | * @return 19 | */ 20 | List findIYqueUser(); 21 | 22 | 23 | /** 24 | * 获取成员,如果不存在则从企业微信端获取同时入库 25 | * @param userId 26 | * @return 27 | */ 28 | IYqueUser findOrSaveUser(String userId); 29 | 30 | 31 | /** 32 | * 分页获取成员数据 33 | * @param name 34 | * @param pageable 35 | * @return 36 | */ 37 | Page findIYqueUserPage(String name,Pageable pageable); 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/impl/IYqueAiTokenRecordServiceImpl.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service.impl; 2 | 3 | import cn.iyque.dao.IYqueAiTokenRecordDao; 4 | import cn.iyque.entity.IYqueAiTokenRecord; 5 | import cn.iyque.service.IYqueAiTokenRecordService; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.data.jpa.domain.Specification; 9 | import org.springframework.stereotype.Service; 10 | 11 | 12 | @Service 13 | @Slf4j 14 | public class IYqueAiTokenRecordServiceImpl implements IYqueAiTokenRecordService { 15 | 16 | @Autowired 17 | private IYqueAiTokenRecordDao aiTokenRecordDao; 18 | 19 | 20 | @Override 21 | public Long getTotalTokensToday() { 22 | Specification spec = IYqueAiTokenRecord.hasCreateTimeToday(); 23 | return aiTokenRecordDao.findAll(spec).stream() 24 | .mapToLong(IYqueAiTokenRecord::getTotalTokens) 25 | .sum(); 26 | } 27 | 28 | @Override 29 | public void save(IYqueAiTokenRecord tokenRecord) { 30 | aiTokenRecordDao.save(tokenRecord); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/impl/IYqueConfigServiceImpl.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service.impl; 2 | 3 | import cn.hutool.core.collection.CollectionUtil; 4 | import cn.iyque.dao.IYqueConfigDao; 5 | import cn.iyque.entity.IYqueConfig; 6 | import cn.iyque.service.IYqueConfigService; 7 | import me.chanjar.weixin.cp.api.WxCpService; 8 | import org.apache.commons.lang3.StringUtils; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Service; 11 | 12 | import java.util.List; 13 | 14 | 15 | @Service 16 | public class IYqueConfigServiceImpl implements IYqueConfigService { 17 | 18 | @Autowired 19 | IYqueConfigDao iYqueConfigDao; 20 | @Override 21 | public IYqueConfig findIYqueConfig() { 22 | List iYqueConfigs = iYqueConfigDao.findAll(); 23 | if(CollectionUtil.isEmpty(iYqueConfigs)){ 24 | return new IYqueConfig(); 25 | } 26 | IYqueConfig iYqueConfig = iYqueConfigs.stream().findFirst().get(); 27 | 28 | return iYqueConfig; 29 | } 30 | 31 | @Override 32 | public void saveOrUpdate(IYqueConfig iYqueConfig) { 33 | iYqueConfigDao.saveAndFlush(iYqueConfig); 34 | } 35 | 36 | @Override 37 | public WxCpService findWxcpservice() throws Exception { 38 | 39 | WxCpService config = WxCpServiceFactory.createWxCpService(findIYqueConfig()); 40 | if(null == config){ 41 | throw new Exception("请配置系统应用参数"); 42 | } 43 | 44 | return config; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/impl/IYqueEmbeddingServiceImpl.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service.impl; 2 | 3 | import cn.iyque.chain.vectorizer.Vectorization; 4 | import cn.iyque.chain.vectorstore.IYqueVectorStore; 5 | import cn.iyque.service.IYqueEmbeddingService; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.util.List; 11 | import java.util.stream.Collectors; 12 | 13 | @Service 14 | @Slf4j 15 | public class IYqueEmbeddingServiceImpl implements IYqueEmbeddingService { 16 | 17 | @Autowired 18 | private IYqueVectorStore iYqueVectorStore; 19 | 20 | 21 | @Autowired 22 | private Vectorization vectorization; 23 | 24 | 25 | @Override 26 | public void createSchema(Long kid) { 27 | iYqueVectorStore.newSchema(String.valueOf(kid)); 28 | } 29 | 30 | @Override 31 | public void storeEmbeddings(List chunkList, String kid, String docId, List fidList) { 32 | 33 | List> vectorList = vectorization.batchVectorization(chunkList, kid); 34 | iYqueVectorStore.storeEmbeddings(chunkList,vectorList,kid,docId,fidList); 35 | } 36 | 37 | @Override 38 | public void removeByKid(String kid) { 39 | iYqueVectorStore.removeByKid(kid); 40 | } 41 | 42 | @Override 43 | public List getQueryVector(String query, String kid) { 44 | return vectorization.singleVectorization(query,kid); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/service/impl/IYqueGroupMsgSubServiceImpl.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.service.impl; 2 | 3 | import cn.iyque.service.IYqueGroupMsgSubService; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.stereotype.Service; 6 | 7 | 8 | @Service 9 | @Slf4j 10 | public class IYqueGroupMsgSubServiceImpl implements IYqueGroupMsgSubService { 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/strategy/callback/ActionContext.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.strategy.callback; 2 | 3 | import cn.iyque.domain.IYQueCallbackQuery; 4 | import cn.iyque.domain.IYqueCallBackBaseMsg; 5 | import cn.iyque.entity.IYqueUserCode; 6 | import me.chanjar.weixin.cp.bean.external.contact.WxCpExternalContactInfo; 7 | 8 | public class ActionContext { 9 | private ActionStrategy actionStrategy; 10 | 11 | 12 | 13 | public ActionContext(ActionStrategy actionStrategy) { 14 | this.actionStrategy = actionStrategy; 15 | } 16 | 17 | public void setActionStrategy(ActionStrategy actionStrategy) { 18 | this.actionStrategy = actionStrategy; 19 | } 20 | 21 | public void executeStrategy(IYqueCallBackBaseMsg callBackBaseMsg, IYQueCallbackQuery iyQueCallbackQuery, WxCpExternalContactInfo contactDetail) { 22 | actionStrategy.execute(callBackBaseMsg,iyQueCallbackQuery,contactDetail); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/strategy/callback/ActionStrategy.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.strategy.callback; 2 | 3 | import cn.iyque.domain.IYQueCallbackQuery; 4 | import cn.iyque.domain.IYqueCallBackBaseMsg; 5 | import cn.iyque.entity.IYqueUserCode; 6 | import me.chanjar.weixin.cp.bean.external.contact.WxCpExternalContactInfo; 7 | 8 | public interface ActionStrategy { 9 | void execute(IYqueCallBackBaseMsg callBackBaseMsg, IYQueCallbackQuery iyQueCallbackQuery, WxCpExternalContactInfo contactDetail); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/strategy/callback/MakeTagCustomerStrategy.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.strategy.callback; 2 | 3 | import cn.hutool.core.util.StrUtil; 4 | import cn.hutool.extra.spring.SpringUtil; 5 | import cn.iyque.domain.IYQueCallbackQuery; 6 | import cn.iyque.domain.IYqueCallBackBaseMsg; 7 | import cn.iyque.entity.IYqueUserCode; 8 | import cn.iyque.service.IYqueConfigService; 9 | import lombok.extern.slf4j.Slf4j; 10 | import me.chanjar.weixin.cp.bean.external.contact.WxCpExternalContactInfo; 11 | 12 | 13 | /** 14 | * 自动打标签 15 | */ 16 | @Slf4j 17 | public class MakeTagCustomerStrategy implements ActionStrategy { 18 | @Override 19 | public void execute(IYqueCallBackBaseMsg callBackBaseMsg, IYQueCallbackQuery iyQueCallbackQuery, WxCpExternalContactInfo contactDetail) { 20 | if(null != iyQueCallbackQuery && StrUtil.isNotEmpty(iyQueCallbackQuery.getTagId())){ 21 | try { 22 | SpringUtil.getBean(IYqueConfigService.class).findWxcpservice().getExternalContactService() 23 | .markTag(callBackBaseMsg.getUserID(),callBackBaseMsg.getExternalUserID(),iyQueCallbackQuery.getTagId().split(","),null); 24 | }catch (Exception e){ 25 | log.error("未客户打标签失败:"+e.getMessage()); 26 | } 27 | 28 | } 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/strategy/callback/SaveCustomerStrategy.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.strategy.callback; 2 | 3 | import cn.hutool.extra.spring.SpringUtil; 4 | import cn.iyque.dao.IYQueCustomerInfoDao; 5 | import cn.iyque.domain.IYQueCallbackQuery; 6 | import cn.iyque.domain.IYQueCustomerInfo; 7 | import cn.iyque.domain.IYqueCallBackBaseMsg; 8 | import cn.iyque.entity.IYqueUserCode; 9 | import cn.iyque.enums.CustomerStatusType; 10 | import cn.iyque.service.IYqueConfigService; 11 | import cn.iyque.service.IYqueCustomerInfoService; 12 | import lombok.extern.slf4j.Slf4j; 13 | import me.chanjar.weixin.cp.bean.external.contact.WxCpExternalContactInfo; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | 16 | import java.util.Date; 17 | 18 | 19 | /** 20 | * 客户相关信息入库 21 | */ 22 | @Slf4j 23 | public class SaveCustomerStrategy implements ActionStrategy{ 24 | 25 | 26 | 27 | @Override 28 | public void execute(IYqueCallBackBaseMsg callBackBaseMsg, IYQueCallbackQuery iyQueCallbackQuery, WxCpExternalContactInfo contactDetail) { 29 | 30 | 31 | try { 32 | log.info("客户信息:"+contactDetail); 33 | 34 | 35 | SpringUtil.getBean(IYqueCustomerInfoService.class).saveCustomer(callBackBaseMsg.getExternalUserID()); 36 | 37 | }catch (Exception e){ 38 | log.error("回调客户入库:"+e.getMessage()); 39 | 40 | } 41 | 42 | 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/utils/ByteGroupUtils.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.utils; 2 | 3 | import me.chanjar.weixin.common.util.crypto.ByteGroup; 4 | 5 | import java.util.ArrayList; 6 | 7 | public class ByteGroupUtils { 8 | ArrayList byteContainer = new ArrayList<>(); 9 | 10 | public byte[] toBytes() { 11 | byte[] bytes = new byte[this.byteContainer.size()]; 12 | for (int i = 0; i < this.byteContainer.size(); i++) { 13 | bytes[i] = this.byteContainer.get(i); 14 | } 15 | return bytes; 16 | } 17 | 18 | public ByteGroupUtils addBytes(byte[] bytes) { 19 | for (byte b : bytes) { 20 | this.byteContainer.add(b); 21 | } 22 | return this; 23 | } 24 | 25 | public int size() { 26 | return this.byteContainer.size(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/utils/MapUtils.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.utils; 2 | 3 | import java.util.Set; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | import java.util.function.Function; 6 | import java.util.function.Predicate; 7 | 8 | public class MapUtils { 9 | public static Predicate distinctByKey(Function keyExtractor) { 10 | Set seen = ConcurrentHashMap.newKeySet(); 11 | return t -> seen.add(keyExtractor.apply(t)); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/utils/PKCS7EncoderUtils.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.utils; 2 | 3 | import java.nio.charset.Charset; 4 | import java.nio.charset.StandardCharsets; 5 | import java.util.Arrays; 6 | 7 | public class PKCS7EncoderUtils { 8 | private static final Charset CHARSET = StandardCharsets.UTF_8; 9 | private static final int BLOCK_SIZE = 32; 10 | 11 | /** 12 | * 获得对明文进行补位填充的字节. 13 | * 14 | * @param count 需要进行填充补位操作的明文字节个数 15 | * @return 补齐用的字节数组 16 | */ 17 | public static byte[] encode(int count) { 18 | // 计算需要填充的位数 19 | int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE); 20 | // 获得补位所用的字符 21 | char padChr = chr(amountToPad); 22 | StringBuilder tmp = new StringBuilder(); 23 | for (int index = 0; index < amountToPad; index++) { 24 | tmp.append(padChr); 25 | } 26 | return tmp.toString().getBytes(CHARSET); 27 | } 28 | 29 | /** 30 | * 删除解密后明文的补位字符. 31 | * 32 | * @param decrypted 解密后的明文 33 | * @return 删除补位字符后的明文 34 | */ 35 | public static byte[] decode(byte[] decrypted) { 36 | int pad = decrypted[decrypted.length - 1]; 37 | if (pad < 1 || pad > 32) { 38 | pad = 0; 39 | } 40 | return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad); 41 | } 42 | 43 | /** 44 | * 将数字转化成ASCII码对应的字符,用于对明文进行补码. 45 | * 46 | * @param a 需要转化的数字 47 | * @return 转化得到的字符 48 | */ 49 | private static char chr(int a) { 50 | byte target = (byte) (a & 0xFF); 51 | return (char) target; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/utils/SecurityUtils.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.utils; 2 | 3 | public class SecurityUtils { 4 | 5 | 6 | /** 7 | * 企业微信移动端,当前则代表userId 8 | * @return 9 | */ 10 | public static String getCurrentUserName(){ 11 | 12 | return JwtUtils.getUsernameFromToken(ServletUtils.getToken()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/utils/SnowFlakeUtils.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.utils; 2 | 3 | import cn.hutool.core.lang.Snowflake; 4 | import cn.hutool.core.util.IdUtil; 5 | import org.hibernate.HibernateException; 6 | import org.hibernate.engine.spi.SharedSessionContractImplementor; 7 | import org.hibernate.id.IdentifierGenerator; 8 | 9 | import java.io.Serializable; 10 | 11 | public class SnowFlakeUtils implements IdentifierGenerator { 12 | /** 13 | * 派号器workid:0~31 14 | * 机房datacenterid:0~31 15 | */ 16 | private static Snowflake snowflake = IdUtil.createSnowflake(1, 1); 17 | 18 | public static Long nextId() { 19 | return snowflake.nextId(); 20 | } 21 | 22 | @Override 23 | public Serializable generate(SharedSessionContractImplementor sharedSessionContractImplementor, Object o) throws HibernateException { 24 | 25 | return nextId(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/utils/SpringUtils.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.utils; 2 | 3 | import org.springframework.beans.BeansException; 4 | import org.springframework.context.ApplicationContext; 5 | import org.springframework.context.ApplicationContextAware; 6 | import org.springframework.stereotype.Component; 7 | 8 | @Component 9 | public class SpringUtils implements ApplicationContextAware { 10 | 11 | private static ApplicationContext applicationContext; 12 | 13 | @Override 14 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 15 | SpringUtils.applicationContext = applicationContext; 16 | } 17 | 18 | public static T getBean(Class clazz) { 19 | return applicationContext.getBean(clazz); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/cn/iyque/utils/TableSupport.java: -------------------------------------------------------------------------------- 1 | package cn.iyque.utils; 2 | 3 | 4 | import cn.iyque.domain.PageDomain; 5 | 6 | /** 7 | * 表格数据处理 8 | * 9 | * @author ruoyi 10 | */ 11 | public class TableSupport { 12 | 13 | /** 14 | * 当前记录起始索引 15 | */ 16 | public static final String PAGE_NUM = "page"; 17 | 18 | /** 19 | * 每页显示记录数 20 | */ 21 | public static final String PAGE_SIZE = "size"; 22 | 23 | 24 | 25 | /** 26 | * 封装分页对象 27 | */ 28 | public static PageDomain getPageDomain() 29 | { 30 | PageDomain pageDomain = new PageDomain(); 31 | Integer pageNum = ServletUtils.getParameterToInt(PAGE_NUM); 32 | pageDomain.setPageNum(pageNum==null?0:pageNum-1); 33 | Integer parameterToInt = ServletUtils.getParameterToInt(PAGE_SIZE); 34 | pageDomain.setPageSize(parameterToInt == null?10:ServletUtils.getParameterToInt(PAGE_SIZE)); 35 | return pageDomain; 36 | } 37 | 38 | public static PageDomain buildPageRequest() 39 | { 40 | return getPageDomain(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | # # 2 | # ########## # # # 3 | ## # # ## # ## 4 | # # # # # # ## 5 | # # # # # ## # 6 | ## # ######## ## 7 | # # # # ## 8 | ## ####### ## # # 9 | # # # # ## ########### 10 | # # ####### # # 11 | ### # # ########## 12 | # # # # # # # 13 | # # ## # ## ########## 14 | # # # # # # # 15 | ## # # ############ 16 | # # # 17 | -------------------------------------------------------------------------------- /upload/074824b7-255a-47c5-aa62-48529dacb6b5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/upload/074824b7-255a-47c5-aa62-48529dacb6b5.jpg -------------------------------------------------------------------------------- /upload/09681c07-81a3-49da-ac30-4defb391dae7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/upload/09681c07-81a3-49da-ac30-4defb391dae7.jpg -------------------------------------------------------------------------------- /upload/1916739531953016832.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/upload/1916739531953016832.png -------------------------------------------------------------------------------- /upload/1916740883139661824.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/upload/1916740883139661824.png -------------------------------------------------------------------------------- /upload/1916741426302029824.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/upload/1916741426302029824.png -------------------------------------------------------------------------------- /upload/1916748808138657792.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/upload/1916748808138657792.png -------------------------------------------------------------------------------- /upload/511ed115-66c1-4faa-881d-0be43b6be9cb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/upload/511ed115-66c1-4faa-881d-0be43b6be9cb.jpg -------------------------------------------------------------------------------- /upload/64f1e239-0cca-485a-b4ae-0f0e57776a62.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/upload/64f1e239-0cca-485a-b4ae-0f0e57776a62.jpg -------------------------------------------------------------------------------- /upload/8265c6c6-8438-45ee-b537-52498d3d4f88.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/upload/8265c6c6-8438-45ee-b537-52498d3d4f88.jpg -------------------------------------------------------------------------------- /upload/8768e0ac-0481-4af6-a321-49f60fac3385.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/upload/8768e0ac-0481-4af6-a321-49f60fac3385.jpg -------------------------------------------------------------------------------- /upload/8f353a71-e5a1-4bcd-b540-1344a33f5f9c.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/upload/8f353a71-e5a1-4bcd-b540-1344a33f5f9c.jpg -------------------------------------------------------------------------------- /upload/99e0ddb7-51da-4a03-9261-359e84893ab1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/upload/99e0ddb7-51da-4a03-9261-359e84893ab1.jpg -------------------------------------------------------------------------------- /upload/9f7fe11f-ede5-42c9-b660-1f64cd66d277.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/upload/9f7fe11f-ede5-42c9-b660-1f64cd66d277.jpg -------------------------------------------------------------------------------- /upload/c052be96-7dd1-4d9d-abb3-9cd67e0d9091.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/upload/c052be96-7dd1-4d9d-abb3-9cd67e0d9091.jpg -------------------------------------------------------------------------------- /upload/ef928e04-ffc8-4bcb-8e3d-79c496d252a7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/upload/ef928e04-ffc8-4bcb-8e3d-79c496d252a7.jpg -------------------------------------------------------------------------------- /upload/f0f0337b-9074-43ba-a3fc-4e5537eed403.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IYque/Iyque-SCRM/0eb1c865935e5d4609400f4bd9ca586ea79537b5/upload/f0f0337b-9074-43ba-a3fc-4e5537eed403.jpg --------------------------------------------------------------------------------