├── screenshot ├── 1.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png ├── 6.png ├── 7.png ├── 8.png └── 9.png ├── src └── main │ ├── resources │ ├── public │ │ ├── favicon.ico │ │ ├── js │ │ │ ├── layui-table.js │ │ │ ├── config.js │ │ │ └── ws-im-chat.js │ │ └── css │ │ │ └── public.css │ ├── static │ │ ├── login │ │ │ ├── img │ │ │ │ ├── 1.jpg │ │ │ │ ├── 2.jpg │ │ │ │ ├── 3.jpg │ │ │ │ ├── key.png │ │ │ │ ├── user.png │ │ │ │ └── verify.png │ │ │ ├── login.html │ │ │ └── login.css │ │ ├── layui │ │ │ ├── images │ │ │ │ ├── 0.jpg │ │ │ │ └── face │ │ │ │ │ ├── 0.gif │ │ │ │ │ ├── 1.gif │ │ │ │ │ ├── 2.gif │ │ │ │ │ ├── 3.gif │ │ │ │ │ ├── 4.gif │ │ │ │ │ ├── 5.gif │ │ │ │ │ ├── 6.gif │ │ │ │ │ ├── 7.gif │ │ │ │ │ ├── 8.gif │ │ │ │ │ ├── 9.gif │ │ │ │ │ ├── 10.gif │ │ │ │ │ ├── 11.gif │ │ │ │ │ ├── 12.gif │ │ │ │ │ ├── 13.gif │ │ │ │ │ ├── 14.gif │ │ │ │ │ ├── 15.gif │ │ │ │ │ ├── 16.gif │ │ │ │ │ ├── 17.gif │ │ │ │ │ ├── 18.gif │ │ │ │ │ ├── 19.gif │ │ │ │ │ ├── 20.gif │ │ │ │ │ ├── 21.gif │ │ │ │ │ ├── 22.gif │ │ │ │ │ ├── 23.gif │ │ │ │ │ ├── 24.gif │ │ │ │ │ ├── 25.gif │ │ │ │ │ ├── 26.gif │ │ │ │ │ ├── 27.gif │ │ │ │ │ ├── 28.gif │ │ │ │ │ ├── 29.gif │ │ │ │ │ ├── 30.gif │ │ │ │ │ ├── 31.gif │ │ │ │ │ ├── 32.gif │ │ │ │ │ ├── 33.gif │ │ │ │ │ ├── 34.gif │ │ │ │ │ ├── 35.gif │ │ │ │ │ ├── 36.gif │ │ │ │ │ ├── 37.gif │ │ │ │ │ ├── 38.gif │ │ │ │ │ ├── 39.gif │ │ │ │ │ ├── 40.gif │ │ │ │ │ ├── 41.gif │ │ │ │ │ ├── 42.gif │ │ │ │ │ ├── 43.gif │ │ │ │ │ ├── 44.gif │ │ │ │ │ ├── 45.gif │ │ │ │ │ ├── 46.gif │ │ │ │ │ ├── 47.gif │ │ │ │ │ ├── 48.gif │ │ │ │ │ ├── 49.gif │ │ │ │ │ ├── 50.gif │ │ │ │ │ ├── 51.gif │ │ │ │ │ ├── 52.gif │ │ │ │ │ ├── 53.gif │ │ │ │ │ ├── 54.gif │ │ │ │ │ ├── 55.gif │ │ │ │ │ ├── 56.gif │ │ │ │ │ ├── 57.gif │ │ │ │ │ ├── 58.gif │ │ │ │ │ ├── 59.gif │ │ │ │ │ ├── 60.gif │ │ │ │ │ ├── 61.gif │ │ │ │ │ ├── 62.gif │ │ │ │ │ ├── 63.gif │ │ │ │ │ ├── 64.gif │ │ │ │ │ ├── 65.gif │ │ │ │ │ ├── 66.gif │ │ │ │ │ ├── 67.gif │ │ │ │ │ ├── 68.gif │ │ │ │ │ ├── 69.gif │ │ │ │ │ ├── 70.gif │ │ │ │ │ └── 71.gif │ │ │ ├── font │ │ │ │ ├── iconfont.eot │ │ │ │ ├── iconfont.ttf │ │ │ │ └── iconfont.woff │ │ │ ├── css │ │ │ │ └── modules │ │ │ │ │ ├── laydate │ │ │ │ │ ├── icon.png │ │ │ │ │ └── default │ │ │ │ │ │ └── laydate.css │ │ │ │ │ ├── layim │ │ │ │ │ ├── skin │ │ │ │ │ │ ├── 1.jpg │ │ │ │ │ │ ├── 2.jpg │ │ │ │ │ │ ├── 3.jpg │ │ │ │ │ │ ├── 4.jpg │ │ │ │ │ │ ├── 5.jpg │ │ │ │ │ │ └── logo.jpg │ │ │ │ │ ├── voice │ │ │ │ │ │ └── default.wav │ │ │ │ │ ├── html │ │ │ │ │ │ ├── find.html │ │ │ │ │ │ ├── getmsg.json │ │ │ │ │ │ ├── chatlog.html │ │ │ │ │ │ └── msgbox.html │ │ │ │ │ └── mobile │ │ │ │ │ │ └── layim.css │ │ │ │ │ ├── layer │ │ │ │ │ └── default │ │ │ │ │ │ ├── icon.png │ │ │ │ │ │ ├── icon-ext.png │ │ │ │ │ │ ├── loading-0.gif │ │ │ │ │ │ ├── loading-1.gif │ │ │ │ │ │ └── loading-2.gif │ │ │ │ │ └── code.css │ │ │ ├── lay │ │ │ │ └── modules │ │ │ │ │ ├── code.js │ │ │ │ │ ├── laytpl.js │ │ │ │ │ ├── flow.js │ │ │ │ │ ├── rate.js │ │ │ │ │ ├── tree.js │ │ │ │ │ ├── util.js │ │ │ │ │ ├── carousel.js │ │ │ │ │ ├── laypage.js │ │ │ │ │ ├── upload.js │ │ │ │ │ ├── slider.js │ │ │ │ │ └── element.js │ │ │ └── layui.js │ │ └── json │ │ │ ├── bai_resquest.json │ │ │ └── bai_response.json │ ├── templates │ │ ├── layim │ │ │ ├── find.html │ │ │ ├── chatlog.html │ │ │ └── index.html │ │ └── include.html │ └── application.yaml │ └── java │ └── com │ └── chao │ └── cloud │ └── im │ ├── dal │ ├── mapper │ │ ├── ImMsgMapper.xml │ │ ├── ImDeptMapper.xml │ │ ├── ImGroupMapper.xml │ │ ├── ImUserMapper.xml │ │ ├── ImMsgHisMapper.xml │ │ ├── ImGroupUserMapper.xml │ │ ├── ImMsgMapper.java │ │ ├── ImDeptMapper.java │ │ ├── ImUserMapper.java │ │ ├── ImGroupMapper.java │ │ ├── ImMsgHisMapper.java │ │ └── ImGroupUserMapper.java │ └── entity │ │ ├── ImGroupUser.java │ │ ├── ImDept.java │ │ ├── ImGroup.java │ │ ├── ImMsg.java │ │ ├── ImMsgHis.java │ │ └── ImUser.java │ ├── service │ ├── ImDeptService.java │ ├── ImGroupService.java │ ├── ImUserService.java │ ├── ImGroupUserService.java │ ├── impl │ │ ├── ImDeptServiceImpl.java │ │ ├── ImUserServiceImpl.java │ │ ├── ImGroupServiceImpl.java │ │ ├── ImMsgHisServiceImpl.java │ │ ├── ImGroupUserServiceImpl.java │ │ └── ImMsgServiceImpl.java │ ├── ImMsgService.java │ └── ImMsgHisService.java │ ├── domain │ ├── dto │ │ ├── LayFileDTO.java │ │ └── LoginDTO.java │ └── vo │ │ ├── MsgHisVO.java │ │ └── LoginVO.java │ ├── ai │ ├── model │ │ ├── TAiResp.java │ │ └── BAiResp.java │ ├── config │ │ ├── BAiConfig.java │ │ └── TAiConfig.java │ ├── constant │ │ └── AiConstant.java │ └── service │ │ ├── TAipImageClassifyService.java │ │ ├── TAiRobotService.java │ │ └── AipUnitService.java │ ├── websocket │ ├── constant │ │ ├── MsgConstant.java │ │ ├── MsgEnum.java │ │ └── ImConstant.java │ ├── model │ │ ├── ImMsgDTO.java │ │ ├── WsMsgDTO.java │ │ ├── WsMsgVO.java │ │ └── LayimModel.java │ └── BaseWsSocket.java │ ├── controller │ ├── RobotController.java │ ├── BaseController.java │ ├── MsgHisController.java │ ├── MsgController.java │ ├── UserController.java │ ├── DeptController.java │ ├── GroupController.java │ ├── FileController.java │ ├── LoginController.java │ └── LayimController.java │ └── ChaoCloudImApplication.java ├── .gitattributes ├── license.txt ├── license_996.txt ├── pom.xml └── README.md /screenshot/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/screenshot/1.png -------------------------------------------------------------------------------- /screenshot/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/screenshot/2.png -------------------------------------------------------------------------------- /screenshot/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/screenshot/3.png -------------------------------------------------------------------------------- /screenshot/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/screenshot/4.png -------------------------------------------------------------------------------- /screenshot/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/screenshot/5.png -------------------------------------------------------------------------------- /screenshot/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/screenshot/6.png -------------------------------------------------------------------------------- /screenshot/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/screenshot/7.png -------------------------------------------------------------------------------- /screenshot/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/screenshot/8.png -------------------------------------------------------------------------------- /screenshot/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/screenshot/9.png -------------------------------------------------------------------------------- /src/main/resources/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/public/favicon.ico -------------------------------------------------------------------------------- /src/main/resources/static/login/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/login/img/1.jpg -------------------------------------------------------------------------------- /src/main/resources/static/login/img/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/login/img/2.jpg -------------------------------------------------------------------------------- /src/main/resources/static/login/img/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/login/img/3.jpg -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js linguist-language=java 2 | *.css linguist-language=java 3 | *.html linguist-language=java 4 | *.sql linguist-language=java 5 | -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/0.jpg -------------------------------------------------------------------------------- /src/main/resources/static/login/img/key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/login/img/key.png -------------------------------------------------------------------------------- /src/main/resources/static/login/img/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/login/img/user.png -------------------------------------------------------------------------------- /src/main/resources/static/login/img/verify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/login/img/verify.png -------------------------------------------------------------------------------- /src/main/resources/static/layui/font/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/font/iconfont.eot -------------------------------------------------------------------------------- /src/main/resources/static/layui/font/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/font/iconfont.ttf -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/0.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/0.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/1.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/2.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/3.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/4.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/5.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/6.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/7.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/8.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/8.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/9.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/9.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/font/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/font/iconfont.woff -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/10.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/10.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/11.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/11.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/12.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/12.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/13.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/13.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/14.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/14.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/15.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/15.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/16.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/16.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/17.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/17.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/18.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/18.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/19.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/19.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/20.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/20.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/21.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/21.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/22.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/22.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/23.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/23.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/24.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/24.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/25.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/25.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/26.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/26.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/27.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/27.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/28.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/28.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/29.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/29.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/30.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/30.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/31.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/31.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/32.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/32.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/33.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/33.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/34.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/34.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/35.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/35.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/36.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/36.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/37.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/37.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/38.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/38.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/39.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/39.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/40.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/40.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/41.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/41.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/42.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/42.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/43.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/43.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/44.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/44.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/45.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/45.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/46.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/46.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/47.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/47.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/48.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/48.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/49.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/49.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/50.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/50.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/51.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/51.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/52.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/52.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/53.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/53.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/54.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/54.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/55.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/55.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/56.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/56.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/57.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/57.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/58.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/58.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/59.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/59.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/60.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/60.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/61.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/61.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/62.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/62.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/63.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/63.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/64.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/64.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/65.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/65.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/66.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/66.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/67.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/67.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/68.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/68.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/69.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/69.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/70.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/70.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/images/face/71.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/images/face/71.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/css/modules/laydate/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/css/modules/laydate/icon.png -------------------------------------------------------------------------------- /src/main/resources/static/layui/css/modules/layim/skin/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/css/modules/layim/skin/1.jpg -------------------------------------------------------------------------------- /src/main/resources/static/layui/css/modules/layim/skin/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/css/modules/layim/skin/2.jpg -------------------------------------------------------------------------------- /src/main/resources/static/layui/css/modules/layim/skin/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/css/modules/layim/skin/3.jpg -------------------------------------------------------------------------------- /src/main/resources/static/layui/css/modules/layim/skin/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/css/modules/layim/skin/4.jpg -------------------------------------------------------------------------------- /src/main/resources/static/layui/css/modules/layim/skin/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/css/modules/layim/skin/5.jpg -------------------------------------------------------------------------------- /src/main/resources/static/layui/css/modules/layim/skin/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/css/modules/layim/skin/logo.jpg -------------------------------------------------------------------------------- /src/main/resources/static/layui/css/modules/layer/default/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/css/modules/layer/default/icon.png -------------------------------------------------------------------------------- /src/main/resources/static/layui/css/modules/layim/voice/default.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/css/modules/layim/voice/default.wav -------------------------------------------------------------------------------- /src/main/resources/static/layui/css/modules/layer/default/icon-ext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/css/modules/layer/default/icon-ext.png -------------------------------------------------------------------------------- /src/main/resources/static/layui/css/modules/layer/default/loading-0.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/css/modules/layer/default/loading-0.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/css/modules/layer/default/loading-1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/css/modules/layer/default/loading-1.gif -------------------------------------------------------------------------------- /src/main/resources/static/layui/css/modules/layer/default/loading-2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chaojunzi/chao-cloud-im/HEAD/src/main/resources/static/layui/css/modules/layer/default/loading-2.gif -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/dal/mapper/ImMsgMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/dal/mapper/ImDeptMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/dal/mapper/ImGroupMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/dal/mapper/ImUserMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/dal/mapper/ImMsgHisMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/dal/mapper/ImGroupUserMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/service/ImDeptService.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.service; 2 | 3 | import com.chao.cloud.im.dal.entity.ImDept; 4 | import com.baomidou.mybatisplus.extension.service.IService; 5 | 6 | /** 7 | * @功能: 8 | * @author: 超君子 9 | * @时间:2019-06-26 10 | * @version 1.0.0 11 | */ 12 | public interface ImDeptService extends IService { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/service/ImGroupService.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.service; 2 | 3 | import com.chao.cloud.im.dal.entity.ImGroup; 4 | import com.baomidou.mybatisplus.extension.service.IService; 5 | 6 | /** 7 | * @功能: 8 | * @author: 超君子 9 | * @时间:2019-06-26 10 | * @version 1.0.0 11 | */ 12 | public interface ImGroupService extends IService { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/service/ImUserService.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.service; 2 | 3 | import com.chao.cloud.im.dal.entity.ImUser; 4 | import com.baomidou.mybatisplus.extension.service.IService; 5 | 6 | /** 7 | * @功能: 8 | * @author: 超君子 9 | * @时间:2019-06-26 10 | * @version 1.0.0 11 | */ 12 | public interface ImUserService extends IService { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/domain/dto/LayFileDTO.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.domain.dto; 2 | 3 | import lombok.Builder; 4 | import lombok.Data; 5 | 6 | @Data 7 | @Builder 8 | public class LayFileDTO { 9 | /** 10 | * 图片路径 11 | */ 12 | private String src; 13 | /** 14 | * 图片域名 15 | */ 16 | private String domain; 17 | /** 18 | *文件|图片名称(可选) 19 | */ 20 | private String name; 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/domain/vo/MsgHisVO.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.domain.vo; 2 | 3 | import javax.validation.constraints.NotBlank; 4 | import javax.validation.constraints.NotNull; 5 | 6 | import lombok.Data; 7 | 8 | @Data 9 | public class MsgHisVO { 10 | 11 | @NotNull(message = "对方不能为空") 12 | private Integer id; 13 | @NotBlank(message = "消息类型不能为空") 14 | private String type; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/service/ImGroupUserService.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.service; 2 | 3 | import com.chao.cloud.im.dal.entity.ImGroupUser; 4 | import com.baomidou.mybatisplus.extension.service.IService; 5 | 6 | /** 7 | * @功能: 8 | * @author: 超君子 9 | * @时间:2019-06-27 10 | * @version 1.0.0 11 | */ 12 | public interface ImGroupUserService extends IService { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/domain/vo/LoginVO.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.domain.vo; 2 | 3 | import javax.validation.constraints.NotBlank; 4 | 5 | import lombok.Data; 6 | 7 | @Data 8 | public class LoginVO { 9 | @NotBlank(message = "请输入用户名") 10 | private String userName; 11 | @NotBlank(message = "请输入密码") 12 | private String password; 13 | @NotBlank(message = "请输入验证码") 14 | private String verify; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/dal/mapper/ImMsgMapper.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.dal.mapper; 2 | 3 | import com.chao.cloud.im.dal.entity.ImMsg; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | import org.apache.ibatis.annotations.Mapper; 7 | 8 | /** 9 | * @功能: 10 | * @author: 超君子 11 | * @时间:2019-06-28 12 | * @version 1.0.0 13 | */ 14 | @Mapper 15 | public interface ImMsgMapper extends BaseMapper { 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/dal/mapper/ImDeptMapper.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.dal.mapper; 2 | 3 | import com.chao.cloud.im.dal.entity.ImDept; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | import org.apache.ibatis.annotations.Mapper; 7 | 8 | /** 9 | * @功能: 10 | * @author: 超君子 11 | * @时间:2019-06-26 12 | * @version 1.0.0 13 | */ 14 | @Mapper 15 | public interface ImDeptMapper extends BaseMapper { 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/dal/mapper/ImUserMapper.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.dal.mapper; 2 | 3 | import com.chao.cloud.im.dal.entity.ImUser; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | import org.apache.ibatis.annotations.Mapper; 7 | 8 | /** 9 | * @功能: 10 | * @author: 超君子 11 | * @时间:2019-06-26 12 | * @version 1.0.0 13 | */ 14 | @Mapper 15 | public interface ImUserMapper extends BaseMapper { 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/dal/mapper/ImGroupMapper.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.dal.mapper; 2 | 3 | import com.chao.cloud.im.dal.entity.ImGroup; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | import org.apache.ibatis.annotations.Mapper; 7 | 8 | /** 9 | * @功能: 10 | * @author: 超君子 11 | * @时间:2019-06-26 12 | * @version 1.0.0 13 | */ 14 | @Mapper 15 | public interface ImGroupMapper extends BaseMapper { 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/dal/mapper/ImMsgHisMapper.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.dal.mapper; 2 | 3 | import com.chao.cloud.im.dal.entity.ImMsgHis; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | import org.apache.ibatis.annotations.Mapper; 7 | 8 | /** 9 | * @功能: 10 | * @author: 超君子 11 | * @时间:2019-06-28 12 | * @version 1.0.0 13 | */ 14 | @Mapper 15 | public interface ImMsgHisMapper extends BaseMapper { 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/dal/mapper/ImGroupUserMapper.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.dal.mapper; 2 | 3 | import com.chao.cloud.im.dal.entity.ImGroupUser; 4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 5 | 6 | import org.apache.ibatis.annotations.Mapper; 7 | 8 | /** 9 | * @功能: 10 | * @author: 超君子 11 | * @时间:2019-06-27 12 | * @version 1.0.0 13 | */ 14 | @Mapper 15 | public interface ImGroupUserMapper extends BaseMapper { 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/ai/model/TAiResp.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.ai.model; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | 7 | { 8 | "ret":0, 9 | "msg":"ok", 10 | "data":{ 11 | "session":"1", 12 | "answer":"呃。。你应该不认得我。。。。。用最末的话说曾经点头之交吧" 13 | } 14 | } 15 | 16 | */ 17 | @Data 18 | public class TAiResp { 19 | private Integer ret; 20 | private String msg; 21 | private ResultData data; 22 | 23 | @Data 24 | public static class ResultData { 25 | private String session; 26 | private String answer; 27 | private String text; 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/websocket/constant/MsgConstant.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.websocket.constant; 2 | 3 | /** 4 | * 消息常量 5 | * @功能: 6 | * @author: 薛超 7 | * @时间:2019年6月19日 8 | * @version 1.0.0 9 | */ 10 | public interface MsgConstant { 11 | 12 | /** 13 | * 未读 14 | */ 15 | Byte NO_READ = 0; 16 | /** 17 | * 已读 18 | */ 19 | Byte IS_READ = 1; 20 | /** 21 | * 图片正则 22 | */ 23 | String LAYIM_IMG_REGEX = "^img\\[(.*)\\]$"; 24 | /** 25 | * 文件正则 26 | */ 27 | String LAYIM_FILE_REGEX = "^file\\((.*)\\)\\[.*\\]$"; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/websocket/constant/MsgEnum.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.websocket.constant; 2 | 3 | /** 4 | * 5 | * @功能:消息类型 6 | * @author: 薛超 7 | * @时间: 2019年6月27日 8 | * @version 1.0.0 9 | */ 10 | public enum MsgEnum { 11 | 12 | CLOSE(0), // 关闭 13 | START(1), // 开始连接 14 | TIPS(2), // 提示 15 | ON_LINE(3), // 上线 16 | OFF_LINE(4), // 下线 17 | CHAT(5), // 聊天 18 | OFF_MSG(6), // 离线消息 19 | OTHER_INPUT(7), // 对方正在输入 20 | ; 21 | 22 | public Integer type; 23 | 24 | MsgEnum(Integer type) { 25 | this.type = type; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/resources/static/json/bai_resquest.json: -------------------------------------------------------------------------------- 1 | { 2 | "log_id": "UNITTEST_10000", 3 | "version": "2.0", 4 | "service_id": "S19840", 5 | "session_id": "S19840", 6 | "comment": "@65204-名词解释@65192-问候65191-闲聊", 7 | "skill_ids": [ 8 | "65204", 9 | "65192", 10 | "65191" 11 | ], 12 | "request": { 13 | "comment": "query 为请求参数@ user_id 内部唯一id", 14 | "query": "{}", 15 | "user_id": "{}" 16 | }, 17 | "dialog_state": { 18 | "contexts": { 19 | "SYS_REMEMBERED_SKILLS": [ 20 | "65204", 21 | "65192", 22 | "65191" 23 | ] 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/main/resources/static/json/bai_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "result": [ 3 | { 4 | "score": 0.787093, 5 | "root": "公众人物", 6 | "keyword": "棒球大联盟" 7 | }, 8 | { 9 | "score": 0.63665, 10 | "root": "人物-人物特写", 11 | "keyword": "美女" 12 | }, 13 | { 14 | "score": 0.411692, 15 | "root": "非自然图像-彩色动漫", 16 | "keyword": "卡通动漫人物" 17 | }, 18 | { 19 | "score": 0.201531, 20 | "root": "商品-绘画", 21 | "keyword": "图画" 22 | }, 23 | { 24 | "score": 0.035233, 25 | "root": "商品-玩具", 26 | "keyword": "芭芘娃娃" 27 | } 28 | ], 29 | "log_id": 1749032318028241221, 30 | "result_num": 5 31 | } -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/service/impl/ImDeptServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.service.impl; 2 | 3 | import com.chao.cloud.im.dal.entity.ImDept; 4 | import com.chao.cloud.im.dal.mapper.ImDeptMapper; 5 | import com.chao.cloud.im.service.ImDeptService; 6 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 7 | import org.springframework.stereotype.Service; 8 | 9 | /** 10 | * @功能: 11 | * @author: 超君子 12 | * @时间:2019-06-26 13 | * @version 1.0.0 14 | */ 15 | @Service 16 | public class ImDeptServiceImpl extends ServiceImpl implements ImDeptService { 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/service/impl/ImUserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.service.impl; 2 | 3 | import com.chao.cloud.im.dal.entity.ImUser; 4 | import com.chao.cloud.im.dal.mapper.ImUserMapper; 5 | import com.chao.cloud.im.service.ImUserService; 6 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 7 | import org.springframework.stereotype.Service; 8 | 9 | /** 10 | * @功能: 11 | * @author: 超君子 12 | * @时间:2019-06-26 13 | * @version 1.0.0 14 | */ 15 | @Service 16 | public class ImUserServiceImpl extends ServiceImpl implements ImUserService { 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/domain/dto/LoginDTO.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.domain.dto; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class LoginDTO { 7 | 8 | private Integer id; 9 | 10 | /** 11 | * 用户名 12 | */ 13 | private String userName; 14 | 15 | /** 16 | * 密码 17 | */ 18 | private transient String password; 19 | 20 | /** 21 | * 昵称 22 | */ 23 | private String nickName; 24 | 25 | /** 26 | * 签名 27 | */ 28 | private String sign; 29 | 30 | /** 31 | * 头像 32 | */ 33 | private String headImg; 34 | 35 | /** 36 | * 状态 0.冻结 1.正常 37 | */ 38 | private Integer status; 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/service/ImMsgService.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.service; 2 | 3 | import java.util.List; 4 | 5 | import com.baomidou.mybatisplus.extension.service.IService; 6 | import com.chao.cloud.im.dal.entity.ImMsg; 7 | import com.chao.cloud.im.websocket.model.WsMsgVO; 8 | 9 | /** 10 | * @功能: 11 | * @author: 超君子 12 | * @时间:2019-06-26 13 | * @version 1.0.0 14 | */ 15 | public interface ImMsgService extends IService { 16 | 17 | /** 18 | * 添加离线消息 19 | * @param vo 消息 20 | * @param receiveIds 接收者 21 | */ 22 | void saveOffLineMsg(WsMsgVO vo, List receiveIds); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/service/impl/ImGroupServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.service.impl; 2 | 3 | import com.chao.cloud.im.dal.entity.ImGroup; 4 | import com.chao.cloud.im.dal.mapper.ImGroupMapper; 5 | import com.chao.cloud.im.service.ImGroupService; 6 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 7 | import org.springframework.stereotype.Service; 8 | 9 | /** 10 | * @功能: 11 | * @author: 超君子 12 | * @时间:2019-06-26 13 | * @version 1.0.0 14 | */ 15 | @Service 16 | public class ImGroupServiceImpl extends ServiceImpl implements ImGroupService { 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/service/impl/ImMsgHisServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.service.impl; 2 | 3 | import com.chao.cloud.im.dal.entity.ImMsgHis; 4 | import com.chao.cloud.im.dal.mapper.ImMsgHisMapper; 5 | import com.chao.cloud.im.service.ImMsgHisService; 6 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 7 | import org.springframework.stereotype.Service; 8 | 9 | /** 10 | * @功能: 11 | * @author: 超君子 12 | * @时间:2019-06-28 13 | * @version 1.0.0 14 | */ 15 | @Service 16 | public class ImMsgHisServiceImpl extends ServiceImpl implements ImMsgHisService { 17 | 18 | } 19 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019, xuechao (1521515935@qq.com). 2 |

3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 | use this file except in compliance with the License. You may obtain a copy of 5 | the License at 6 |

7 | https://www.apache.org/licenses/LICENSE-2.0 8 |

9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | License for the specific language governing permissions and limitations under 13 | the License. 14 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/service/ImMsgHisService.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.chao.cloud.im.dal.entity.ImMsgHis; 5 | 6 | import cn.hutool.core.util.StrUtil; 7 | 8 | /** 9 | * @功能: 10 | * @author: 超君子 11 | * @时间:2019-06-28 12 | * @version 1.0.0 13 | */ 14 | public interface ImMsgHisService extends IService { 15 | /** 16 | * 用户类型模板 17 | */ 18 | String USER_TEMPLATE = "{}-{}"; 19 | 20 | static String fromTo(Integer from, Integer to) { 21 | return StrUtil.format(ImMsgHisService.USER_TEMPLATE, from, to); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/service/impl/ImGroupUserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.service.impl; 2 | 3 | import com.chao.cloud.im.dal.entity.ImGroupUser; 4 | import com.chao.cloud.im.dal.mapper.ImGroupUserMapper; 5 | import com.chao.cloud.im.service.ImGroupUserService; 6 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 7 | import org.springframework.stereotype.Service; 8 | 9 | /** 10 | * @功能: 11 | * @author: 超君子 12 | * @时间:2019-06-27 13 | * @version 1.0.0 14 | */ 15 | @Service 16 | public class ImGroupUserServiceImpl extends ServiceImpl implements ImGroupUserService { 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/dal/entity/ImGroupUser.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.dal.entity; 2 | 3 | import java.io.Serializable; 4 | 5 | import lombok.Data; 6 | import lombok.EqualsAndHashCode; 7 | import lombok.experimental.Accessors; 8 | 9 | /** 10 | * @功能: 11 | * @author: 超君子 12 | * @时间:2019-06-27 13 | * @version 1.0.0 14 | */ 15 | @Data 16 | @EqualsAndHashCode(callSuper = false) 17 | @Accessors(chain = true) 18 | public class ImGroupUser implements Serializable { 19 | 20 | private static final long serialVersionUID = 1L; 21 | 22 | /** 23 | * 用户id 24 | */ 25 | private Integer userId; 26 | 27 | /** 28 | * 群id 29 | */ 30 | private Integer groupId; 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/websocket/model/ImMsgDTO.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.websocket.model; 2 | 3 | import java.util.Date; 4 | 5 | import lombok.Data; 6 | 7 | @Data 8 | public class ImMsgDTO { 9 | 10 | /** 11 | * group=群id friend=发送者id 12 | */ 13 | private Integer id; 14 | 15 | /** 16 | * 用户名 17 | */ 18 | private String username; 19 | 20 | /** 21 | * 头像 22 | */ 23 | private String avatar; 24 | 25 | /** 26 | * 消息内容 27 | */ 28 | private String content; 29 | 30 | /** 31 | * 类型 group friend 32 | */ 33 | private String type; 34 | /** 35 | * 时间戳 36 | */ 37 | private transient Date createTime; 38 | 39 | public Long getTimestamp() { 40 | return createTime.getTime(); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/websocket/model/WsMsgDTO.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.websocket.model; 2 | 3 | import com.chao.cloud.im.websocket.constant.MsgEnum; 4 | 5 | import lombok.Data; 6 | 7 | /** 8 | * 返回值 9 | * @功能: 10 | * @author: 薛超 11 | * @时间:2019年6月19日 12 | * @version 1.0.0 13 | */ 14 | @Data 15 | public class WsMsgDTO { 16 | 17 | /** 18 | * 数据类型 19 | */ 20 | private Integer type; 21 | 22 | /** 23 | * 数据内容 24 | */ 25 | private Object msg; 26 | 27 | /** 28 | * 提示消息 29 | * @param msg 30 | * @return 31 | */ 32 | public static WsMsgDTO buildMsg(MsgEnum type, Object msg) { 33 | WsMsgDTO resp = new WsMsgDTO(); 34 | resp.setType(type.type); 35 | resp.setMsg(msg); 36 | return resp; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/resources/templates/layim/find.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |

6 |
7 | 此为自定义的【查找】页面,因需求不一,所以官方暂不提供该模版结构与样式,实际使用时,可移至该文件到你的项目中,对页面自行把控。 8 |
9 | 文件所在目录(相对于layui.js):/css/modules/layim/html/find.html 10 |
11 |
12 |
13 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/main/resources/public/js/layui-table.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 自定义分页参数 3 | */ 4 | var chaoLayuiTable = { 5 | // 请求 6 | request : { 7 | pageName : 'current', // 页码的参数名称,默认:page 8 | limitName : 'size', // 每页数据量的参数名,默认:limit 9 | }, 10 | // 响应 11 | response : { 12 | statusName : 'code', // 规定数据状态的字段名称,默认:code 13 | statusCode : 0000, // 规定成功的状态码,默认:0 14 | msgName : 'msg',// 规定状态信息的字段名称,默认:msg 15 | countName : 'count', // 规定数据总数的字段名称,默认:count 16 | dataName : 'data', // 规定数据列表的字段名称,默认:data 17 | }, 18 | // 数据解析 19 | parseData : function(res) { // res 即为原始返回的数据 20 | return { 21 | "code" : res.retCode, // 解析接口状态 22 | "msg" : res.retMsg, // 解析提示文本 23 | "count" : res.body.total, // 解析数据长度 24 | "data" : res.body.records 25 | // 解析数据列表 26 | }; 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/ai/config/BAiConfig.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.ai.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | import com.chao.cloud.im.ai.service.AipUnitService; 8 | 9 | import lombok.Data; 10 | 11 | @Data 12 | @Configuration 13 | @ConfigurationProperties("chao.cloud.im.bai") 14 | public class BAiConfig { 15 | 16 | private String appId; 17 | private String apiKey; 18 | private String secretKey; // 唯一标识 19 | 20 | @Bean 21 | public AipUnitService AipUnit(BAiConfig config) { 22 | AipUnitService aipUnit = new AipUnitService(config.appId, config.apiKey, config.secretKey); 23 | return aipUnit; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/resources/public/css/public.css: -------------------------------------------------------------------------------- 1 | @CHARSET "UTF-8"; 2 | 3 | .layui-main-height450 { 4 | height: 450px; 5 | } 6 | 7 | .layui-main-height400 { 8 | height: 400px; 9 | } 10 | 11 | .layui-main-height380 { 12 | height: 380px; 13 | } 14 | 15 | .layui-height20 { 16 | height: 20px; 17 | } 18 | 19 | .layui-height80 { 20 | height: 80px; 21 | } 22 | 23 | .layui-padding5 { 24 | padding: 5px; 25 | } 26 | 27 | .layui-margin5 { 28 | margin: 5px; 29 | } 30 | 31 | .layui-padding10 { 32 | padding: 10px; 33 | } 34 | 35 | .layui-margin10 { 36 | margin: 10px; 37 | } 38 | 39 | .layui-padding20 { 40 | padding: 20px; 41 | } 42 | 43 | .layui-margin20 { 44 | margin: 20px; 45 | } 46 | 47 | body { 48 | background-color: #ABABAB; 49 | color: #333333; 50 | font: 12px/150% 'Microsoft YaHei', Arial, Verdana, "宋体"; 51 | font-weight: normal; 52 | } -------------------------------------------------------------------------------- /license_996.txt: -------------------------------------------------------------------------------- 1 | 版权所有 (c) 2019, xuechao (1521515935@qq.com). 2 | 3 | Apache 2.0 License 同时该协议为补充协议,不允许 996 工作制度企业使用该开源软件 4 | 5 | 反996许可证版本1.0 6 | 7 | 在符合下列条件的情况下,特此免费向任何得到本授权作品的副本(包括源代码、文件和/或相关内容,以下 8 | 统称为“授权作品”)的个人和法人实体授权:被授权个人或法人实体有权以任何目的处置授权作品,包括但 9 | 不限于使用、复制,修改,衍生利用、散布,发布和再许可: 10 | 11 | 1. 个人或法人实体必须在许可作品的每个再散布或衍生副本上包含以上版权声明和本许可证,不得自行修 12 | 改。 13 | 2. 个人或法人实体必须严格遵守与个人实际所在地或个人出生地或归化地、或法人实体注册地或经营地 14 | (以较严格者为准)的司法管辖区所有适用的与劳动和就业相关法律、法规、规则和标准。如果该司法管辖 15 | 区没有此类法律、法规、规章和标准或其法律、法规、规章和标准不可执行,则个人或法人实体必须遵守国 16 | 际劳工标准的核心公约。 17 | 3. 个人或法人不得以任何方式诱导、暗示或强迫其全职或兼职员工或其独立承包人以口头或书面形式同意直接或 18 | 间接限制、削弱或放弃其所拥有的,受相关与劳动和就业有关的法律、法规、规则和标准保护的权利或补救 19 | 措施,无论该等书面或口头协议是否被该司法管辖区的法律所承认,该等个人或法人实体也不得以任何方法 20 | 限制其雇员或独立承包人向版权持有人或监督许可证合规情况的有关当局报告或投诉上述违反许可证的行为 21 | 的权利。 22 | 23 | 该授权作品是"按原样"提供,不做任何明示或暗示的保证,包括但不限于对适销性、特定用途适用性和非侵 24 | 权性的保证。在任何情况下,无论是在合同诉讼、侵权诉讼或其他诉讼中,版权持有人均不承担因本软件或 25 | 本软件的使用或其他交易而产生、引起或与之相关的任何索赔、损害或其他责任。 26 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/websocket/constant/ImConstant.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.websocket.constant; 2 | 3 | /** 4 | * 常量 5 | * @功能: 6 | * @author: 薛超 7 | * @时间: 2019年6月26日 8 | * @version 1.0.0 9 | */ 10 | public interface ImConstant { 11 | 12 | String OTHER_INPUT = "对方正在输入..."; 13 | 14 | /** 15 | * 状态 16 | */ 17 | interface Status { 18 | /** 19 | * 冻结 20 | */ 21 | Integer FREEZE = 0; 22 | /** 23 | * 正常 24 | */ 25 | Integer OK = 1; 26 | } 27 | 28 | /** 29 | * 在线状态 30 | */ 31 | interface LineStatus { 32 | /** 33 | * 在线 34 | */ 35 | String ON = "online"; 36 | /** 37 | * 离线 38 | */ 39 | String OFF = "offline"; 40 | } 41 | 42 | /** 43 | * 在线状态 44 | */ 45 | interface Type { 46 | /** 47 | * 群消息 48 | */ 49 | String GROUP = "group"; 50 | /** 51 | * 朋友消息 52 | */ 53 | String FRIEND = "friend"; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/ai/model/BAiResp.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.ai.model; 2 | 3 | import java.util.List; 4 | 5 | import lombok.Data; 6 | 7 | @Data 8 | public class BAiResp { 9 | 10 | private Integer error_code; 11 | private String error_msg; 12 | private Result result; 13 | 14 | @Data 15 | public static class Result { 16 | 17 | private String log_id; 18 | private String interaction_id; 19 | private String version; 20 | private List response_list; 21 | 22 | @Data 23 | public static class Response { 24 | private String msg; 25 | private String origin; // 技能编号 26 | private Schema schema;// 信任度 27 | private List action_list; 28 | 29 | @Data 30 | public static class Schema { 31 | private Double intent_confidence;// 一级准确度 32 | 33 | } 34 | 35 | @Data 36 | public static class Action { 37 | private String say; 38 | private String type;// 返回类型 39 | private Double confidence;// 二级准确度 40 | 41 | } 42 | } 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/controller/RobotController.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.controller; 2 | 3 | import javax.validation.constraints.NotBlank; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.validation.annotation.Validated; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | import com.chao.cloud.common.entity.Response; 11 | import com.chao.cloud.im.ai.service.TAiRobotService; 12 | 13 | /** 14 | * @功能:机器人聊天 15 | * @author: 超君子 16 | * @时间:2019-07-03 17 | * @version 1.0.0 18 | */ 19 | @RequestMapping("/robot") 20 | @RestController 21 | @Validated 22 | public class RobotController { 23 | 24 | @Autowired 25 | private TAiRobotService robotService; 26 | 27 | @RequestMapping("/text") 28 | public Response text(@NotBlank(message = "请输入 text") String text) { 29 | String result = robotService.text(text); 30 | return Response.ok(result); 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /src/main/resources/static/layui/css/modules/layim/html/find.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 发现 9 | 10 | 11 | 14 | 15 | 16 | 17 |
18 |
此为自定义的【查找】页面,因需求不一,所以官方暂不提供该模版结构与样式,实际使用时,可移至该文件到你的项目中,对页面自行把控。 19 |
文件所在目录(相对于layui.js):/css/modules/layim/html/find.html
20 |
21 | 22 | 23 | 24 | 25 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/controller/BaseController.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.controller; 2 | 3 | import javax.servlet.http.HttpSession; 4 | 5 | import com.chao.cloud.common.exception.BusinessException; 6 | import com.chao.cloud.im.domain.dto.LoginDTO; 7 | 8 | /** 9 | * 10 | * @功能: 11 | * @author: 薛超 12 | * @时间: 2019年6月26日 13 | * @version 1.0.0 14 | */ 15 | public abstract class BaseController { 16 | 17 | protected static final String randomCookie = "im-login-cookie:"; 18 | protected static final String token_key = "user"; 19 | 20 | /** 21 | * 获取当前用户 22 | * @return 23 | */ 24 | protected LoginDTO getUser(HttpSession session) { 25 | Object obj = session.getAttribute(token_key); 26 | if (obj instanceof LoginDTO) { 27 | return (LoginDTO) obj; 28 | } 29 | throw new BusinessException("未登录"); 30 | } 31 | 32 | /** 33 | * 是否登录 34 | * @return 35 | */ 36 | protected boolean isLogin(HttpSession session) { 37 | return session.getAttribute(token_key) instanceof LoginDTO; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/resources/static/layui/css/modules/code.css: -------------------------------------------------------------------------------- 1 | /** layui-v2.4.5 MIT License By https://www.layui.com */ 2 | html #layuicss-skincodecss{display:none;position:absolute;width:1989px}.layui-code-h3,.layui-code-view{position:relative;font-size:12px}.layui-code-view{display:block;margin:10px 0;padding:0;border:1px solid #e2e2e2;border-left-width:6px;background-color:#F2F2F2;color:#333;font-family:Courier New}.layui-code-h3{padding:0 10px;height:32px;line-height:32px;border-bottom:1px solid #e2e2e2}.layui-code-h3 a{position:absolute;right:10px;top:0;color:#999}.layui-code-view .layui-code-ol{position:relative;overflow:auto}.layui-code-view .layui-code-ol li{position:relative;margin-left:45px;line-height:20px;padding:0 5px;border-left:1px solid #e2e2e2;list-style-type:decimal-leading-zero;*list-style-type:decimal;background-color:#fff}.layui-code-view pre{margin:0}.layui-code-notepad{border:1px solid #0C0C0C;border-left-color:#3F3F3F;background-color:#0C0C0C;color:#C2BE9E}.layui-code-notepad .layui-code-h3{border-bottom:none}.layui-code-notepad .layui-code-ol li{background-color:#3F3F3F;border-left:none} -------------------------------------------------------------------------------- /src/main/resources/templates/include.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 |
24 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/ai/constant/AiConstant.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.ai.constant; 2 | 3 | import java.util.List; 4 | 5 | import cn.hutool.core.collection.CollUtil; 6 | 7 | /** 8 | * 9 | * @功能: 10 | * @author: 薛超 11 | * @时间: 2019年7月3日 12 | * @version 1.0.0 13 | */ 14 | public interface AiConstant { 15 | 16 | /** 17 | * 机器人白名单 18 | */ 19 | List REBOT_ID_LIST = CollUtil.toList(AiConstant.XUE, AiConstant.CHAO); 20 | 21 | int XUE = 3; 22 | 23 | int CHAO = 4; 24 | 25 | int CONFIDENCE_LIMIT = 50; 26 | /** 27 | * 问候编码 28 | */ 29 | String GREET_CODE = "65192"; 30 | 31 | /** 32 | * 腾讯响应成功返回码 33 | */ 34 | Integer TAI_SUCCESS = 0; 35 | /** 36 | * 错误返回值 37 | */ 38 | String ERROR_RESULT = "抱歉,无法听懂您的描述,请不要输入特殊字符,包括标点符号"; 39 | /** 40 | * 百度api路径 41 | */ 42 | String BAI_URL = "https://aip.baidubce.com/rpc/2.0/unit/service/chat"; 43 | /** 44 | * 百度请求路径 45 | */ 46 | String BAI_REQUEST_TEMPLATE = "static/json/bai_resquest.json"; 47 | /** 48 | * 错误的响应状态 49 | */ 50 | String BAI_ERROR_TYPE = "failure"; 51 | /** 52 | * 要解析的状态 53 | */ 54 | String BAI_OK_TYPE = "(clarify|satisfy|chat)"; 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/ai/config/TAiConfig.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.ai.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | import com.chao.cloud.im.ai.service.TAiRobotService; 8 | import com.chao.cloud.im.ai.service.TAipImageClassifyService; 9 | 10 | import lombok.Data; 11 | 12 | @Data 13 | @Configuration 14 | @ConfigurationProperties("chao.cloud.im.tai") 15 | public class TAiConfig { 16 | 17 | private String appId; 18 | private String appKey; 19 | private String session; // 唯一标识 20 | 21 | @Bean 22 | public TAiRobotService tAiRobotService(TAiConfig config) { 23 | TAiRobotService robotService = new TAiRobotService(); 24 | robotService.setConfig(config); 25 | return robotService; 26 | } 27 | 28 | @Bean 29 | public TAipImageClassifyService tAipImageClassifyService(TAiConfig config) { 30 | TAipImageClassifyService aipImageClassifyService = new TAipImageClassifyService(); 31 | aipImageClassifyService.setConfig(config); 32 | return aipImageClassifyService; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/websocket/model/WsMsgVO.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.websocket.model; 2 | 3 | import java.util.Date; 4 | 5 | import cn.hutool.core.date.DateUtil; 6 | import lombok.Data; 7 | 8 | /** 9 | * 返回值 10 | * @功能: 11 | * @author: 薛超 12 | * @时间:2019年6月19日 13 | * @version 1.0.0 14 | */ 15 | @Data 16 | public class WsMsgVO { 17 | 18 | /** 19 | * 发送人 20 | */ 21 | private Integer fromid; 22 | 23 | /** 24 | * 接收人 25 | */ 26 | private Integer toid; 27 | 28 | /** 29 | * 接收人名称 30 | */ 31 | private String toname; 32 | /** 33 | * 接收人头像 34 | */ 35 | private String toavatar; 36 | 37 | /** 38 | * 以下为页面消息展示使用 39 | */ 40 | private Boolean system; 41 | /** 42 | * 接收者id 43 | */ 44 | private Integer id; 45 | /** 46 | * 发送者名称 47 | */ 48 | private String username; 49 | /** 50 | * 内容 51 | */ 52 | private String content; 53 | /** 54 | * 头像 55 | */ 56 | private String avatar; 57 | /** 58 | * 消息类型 group/friend 59 | */ 60 | private String type; 61 | /** 62 | * 毫秒数 63 | */ 64 | private Date createTime = DateUtil.date(); 65 | 66 | public Long getTimestamp() { 67 | return createTime.getTime(); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/resources/static/layui/lay/modules/code.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.4.5 MIT License By https://www.layui.com */ 2 | ;layui.define("jquery",function(e){"use strict";var a=layui.$,l="http://www.layui.com/doc/modules/code.html";e("code",function(e){var t=[];e=e||{},e.elem=a(e.elem||".layui-code"),e.about=!("about"in e)||e.about,e.elem.each(function(){t.push(this)}),layui.each(t.reverse(),function(t,i){var c=a(i),o=c.html();(c.attr("lay-encode")||e.encode)&&(o=o.replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,""")),c.html('
  1. '+o.replace(/[\r\t\n]+/g,"
  2. ")+"
"),c.find(">.layui-code-h3")[0]||c.prepend('

'+(c.attr("lay-title")||e.title||"code")+(e.about?'layui.code':"")+"

");var d=c.find(">.layui-code-ol");c.addClass("layui-box layui-code-view"),(c.attr("lay-skin")||e.skin)&&c.addClass("layui-code-"+(c.attr("lay-skin")||e.skin)),(d.find("li").length/100|0)>0&&d.css("margin-left",(d.find("li").length/100|0)+"px"),(c.attr("lay-height")||e.height)&&d.css("max-height",c.attr("lay-height")||e.height)})})}).addcss("modules/code.css","skincodecss"); -------------------------------------------------------------------------------- /src/main/resources/public/js/config.js: -------------------------------------------------------------------------------- 1 | var $, layer; 2 | layui.use([ 'layer', 'jquery' ], function() { 3 | layer = layui.layer; 4 | $ = layui.$; 5 | }); 6 | 7 | /** 8 | * 不刷新当前页 9 | * 10 | * @param url 11 | * @param data 12 | * @returns 13 | */ 14 | function ajaxPost(url, data) { 15 | ajaxPostLoad(url, data, false); 16 | } 17 | 18 | /** 19 | * 全局ajax-post提交(刷新当前页) 20 | */ 21 | function ajaxPostLoad(url, data, reload) { 22 | $.ajax({ 23 | cache : true, 24 | type : "POST", 25 | url : url, 26 | data : data, 27 | // async : false, //同步 28 | layerIndex : -1, 29 | beforeSend : function() { 30 | this.layerIndex = parent.layer.load(0, { 31 | shade : [ 0.1, '#000' ] 32 | }); 33 | }, 34 | complete : function() { 35 | parent.layer.close(this.layerIndex); 36 | }, 37 | success : function(data) { 38 | if (data.retCode == '0000') { 39 | parent.layer.msg("操作成功"); 40 | if (reload != false) {// 刷新 41 | parent.reloadCurrTab(); // 当前页面刷新 42 | var index = parent.layer.getFrameIndex(window.name); // 获取窗口索引 43 | parent.layer.close(index); 44 | } 45 | } else { 46 | layer.alert(data.retMsg) 47 | } 48 | }, 49 | error : function(request) { 50 | layer.alert("请检查参数"); 51 | } 52 | }); 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/ChaoCloudImApplication.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.scheduling.annotation.EnableAsync; 7 | import org.springframework.web.socket.server.standard.ServerEndpointExporter; 8 | 9 | import com.chao.cloud.common.extra.ftp.annotation.EnableFtp; 10 | import com.chao.cloud.common.extra.mybatis.annotation.EnableMybatisPlus; 11 | import com.chao.cloud.common.web.annotation.EnableGlobalException; 12 | import com.chao.cloud.common.web.annotation.EnableWeb; 13 | 14 | /** 15 | * 16 | * @功能:im -> web 聊天系统 17 | * @author: 薛超 18 | * @时间: 2019年6月24日 19 | * @version 1.0.0 20 | */ 21 | @SpringBootApplication 22 | @EnableWeb // web 23 | @EnableGlobalException // 全局异常处理 24 | @EnableMybatisPlus // 数据库插件-乐观锁 25 | @EnableAsync // 异步调用 26 | @EnableFtp 27 | public class ChaoCloudImApplication { 28 | 29 | public static void main(String[] args) { 30 | SpringApplication.run(ChaoCloudImApplication.class, args); 31 | } 32 | 33 | /** 34 | * 开启WebSocket支持 35 | * @return 36 | */ 37 | @Bean 38 | public ServerEndpointExporter serverEndpointExporter() { 39 | return new ServerEndpointExporter(); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/dal/entity/ImDept.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.dal.entity; 2 | 3 | import java.io.Serializable; 4 | import java.util.Date; 5 | 6 | import org.springframework.format.annotation.DateTimeFormat; 7 | 8 | import com.baomidou.mybatisplus.annotation.IdType; 9 | import com.baomidou.mybatisplus.annotation.TableId; 10 | import com.baomidou.mybatisplus.annotation.TableLogic; 11 | import com.baomidou.mybatisplus.annotation.Version; 12 | 13 | import cn.hutool.core.date.DatePattern; 14 | import lombok.Data; 15 | import lombok.EqualsAndHashCode; 16 | import lombok.experimental.Accessors; 17 | 18 | /** 19 | * @功能: 20 | * @author: 超君子 21 | * @时间:2019-06-26 22 | * @version 1.0.0 23 | */ 24 | @Data 25 | @EqualsAndHashCode(callSuper = false) 26 | @Accessors(chain = true) 27 | public class ImDept implements Serializable { 28 | 29 | private static final long serialVersionUID = 1L; 30 | 31 | @TableId(value = "id", type = IdType.AUTO) 32 | private Integer id; 33 | 34 | /** 35 | * 部门名称 36 | */ 37 | private String name; 38 | 39 | /** 40 | * 是否删除(0未删除1已删除) 41 | */ 42 | @TableLogic 43 | private Integer deleted; 44 | 45 | /** 46 | * 乐观锁 47 | */ 48 | @Version 49 | private Integer version; 50 | 51 | /** 52 | * 创建日期 53 | */ 54 | @DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN) 55 | private Date createTime; 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/ai/service/TAipImageClassifyService.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.ai.service; 2 | 3 | import org.springframework.beans.factory.InitializingBean; 4 | 5 | import com.chao.cloud.common.exception.BusinessException; 6 | import com.chao.cloud.im.ai.config.TAiConfig; 7 | import com.chao.cloud.im.ai.constant.AiConstant; 8 | import com.chao.cloud.im.ai.model.TAiResp; 9 | 10 | import cn.hutool.core.lang.Assert; 11 | import cn.hutool.json.JSONUtil; 12 | import cn.xsshome.taip.imageclassify.TAipImageClassify; 13 | 14 | /** 15 | * 16 | * @功能:图像识别 17 | * @author: 薛超 18 | * @时间: 2019年7月5日 19 | * @version 1.0.0 20 | */ 21 | public class TAipImageClassifyService implements InitializingBean { 22 | 23 | private TAiConfig config; 24 | private TAipImageClassify client; 25 | 26 | public void setConfig(TAiConfig config) { 27 | this.config = config; 28 | } 29 | 30 | public String visionImg(byte[] image) throws Exception { 31 | String result = client.visionImgtotext(image, config.getSession()); 32 | // 解析 33 | TAiResp tAiResp = JSONUtil.toBean(result, TAiResp.class); 34 | if (AiConstant.TAI_SUCCESS.equals(tAiResp.getRet())) { 35 | return tAiResp.getData().getText(); 36 | } 37 | throw new BusinessException("图片识别失败"); 38 | } 39 | 40 | @Override 41 | public void afterPropertiesSet() throws Exception { 42 | Assert.notNull(config); 43 | client = new TAipImageClassify(config.getAppId(), config.getAppKey()); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/dal/entity/ImGroup.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.dal.entity; 2 | 3 | import java.io.Serializable; 4 | import java.util.Date; 5 | 6 | import org.springframework.format.annotation.DateTimeFormat; 7 | 8 | import com.baomidou.mybatisplus.annotation.IdType; 9 | import com.baomidou.mybatisplus.annotation.TableId; 10 | import com.baomidou.mybatisplus.annotation.TableLogic; 11 | import com.baomidou.mybatisplus.annotation.Version; 12 | 13 | import cn.hutool.core.date.DatePattern; 14 | import lombok.Data; 15 | import lombok.EqualsAndHashCode; 16 | import lombok.experimental.Accessors; 17 | 18 | /** 19 | * @功能: 20 | * @author: 超君子 21 | * @时间:2019-06-26 22 | * @version 1.0.0 23 | */ 24 | @Data 25 | @EqualsAndHashCode(callSuper = false) 26 | @Accessors(chain = true) 27 | public class ImGroup implements Serializable { 28 | 29 | private static final long serialVersionUID = 1L; 30 | 31 | /** 32 | * 群id 33 | */ 34 | @TableId(value = "id", type = IdType.AUTO) 35 | private Integer id; 36 | 37 | /** 38 | * 昵称 39 | */ 40 | private String nickName; 41 | 42 | /** 43 | * 头像 44 | */ 45 | private String headImg; 46 | 47 | /** 48 | * 是否删除(0未删除1已删除) 49 | */ 50 | @TableLogic 51 | private Integer deleted; 52 | 53 | /** 54 | * 乐观锁 55 | */ 56 | @Version 57 | private Integer version; 58 | 59 | /** 60 | * 创建日期 61 | */ 62 | @DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN) 63 | private Date createTime; 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/ai/service/TAiRobotService.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.ai.service; 2 | 3 | import org.springframework.beans.factory.InitializingBean; 4 | 5 | import com.chao.cloud.im.ai.config.TAiConfig; 6 | import com.chao.cloud.im.ai.constant.AiConstant; 7 | import com.chao.cloud.im.ai.model.TAiResp; 8 | 9 | import cn.hutool.core.lang.Assert; 10 | import cn.hutool.json.JSONUtil; 11 | import cn.xsshome.taip.nlp.TAipNlp; 12 | import lombok.extern.slf4j.Slf4j; 13 | 14 | /** 15 | * 16 | * @功能:腾讯机器人 17 | * @author: 薛超 18 | * @时间: 2019年7月3日 19 | * @version 1.0.0 20 | */ 21 | @Slf4j 22 | public class TAiRobotService implements InitializingBean { 23 | 24 | private TAiConfig config; 25 | private TAipNlp client; 26 | 27 | public void setConfig(TAiConfig config) { 28 | this.config = config; 29 | } 30 | 31 | public String text(String text) { 32 | try { 33 | String result = client.nlpTextchat(config.getSession(), text);// 基础闲聊 34 | // 解析 35 | TAiResp tAiResp = JSONUtil.toBean(result, TAiResp.class); 36 | if (AiConstant.TAI_SUCCESS.equals(tAiResp.getRet())) { 37 | return tAiResp.getData().getAnswer(); 38 | } 39 | log.info("[腾讯闲聊解析失败={}]", result); 40 | } catch (Exception e) { 41 | log.error("{}", e); 42 | } 43 | return AiConstant.ERROR_RESULT; 44 | } 45 | 46 | @Override 47 | public void afterPropertiesSet() throws Exception { 48 | Assert.notNull(config); 49 | client = new TAipNlp(config.getAppId(), config.getAppKey()); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/websocket/model/LayimModel.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.websocket.model; 2 | 3 | import java.util.List; 4 | 5 | import cn.hutool.core.util.ReflectUtil; 6 | import lombok.Builder; 7 | import lombok.Data; 8 | 9 | @Data 10 | public class LayimModel { 11 | 12 | private User mine;// 个人信息 13 | private List friend;// 好友列表 14 | private List group;// 群 15 | 16 | public static User userConvert(Object obj) { 17 | User user = new User(); 18 | ReflectUtil.setFieldValue(user, "id", ReflectUtil.getFieldValue(obj, "id")); 19 | ReflectUtil.setFieldValue(user, "username", ReflectUtil.getFieldValue(obj, "nickName")); 20 | ReflectUtil.setFieldValue(user, "sign", ReflectUtil.getFieldValue(obj, "sign")); 21 | ReflectUtil.setFieldValue(user, "avatar", ReflectUtil.getFieldValue(obj, "headImg")); 22 | return user; 23 | } 24 | 25 | @Data 26 | public static class User {// 用户 27 | private Integer id; 28 | private String username;// 昵称 29 | private String status;// 状态 若值为offline代表离线,online或者不填为在线 30 | private String sign;// 签名 31 | private String avatar;// 头像 32 | } 33 | 34 | @Data 35 | public static class Friend {// 好友 36 | private Integer id; 37 | private String groupname;// 群组昵称 38 | private List list;// 好友列表 39 | } 40 | 41 | @Data 42 | public static class Group {// 群组 43 | private Integer id; 44 | private String groupname;// 昵称 45 | private String avatar;// 头像 46 | } 47 | 48 | @Data 49 | @Builder 50 | public static class Member {// 群成员 51 | private List list;// 列表 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/dal/entity/ImMsg.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.dal.entity; 2 | 3 | import java.io.Serializable; 4 | import java.util.Date; 5 | 6 | import org.springframework.format.annotation.DateTimeFormat; 7 | 8 | import com.baomidou.mybatisplus.annotation.IdType; 9 | import com.baomidou.mybatisplus.annotation.TableId; 10 | import com.baomidou.mybatisplus.annotation.Version; 11 | 12 | import cn.hutool.core.date.DatePattern; 13 | import lombok.Data; 14 | import lombok.EqualsAndHashCode; 15 | import lombok.experimental.Accessors; 16 | 17 | /** 18 | * @功能: 19 | * @author: 超君子 20 | * @时间:2019-06-28 21 | * @version 1.0.0 22 | */ 23 | @Data 24 | @EqualsAndHashCode(callSuper = false) 25 | @Accessors(chain = true) 26 | public class ImMsg implements Serializable { 27 | 28 | private static final long serialVersionUID = 1L; 29 | 30 | @TableId(value = "msg_id", type = IdType.AUTO) 31 | private Integer msgId; 32 | 33 | /** 34 | * 发送人 35 | */ 36 | private Integer fromid; 37 | 38 | /** 39 | * 接收人 40 | */ 41 | private Integer toid; 42 | 43 | /** 44 | * group=群id friend=发送者id 45 | */ 46 | private Integer id; 47 | 48 | /** 49 | * 用户名 50 | */ 51 | private String username; 52 | 53 | /** 54 | * 头像 55 | */ 56 | private String avatar; 57 | 58 | /** 59 | * 消息内容 60 | */ 61 | private String content; 62 | 63 | /** 64 | * 类型 group friend 65 | */ 66 | private String type; 67 | 68 | /** 69 | * 乐观锁 70 | */ 71 | @Version 72 | private Integer version; 73 | 74 | /** 75 | * 创建日期 76 | */ 77 | @DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN) 78 | private Date createTime; 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/dal/entity/ImMsgHis.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.dal.entity; 2 | 3 | import java.io.Serializable; 4 | import java.util.Date; 5 | 6 | import org.springframework.format.annotation.DateTimeFormat; 7 | 8 | import com.baomidou.mybatisplus.annotation.IdType; 9 | import com.baomidou.mybatisplus.annotation.TableId; 10 | import com.baomidou.mybatisplus.annotation.Version; 11 | 12 | import cn.hutool.core.date.DatePattern; 13 | import lombok.Data; 14 | import lombok.EqualsAndHashCode; 15 | import lombok.experimental.Accessors; 16 | 17 | /** 18 | * @功能: 19 | * @author: 超君子 20 | * @时间:2019-06-28 21 | * @version 1.0.0 22 | */ 23 | @Data 24 | @EqualsAndHashCode(callSuper = false) 25 | @Accessors(chain = true) 26 | public class ImMsgHis implements Serializable { 27 | 28 | private static final long serialVersionUID = 1L; 29 | 30 | @TableId(value = "msg_id", type = IdType.AUTO) 31 | private Integer msgId; 32 | 33 | /** 34 | * 发送人->接收人 如 1-2 35 | */ 36 | private String fromTo; 37 | 38 | /** 39 | * group=群id friend=发送者id 40 | */ 41 | private Integer id; 42 | 43 | /** 44 | * 用户名 45 | */ 46 | private String username; 47 | 48 | /** 49 | * 头像 50 | */ 51 | private String avatar; 52 | 53 | /** 54 | * 消息内容 55 | */ 56 | private String content; 57 | 58 | /** 59 | * 类型 group friend 60 | */ 61 | private String type; 62 | 63 | /** 64 | * 乐观锁 65 | */ 66 | @Version 67 | private Integer version; 68 | 69 | /** 70 | * 创建日期 71 | */ 72 | @DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN) 73 | private Date createTime; 74 | 75 | public Long getTimestamp() { 76 | return createTime.getTime(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/resources/static/layui/lay/modules/laytpl.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.4.5 MIT License By https://www.layui.com */ 2 | ;layui.define(function(e){"use strict";var r={open:"{{",close:"}}"},c={exp:function(e){return new RegExp(e,"g")},query:function(e,c,t){var o=["#([\\s\\S])+?","([^{#}])*?"][e||0];return n((c||"")+r.open+o+r.close+(t||""))},escape:function(e){return String(e||"").replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,""")},error:function(e,r){var c="Laytpl Error:";return"object"==typeof console&&console.error(c+e+"\n"+(r||"")),c+e}},n=c.exp,t=function(e){this.tpl=e};t.pt=t.prototype,window.errors=0,t.pt.parse=function(e,t){var o=this,p=e,a=n("^"+r.open+"#",""),l=n(r.close+"$","");e=e.replace(/\s+|\r|\t|\n/g," ").replace(n(r.open+"#"),r.open+"# ").replace(n(r.close+"}"),"} "+r.close).replace(/\\/g,"\\\\").replace(n(r.open+"!(.+?)!"+r.close),function(e){return e=e.replace(n("^"+r.open+"!"),"").replace(n("!"+r.close),"").replace(n(r.open+"|"+r.close),function(e){return e.replace(/(.)/g,"\\$1")})}).replace(/(?="|')/g,"\\").replace(c.query(),function(e){return e=e.replace(a,"").replace(l,""),'";'+e.replace(/\\/g,"")+';view+="'}).replace(c.query(1),function(e){var c='"+(';return e.replace(/\s/g,"")===r.open+r.close?"":(e=e.replace(n(r.open+"|"+r.close),""),/^=/.test(e)&&(e=e.replace(/^=/,""),c='"+_escape_('),c+e.replace(/\\/g,"")+')+"')}),e='"use strict";var view = "'+e+'";return view;';try{return o.cache=e=new Function("d, _escape_",e),e(t,c.escape)}catch(u){return delete o.cache,c.error(u,p)}},t.pt.render=function(e,r){var n,t=this;return e?(n=t.cache?t.cache(e,c.escape):t.parse(t.tpl,e),r?void r(n):n):c.error("no data")};var o=function(e){return"string"!=typeof e?c.error("Template not found"):new t(e)};o.config=function(e){e=e||{};for(var c in e)r[c]=e[c]},o.v="1.2.0",e("laytpl",o)}); -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/dal/entity/ImUser.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.dal.entity; 2 | 3 | import java.io.Serializable; 4 | import java.util.Date; 5 | 6 | import org.springframework.format.annotation.DateTimeFormat; 7 | 8 | import com.baomidou.mybatisplus.annotation.IdType; 9 | import com.baomidou.mybatisplus.annotation.TableId; 10 | import com.baomidou.mybatisplus.annotation.TableLogic; 11 | import com.baomidou.mybatisplus.annotation.Version; 12 | 13 | import cn.hutool.core.date.DatePattern; 14 | import lombok.Data; 15 | import lombok.EqualsAndHashCode; 16 | import lombok.experimental.Accessors; 17 | 18 | /** 19 | * @功能: 20 | * @author: 超君子 21 | * @时间:2019-06-26 22 | * @version 1.0.0 23 | */ 24 | @Data 25 | @EqualsAndHashCode(callSuper = false) 26 | @Accessors(chain = true) 27 | public class ImUser implements Serializable { 28 | 29 | private static final long serialVersionUID = 1L; 30 | 31 | @TableId(value = "id", type = IdType.AUTO) 32 | private Integer id; 33 | 34 | /** 35 | * 用户名 36 | */ 37 | private String userName; 38 | 39 | /** 40 | * 密码 41 | */ 42 | private String password; 43 | 44 | /** 45 | * 昵称 46 | */ 47 | private String nickName; 48 | 49 | /** 50 | * 签名 51 | */ 52 | private String sign; 53 | 54 | /** 55 | * 头像 56 | */ 57 | private String headImg; 58 | 59 | /** 60 | * 部门id 61 | */ 62 | private Integer deptId; 63 | 64 | /** 65 | * 部门名称 66 | */ 67 | private String deptName; 68 | 69 | /** 70 | * 状态 0.冻结 1.正常 71 | */ 72 | private Integer status; 73 | 74 | /** 75 | * 是否删除(0未删除1已删除) 76 | */ 77 | @TableLogic 78 | private Integer deleted; 79 | 80 | /** 81 | * 乐观锁 82 | */ 83 | @Version 84 | private Integer version; 85 | 86 | /** 87 | * 创建日期 88 | */ 89 | @DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN) 90 | private Date createTime; 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | #日志 2 | logging.config: classpath:chao-logback.xml 3 | log.path: /logs/chao/${spring.application.name} 4 | log.maxHistory: 30 5 | 6 | server: 7 | port: 9001 8 | tomcat.uri-encoding: utf-8 9 | servlet: session: timeout: 1800 10 | #共享文件(功能类型) 11 | spring: 12 | application: 13 | name: chao-im 14 | aop: 15 | auto: true 16 | output: 17 | ansi: 18 | enabled: always 19 | jackson: 20 | date-format: yyyy-MM-dd HH:mm:ss 21 | time-zone: GMT+8 22 | datasource: 23 | url: jdbc:mysql://127.0.0.1:3306/im?useSSL=false&useUnicode=true&characterEncoding=UTF8&allowMultiQueries=true&serverTimezone=Asia/Shanghai 24 | driver-class-name: com.mysql.cj.jdbc.Driver 25 | username: root 26 | password: 123456 27 | type: com.alibaba.druid.pool.DruidDataSource 28 | druid: 29 | validation-query: SELECT 1 30 | test-on-borrow: true 31 | connection-init-sqls: SET NAMES utf8mb4; 32 | filter: 33 | wall: 34 | enabled: false 35 | thymeleaf: 36 | mode: LEGACYHTML5 37 | cache: false 38 | resources: #这里必须使用字符串 后面的 / 必须有 39 | static-locations: file:/softrun/tech/dcdy/web/chao/resource/im/ 40 | servlet: #文件上传 41 | multipart: 42 | max-file-size: 5MB 43 | max-request-size: 5MB 44 | 45 | mybatis-plus: 46 | configuration: 47 | map-underscore-to-camel-case: true 48 | log-impl: com.chao.cloud.common.extra.mybatis.log.Slf4jLogImpl 49 | 50 | #默认使用本地数据源-代码自动生成 51 | chao: 52 | cloud: 53 | im: 54 | tai: #腾讯 55 | app-id: 56 | app-key: 57 | session: 58 | bai: 59 | app-id: 60 | api-key: 61 | secret-key: 62 | ftp: 63 | config: 64 | local: true #使用本地硬盘 65 | prefix: /softrun/tech/dcdy/web/chao/resource/im 66 | path: ${chao.cloud.ftp.config.prefix}/img 67 | -------------------------------------------------------------------------------- /src/main/resources/static/layui/lay/modules/flow.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.4.5 MIT License By https://www.layui.com */ 2 | ;layui.define("jquery",function(e){"use strict";var l=layui.$,o=function(e){},t='';o.prototype.load=function(e){var o,i,n,r,a=this,c=0;e=e||{};var f=l(e.elem);if(f[0]){var m=l(e.scrollElem||document),u=e.mb||50,s=!("isAuto"in e)||e.isAuto,v=e.end||"没有更多了",y=e.scrollElem&&e.scrollElem!==document,d="加载更多",h=l('");f.find(".layui-flow-more")[0]||f.append(h);var p=function(e,t){e=l(e),h.before(e),t=0==t||null,t?h.html(v):h.find("a").html(d),i=t,o=null,n&&n()},g=function(){o=!0,h.find("a").html(t),"function"==typeof e.done&&e.done(++c,p)};if(g(),h.find("a").on("click",function(){l(this);i||o||g()}),e.isLazyimg)var n=a.lazyimg({elem:e.elem+" img",scrollElem:e.scrollElem});return s?(m.on("scroll",function(){var e=l(this),t=e.scrollTop();r&&clearTimeout(r),i||(r=setTimeout(function(){var i=y?e.height():l(window).height(),n=y?e.prop("scrollHeight"):document.documentElement.scrollHeight;n-t-i<=u&&(o||g())},100))}),a):a}},o.prototype.lazyimg=function(e){var o,t=this,i=0;e=e||{};var n=l(e.scrollElem||document),r=e.elem||"img",a=e.scrollElem&&e.scrollElem!==document,c=function(e,l){var o=n.scrollTop(),r=o+l,c=a?function(){return e.offset().top-n.offset().top+o}():e.offset().top;if(c>=o&&c<=r&&!e.attr("src")){var m=e.attr("lay-src");layui.img(m,function(){var l=t.lazyimg.elem.eq(i);e.attr("src",m).removeAttr("lay-src"),l[0]&&f(l),i++})}},f=function(e,o){var f=a?(o||n).height():l(window).height(),m=n.scrollTop(),u=m+f;if(t.lazyimg.elem=l(r),e)c(e,f);else for(var s=0;su)break}};if(f(),!o){var m;n.on("scroll",function(){var e=l(this);m&&clearTimeout(m),m=setTimeout(function(){f(null,e)},50)}),o=!0}return f},e("flow",new o)}); -------------------------------------------------------------------------------- /src/main/resources/public/js/ws-im-chat.js: -------------------------------------------------------------------------------- 1 | var $, layer, connSingleChat, layim, ws; 2 | layui.use([ 'layer', 'jquery' ], function() { 3 | layer = layui.layer; 4 | $ = layui.$; 5 | 6 | $("#off_line").click(function(){ 7 | // 退出 8 | layer.msg('您确定要下线吗?', { 9 | time: 0 // 不自动关闭 10 | ,btn: ['确定', '取消'] 11 | ,yes: function(index){ 12 | layer.close(index); 13 | ws.close(); 14 | window.top.location ="/logout"; 15 | } 16 | }); 17 | }); 18 | 19 | // 连接websocket 20 | connSingleChat = function() { 21 | var url = document.location.protocol == "https:" ? "wss://" : "ws://" + window.location.host// 22 | + "/im/chat/" + $("#userId").val(); 23 | // 连接 24 | 25 | // 连接服务器 26 | ws = new ReconnectingWebSocket(url); 27 | // 刚刚打开连接 28 | ws.onopen = function(evt) { 29 | console.log("Connection open ..."); 30 | }; 31 | 32 | // 接收消息的情况 33 | ws.onmessage = function(evt) { 34 | var r = JSON.parse(evt.data); 35 | console.log(r); 36 | switch (r.type) { 37 | case 0:// 关闭-已经登录 38 | layer.msg(r.msg); 39 | setTimeout(function() { 40 | // 跳转登录页 41 | window.top.location = "/logout"; 42 | }, 3000); 43 | break; 44 | case 1:// 开始连接 45 | break; 46 | case 2:// 提示 47 | break; 48 | case 3:// 上线 49 | layim.setFriendStatus(r.msg, 'online'); 50 | break; 51 | case 4:// 下线 52 | layim.setFriendStatus(r.msg, 'offline'); 53 | break; 54 | case 5:// 聊天->追加消息 55 | layim.setChatStatus('');// 清除对方正在输入 56 | layim.getMessage(r.msg); 57 | break; 58 | case 6:// 离线消息 59 | $.each(r.msg,function(i,item){ 60 | layim.getMessage(item); 61 |    }); 62 | break; 63 | case 7:// 对方正在输入 64 | layim.setChatStatus(r.msg); 65 | break; 66 | 67 | } 68 | 69 | }; 70 | // 关闭连接的情况 71 | ws.onclose = function(evt) { 72 | console.log("连接关闭"); 73 | }; 74 | 75 | // 连接失败的情况 76 | ws.onerror = function(event) { 77 | console.log("连接失败"); 78 | }; 79 | 80 | } 81 | }); 82 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/controller/MsgHisController.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.controller; 2 | 3 | import java.util.Set; 4 | 5 | import javax.servlet.http.HttpSession; 6 | import javax.validation.Valid; 7 | 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.validation.annotation.Validated; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 14 | import com.baomidou.mybatisplus.core.metadata.IPage; 15 | import com.baomidou.mybatisplus.core.toolkit.Wrappers; 16 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 17 | import com.chao.cloud.common.entity.Response; 18 | import com.chao.cloud.im.dal.entity.ImMsgHis; 19 | import com.chao.cloud.im.domain.dto.LoginDTO; 20 | import com.chao.cloud.im.domain.vo.MsgHisVO; 21 | import com.chao.cloud.im.service.ImMsgHisService; 22 | 23 | import cn.hutool.core.collection.CollUtil; 24 | 25 | /** 26 | * @功能:历史记录 27 | * @author: 超君子 28 | * @时间:2019-06-28 29 | * @version 1.0.0 30 | */ 31 | @RequestMapping("/im/msg_his") 32 | @RestController 33 | @Validated 34 | public class MsgHisController extends BaseController { 35 | 36 | @Autowired 37 | private ImMsgHisService imMsgHisService; 38 | 39 | @RequestMapping("/list") 40 | public Response> list(Page page, // 分页 41 | HttpSession session, @Valid MsgHisVO vo) { 42 | // 获取当前用户 43 | LoginDTO user = getUser(session); 44 | // 去重 45 | Set fromTo = CollUtil.newHashSet(ImMsgHisService.fromTo(user.getId(), vo.getId()), 46 | ImMsgHisService.fromTo(vo.getId(), user.getId())); 47 | // 构造条件 48 | LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); 49 | queryWrapper.in(ImMsgHis::getFromTo, fromTo); 50 | queryWrapper.eq(ImMsgHis::getType, vo.getType()); 51 | return Response.ok(imMsgHisService.page(page, queryWrapper)); 52 | } 53 | 54 | } -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/service/impl/ImMsgServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.service.impl; 2 | 3 | import java.util.List; 4 | import java.util.Set; 5 | import java.util.stream.Collectors; 6 | 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.scheduling.annotation.Async; 9 | import org.springframework.stereotype.Service; 10 | import org.springframework.transaction.annotation.Transactional; 11 | 12 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 13 | import com.chao.cloud.im.dal.entity.ImMsg; 14 | import com.chao.cloud.im.dal.entity.ImMsgHis; 15 | import com.chao.cloud.im.dal.mapper.ImMsgMapper; 16 | import com.chao.cloud.im.service.ImMsgHisService; 17 | import com.chao.cloud.im.service.ImMsgService; 18 | import com.chao.cloud.im.websocket.LayimChatWebSocket; 19 | import com.chao.cloud.im.websocket.model.WsMsgVO; 20 | 21 | import cn.hutool.core.bean.BeanUtil; 22 | import cn.hutool.core.collection.CollUtil; 23 | import cn.hutool.core.util.BooleanUtil; 24 | 25 | /** 26 | * @功能: 27 | * @author: 超君子 28 | * @时间:2019-06-26 29 | * @version 1.0.0 30 | */ 31 | @Service 32 | public class ImMsgServiceImpl extends ServiceImpl implements ImMsgService { 33 | 34 | @Autowired 35 | private LayimChatWebSocket layimChatWebSocket; 36 | @Autowired 37 | private ImMsgHisService imMsgHisService; 38 | 39 | /** 40 | * 异步消息推送 41 | */ 42 | @Async 43 | @Override 44 | @Transactional 45 | public void saveOffLineMsg(WsMsgVO vo, List receiveIds) { 46 | boolean isSystem = BooleanUtil.isTrue(vo.getSystem()); 47 | if (!isSystem) {// 非系统消息 48 | Set key = layimChatWebSocket.onlineKey(); 49 | // 遍历接收者->改变to的值 50 | List list = receiveIds.stream().filter(k -> !key.contains(k)) 51 | .map(BeanUtil.toBean(vo, ImMsg.class)::setToid).collect(Collectors.toList()); 52 | // 批量添加 53 | if (CollUtil.isNotEmpty(list)) { 54 | this.saveBatch(list, list.size()); 55 | } 56 | // 增加历史记录 57 | ImMsgHis msgHis = BeanUtil.toBean(vo, ImMsgHis.class) 58 | .setFromTo(ImMsgHisService.fromTo(vo.getFromid(), vo.getToid())); 59 | imMsgHisService.save(msgHis); 60 | } 61 | 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.github.chaojunzi 8 | chao-cloud-parent 9 | 1.0.8 10 | 11 | chao-cloud-im 12 | jar 13 | 14 | 4.3.5 15 | 16 | 17 | 18 | 19 | cn.xsshome 20 | taip 21 | ${taip.version} 22 | 23 | 24 | com.github.chaojunzi 25 | chao-cloud-common-config 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-web 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-thymeleaf 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-starter-websocket 38 | 39 | 40 | 41 | com.alibaba 42 | druid-spring-boot-starter 43 | 44 | 45 | com.baomidou 46 | mybatis-plus-boot-starter 47 | 48 | 49 | 50 | chao-im 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-maven-plugin 55 | 56 | 57 | 58 | 59 | ${project.basedir}/src/main/resources 60 | true 61 | 62 | */** 63 | 64 | 65 | 66 | ${project.basedir}/src/main/resources 67 | false 68 | 69 | */** 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /src/main/resources/static/layui/css/modules/layim/html/getmsg.json: -------------------------------------------------------------------------------- 1 | { 2 | "code": 0, 3 | "pages": 1, 4 | "data": [ 5 | { 6 | "id": 76, 7 | "content": "申请添加你为好友", 8 | "uid": 168, 9 | "from": 166488, 10 | "from_group": 0, 11 | "type": 1, 12 | "remark": "有问题要问", 13 | "href": null, 14 | "read": 1, 15 | "time": "刚刚", 16 | "user": { 17 | "id": 166488, 18 | "avatar": "http://q.qlogo.cn/qqapp/101235792/B704597964F9BD0DB648292D1B09F7E8/100", 19 | "username": "李彦宏", 20 | "sign": null 21 | } 22 | }, 23 | { 24 | "id": 75, 25 | "content": "申请添加你为好友", 26 | "uid": 168, 27 | "from": 347592, 28 | "from_group": 0, 29 | "type": 1, 30 | "remark": "你好啊!", 31 | "href": null, 32 | "read": 1, 33 | "time": "刚刚", 34 | "user": { 35 | "id": 347592, 36 | "avatar": "http://q.qlogo.cn/qqapp/101235792/B78751375E0531675B1272AD994BA875/100", 37 | "username": "麻花疼", 38 | "sign": null 39 | } 40 | }, 41 | { 42 | "id": 62, 43 | "content": "雷军 拒绝了你的好友申请", 44 | "uid": 168, 45 | "from": null, 46 | "from_group": null, 47 | "type": 1, 48 | "remark": null, 49 | "href": null, 50 | "read": 1, 51 | "time": "10天前", 52 | "user": { 53 | "id": null 54 | } 55 | }, 56 | { 57 | "id": 60, 58 | "content": "马小云 已经同意你的好友申请", 59 | "uid": 168, 60 | "from": null, 61 | "from_group": null, 62 | "type": 1, 63 | "remark": null, 64 | "href": null, 65 | "read": 1, 66 | "time": "10天前", 67 | "user": { 68 | "id": null 69 | } 70 | }, 71 | { 72 | "id": 61, 73 | "content": "贤心 已经同意你的好友申请", 74 | "uid": 168, 75 | "from": null, 76 | "from_group": null, 77 | "type": 1, 78 | "remark": null, 79 | "href": null, 80 | "read": 1, 81 | "time": "10天前", 82 | "user": { 83 | "id": null 84 | } 85 | } 86 | ] 87 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 996icu 4 | 5 | 6 | 7 | code style 8 | 9 |

10 | 11 | # chao-cloud-im 12 | spring-boot为基础,websocket+mybatis-plus+layui+layim+腾讯闲聊机器人+百度聊天机器人 13 | 14 | ## 集成 15 | 16 | - [腾讯ai@申请](https://ai.qq.com/console/home) 17 | - [百度ai@申请](http://ai.baidu.com/) 18 | 19 | ``` 20 | //1.导入sql 21 | resource 22 | │ 23 | └─sql/mysql-im.sql 24 | //2.修改 bootstrap.yaml 25 | chao: 26 | cloud: 27 | im: 28 | tai: #腾讯AI-机器人 29 | app-id: 30 | app-key: 31 | session: 32 | bai: #百度Ai-机器人 33 | app-id: 34 | api-key: 35 | secret-key: 36 | //3.引入layim.js 37 | resource 38 | │ 39 | └─static 40 | └─layui 41 | └─lay 42 | └─modules/layim.js 43 | ``` 44 | 45 | ## 注意 46 | 47 | - layim是收费UI,请大家自行前往官网授权 48 | - 项目源代码中不包含layim.js包 49 | - 拿去玩吧,禁止不授权使用,[贤心](https://github.com/sentsin)会找你的 50 | - [LAYIM@官网](http://layim.layui.com/) 51 | 52 | ## 效果图展示 53 | 54 | ![Image text](screenshot/1.png) 55 | ![Image text](screenshot/2.png) 56 | ![Image text](screenshot/3.png) 57 | ![Image text](screenshot/4.png) 58 | ![Image text](screenshot/5.png) 59 | ![Image text](screenshot/6.png) 60 | ![Image text](screenshot/7.png) 61 | ![Image text](screenshot/8.png) 62 | ![Image text](screenshot/9.png) 63 | 64 | ## 版权 65 | 66 | ### Apache License Version 2.0 67 | 68 | - 如不特殊注明,所有模块都以此协议授权使用。 69 | - 任何使用了chao-cloud-im的全部或部分功能的项目、产品或文章等形式的成果必须显式注明chao-cloud-im。 70 | 71 | ### NPL (The 996 Prohibited License) 72 | 73 | - 不允许 996 工作制度企业使用该开源软件 74 | 75 | ### LAYIM 76 | 77 | - LayIM 受国家计算机软件著作权保护(登记号:2018SR064263) 78 | - 未经官网正规渠道授权擅自公开产品源文件、和直接对产品二次出售的,将追究法律责任 79 | 80 | ### 鸣谢 81 | - [java-sdk@百度AI](https://github.com/Baidu-AIP/java-sdk) 82 | - [xshuai@腾讯AI](https://gitee.com/xshuai/taip) 83 | - [hutool-超级工具类](https://github.com/looly/hutool) 84 | - [lombok](https://github.com/rzwitserloot/lombok) 85 | - [layim-js](https://gitee.com/pctao/instant_chat_tools) 86 | - [mybatis-plus](https://github.com/baomidou/mybatis-plus) 87 | - [layui](https://github.com/sentsin/layui/) 88 | - [......](https://github.com/) 89 | 90 | 感谢诸位用户的关注和使用,chao-cloud-im并不完善,未来还恳求各位开源爱好者多多关照,提出宝贵意见。 91 | 92 | 作者 [@chaojunzi 1521515935@qq.com] 93 | 94 | 2019年8月15日 -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/controller/MsgController.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.controller; 2 | 3 | import javax.validation.constraints.NotNull; 4 | import javax.validation.constraints.Size; 5 | 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.validation.annotation.Validated; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RequestParam; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 13 | import com.baomidou.mybatisplus.core.metadata.IPage; 14 | import com.baomidou.mybatisplus.core.toolkit.Wrappers; 15 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 16 | import com.chao.cloud.common.entity.Response; 17 | import com.chao.cloud.im.dal.entity.ImMsg; 18 | import com.chao.cloud.im.service.ImMsgService; 19 | 20 | import cn.hutool.core.collection.CollUtil; 21 | 22 | /** 23 | * @功能: 24 | * @author: 超君子 25 | * @时间:2019-06-26 26 | * @version 1.0.0 27 | */ 28 | @RequestMapping("/im/msg") 29 | @RestController 30 | @Validated 31 | public class MsgController { 32 | 33 | @Autowired 34 | private ImMsgService imMsgService; 35 | 36 | @RequestMapping("/list") 37 | public Response> list(Page page // 38 | ) { // 分页 39 | LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); 40 | return Response.ok(imMsgService.page(page, queryWrapper)); 41 | } 42 | 43 | /** 44 | * 保存 45 | */ 46 | @RequestMapping("/save") 47 | public Response save(ImMsg imMsg) { 48 | boolean result = imMsgService.save(imMsg); 49 | return result ? Response.ok() : Response.error(); 50 | } 51 | 52 | /** 53 | * 修改 54 | */ 55 | @RequestMapping("/update") 56 | public Response update(ImMsg imMsg) { 57 | boolean result = imMsgService.updateById(imMsg); 58 | return result ? Response.ok() : Response.error(); 59 | } 60 | 61 | /** 62 | * 删除 63 | */ 64 | @RequestMapping("/remove") 65 | public Response remove(@NotNull(message = "id 不能为空") Integer id) { 66 | boolean result = imMsgService.removeById(id); 67 | return result ? Response.ok() : Response.error(); 68 | } 69 | 70 | /** 71 | * 批量删除 72 | */ 73 | @RequestMapping("/batchRemove") 74 | public Response batchRemove( 75 | @NotNull(message = "不能为空") @Size(min = 1, message = "请至少选择一个") @RequestParam("ids[]") Integer[] ids) { 76 | boolean result = imMsgService.removeByIds(CollUtil.toList(ids)); 77 | return result ? Response.ok() : Response.error(); 78 | } 79 | 80 | } -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.controller; 2 | 3 | import javax.validation.constraints.NotNull; 4 | import javax.validation.constraints.Size; 5 | 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.validation.annotation.Validated; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RequestParam; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 13 | import com.baomidou.mybatisplus.core.metadata.IPage; 14 | import com.baomidou.mybatisplus.core.toolkit.Wrappers; 15 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 16 | import com.chao.cloud.common.entity.Response; 17 | import com.chao.cloud.im.dal.entity.ImUser; 18 | import com.chao.cloud.im.service.ImUserService; 19 | 20 | import cn.hutool.core.collection.CollUtil; 21 | 22 | /** 23 | * @功能: 24 | * @author: 超君子 25 | * @时间:2019-06-26 26 | * @version 1.0.0 27 | */ 28 | @RequestMapping("/im/user") 29 | @RestController 30 | @Validated 31 | public class UserController { 32 | 33 | @Autowired 34 | private ImUserService imUserService; 35 | 36 | @RequestMapping("/list") 37 | public Response> list(Page page) { // 分页 38 | LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); 39 | return Response.ok(imUserService.page(page, queryWrapper)); 40 | } 41 | 42 | /** 43 | * 保存 44 | */ 45 | @RequestMapping("/save") 46 | public Response save(ImUser imUser) { 47 | boolean result = imUserService.save(imUser); 48 | return result ? Response.ok() : Response.error(); 49 | } 50 | 51 | /** 52 | * 修改 53 | */ 54 | @RequestMapping("/update") 55 | public Response update(ImUser imUser) { 56 | boolean result = imUserService.updateById(imUser); 57 | return result ? Response.ok() : Response.error(); 58 | } 59 | 60 | /** 61 | * 删除 62 | */ 63 | @RequestMapping("/remove") 64 | public Response remove(@NotNull(message = "id 不能为空") Integer id) { 65 | boolean result = imUserService.removeById(id); 66 | return result ? Response.ok() : Response.error(); 67 | } 68 | 69 | /** 70 | * 批量删除 71 | */ 72 | @RequestMapping("/batchRemove") 73 | public Response batchRemove( 74 | @NotNull(message = "不能为空") @Size(min = 1, message = "请至少选择一个") @RequestParam("ids[]") Integer[] ids) { 75 | boolean result = imUserService.removeByIds(CollUtil.toList(ids)); 76 | return result ? Response.ok() : Response.error(); 77 | } 78 | 79 | } -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/controller/DeptController.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.controller; 2 | 3 | import javax.validation.constraints.NotNull; 4 | import javax.validation.constraints.Size; 5 | 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.validation.annotation.Validated; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RequestParam; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 13 | import com.baomidou.mybatisplus.core.metadata.IPage; 14 | import com.baomidou.mybatisplus.core.toolkit.Wrappers; 15 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 16 | import com.chao.cloud.common.entity.Response; 17 | import com.chao.cloud.im.dal.entity.ImDept; 18 | import com.chao.cloud.im.service.ImDeptService; 19 | 20 | import cn.hutool.core.collection.CollUtil; 21 | 22 | /** 23 | * @功能: 24 | * @author: 超君子 25 | * @时间:2019-06-26 26 | * @version 1.0.0 27 | */ 28 | @RequestMapping("/im/dept") 29 | @RestController 30 | @Validated 31 | public class DeptController { 32 | 33 | @Autowired 34 | private ImDeptService imDeptService; 35 | 36 | @RequestMapping("/list") 37 | public Response> list(Page page // 38 | ) { // 分页 39 | LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); 40 | return Response.ok(imDeptService.page(page, queryWrapper)); 41 | } 42 | 43 | /** 44 | * 保存 45 | */ 46 | @RequestMapping("/save") 47 | public Response save(ImDept imDept) { 48 | boolean result = imDeptService.save(imDept); 49 | return result ? Response.ok() : Response.error(); 50 | } 51 | 52 | /** 53 | * 修改 54 | */ 55 | @RequestMapping("/update") 56 | public Response update(ImDept imDept) { 57 | boolean result = imDeptService.updateById(imDept); 58 | return result ? Response.ok() : Response.error(); 59 | } 60 | 61 | /** 62 | * 删除 63 | */ 64 | @RequestMapping("/remove") 65 | public Response remove(@NotNull(message = "id 不能为空") Integer id) { 66 | boolean result = imDeptService.removeById(id); 67 | return result ? Response.ok() : Response.error(); 68 | } 69 | 70 | /** 71 | * 批量删除 72 | */ 73 | @RequestMapping("/batchRemove") 74 | public Response batchRemove( 75 | @NotNull(message = "不能为空") @Size(min = 1, message = "请至少选择一个") @RequestParam("ids[]") Integer[] ids) { 76 | boolean result = imDeptService.removeByIds(CollUtil.toList(ids)); 77 | return result ? Response.ok() : Response.error(); 78 | } 79 | 80 | } -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/controller/GroupController.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.controller; 2 | 3 | import javax.validation.constraints.NotNull; 4 | import javax.validation.constraints.Size; 5 | 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.validation.annotation.Validated; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RequestParam; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 13 | import com.baomidou.mybatisplus.core.metadata.IPage; 14 | import com.baomidou.mybatisplus.core.toolkit.Wrappers; 15 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 16 | import com.chao.cloud.common.entity.Response; 17 | import com.chao.cloud.im.dal.entity.ImGroup; 18 | import com.chao.cloud.im.service.ImGroupService; 19 | 20 | import cn.hutool.core.collection.CollUtil; 21 | 22 | /** 23 | * @功能: 24 | * @author: 超君子 25 | * @时间:2019-06-26 26 | * @version 1.0.0 27 | */ 28 | @RequestMapping("/im/group") 29 | @RestController 30 | @Validated 31 | public class GroupController { 32 | 33 | @Autowired 34 | private ImGroupService imGroupService; 35 | 36 | @RequestMapping("/list") 37 | public Response> list(Page page // 38 | ) { // 分页 39 | LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); 40 | return Response.ok(imGroupService.page(page, queryWrapper)); 41 | } 42 | 43 | /** 44 | * 保存 45 | */ 46 | @RequestMapping("/save") 47 | public Response save(ImGroup imGroup) { 48 | boolean result = imGroupService.save(imGroup); 49 | return result ? Response.ok() : Response.error(); 50 | } 51 | 52 | /** 53 | * 修改 54 | */ 55 | @RequestMapping("/update") 56 | public Response update(ImGroup imGroup) { 57 | boolean result = imGroupService.updateById(imGroup); 58 | return result ? Response.ok() : Response.error(); 59 | } 60 | 61 | /** 62 | * 删除 63 | */ 64 | @RequestMapping("/remove") 65 | public Response remove(@NotNull(message = "id 不能为空") Integer id) { 66 | boolean result = imGroupService.removeById(id); 67 | return result ? Response.ok() : Response.error(); 68 | } 69 | 70 | /** 71 | * 批量删除 72 | */ 73 | @RequestMapping("/batchRemove") 74 | public Response batchRemove( 75 | @NotNull(message = "不能为空") @Size(min = 1, message = "请至少选择一个") @RequestParam("ids[]") Integer[] ids) { 76 | boolean result = imGroupService.removeByIds(CollUtil.toList(ids)); 77 | return result ? Response.ok() : Response.error(); 78 | } 79 | 80 | } -------------------------------------------------------------------------------- /src/main/resources/templates/layim/chatlog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 |
13 |
    14 |
    15 | 16 |
    17 | 18 | 19 | 42 | 43 |
    44 | 92 | 93 | -------------------------------------------------------------------------------- /src/main/resources/static/layui/lay/modules/rate.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.4.5 MIT License By https://www.layui.com */ 2 | ;layui.define("jquery",function(e){"use strict";var a=layui.jquery,i={config:{},index:layui.rate?layui.rate.index+1e4:0,set:function(e){var i=this;return i.config=a.extend({},i.config,e),i},on:function(e,a){return layui.onevent.call(this,n,e,a)}},l=function(){var e=this,a=e.config;return{setvalue:function(a){e.setvalue.call(e,a)},config:a}},n="rate",t="layui-rate",o="layui-icon-rate",s="layui-icon-rate-solid",u="layui-icon-rate-half",r="layui-icon-rate-solid layui-icon-rate-half",c="layui-icon-rate-solid layui-icon-rate",f="layui-icon-rate layui-icon-rate-half",v=function(e){var l=this;l.index=++i.index,l.config=a.extend({},l.config,i.config,e),l.render()};v.prototype.config={length:5,text:!1,readonly:!1,half:!1,value:0,theme:""},v.prototype.render=function(){var e=this,i=e.config,l=i.theme?'style="color: '+i.theme+';"':"";i.elem=a(i.elem),parseInt(i.value)!==i.value&&(i.half||(i.value=Math.ceil(i.value)-i.value<.5?Math.ceil(i.value):Math.floor(i.value)));for(var n='
      ",u=1;u<=i.length;u++){var r='
    • ";i.half&&parseInt(i.value)!==i.value&&u==Math.ceil(i.value)?n=n+'
    • ":n+=r}n+="
    "+(i.text?''+i.value+"星":"")+"";var c=i.elem,f=c.next("."+t);f[0]&&f.remove(),e.elemTemp=a(n),i.span=e.elemTemp.next("span"),i.setText&&i.setText(i.value),c.html(e.elemTemp),c.addClass("layui-inline"),i.readonly||e.action()},v.prototype.setvalue=function(e){var a=this,i=a.config;i.value=e,a.render()},v.prototype.action=function(){var e=this,i=e.config,l=e.elemTemp,n=l.find("i").width();l.children("li").each(function(e){var t=e+1,v=a(this);v.on("click",function(e){if(i.value=t,i.half){var o=e.pageX-a(this).offset().left;o<=n/2&&(i.value=i.value-.5)}i.text&&l.next("span").text(i.value+"星"),i.choose&&i.choose(i.value),i.setText&&i.setText(i.value)}),v.on("mousemove",function(e){if(l.find("i").each(function(){a(this).addClass(o).removeClass(r)}),l.find("i:lt("+t+")").each(function(){a(this).addClass(s).removeClass(f)}),i.half){var c=e.pageX-a(this).offset().left;c<=n/2&&v.children("i").addClass(u).removeClass(s)}}),v.on("mouseleave",function(){l.find("i").each(function(){a(this).addClass(o).removeClass(r)}),l.find("i:lt("+Math.floor(i.value)+")").each(function(){a(this).addClass(s).removeClass(f)}),i.half&&parseInt(i.value)!==i.value&&l.children("li:eq("+Math.floor(i.value)+")").children("i").addClass(u).removeClass(c)})})},v.prototype.events=function(){var e=this;e.config},i.render=function(e){var a=new v(e);return l.call(a)},e(n,i)}); -------------------------------------------------------------------------------- /src/main/resources/static/layui/css/modules/layim/html/chatlog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 聊天记录 9 | 10 | 11 | 14 | 15 | 16 | 17 |
    18 |
      19 |
      20 | 21 |
      22 | 23 | 24 | 33 | 34 | 38 | 39 | 40 | 41 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /src/main/resources/static/layui/lay/modules/tree.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.4.5 MIT License By https://www.layui.com */ 2 | ;layui.define("jquery",function(e){"use strict";var o=layui.$,a=layui.hint(),i="layui-tree-enter",r=function(e){this.options=e},t={arrow:["",""],checkbox:["",""],radio:["",""],branch:["",""],leaf:""};r.prototype.init=function(e){var o=this;e.addClass("layui-box layui-tree"),o.options.skin&&e.addClass("layui-tree-skin-"+o.options.skin),o.tree(e),o.on(e)},r.prototype.tree=function(e,a){var i=this,r=i.options,n=a||r.nodes;layui.each(n,function(a,n){var l=n.children&&n.children.length>0,c=o('
        '),s=o(["
      • ",function(){return l?''+(n.spread?t.arrow[1]:t.arrow[0])+"":""}(),function(){return r.check?''+("checkbox"===r.check?t.checkbox[0]:"radio"===r.check?t.radio[0]:"")+"":""}(),function(){return'"+(''+(l?n.spread?t.branch[1]:t.branch[0]:t.leaf)+"")+(""+(n.name||"未命名")+"")}(),"
      • "].join(""));l&&(s.append(c),i.tree(c,n.children)),e.append(s),"function"==typeof r.click&&i.click(s,n),i.spread(s,n),r.drag&&i.drag(s,n)})},r.prototype.click=function(e,o){var a=this,i=a.options;e.children("a").on("click",function(e){layui.stope(e),i.click(o)})},r.prototype.spread=function(e,o){var a=this,i=(a.options,e.children(".layui-tree-spread")),r=e.children("ul"),n=e.children("a"),l=function(){e.data("spread")?(e.data("spread",null),r.removeClass("layui-show"),i.html(t.arrow[0]),n.find(".layui-icon").html(t.branch[0])):(e.data("spread",!0),r.addClass("layui-show"),i.html(t.arrow[1]),n.find(".layui-icon").html(t.branch[1]))};r[0]&&(i.on("click",l),n.on("dblclick",l))},r.prototype.on=function(e){var a=this,r=a.options,t="layui-tree-drag";e.find("i").on("selectstart",function(e){return!1}),r.drag&&o(document).on("mousemove",function(e){var i=a.move;if(i.from){var r=(i.to,o('
        '));e.preventDefault(),o("."+t)[0]||o("body").append(r);var n=o("."+t)[0]?o("."+t):r;n.addClass("layui-show").html(i.from.elem.children("a").html()),n.css({left:e.pageX+10,top:e.pageY+10})}}).on("mouseup",function(){var e=a.move;e.from&&(e.from.elem.children("a").removeClass(i),e.to&&e.to.elem.children("a").removeClass(i),a.move={},o("."+t).remove())})},r.prototype.move={},r.prototype.drag=function(e,a){var r=this,t=(r.options,e.children("a")),n=function(){var t=o(this),n=r.move;n.from&&(n.to={item:a,elem:e},t.addClass(i))};t.on("mousedown",function(){var o=r.move;o.from={item:a,elem:e}}),t.on("mouseenter",n).on("mousemove",n).on("mouseleave",function(){var e=o(this),a=r.move;a.from&&(delete a.to,e.removeClass(i))})},e("tree",function(e){var i=new r(e=e||{}),t=o(e.elem);return t[0]?void i.init(t):a.error("layui.tree 没有找到"+e.elem+"元素")})}); -------------------------------------------------------------------------------- /src/main/resources/static/layui/lay/modules/util.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.4.5 MIT License By https://www.layui.com */ 2 | ;layui.define("jquery",function(t){"use strict";var e=layui.$,i={fixbar:function(t){var i,a,n="layui-fixbar",r="layui-fixbar-top",o=e(document),l=e("body");t=e.extend({showHeight:200},t),t.bar1=t.bar1===!0?"":t.bar1,t.bar2=t.bar2===!0?"":t.bar2,t.bgcolor=t.bgcolor?"background-color:"+t.bgcolor:"";var c=[t.bar1,t.bar2,""],g=e(['
          ',t.bar1?'
        • '+c[0]+"
        • ":"",t.bar2?'
        • '+c[1]+"
        • ":"",'
        • '+c[2]+"
        • ","
        "].join("")),s=g.find("."+r),u=function(){var e=o.scrollTop();e>=t.showHeight?i||(s.show(),i=1):i&&(s.hide(),i=0)};e("."+n)[0]||("object"==typeof t.css&&g.css(t.css),l.append(g),u(),g.find("li").on("click",function(){var i=e(this),a=i.attr("lay-type");"top"===a&&e("html,body").animate({scrollTop:0},200),t.click&&t.click.call(this,a)}),o.on("scroll",function(){clearTimeout(a),a=setTimeout(function(){u()},100)}))},countdown:function(t,e,i){var a=this,n="function"==typeof e,r=new Date(t).getTime(),o=new Date(!e||n?(new Date).getTime():e).getTime(),l=r-o,c=[Math.floor(l/864e5),Math.floor(l/36e5)%24,Math.floor(l/6e4)%60,Math.floor(l/1e3)%60];n&&(i=e);var g=setTimeout(function(){a.countdown(t,o+1e3,i)},1e3);return i&&i(l>0?c:[0,0,0,0],e,g),l<=0&&clearTimeout(g),g},timeAgo:function(t,e){var i=this,a=[[],[]],n=(new Date).getTime()-new Date(t).getTime();return n>6912e5?(n=new Date(t),a[0][0]=i.digit(n.getFullYear(),4),a[0][1]=i.digit(n.getMonth()+1),a[0][2]=i.digit(n.getDate()),e||(a[1][0]=i.digit(n.getHours()),a[1][1]=i.digit(n.getMinutes()),a[1][2]=i.digit(n.getSeconds())),a[0].join("-")+" "+a[1].join(":")):n>=864e5?(n/1e3/60/60/24|0)+"天前":n>=36e5?(n/1e3/60/60|0)+"小时前":n>=12e4?(n/1e3/60|0)+"分钟前":n<0?"未来":"刚刚"},digit:function(t,e){var i="";t=String(t),e=e||2;for(var a=t.length;a/g,">").replace(/'/g,"'").replace(/"/g,""")}};!function(t,e,i){"$:nomunge";function a(){n=e[l](function(){r.each(function(){var e=t(this),i=e.width(),a=e.height(),n=t.data(this,g);(i!==n.w||a!==n.h)&&e.trigger(c,[n.w=i,n.h=a])}),a()},o[s])}var n,r=t([]),o=t.resize=t.extend(t.resize,{}),l="setTimeout",c="resize",g=c+"-special-event",s="delay",u="throttleWindow";o[s]=250,o[u]=!0,t.event.special[c]={setup:function(){if(!o[u]&&this[l])return!1;var e=t(this);r=r.add(e),t.data(this,g,{w:e.width(),h:e.height()}),1===r.length&&a()},teardown:function(){if(!o[u]&&this[l])return!1;var e=t(this);r=r.not(e),e.removeData(g),r.length||clearTimeout(n)},add:function(e){function a(e,a,r){var o=t(this),l=t.data(this,g)||{};l.w=a!==i?a:o.width(),l.h=r!==i?r:o.height(),n.apply(this,arguments)}if(!o[u]&&this[l])return!1;var n;return t.isFunction(e)?(n=e,a):(n=e.handler,void(e.handler=a))}}}(e,window),t("util",i)}); -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/websocket/BaseWsSocket.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.websocket; 2 | 3 | import cn.hutool.core.util.StrUtil; 4 | import cn.hutool.json.JSONUtil; 5 | import cn.hutool.log.StaticLog; 6 | import com.chao.cloud.common.exception.BusinessException; 7 | import com.chao.cloud.im.websocket.constant.MsgEnum; 8 | import com.chao.cloud.im.websocket.model.WsMsgDTO; 9 | 10 | import javax.websocket.Session; 11 | import java.io.IOException; 12 | import java.util.Map; 13 | import java.util.concurrent.ConcurrentHashMap; 14 | 15 | public abstract class BaseWsSocket { 16 | 17 | private static Map, Map> pool = new ConcurrentHashMap<>(); 18 | // concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。 19 | protected Map> webSocketSet = getWsSocketMap(this.getClass()); 20 | // 与某个客户端的连接会话,需要通过它来给客户端发送数据 21 | protected Session session; 22 | // 接收sid 23 | protected T sid; 24 | 25 | /** 26 | * 连接建立成功调用的方法 27 | */ 28 | public final void open(Session session, T sid) { 29 | this.session = session; 30 | webSocketSet.put(sid, this); // 加入set中 31 | this.sid = sid; 32 | try { 33 | StaticLog.info("[{}:有新用户开始连接:user={},当前在线人数为:{}]", serverName(), sid, webSocketSet.size()); 34 | sendMessage(WsMsgDTO.buildMsg(MsgEnum.START, "连接成功!")); 35 | } catch (Exception e) { 36 | StaticLog.error("[{}:user={},websocket IO异常:{}]", serverName(), sid, e.getMessage()); 37 | } 38 | } 39 | 40 | /** 41 | * 连接关闭调用的方法 42 | */ 43 | protected void onClose() { 44 | webSocketSet.remove(this.sid); // 从set中删除 45 | StaticLog.info("{}:有一连接关闭!当前在线人数为:{}", serverName(), webSocketSet.size()); 46 | } 47 | 48 | /** 49 | * 收到客户端消息后调用的方法 50 | * 51 | * @param msg 客户端发送过来的消息 52 | * @throws IOException 53 | */ 54 | protected void onMessage(String msg, Session session) { 55 | StaticLog.info("{}:收到来自用户[{}]的信息:{}", serverName(), sid, msg); 56 | } 57 | 58 | protected void onError(Session session, Throwable error) { 59 | StaticLog.error("{}:发生错误--->{}", serverName(), error); 60 | } 61 | 62 | /** 63 | * 实现服务器主动推送 64 | */ 65 | public void sendMessage(Object msg) { 66 | try { 67 | this.session.getBasicRemote().sendText(JSONUtil.toJsonStr(msg)); 68 | } catch (Exception e) { 69 | throw new BusinessException(e.getMessage()); 70 | } 71 | } 72 | 73 | protected String serverName() { 74 | return StrUtil.lowerFirst(this.getClass().getSimpleName()); 75 | } 76 | 77 | ; 78 | 79 | /** 80 | * 是否存在 81 | * 82 | * @param sid 83 | * @return 84 | */ 85 | protected boolean exist(T sid) { 86 | return webSocketSet.containsKey(sid); 87 | } 88 | 89 | public T getSid() { 90 | return sid; 91 | } 92 | 93 | private static Map getWsSocketMap(Class clazz) { 94 | Map map = pool.get(clazz); 95 | if (map == null) { 96 | synchronized (BaseWsSocket.class) { 97 | map = pool.get(clazz); 98 | if (null == map) { 99 | map = new ConcurrentHashMap<>(); 100 | pool.put(clazz, map); 101 | } 102 | } 103 | } 104 | return map; 105 | } 106 | 107 | } -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/controller/FileController.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.controller; 2 | 3 | import java.io.BufferedOutputStream; 4 | import java.io.OutputStream; 5 | 6 | import javax.servlet.http.HttpServletRequest; 7 | import javax.servlet.http.HttpServletResponse; 8 | import javax.validation.constraints.NotEmpty; 9 | import javax.validation.constraints.NotNull; 10 | 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.validation.annotation.Validated; 13 | import org.springframework.web.bind.annotation.PostMapping; 14 | import org.springframework.web.bind.annotation.RequestMapping; 15 | import org.springframework.web.bind.annotation.RestController; 16 | import org.springframework.web.multipart.MultipartFile; 17 | 18 | import com.baomidou.mybatisplus.extension.api.R; 19 | import com.chao.cloud.common.extra.ftp.IFileOperation; 20 | import com.chao.cloud.common.extra.ftp.annotation.FtpConfig; 21 | import com.chao.cloud.im.domain.dto.LayFileDTO; 22 | 23 | import cn.hutool.extra.servlet.ServletUtil; 24 | import lombok.extern.slf4j.Slf4j; 25 | 26 | /** 27 | * 文件上传 28 | * @功能: 29 | * @author: 薛超 30 | * @时间: 2019年5月30日 31 | * @version 1.0.0 32 | */ 33 | @Slf4j 34 | @Validated 35 | @RestController 36 | @RequestMapping("file") 37 | public class FileController { 38 | 39 | private static final String MESSAGE = "文件不能为空"; 40 | 41 | @Autowired 42 | private IFileOperation fileOperation; 43 | 44 | @Autowired 45 | private FtpConfig ftpConfig; 46 | 47 | /** 48 | * 图片上传 49 | * @return 50 | * @throws Exception 51 | */ 52 | @PostMapping(value = "uploadImg") 53 | public R uploadImg(@NotNull(message = MESSAGE) MultipartFile file, HttpServletRequest request) 54 | throws Exception { 55 | String uploadImg = fileOperation.uploadImg(file.getInputStream(), file.getOriginalFilename()); 56 | // 获取域名 57 | String realm = ServletUtil.getHeaderIgnoreCase(request, "Origin"); 58 | return R.ok(LayFileDTO.builder().src(realm + uploadImg).domain(ftpConfig.getRealm()).build()); 59 | } 60 | 61 | /** 62 | * 上传文件 63 | * @param file 64 | * @return 65 | * @throws Exception 66 | */ 67 | @PostMapping(value = "upload") 68 | public R upload(@NotNull(message = MESSAGE) MultipartFile file, HttpServletRequest request) 69 | throws Exception { 70 | String name = file.getOriginalFilename(); 71 | String uploadImg = fileOperation.uploadInputStream(file.getInputStream(), name); 72 | // 获取域名 73 | String realm = ServletUtil.getHeaderIgnoreCase(request, "Origin"); 74 | return R.ok(LayFileDTO.builder().src(realm + uploadImg).domain(ftpConfig.getRealm()).name(name).build()); 75 | } 76 | 77 | /** 78 | * 文件下载 79 | * @return 80 | * @throws Exception 81 | */ 82 | @RequestMapping(value = "downLoad") 83 | public void downLoad(@NotEmpty(message = MESSAGE) String fileName, HttpServletResponse response) throws Exception { 84 | String finalName = fileName.substring(fileName.lastIndexOf("/")); 85 | try (OutputStream os = new BufferedOutputStream(response.getOutputStream())) { 86 | byte[] downLoad = null; 87 | response.reset(); 88 | response.setContentType("application/x-msdownload"); // 设置返回的文件类型 89 | response.setHeader("Content-Disposition", "attachment;filename=" + finalName); 90 | os.write(downLoad); 91 | os.flush(); 92 | } catch (Exception e) { 93 | log.info("[下载异常信息:fileName={},error={}]", fileName, e.getMessage()); 94 | log.error("[下载异常{}]", e); 95 | } 96 | 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/ai/service/AipUnitService.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.ai.service; 2 | 3 | import java.io.InputStream; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.stream.Collectors; 7 | 8 | import org.json.JSONObject; 9 | import org.springframework.beans.factory.InitializingBean; 10 | 11 | import com.baidu.aip.client.BaseClient; 12 | import com.baidu.aip.http.AipRequest; 13 | import com.baidu.aip.http.EBodyFormat; 14 | import com.chao.cloud.im.ai.constant.AiConstant; 15 | import com.chao.cloud.im.ai.model.BAiResp; 16 | import com.chao.cloud.im.ai.model.BAiResp.Result.Response; 17 | import com.chao.cloud.im.ai.model.BAiResp.Result.Response.Action; 18 | 19 | import cn.hutool.core.bean.BeanUtil; 20 | import cn.hutool.core.collection.CollUtil; 21 | import cn.hutool.core.io.IoUtil; 22 | import cn.hutool.core.io.resource.ResourceUtil; 23 | import cn.hutool.core.lang.Console; 24 | import cn.hutool.core.util.CharsetUtil; 25 | import cn.hutool.core.util.RandomUtil; 26 | import cn.hutool.core.util.ReUtil; 27 | import cn.hutool.core.util.StrUtil; 28 | import cn.hutool.json.JSONUtil; 29 | 30 | /** 31 | * http://ai.baidu.com/docs#/UNIT-v2-service-API/top 32 | * @功能:百度:UNIT机器人对话API文档 33 | * @author: 薛超 34 | * @时间: 2019年7月5日 35 | * @version 1.0.0 36 | */ 37 | public class AipUnitService extends BaseClient implements InitializingBean { 38 | 39 | public AipUnitService(String appId, String apiKey, String secretKey) { 40 | super(appId, apiKey, secretKey); 41 | } 42 | 43 | private String parmTemplate;// request 模板 44 | 45 | /** 46 | * 根据文本返回 47 | * @param text 问题 48 | * @param userId 内部用户id 49 | * @return 50 | */ 51 | public String text(String text, Integer userId) { 52 | AipRequest request = new AipRequest(); 53 | preOperation(request); 54 | // 请求参数 55 | String params = StrUtil.format(parmTemplate, text, userId); 56 | HashMap map = JSONUtil.toBean(params, HashMap.class); 57 | request.setBody(map); 58 | // 设置请求路径 59 | request.setUri(AiConstant.BAI_URL); 60 | request.setBodyFormat(EBodyFormat.RAW_JSON); 61 | postOperation(request); 62 | JSONObject server = requestServer(request); 63 | BAiResp resp = JSONUtil.toBean(server.toString(), BAiResp.class); 64 | if (!AiConstant.TAI_SUCCESS.equals(resp.getError_code())) { 65 | return resp.getError_msg(); 66 | } 67 | List list = resp.getResult().getResponse_list(); 68 | if (CollUtil.isNotEmpty(list)) { 69 | // 获取需要解析的数据 70 | list = list.stream() 71 | .filter(l -> (!AiConstant.GREET_CODE.equals(l.getOrigin()) 72 | || AiConstant.CONFIDENCE_LIMIT < l.getSchema().getIntent_confidence()) // 问候类型 大于50 73 | && CollUtil.isNotEmpty(l.getAction_list())// action不能为空 74 | && l.getAction_list().stream()// 75 | .filter(a -> ReUtil.isMatch(AiConstant.BAI_OK_TYPE, a.getType())).count() > 0)// 只解析这几种类型 76 | .collect(Collectors.toList()); 77 | // 继续解析 78 | Console.log(JSONUtil.toJsonStr(list)); 79 | Response first = CollUtil.getFirst(list); 80 | // 判断信任值 81 | if (!BeanUtil.isEmpty(first) && CollUtil.isNotEmpty(first.getAction_list())) { 82 | List action_list = first.getAction_list(); 83 | // 随机取一条 84 | int index = RandomUtil.randomInt(action_list.size()); 85 | return action_list.get(index).getSay(); 86 | } 87 | } 88 | return AiConstant.ERROR_RESULT; 89 | } 90 | 91 | @Override 92 | public void afterPropertiesSet() throws Exception { 93 | // 解析json 94 | try (InputStream in = ResourceUtil.getStream(AiConstant.BAI_REQUEST_TEMPLATE);) { 95 | parmTemplate = IoUtil.read(in, CharsetUtil.CHARSET_UTF_8); 96 | } 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/main/resources/static/layui/lay/modules/carousel.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.4.5 MIT License By https://www.layui.com */ 2 | ;layui.define("jquery",function(e){"use strict";var i=layui.$,n=(layui.hint(),layui.device(),{config:{},set:function(e){var n=this;return n.config=i.extend({},n.config,e),n},on:function(e,i){return layui.onevent.call(this,t,e,i)}}),t="carousel",a="layui-this",l=">*[carousel-item]>*",o="layui-carousel-left",r="layui-carousel-right",d="layui-carousel-prev",s="layui-carousel-next",u="layui-carousel-arrow",c="layui-carousel-ind",m=function(e){var t=this;t.config=i.extend({},t.config,n.config,e),t.render()};m.prototype.config={width:"600px",height:"280px",full:!1,arrow:"hover",indicator:"inside",autoplay:!0,interval:3e3,anim:"",trigger:"click",index:0},m.prototype.render=function(){var e=this,n=e.config;n.elem=i(n.elem),n.elem[0]&&(e.elemItem=n.elem.find(l),n.index<0&&(n.index=0),n.index>=e.elemItem.length&&(n.index=e.elemItem.length-1),n.interval<800&&(n.interval=800),n.full?n.elem.css({position:"fixed",width:"100%",height:"100%",zIndex:9999}):n.elem.css({width:n.width,height:n.height}),n.elem.attr("lay-anim",n.anim),e.elemItem.eq(n.index).addClass(a),e.elemItem.length<=1||(e.indicator(),e.arrow(),e.autoplay(),e.events()))},m.prototype.reload=function(e){var n=this;clearInterval(n.timer),n.config=i.extend({},n.config,e),n.render()},m.prototype.prevIndex=function(){var e=this,i=e.config,n=i.index-1;return n<0&&(n=e.elemItem.length-1),n},m.prototype.nextIndex=function(){var e=this,i=e.config,n=i.index+1;return n>=e.elemItem.length&&(n=0),n},m.prototype.addIndex=function(e){var i=this,n=i.config;e=e||1,n.index=n.index+e,n.index>=i.elemItem.length&&(n.index=0)},m.prototype.subIndex=function(e){var i=this,n=i.config;e=e||1,n.index=n.index-e,n.index<0&&(n.index=i.elemItem.length-1)},m.prototype.autoplay=function(){var e=this,i=e.config;i.autoplay&&(e.timer=setInterval(function(){e.slide()},i.interval))},m.prototype.arrow=function(){var e=this,n=e.config,t=i(['",'"].join(""));n.elem.attr("lay-arrow",n.arrow),n.elem.find("."+u)[0]&&n.elem.find("."+u).remove(),n.elem.append(t),t.on("click",function(){var n=i(this),t=n.attr("lay-type");e.slide(t)})},m.prototype.indicator=function(){var e=this,n=e.config,t=e.elemInd=i(['
          ',function(){var i=[];return layui.each(e.elemItem,function(e){i.push("")}),i.join("")}(),"
        "].join(""));n.elem.attr("lay-indicator",n.indicator),n.elem.find("."+c)[0]&&n.elem.find("."+c).remove(),n.elem.append(t),"updown"===n.anim&&t.css("margin-top",-(t.height()/2)),t.find("li").on("hover"===n.trigger?"mouseover":n.trigger,function(){var t=i(this),a=t.index();a>n.index?e.slide("add",a-n.index):a ajaxLogin(@Valid LoginVO vo, HttpSession session) { 55 | String random = (String) session.getAttribute(randomCookie); 56 | if (StrUtil.isBlank(random)) { 57 | throw new BusinessException("请刷新验证码"); 58 | } 59 | if (!vo.getVerify().equals(random)) { 60 | throw new BusinessException("请输入正确的验证码"); 61 | } 62 | // 根据登录名获取用户 63 | ImUser user = imUserService.getOne(Wrappers.lambdaQuery().eq(ImUser::getUserName, vo.getUserName())); 64 | if (BeanUtil.isEmpty(user)) { 65 | throw new BusinessException("用户不存在"); 66 | } 67 | if (!vo.getPassword().equals(user.getPassword())) { 68 | throw new BusinessException("密码错误"); 69 | } 70 | if (!ImConstant.Status.OK.equals(user.getStatus())) { 71 | throw new BusinessException("账号被冻结"); 72 | } 73 | LoginDTO dto = BeanUtil.toBean(user, LoginDTO.class); 74 | session.setAttribute(token_key, dto); 75 | return Response.ok(); 76 | 77 | } 78 | 79 | @RequestMapping("/logout") 80 | public String logout(HttpSession session) { 81 | session.invalidate(); 82 | return "redirect:/login"; 83 | } 84 | 85 | /** 86 | * 生成验证码 87 | */ 88 | @RequestMapping("/getVerify") 89 | public void getVerify(HttpServletRequest request, HttpServletResponse response) { 90 | try (OutputStream os = response.getOutputStream()) { 91 | response.setContentType("image/jpeg");// 设置相应类型,告诉浏览器输出的内容为图片 92 | response.setHeader("Pragma", "No-cache");// 设置响应头信息,告诉浏览器不要缓存此内容 93 | response.setHeader("Cache-Control", "no-cache"); 94 | response.setDateHeader("Expire", 0); 95 | // 制作验证码 96 | HyalineCircleCaptcha captcha = HyalineCaptchaUtil.createCircleCaptcha(100, 42, 4, 3); 97 | String code = captcha.getCode(); 98 | log.info("[验证码: {}]", code); 99 | // 存入session 100 | HttpSession session = request.getSession(); 101 | // 将生成的随机字符串保存到session中 102 | session.removeAttribute(randomCookie); 103 | session.setAttribute(randomCookie, code); 104 | // 输出 105 | captcha.write(os); 106 | } catch (Exception e) { 107 | log.error("获取验证码失败--->{} ", e); 108 | } 109 | } 110 | 111 | } -------------------------------------------------------------------------------- /src/main/resources/static/layui/css/modules/layim/mobile/layim.css: -------------------------------------------------------------------------------- 1 | /** layui-v1.0.7 MIT License By http://www.layui.com */ 2 | .layim-chat-main,.layim-chat-main ul{overflow-x:hidden}html #layuicss-skinlayim-mobilecss{display:none;position:absolute;width:1989px}.layim-chat,.layim-chat-main,.layim-chat-title{position:fixed;left:0;right:0}.layim-chat{bottom:0;top:0;background-color:#eee}.layim-chat-title{top:0;height:50px;line-height:50px;text-align:center;background-color:#36373C;color:#fff;font-size:16px}.layim-chat-status{padding-left:5px;font-size:14px}.layim-chat-main{width:100%;bottom:85px;top:50px;padding:15px;overflow-y:auto;-webkit-box-sizing:border-box!important;-moz-box-sizing:border-box!important;box-sizing:border-box!important}.layim-chat-main[nonetitle]{top:0}.layim-chat-main ul li{position:relative;font-size:0;margin-bottom:10px;padding-left:60px;min-height:68px}.layim-chat-text,.layim-chat-user{display:inline-block;*display:inline;*zoom:1;vertical-align:top;font-size:14px}.layim-chat-user{position:absolute;left:3px}.layim-chat-user img{width:40px;height:40px;border-radius:100%}.layim-chat-user cite{position:absolute;left:60px;top:-2px;width:500px;line-height:24px;font-size:12px;white-space:nowrap;color:#999;text-align:left;font-style:normal}.layim-chat-user cite i{padding-left:15px;font-style:normal}.layim-chat-text{position:relative;min-height:22px;line-height:22px;margin-top:25px;padding:8px 15px;background-color:#fff;border-radius:3px;color:#333;word-break:break-all}.layim-chat-text:after{content:'';position:absolute;left:-10px;top:13px;width:0;height:0;border-style:solid dashed dashed;border-color:#fff transparent transparent;overflow:hidden;border-width:10px}.layim-chat-text a{color:#33DF83}.layim-chat-text img{max-width:100%;vertical-align:middle}.layim-chat-text .layui-layim-file,.layui-layim-file{display:block;text-align:center}.layim-chat-text .layui-layim-file{color:#333}.layui-layim-file:hover{opacity:.9}.layui-layim-file i{font-size:80px;line-height:80px}.layui-layim-file cite{display:block;line-height:20px;font-size:14px}.layim-chat-main ul .layim-chat-mine{text-align:right;padding-left:0;padding-right:60px}.layim-chat-mine .layim-chat-user{left:auto;right:3px}.layim-chat-mine .layim-chat-user cite{left:auto;right:60px;text-align:right}.layim-chat-mine .layim-chat-user cite i{padding-left:0;padding-right:15px}.layim-chat-mine .layim-chat-text{margin-left:0;text-align:left;background-color:#5FB878;color:#fff}.layim-chat-mine .layim-chat-text:after{left:auto;right:-10px;border-top-color:#5FB878}.layim-chat-mine .layim-chat-text a{color:#fff}.layim-chat-main ul .layim-chat-system{min-height:0;margin:20px 0 5px;padding:0}.layim-chat-system{margin:10px 0;text-align:center}.layim-chat-system span{display:inline-block;line-height:30px;padding:0 15px;border-radius:3px;background-color:#ddd;color:#fff;font-size:14px}.layim-chat-footer{position:fixed;bottom:0;left:10px;right:10px;height:80px}.layim-chat-send{display:-webkit-box;display:-webkit-flex;display:flex}.layim-chat-send input{-webkit-box-flex:1;-webkit-flex:1;flex:1;height:36px;padding-left:5px;border:0;background-color:#fff;border-radius:3px}.layim-chat-send button{border-radius:3px;height:36px;padding:0 10px;border:0;margin-left:10px;background-color:#5FB878;color:#fff}.layim-chat-tool{position:relative;width:100%;overflow-x:auto;padding:0;height:38px;line-height:38px;margin-top:5px;font-size:0;white-space:nowrap}.layim-chat-tool span{position:relative;margin:0 10px;display:inline-block;*display:inline;*zoom:1;vertical-align:top;font-size:24px;cursor:pointer}.layim-chat-tool .layim-tool-log{position:absolute;right:5px;font-size:14px}.layim-tool-log i{position:relative;top:2px;margin-right:5px;font-size:20px;color:#999}.layim-tool-image input{position:absolute;font-size:0;left:0;top:0;width:100%;height:100%;opacity:.01;filter:Alpha(opacity=1);cursor:pointer}.layim-layer{position:fixed;bottom:85px;left:10px;right:10px;margin:0 auto}.layui-layim-face{position:relative;max-height:180px;overflow:auto;padding:10px;font-size:0}.layui-layim-face li{cursor:pointer;display:inline-block;vertical-align:bottom;padding:5px 2px;text-align:center;width:10%;-webkit-box-sizing:border-box!important;-moz-box-sizing:border-box!important;box-sizing:border-box!important}.layui-layim-face li img{width:22px;height:22px} -------------------------------------------------------------------------------- /src/main/resources/static/layui/lay/modules/laypage.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.4.5 MIT License By https://www.layui.com */ 2 | ;layui.define(function(e){"use strict";var a=document,t="getElementById",n="getElementsByTagName",i="laypage",r="layui-disabled",u=function(e){var a=this;a.config=e||{},a.config.index=++s.index,a.render(!0)};u.prototype.type=function(){var e=this.config;if("object"==typeof e.elem)return void 0===e.elem.length?2:3},u.prototype.view=function(){var e=this,a=e.config,t=a.groups="groups"in a?0|a.groups:5;a.layout="object"==typeof a.layout?a.layout:["prev","page","next"],a.count=0|a.count,a.curr=0|a.curr||1,a.limits="object"==typeof a.limits?a.limits:[10,20,30,40,50],a.limit=0|a.limit||10,a.pages=Math.ceil(a.count/a.limit)||1,a.curr>a.pages&&(a.curr=a.pages),t<0?t=1:t>a.pages&&(t=a.pages),a.prev="prev"in a?a.prev:"上一页",a.next="next"in a?a.next:"下一页";var n=a.pages>t?Math.ceil((a.curr+(t>1?1:0))/(t>0?t:1)):1,i={prev:function(){return a.prev?''+a.prev+"":""}(),page:function(){var e=[];if(a.count<1)return"";n>1&&a.first!==!1&&0!==t&&e.push(''+(a.first||1)+"");var i=Math.floor((t-1)/2),r=n>1?a.curr-i:1,u=n>1?function(){var e=a.curr+(t-i-1);return e>a.pages?a.pages:e}():t;for(u-r2&&e.push('');r<=u;r++)r===a.curr?e.push('"+r+""):e.push(''+r+"");return a.pages>t&&a.pages>u&&a.last!==!1&&(u+1…'),0!==t&&e.push(''+(a.last||a.pages)+"")),e.join("")}(),next:function(){return a.next?''+a.next+"":""}(),count:'共 '+a.count+" 条",limit:function(){var e=['"}(),refresh:['','',""].join(""),skip:function(){return['到第','','页',""].join("")}()};return['
        ',function(){var e=[];return layui.each(a.layout,function(a,t){i[t]&&e.push(i[t])}),e.join("")}(),"
        "].join("")},u.prototype.jump=function(e,a){if(e){var t=this,i=t.config,r=e.children,u=e[n]("button")[0],l=e[n]("input")[0],p=e[n]("select")[0],c=function(){var e=0|l.value.replace(/\s|\D/g,"");e&&(i.curr=e,t.render())};if(a)return c();for(var o=0,y=r.length;oi.pages||(i.curr=e,t.render())});p&&s.on(p,"change",function(){var e=this.value;i.curr*e>i.count&&(i.curr=Math.ceil(i.count/e)),i.limit=e,t.render()}),u&&s.on(u,"click",function(){c()})}},u.prototype.skip=function(e){if(e){var a=this,t=e[n]("input")[0];t&&s.on(t,"keyup",function(t){var n=this.value,i=t.keyCode;/^(37|38|39|40)$/.test(i)||(/\D/.test(n)&&(this.value=n.replace(/\D/,"")),13===i&&a.jump(e,!0))})}},u.prototype.render=function(e){var n=this,i=n.config,r=n.type(),u=n.view();2===r?i.elem&&(i.elem.innerHTML=u):3===r?i.elem.html(u):a[t](i.elem)&&(a[t](i.elem).innerHTML=u),i.jump&&i.jump(i,e);var s=a[t]("layui-laypage-"+i.index);n.jump(s),i.hash&&!e&&(location.hash="!"+i.hash+"="+i.curr),n.skip(s)};var s={render:function(e){var a=new u(e);return a.index},index:layui.laypage?layui.laypage.index+1e4:0,on:function(e,a,t){return e.attachEvent?e.attachEvent("on"+a,function(a){a.target=a.srcElement,t.call(e,a)}):e.addEventListener(a,t,!1),this}};e(i,s)}); -------------------------------------------------------------------------------- /src/main/resources/static/login/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Login 4 | 5 | 6 | 7 | 8 | 9 | 10 |
        11 | 12 | 13 | 14 |
        15 |
        16 |

        Login

        17 |
        18 |
        19 | 20 |
        21 |
        22 | 24 |
        25 |
        26 | 28 |
        29 |
        30 | 31 |
        32 |
        33 |

        The wood of embracing is born at the end of the millimeter; the platform of nine layers 34 | starts from the earth; the journey of a thousand miles starts from the foot.

        35 |

        合抱之木,生于毫末;九层之台,起于累土;千里之行,始于足下。

        36 |
        37 |
        38 | 39 | 143 | 144 | -------------------------------------------------------------------------------- /src/main/resources/static/login/login.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: "Microsoft YaHei", 微软雅黑, "Microsoft JhengHei", 华文细黑, 3 | STHeiti, MingLiu; 4 | text-align: center; 5 | color: #fff; 6 | margin: 0; 7 | height: 100%; 8 | overflow: hidden; 9 | } 10 | 11 | .bgdiv { 12 | width: 100%; 13 | height: 100%; 14 | position: absolute; 15 | z-index: -999; 16 | } 17 | 18 | .bgdiv img { 19 | width: 100%; 20 | height: 100%; 21 | border: 0px; 22 | } 23 | 24 | .content { 25 | padding-top: 8%; 26 | margin: 0 auto; 27 | } 28 | 29 | h1 { 30 | font-size: 30px; 31 | font-weight: 700; 32 | text-shadow: 0 1px 4px rgba(0, 0, 0, .2); 33 | } 34 | 35 | form { 36 | position: relative; 37 | width: 305px; 38 | margin: 15px auto 0 auto; 39 | text-align: center; 40 | } 41 | 42 | input { 43 | width: 270px; 44 | height: 42px; 45 | line-height: 42px; 46 | margin-top: 25px; 47 | padding: 0 15px; 48 | background: #2d2d2d; /* browsers that don't support rgba */ 49 | *background-color: transparent; 50 | background: rgba(45, 45, 45, .35); 51 | -moz-border-radius: 6px; 52 | -webkit-border-radius: 6px; 53 | border-radius: 6px; 54 | border: 1px solid #3d3d3d; /* browsers that don't support rgba */ 55 | border: 1px solid rgba(255, 255, 255, .15); 56 | -moz-box-shadow: 0 2px 3px 0 rgba(0, 0, 0, .1) inset; 57 | -webkit-box-shadow: 0 2px 3px 0 rgba(0, 0, 0, .1) inset; 58 | box-shadow: 0 2px 3px 0 rgba(0, 0, 0, .1) inset; 59 | font-family: 'PT Sans', Helvetica, Arial, sans-serif; 60 | font-size: 14px; 61 | color: #fff; 62 | text-shadow: 0 1px 2px rgba(0, 0, 0, .1); 63 | -o-transition: all .2s; 64 | -moz-transition: all .2s; 65 | -webkit-transition: all .2s; 66 | -ms-transition: all .2s; 67 | background-repeat: no-repeat; 68 | background-position: 5%; 69 | text-indent: 12%; 70 | } 71 | 72 | .userName { 73 | background-size: 20px; 74 | background-image: url(img/user.png); 75 | } 76 | 77 | .password { 78 | background-size: 20px; 79 | background-image: url(img/key.png); 80 | } 81 | 82 | #verify-icon { 83 | position: absolute; 84 | width: 30px; 85 | height: 42px; 86 | background-position: right; 87 | background-size: 70%; 88 | background-repeat: no-repeat; 89 | background-image: url(img/verify.png); 90 | left: .5em; 91 | top: 38%; 92 | } 93 | 94 | .verify { 95 | background-position: right; 96 | background-image: url(/getVerify;123456789); 97 | } 98 | 99 | .verify.onX { 100 | cursor: pointer; 101 | } 102 | 103 | input:-moz-placeholder { 104 | color: #e6e6e6; 105 | text-indent: 12%; 106 | } 107 | 108 | input:-ms-input-placeholder { 109 | color: #e6e6e6; 110 | text-indent: 12%; 111 | } 112 | 113 | input::-webkit-input-placeholder { 114 | color: #e6e6e6; 115 | text-indent: 12%; 116 | } 117 | 118 | input:focus { 119 | outline: none; 120 | -moz-box-shadow: 0 2px 3px 0 rgba(0, 0, 0, .1) inset, 0 2px 7px 0 121 | rgba(0, 0, 0, .2); 122 | -webkit-box-shadow: 0 2px 3px 0 rgba(0, 0, 0, .1) inset, 0 2px 7px 0 123 | rgba(0, 0, 0, .2); 124 | box-shadow: 0 2px 3px 0 rgba(0, 0, 0, .1) inset, 0 2px 7px 0 125 | rgba(0, 0, 0, .2); 126 | } 127 | 128 | button { 129 | cursor: pointer; 130 | width: 300px; 131 | height: 44px; 132 | margin-top: 25px; 133 | padding: 0; 134 | background: #009688; 135 | -moz-border-radius: 6px; 136 | -webkit-border-radius: 6px; 137 | border-radius: 6px; 138 | border: 0px; 139 | -moz-box-shadow: 0 15px 30px 0 rgba(255, 255, 255, .25) inset, 0 2px 7px 140 | 0 rgba(0, 0, 0, .2); 141 | -webkit-box-shadow: 0 15px 30px 0 rgba(255, 255, 255, .25) inset, 0 2px 142 | 7px 0 rgba(0, 0, 0, .2); 143 | box-shadow: 0 15px 30px 0 rgba(255, 255, 255, .25) inset, 0 2px 7px 0 144 | rgba(0, 0, 0, .2); 145 | font-family: 'PT Sans', Helvetica, Arial, sans-serif; 146 | font-size: 14px; 147 | font-weight: 700; 148 | color: #fff; 149 | text-shadow: 0 1px 2px rgba(0, 0, 0, .1); 150 | -o-transition: all .2s; 151 | -moz-transition: all .2s; 152 | -webkit-transition: all .2s; 153 | -ms-transition: all .2s; 154 | } 155 | 156 | button:hover { 157 | -moz-box-shadow: 0 15px 30px 0 rgba(255, 255, 255, .15) inset, 0 2px 7px 158 | 0 rgba(0, 0, 0, .2); 159 | -webkit-box-shadow: 0 15px 30px 0 rgba(255, 255, 255, .15) inset, 0 2px 160 | 7px 0 rgba(0, 0, 0, .2); 161 | box-shadow: 0 15px 30px 0 rgba(255, 255, 255, .15) inset, 0 2px 7px 0 162 | rgba(0, 0, 0, .2); 163 | } 164 | 165 | button:active { 166 | -moz-box-shadow: 0 15px 30px 0 rgba(255, 255, 255, .15) inset, 0 2px 7px 167 | 0 rgba(0, 0, 0, .2); 168 | -webkit-box-shadow: 0 15px 30px 0 rgba(255, 255, 255, .15) inset, 0 2px 169 | 7px 0 rgba(0, 0, 0, .2); 170 | box-shadow: 0 5px 8px 0 rgba(0, 0, 0, .1) inset, 0 1px 4px 0 171 | rgba(0, 0, 0, .1); 172 | border: 0px solid #ef4300; 173 | } 174 | 175 | .famous { 176 | width: 60%; 177 | margin: 50px auto 0 auto; 178 | font-size: 14px; 179 | text-shadow: 0 1px 3px rgba(0, 0, 0, .2); 180 | } 181 | 182 | .famous p { 183 | position: relative; 184 | left: -140%; 185 | color: white; 186 | top: 0 187 | } -------------------------------------------------------------------------------- /src/main/java/com/chao/cloud/im/controller/LayimController.java: -------------------------------------------------------------------------------- 1 | package com.chao.cloud.im.controller; 2 | 3 | import java.util.Collections; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.Set; 7 | import java.util.stream.Collectors; 8 | 9 | import javax.servlet.http.HttpSession; 10 | import javax.validation.Valid; 11 | import javax.validation.constraints.NotNull; 12 | 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.stereotype.Controller; 15 | import org.springframework.ui.Model; 16 | import org.springframework.validation.annotation.Validated; 17 | import org.springframework.web.bind.annotation.PathVariable; 18 | import org.springframework.web.bind.annotation.RequestMapping; 19 | import org.springframework.web.bind.annotation.ResponseBody; 20 | 21 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 22 | import com.baomidou.mybatisplus.core.toolkit.Wrappers; 23 | import com.baomidou.mybatisplus.extension.api.R; 24 | import com.chao.cloud.im.ai.constant.AiConstant; 25 | import com.chao.cloud.im.dal.entity.ImGroupUser; 26 | import com.chao.cloud.im.dal.entity.ImMsgHis; 27 | import com.chao.cloud.im.dal.entity.ImUser; 28 | import com.chao.cloud.im.domain.dto.LoginDTO; 29 | import com.chao.cloud.im.domain.vo.MsgHisVO; 30 | import com.chao.cloud.im.service.ImGroupService; 31 | import com.chao.cloud.im.service.ImGroupUserService; 32 | import com.chao.cloud.im.service.ImMsgHisService; 33 | import com.chao.cloud.im.service.ImUserService; 34 | import com.chao.cloud.im.websocket.LayimChatWebSocket; 35 | import com.chao.cloud.im.websocket.constant.ImConstant; 36 | import com.chao.cloud.im.websocket.model.LayimModel; 37 | import com.chao.cloud.im.websocket.model.LayimModel.Friend; 38 | import com.chao.cloud.im.websocket.model.LayimModel.Group; 39 | import com.chao.cloud.im.websocket.model.LayimModel.Member; 40 | import com.chao.cloud.im.websocket.model.LayimModel.User; 41 | 42 | import cn.hutool.core.collection.CollUtil; 43 | import cn.hutool.core.util.StrUtil; 44 | 45 | @RequestMapping("layim") 46 | @Controller 47 | @Validated 48 | public class LayimController extends BaseController { 49 | 50 | private final String friendKeyTemplate = "{}@{}"; 51 | @Autowired 52 | private ImUserService imUserService; 53 | @Autowired 54 | private ImGroupService imGroupService; 55 | @Autowired 56 | private ImGroupUserService imGroupUserService; 57 | @Autowired 58 | private LayimChatWebSocket singleChatWebSocket; 59 | @Autowired 60 | private ImMsgHisService imMsgHisService; 61 | 62 | @RequestMapping("/page/{html}") 63 | public String html(@PathVariable("html") String html) { 64 | return "layim/" + html; 65 | } 66 | 67 | @RequestMapping("/chatlog") 68 | public String chatlog(@Valid MsgHisVO vo, HttpSession session, Model m) { 69 | // 获取当前用户 70 | LoginDTO user = getUser(session); 71 | // 去重 72 | Set fromTo = CollUtil.newHashSet(ImMsgHisService.fromTo(user.getId(), vo.getId()), 73 | ImMsgHisService.fromTo(vo.getId(), user.getId())); 74 | // 构造条件 75 | LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); 76 | queryWrapper.in(ImMsgHis::getFromTo, fromTo); 77 | queryWrapper.eq(ImMsgHis::getType, vo.getType()); 78 | // 获取数据总数 79 | int count = imMsgHisService.count(queryWrapper); 80 | m.addAttribute("count", count); 81 | return "layim/chatlog"; 82 | } 83 | 84 | /** 85 | * 初始化参数 86 | * @param html 87 | * @return 88 | */ 89 | @RequestMapping("/initData") 90 | @ResponseBody 91 | public R initData(HttpSession session) { 92 | LayimModel model = new LayimModel(); 93 | // 获取自己-好友列表-群组列表 94 | User mine = LayimModel.userConvert(getUser(session)); 95 | mine.setStatus(ImConstant.LineStatus.ON);// 在线 96 | // mine 97 | model.setMine(mine); 98 | // friend 99 | List list = imUserService.list(); 100 | // 分组->归类 101 | if (CollUtil.isNotEmpty(list)) { 102 | Map> friendMap = list.stream().collect( 103 | Collectors.groupingBy(iu -> StrUtil.format(friendKeyTemplate, iu.getDeptId(), iu.getDeptName()))); 104 | Set onlineKey = singleChatWebSocket.onlineKey(); 105 | // 设置在线状态 106 | List friends = CollUtil.newArrayList(); 107 | friendMap.forEach((k, v) -> { 108 | String[] dept = k.split("@"); 109 | Friend friend = new LayimModel.Friend(); 110 | friend.setId(Integer.valueOf(dept[0])); 111 | friend.setGroupname(dept[1]); 112 | List users = v.stream().map(u -> { 113 | User user = LayimModel.userConvert(u); 114 | user.setStatus(AiConstant.REBOT_ID_LIST.contains(u.getId()) || onlineKey.contains(u.getId()) 115 | ? ImConstant.LineStatus.ON 116 | : ImConstant.LineStatus.OFF); 117 | return user; 118 | }).collect(Collectors.toList()); 119 | friend.setList(users); 120 | friends.add(friend); 121 | }); 122 | model.setFriend(friends); 123 | } 124 | // group 125 | List groups = imGroupService.list().stream().map(g -> { 126 | Group group = new LayimModel.Group(); 127 | group.setId(g.getId()); 128 | group.setGroupname(g.getNickName()); 129 | group.setAvatar(g.getHeadImg()); 130 | return group; 131 | }).collect(Collectors.toList()); 132 | model.setGroup(groups); 133 | return R.ok(model); 134 | } 135 | 136 | /** 137 | * 群成员 138 | * @param id 群id 139 | * @return 140 | */ 141 | @RequestMapping("/members") 142 | @ResponseBody 143 | public R memebers(@NotNull Integer id) { 144 | // 根据群id 查询群下的会员 145 | List groupUsers = imGroupUserService 146 | .list(Wrappers.lambdaQuery().eq(ImGroupUser::getGroupId, id)); 147 | List list = Collections.emptyList(); 148 | if (CollUtil.isNotEmpty(groupUsers)) { 149 | List userIds = groupUsers.stream().map(ImGroupUser::getUserId).collect(Collectors.toList()); 150 | list = imUserService.list(Wrappers.lambdaQuery().in(ImUser::getId, userIds)).stream() 151 | .map(LayimModel::userConvert).collect(Collectors.toList()); 152 | } 153 | return R.ok(Member.builder().list(list).build()); 154 | } 155 | 156 | } -------------------------------------------------------------------------------- /src/main/resources/templates/layim/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | layim 5 | 6 | 7 | 8 | 9 |
        10 | (AI): im 智能聊天历史进程 11 |
        12 |
          13 |
        • 14 | 15 |
          16 |
          2019-07-01,整合腾讯/百度AI,实现智能机器人对话......
          17 |
          18 |
        • 19 |
        • 20 | 21 |
          22 |
          2019-06-20,历史消息,离线消息记录
          23 |
          24 |
        • 25 |
        • 26 | 27 |
          28 |
          2019-06-01,图片,文件上传
          29 |
          30 |
        • 31 |
        • 32 | 33 |
          34 |
          2019-05-20,集成websocket
          35 |
          36 |
        • 37 |
        • 38 | 39 |
          40 |
          2019-05-10,集成layim 前端框架
          41 |
          42 |
        • 43 |
        • 44 | 45 |
          46 |
          2019-04-20,im 首个版本发布
          47 |
          48 |
        • 49 |
        • 50 | 51 |
          52 |
          2019-04-10,im 孵化
          53 |
          54 |
        • 55 |
        • 56 | 57 |
          58 |
          2019-04-05,创立im项目
          59 |
          60 |
        • 61 |
        62 | 63 |
        64 | 65 | 66 | 190 | 191 | -------------------------------------------------------------------------------- /src/main/resources/static/layui/layui.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.4.5 MIT License By https://www.layui.com */ 2 | ;!function(e){"use strict";var t=document,o={modules:{},status:{},timeout:10,event:{}},n=function(){this.v="2.4.5"},r=function(){var e=t.currentScript?t.currentScript.src:function(){for(var e,o=t.scripts,n=o.length-1,r=n;r>0;r--)if("interactive"===o[r].readyState){e=o[r].src;break}return e||o[n].src}();return e.substring(0,e.lastIndexOf("/")+1)}(),i=function(t){e.console&&console.error&&console.error("Layui hint: "+t)},a="undefined"!=typeof opera&&"[object Opera]"===opera.toString(),u={layer:"modules/layer",laydate:"modules/laydate",laypage:"modules/laypage",laytpl:"modules/laytpl",layim:"modules/layim",layedit:"modules/layedit",form:"modules/form",upload:"modules/upload",tree:"modules/tree",table:"modules/table",element:"modules/element",rate:"modules/rate",colorpicker:"modules/colorpicker",slider:"modules/slider",carousel:"modules/carousel",flow:"modules/flow",util:"modules/util",code:"modules/code",jquery:"modules/jquery",mobile:"modules/mobile","layui.all":"../layui.all"};n.prototype.cache=o,n.prototype.define=function(e,t){var n=this,r="function"==typeof e,i=function(){var e=function(e,t){layui[e]=t,o.status[e]=!0};return"function"==typeof t&&t(function(n,r){e(n,r),o.callback[n]=function(){t(e)}}),this};return r&&(t=e,e=[]),layui["layui.all"]||!layui["layui.all"]&&layui["layui.mobile"]?i.call(n):(n.use(e,i),n)},n.prototype.use=function(e,n,l){function s(e,t){var n="PLaySTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/;("load"===e.type||n.test((e.currentTarget||e.srcElement).readyState))&&(o.modules[f]=t,d.removeChild(v),function r(){return++m>1e3*o.timeout/4?i(f+" is not a valid module"):void(o.status[f]?c():setTimeout(r,4))}())}function c(){l.push(layui[f]),e.length>1?y.use(e.slice(1),n,l):"function"==typeof n&&n.apply(layui,l)}var y=this,p=o.dir=o.dir?o.dir:r,d=t.getElementsByTagName("head")[0];e="string"==typeof e?[e]:e,window.jQuery&&jQuery.fn.on&&(y.each(e,function(t,o){"jquery"===o&&e.splice(t,1)}),layui.jquery=layui.$=jQuery);var f=e[0],m=0;if(l=l||[],o.host=o.host||(p.match(/\/\/([\s\S]+?)\//)||["//"+location.host+"/"])[0],0===e.length||layui["layui.all"]&&u[f]||!layui["layui.all"]&&layui["layui.mobile"]&&u[f])return c(),y;if(o.modules[f])!function g(){return++m>1e3*o.timeout/4?i(f+" is not a valid module"):void("string"==typeof o.modules[f]&&o.status[f]?c():setTimeout(g,4))}();else{var v=t.createElement("script"),h=(u[f]?p+"lay/":/^\{\/\}/.test(y.modules[f])?"":o.base||"")+(y.modules[f]||f)+".js";h=h.replace(/^\{\/\}/,""),v.async=!0,v.charset="utf-8",v.src=h+function(){var e=o.version===!0?o.v||(new Date).getTime():o.version||"";return e?"?v="+e:""}(),d.appendChild(v),!v.attachEvent||v.attachEvent.toString&&v.attachEvent.toString().indexOf("[native code")<0||a?v.addEventListener("load",function(e){s(e,h)},!1):v.attachEvent("onreadystatechange",function(e){s(e,h)}),o.modules[f]=h}return y},n.prototype.getStyle=function(t,o){var n=t.currentStyle?t.currentStyle:e.getComputedStyle(t,null);return n[n.getPropertyValue?"getPropertyValue":"getAttribute"](o)},n.prototype.link=function(e,n,r){var a=this,u=t.createElement("link"),l=t.getElementsByTagName("head")[0];"string"==typeof n&&(r=n);var s=(r||e).replace(/\.|\//g,""),c=u.id="layuicss-"+s,y=0;return u.rel="stylesheet",u.href=e+(o.debug?"?v="+(new Date).getTime():""),u.media="all",t.getElementById(c)||l.appendChild(u),"function"!=typeof n?a:(function p(){return++y>1e3*o.timeout/100?i(e+" timeout"):void(1989===parseInt(a.getStyle(t.getElementById(c),"width"))?function(){n()}():setTimeout(p,100))}(),a)},o.callback={},n.prototype.factory=function(e){if(layui[e])return"function"==typeof o.callback[e]?o.callback[e]:null},n.prototype.addcss=function(e,t,n){return layui.link(o.dir+"css/"+e,t,n)},n.prototype.img=function(e,t,o){var n=new Image;return n.src=e,n.complete?t(n):(n.onload=function(){n.onload=null,"function"==typeof t&&t(n)},void(n.onerror=function(e){n.onerror=null,"function"==typeof o&&o(e)}))},n.prototype.config=function(e){e=e||{};for(var t in e)o[t]=e[t];return this},n.prototype.modules=function(){var e={};for(var t in u)e[t]=u[t];return e}(),n.prototype.extend=function(e){var t=this;e=e||{};for(var o in e)t[o]||t.modules[o]?i("模块名 "+o+" 已被占用"):t.modules[o]=e[o];return t},n.prototype.router=function(e){var t=this,e=e||location.hash,o={path:[],search:{},hash:(e.match(/[^#](#.*$)/)||[])[1]||""};return/^#\//.test(e)?(e=e.replace(/^#\//,""),o.href="/"+e,e=e.replace(/([^#])(#.*$)/,"$1").split("/")||[],t.each(e,function(e,t){/^\w+=/.test(t)?function(){t=t.split("="),o.search[t[0]]=t[1]}():o.path.push(t)}),o):o},n.prototype.data=function(t,o,n){if(t=t||"layui",n=n||localStorage,e.JSON&&e.JSON.parse){if(null===o)return delete n[t];o="object"==typeof o?o:{key:o};try{var r=JSON.parse(n[t])}catch(i){var r={}}return"value"in o&&(r[o.key]=o.value),o.remove&&delete r[o.key],n[t]=JSON.stringify(r),o.key?r[o.key]:r}},n.prototype.sessionData=function(e,t){return this.data(e,t,sessionStorage)},n.prototype.device=function(t){var o=navigator.userAgent.toLowerCase(),n=function(e){var t=new RegExp(e+"/([^\\s\\_\\-]+)");return e=(o.match(t)||[])[1],e||!1},r={os:function(){return/windows/.test(o)?"windows":/linux/.test(o)?"linux":/iphone|ipod|ipad|ios/.test(o)?"ios":/mac/.test(o)?"mac":void 0}(),ie:function(){return!!(e.ActiveXObject||"ActiveXObject"in e)&&((o.match(/msie\s(\d+)/)||[])[1]||"11")}(),weixin:n("micromessenger")};return t&&!r[t]&&(r[t]=n(t)),r.android=/android/.test(o),r.ios="ios"===r.os,r},n.prototype.hint=function(){return{error:i}},n.prototype.each=function(e,t){var o,n=this;if("function"!=typeof t)return n;if(e=e||[],e.constructor===Object){for(o in e)if(t.call(e[o],o,e[o]))break}else for(o=0;oi?1:r"].join("")),o=t.elem.next();(o.hasClass(u)||o.hasClass(c))&&o.remove(),a.ie&&a.ie<10&&t.elem.wrap('
        '),e.isFile()?(e.elemFile=t.elem,t.field=t.elem[0].name):t.elem.after(n),a.ie&&a.ie<10&&e.initIE()},p.prototype.initIE=function(){var e=this,t=e.config,n=i(''),a=i(['
        ',"
        "].join(""));i("#"+f)[0]||i("body").append(n),t.elem.next().hasClass(c)||(e.elemFile.wrap(a),t.elem.next("."+c).append(function(){var e=[];return layui.each(t.data,function(i,t){t="function"==typeof t?t():t,e.push('')}),e.join("")}()))},p.prototype.msg=function(e){return t.msg(e,{icon:2,shift:6})},p.prototype.isFile=function(){var e=this.config.elem[0];if(e)return"input"===e.tagName.toLocaleLowerCase()&&"file"===e.type},p.prototype.preview=function(e){var i=this;window.FileReader&&layui.each(i.chooseFiles,function(i,t){var n=new FileReader;n.readAsDataURL(t),n.onload=function(){e&&e(i,t,this.result)}})},p.prototype.upload=function(e,t){var n,o=this,l=o.config,r=o.elemFile[0],u=function(){var t=0,n=0,a=e||o.files||o.chooseFiles||r.files,u=function(){l.multiple&&t+n===o.fileLength&&"function"==typeof l.allDone&&l.allDone({total:o.fileLength,successful:t,aborted:n})};layui.each(a,function(e,a){var r=new FormData;r.append(l.field,a),layui.each(l.data,function(e,i){i="function"==typeof i?i():i,r.append(e,i)}),i.ajax({url:l.url,type:"post",data:r,contentType:!1,processData:!1,dataType:"json",headers:l.headers||{},success:function(i){t++,d(e,i),u()},error:function(){n++,o.msg("请求上传接口出现异常"),m(e),u()}})})},c=function(){var e=i("#"+f);o.elemFile.parent().submit(),clearInterval(p.timer),p.timer=setInterval(function(){var i,t=e.contents().find("body");try{i=t.text()}catch(n){o.msg("获取上传后的响应信息出现异常"),clearInterval(p.timer),m()}i&&(clearInterval(p.timer),t.html(""),d(0,i))},30)},d=function(e,i){if(o.elemFile.next("."+s).remove(),r.value="","object"!=typeof i)try{i=JSON.parse(i)}catch(t){return i={},o.msg("请对上传接口返回有效JSON")}"function"==typeof l.done&&l.done(i,e||0,function(e){o.upload(e)})},m=function(e){l.auto&&(r.value=""),"function"==typeof l.error&&l.error(e||0,function(e){o.upload(e)})},h=l.exts,v=function(){var i=[];return layui.each(e||o.chooseFiles,function(e,t){i.push(t.name)}),i}(),g={preview:function(e){o.preview(e)},upload:function(e,i){var t={};t[e]=i,o.upload(t)},pushFile:function(){return o.files=o.files||{},layui.each(o.chooseFiles,function(e,i){o.files[e]=i}),o.files},resetFile:function(e,i,t){var n=new File([i],t);o.files=o.files||{},o.files[e]=n}},y=function(){if("choose"!==t&&!l.auto||(l.choose&&l.choose(g),"choose"!==t))return l.before&&l.before(g),a.ie?a.ie>9?u():c():void u()};if(v=0===v.length?r.value.match(/[^\/\\]+\..+/g)||[]||"":v,0!==v.length){switch(l.accept){case"file":if(h&&!RegExp("\\w\\.("+h+")$","i").test(escape(v)))return o.msg("选择的文件中包含不支持的格式"),r.value="";break;case"video":if(!RegExp("\\w\\.("+(h||"avi|mp4|wma|rmvb|rm|flash|3gp|flv")+")$","i").test(escape(v)))return o.msg("选择的视频中包含不支持的格式"),r.value="";break;case"audio":if(!RegExp("\\w\\.("+(h||"mp3|wav|mid")+")$","i").test(escape(v)))return o.msg("选择的音频中包含不支持的格式"),r.value="";break;default:if(layui.each(v,function(e,i){RegExp("\\w\\.("+(h||"jpg|png|gif|bmp|jpeg$")+")","i").test(escape(i))||(n=!0)}),n)return o.msg("选择的图片中包含不支持的格式"),r.value=""}if(o.fileLength=function(){var i=0,t=e||o.files||o.chooseFiles||r.files;return layui.each(t,function(){i++}),i}(),l.number&&o.fileLength>l.number)return o.msg("同时最多只能上传的数量为:"+l.number);if(l.size>0&&!(a.ie&&a.ie<10)){var F;if(layui.each(o.chooseFiles,function(e,i){if(i.size>1024*l.size){var t=l.size/1024;t=t>=1?t.toFixed(2)+"MB":l.size+"KB",r.value="",F=t}}),F)return o.msg("文件不能超过"+F)}y()}},p.prototype.events=function(){var e=this,t=e.config,o=function(i){e.chooseFiles={},layui.each(i,function(i,t){var n=(new Date).getTime();e.chooseFiles[n+"-"+i]=t})},l=function(i,n){var a=e.elemFile,o=i.length>1?i.length+"个文件":(i[0]||{}).name||a[0].value.match(/[^\/\\]+\..+/g)||[]||"";a.next().hasClass(s)&&a.next().remove(),e.upload(null,"choose"),e.isFile()||t.choose||a.after(''+o+"")};t.elem.off("upload.start").on("upload.start",function(){var a=i(this),o=a.attr("lay-data");if(o)try{o=new Function("return "+o)(),e.config=i.extend({},t,o)}catch(l){n.error("Upload element property lay-data configuration item has a syntax error: "+o)}e.config.item=a,e.elemFile[0].click()}),a.ie&&a.ie<10||t.elem.off("upload.over").on("upload.over",function(){var e=i(this);e.attr("lay-over","")}).off("upload.leave").on("upload.leave",function(){var e=i(this);e.removeAttr("lay-over")}).off("upload.drop").on("upload.drop",function(n,a){var r=i(this),u=a.originalEvent.dataTransfer.files||[];r.removeAttr("lay-over"),o(u),t.auto?e.upload(u):l(u)}),e.elemFile.off("upload.change").on("upload.change",function(){var i=this.files||[];o(i),t.auto?e.upload():l(i)}),t.bindAction.off("upload.action").on("upload.action",function(){e.upload()}),t.elem.data("haveEvents")||(e.elemFile.on("change",function(){i(this).trigger("upload.change")}),t.elem.on("click",function(){e.isFile()||i(this).trigger("upload.start")}),t.drag&&t.elem.on("dragover",function(e){e.preventDefault(),i(this).trigger("upload.over")}).on("dragleave",function(e){i(this).trigger("upload.leave")}).on("drop",function(e){e.preventDefault(),i(this).trigger("upload.drop",e)}),t.bindAction.on("click",function(){i(this).trigger("upload.action")}),t.elem.data("haveEvents",!0))},o.render=function(e){var i=new p(e);return l.call(i)},e(r,o)}); -------------------------------------------------------------------------------- /src/main/resources/static/layui/lay/modules/slider.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.4.5 MIT License By https://www.layui.com */ 2 | ;layui.define("jquery",function(e){"use strict";var i=layui.jquery,t={config:{},index:layui.slider?layui.slider.index+1e4:0,set:function(e){var t=this;return t.config=i.extend({},t.config,e),t},on:function(e,i){return layui.onevent.call(this,n,e,i)}},a=function(){var e=this,i=e.config;return{setValue:function(i,t){return e.slide("set",i,t||0)},config:i}},n="slider",l="layui-disabled",s="layui-slider",r="layui-slider-bar",o="layui-slider-wrap",u="layui-slider-wrap-btn",d="layui-slider-tips",v="layui-slider-input",c="layui-slider-input-txt",m="layui-slider-input-btn",p="layui-slider-hover",f=function(e){var a=this;a.index=++t.index,a.config=i.extend({},a.config,t.config,e),a.render()};f.prototype.config={type:"default",min:0,max:100,value:0,step:1,showstep:!1,tips:!0,input:!1,range:!1,height:200,disabled:!1,theme:"#009688"},f.prototype.render=function(){var e=this,t=e.config;if(t.step<1&&(t.step=1),t.maxt.min?a:t.min,t.value[1]=n>t.min?n:t.min,t.value[0]=t.value[0]>t.max?t.max:t.value[0],t.value[1]=t.value[1]>t.max?t.max:t.value[1];var r=Math.floor((t.value[0]-t.min)/(t.max-t.min)*100),v=Math.floor((t.value[1]-t.min)/(t.max-t.min)*100),m=v-r+"%";r+="%",v+="%"}else{"object"==typeof t.value&&(t.value=Math.min.apply(null,t.value)),t.valuet.max&&(t.value=t.max);var m=Math.floor((t.value-t.min)/(t.max-t.min)*100)+"%"}var p=t.disabled?"#c2c2c2":t.theme,f='
        '+(t.tips?'
        ':"")+'
        '+(t.range?'
        ':"")+"
        ",h=i(t.elem),y=h.next("."+s);if(y[0]&&y.remove(),e.elemTemp=i(f),t.range?(e.elemTemp.find("."+o).eq(0).data("value",t.value[0]),e.elemTemp.find("."+o).eq(1).data("value",t.value[1])):e.elemTemp.find("."+o).data("value",t.value),h.html(e.elemTemp),"vertical"===t.type&&e.elemTemp.height(t.height+"px"),t.showstep){for(var g=(t.max-t.min)/t.step,b="",x=1;x')}e.elemTemp.append(b)}if(t.input&&!t.range){var w=i('
        ');h.css("position","relative"),h.append(w),h.find("."+c).children("input").val(t.value),"vertical"===t.type?w.css({left:0,top:-48}):e.elemTemp.css("margin-right",w.outerWidth()+15)}t.disabled?(e.elemTemp.addClass(l),e.elemTemp.find("."+u).addClass(l)):e.slide(),e.elemTemp.find("."+u).on("mouseover",function(){var a="vertical"===t.type?t.height:e.elemTemp[0].offsetWidth,n=e.elemTemp.find("."+o),l="vertical"===t.type?a-i(this).parent()[0].offsetTop-n.height():i(this).parent()[0].offsetLeft,s=l/a*100,r=i(this).parent().data("value"),u=t.setTips?t.setTips(r):r;e.elemTemp.find("."+d).html(u),"vertical"===t.type?e.elemTemp.find("."+d).css({bottom:s+"%","margin-bottom":"20px",display:"inline-block"}):e.elemTemp.find("."+d).css({left:s+"%",display:"inline-block"})}).on("mouseout",function(){e.elemTemp.find("."+d).css("display","none")})},f.prototype.slide=function(e,t,a){var n=this,l=n.config,s=n.elemTemp,f=function(){return"vertical"===l.type?l.height:s[0].offsetWidth},h=s.find("."+o),y=s.next("."+v),g=y.children("."+c).children("input").val(),b=100/((l.max-l.min)/Math.ceil(l.step)),x=function(e,i){e=Math.ceil(e)*b>100?Math.ceil(e)*b:Math.round(e)*b,e=e>100?100:e,h.eq(i).css("vertical"===l.type?"bottom":"left",e+"%");var t=T(h[0].offsetLeft),a=l.range?T(h[1].offsetLeft):0;"vertical"===l.type?(s.find("."+d).css({bottom:e+"%","margin-bottom":"20px"}),t=T(f()-h[0].offsetTop-h.height()),a=l.range?T(f()-h[1].offsetTop-h.height()):0):s.find("."+d).css("left",e+"%"),t=t>100?100:t,a=a>100?100:a;var n=Math.min(t,a),o=Math.abs(t-a);"vertical"===l.type?s.find("."+r).css({height:o+"%",bottom:n+"%"}):s.find("."+r).css({width:o+"%",left:n+"%"});var u=l.min+Math.round((l.max-l.min)*e/100);if(g=u,y.children("."+c).children("input").val(g),h.eq(i).data("value",u),u=l.setTips?l.setTips(u):u,s.find("."+d).html(u),l.range){var v=[h.eq(0).data("value"),h.eq(1).data("value")];v[0]>v[1]&&v.reverse()}l.change&&l.change(l.range?v:u)},T=function(e){var i=e/f()*100/b,t=Math.round(i)*b;return e==f()&&(t=Math.ceil(i)*b),t},w=i(['
        f()&&(r=f());var o=r/f()*100/b;x(o,e),t.addClass(p),s.find("."+d).show(),i.preventDefault()},o=function(){t.removeClass(p),s.find("."+d).hide()};M(r,o)})}),s.on("click",function(e){var t=i("."+u);if(!t.is(event.target)&&0===t.has(event.target).length&&t.length){var a,n="vertical"===l.type?f()-e.clientY+i(this).offset().top:e.clientX-i(this).offset().left;n<0&&(n=0),n>f()&&(n=f());var s=n/f()*100/b;a=l.range?"vertical"===l.type?Math.abs(n-parseInt(i(h[0]).css("bottom")))>Math.abs(n-parseInt(i(h[1]).css("bottom")))?1:0:Math.abs(n-h[0].offsetLeft)>Math.abs(n-h[1].offsetLeft)?1:0:0,x(s,a),e.preventDefault()}}),y.hover(function(){var e=i(this);e.children("."+m).fadeIn("fast")},function(){var e=i(this);e.children("."+m).fadeOut("fast")}),y.children("."+m).children("i").each(function(e){i(this).on("click",function(){g=1==e?g-l.stepl.max?l.max:Number(g)+l.step;var i=(g-l.min)/(l.max-l.min)*100/b;x(i,0)})});var q=function(){var e=this.value;e=isNaN(e)?0:e,e=el.max?l.max:e,this.value=e;var i=(e-l.min)/(l.max-l.min)*100/b;x(i,0)};y.children("."+c).children("input").on("keydown",function(e){13===e.keyCode&&(e.preventDefault(),q.call(this))}).on("change",q)},f.prototype.events=function(){var e=this;e.config},t.render=function(e){var i=new f(e);return a.call(i)},e(n,t)}); -------------------------------------------------------------------------------- /src/main/resources/static/layui/css/modules/layim/html/msgbox.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 消息盒子 9 | 10 | 11 | 25 | 26 | 27 | 28 |
          29 | 30 |
          31 |
          注意:这些都是模拟数据,实际使用时,需将其中的模拟接口改为你的项目真实接口。 32 |
          该模版文件所在目录(相对于layui.js):/css/modules/layim/html/msgbox.html
          33 |
          34 | 35 | 62 | 63 | 66 | 67 | 68 | 69 | 206 | 207 | 208 | -------------------------------------------------------------------------------- /src/main/resources/static/layui/lay/modules/element.js: -------------------------------------------------------------------------------- 1 | /** layui-v2.4.5 MIT License By https://www.layui.com */ 2 | ;layui.define("jquery",function(t){"use strict";var a=layui.$,i=(layui.hint(),layui.device()),e="element",l="layui-this",n="layui-show",s=function(){this.config={}};s.prototype.set=function(t){var i=this;return a.extend(!0,i.config,t),i},s.prototype.on=function(t,a){return layui.onevent.call(this,e,t,a)},s.prototype.tabAdd=function(t,i){var e=".layui-tab-title",l=a(".layui-tab[lay-filter="+t+"]"),n=l.children(e),s=n.children(".layui-tab-bar"),o=l.children(".layui-tab-content"),r='
        • "+(i.title||"unnaming")+"
        • ";return s[0]?s.before(r):n.append(r),o.append('
          '+(i.content||"")+"
          "),f.hideTabMore(!0),f.tabAuto(),this},s.prototype.tabDelete=function(t,i){var e=".layui-tab-title",l=a(".layui-tab[lay-filter="+t+"]"),n=l.children(e),s=n.find('>li[lay-id="'+i+'"]');return f.tabDelete(null,s),this},s.prototype.tabChange=function(t,i){var e=".layui-tab-title",l=a(".layui-tab[lay-filter="+t+"]"),n=l.children(e),s=n.find('>li[lay-id="'+i+'"]');return f.tabClick.call(s[0],null,null,s),this},s.prototype.tab=function(t){t=t||{},b.on("click",t.headerElem,function(i){var e=a(this).index();f.tabClick.call(this,i,e,null,t)})},s.prototype.progress=function(t,i){var e="layui-progress",l=a("."+e+"[lay-filter="+t+"]"),n=l.find("."+e+"-bar"),s=n.find("."+e+"-text");return n.css("width",i),s.text(i),this};var o=".layui-nav",r="layui-nav-item",c="layui-nav-bar",u="layui-nav-tree",d="layui-nav-child",y="layui-nav-more",h="layui-anim layui-anim-upbit",f={tabClick:function(t,i,s,o){o=o||{};var r=s||a(this),i=i||r.parent().children("li").index(r),c=o.headerElem?r.parent():r.parents(".layui-tab").eq(0),u=o.bodyElem?a(o.bodyElem):c.children(".layui-tab-content").children(".layui-tab-item"),d=r.find("a"),y=c.attr("lay-filter");"javascript:;"!==d.attr("href")&&"_blank"===d.attr("target")||(r.addClass(l).siblings().removeClass(l),u.eq(i).addClass(n).siblings().removeClass(n)),layui.event.call(this,e,"tab("+y+")",{elem:c,index:i})},tabDelete:function(t,i){var n=i||a(this).parent(),s=n.index(),o=n.parents(".layui-tab").eq(0),r=o.children(".layui-tab-content").children(".layui-tab-item"),c=o.attr("lay-filter");n.hasClass(l)&&(n.next()[0]?f.tabClick.call(n.next()[0],null,s+1):n.prev()[0]&&f.tabClick.call(n.prev()[0],null,s-1)),n.remove(),r.eq(s).remove(),setTimeout(function(){f.tabAuto()},50),layui.event.call(this,e,"tabDelete("+c+")",{elem:o,index:s})},tabAuto:function(){var t="layui-tab-more",e="layui-tab-bar",l="layui-tab-close",n=this;a(".layui-tab").each(function(){var s=a(this),o=s.children(".layui-tab-title"),r=(s.children(".layui-tab-content").children(".layui-tab-item"),'lay-stope="tabmore"'),c=a('');if(n===window&&8!=i.ie&&f.hideTabMore(!0),s.attr("lay-allowClose")&&o.find("li").each(function(){var t=a(this);if(!t.find("."+l)[0]){var i=a('');i.on("click",f.tabDelete),t.append(i)}}),"string"!=typeof s.attr("lay-unauto"))if(o.prop("scrollWidth")>o.outerWidth()+1){if(o.find("."+e)[0])return;o.append(c),s.attr("overflow",""),c.on("click",function(a){o[this.title?"removeClass":"addClass"](t),this.title=this.title?"":"收缩"})}else o.find("."+e).remove(),s.removeAttr("overflow")})},hideTabMore:function(t){var i=a(".layui-tab-title");t!==!0&&"tabmore"===a(t.target).attr("lay-stope")||(i.removeClass("layui-tab-more"),i.find(".layui-tab-bar").attr("title",""))},clickThis:function(){var t=a(this),i=t.parents(o),n=i.attr("lay-filter"),s=t.parent(),c=t.siblings("."+d),y="string"==typeof s.attr("lay-unselect");"javascript:;"!==t.attr("href")&&"_blank"===t.attr("target")||y||c[0]||(i.find("."+l).removeClass(l),s.addClass(l)),i.hasClass(u)&&(c.removeClass(h),c[0]&&(s["none"===c.css("display")?"addClass":"removeClass"](r+"ed"),"all"===i.attr("lay-shrink")&&s.siblings().removeClass(r+"ed"))),layui.event.call(this,e,"nav("+n+")",t)},collapse:function(){var t=a(this),i=t.find(".layui-colla-icon"),l=t.siblings(".layui-colla-content"),s=t.parents(".layui-collapse").eq(0),o=s.attr("lay-filter"),r="none"===l.css("display");if("string"==typeof s.attr("lay-accordion")){var c=s.children(".layui-colla-item").children("."+n);c.siblings(".layui-colla-title").children(".layui-colla-icon").html(""),c.removeClass(n)}l[r?"addClass":"removeClass"](n),i.html(r?"":""),layui.event.call(this,e,"collapse("+o+")",{title:t,content:l,show:r})}};s.prototype.init=function(t,e){var l=function(){return e?'[lay-filter="'+e+'"]':""}(),s={tab:function(){f.tabAuto.call({})},nav:function(){var t=200,e={},s={},p={},b=function(l,o,r){var c=a(this),f=c.find("."+d);o.hasClass(u)?l.css({top:c.position().top,height:c.children("a").outerHeight(),opacity:1}):(f.addClass(h),l.css({left:c.position().left+parseFloat(c.css("marginLeft")),top:c.position().top+c.height()-l.height()}),e[r]=setTimeout(function(){l.css({width:c.width(),opacity:1})},i.ie&&i.ie<10?0:t),clearTimeout(p[r]),"block"===f.css("display")&&clearTimeout(s[r]),s[r]=setTimeout(function(){f.addClass(n),c.find("."+y).addClass(y+"d")},300))};a(o+l).each(function(i){var l=a(this),o=a(''),h=l.find("."+r);l.find("."+c)[0]||(l.append(o),h.on("mouseenter",function(){b.call(this,o,l,i)}).on("mouseleave",function(){l.hasClass(u)||(clearTimeout(s[i]),s[i]=setTimeout(function(){l.find("."+d).removeClass(n),l.find("."+y).removeClass(y+"d")},300))}),l.on("mouseleave",function(){clearTimeout(e[i]),p[i]=setTimeout(function(){l.hasClass(u)?o.css({height:0,top:o.position().top+o.height()/2,opacity:0}):o.css({width:0,left:o.position().left+o.width()/2,opacity:0})},t)})),h.find("a").each(function(){var t=a(this),i=(t.parent(),t.siblings("."+d));i[0]&&!t.children("."+y)[0]&&t.append(''),t.off("click",f.clickThis).on("click",f.clickThis)})})},breadcrumb:function(){var t=".layui-breadcrumb";a(t+l).each(function(){var t=a(this),i="lay-separator",e=t.attr(i)||"/",l=t.find("a");l.next("span["+i+"]")[0]||(l.each(function(t){t!==l.length-1&&a(this).after(""+e+"")}),t.css("visibility","visible"))})},progress:function(){var t="layui-progress";a("."+t+l).each(function(){var i=a(this),e=i.find(".layui-progress-bar"),l=e.attr("lay-percent");e.css("width",function(){return/^.+\/.+$/.test(l)?100*new Function("return "+l)()+"%":l}()),i.attr("lay-showPercent")&&setTimeout(function(){e.html(''+l+"")},350)})},collapse:function(){var t="layui-collapse";a("."+t+l).each(function(){var t=a(this).find(".layui-colla-item");t.each(function(){var t=a(this),i=t.find(".layui-colla-title"),e=t.find(".layui-colla-content"),l="none"===e.css("display");i.find(".layui-colla-icon").remove(),i.append(''+(l?"":"")+""),i.off("click",f.collapse).on("click",f.collapse)})})}};return s[t]?s[t]():layui.each(s,function(t,a){a()})},s.prototype.render=s.prototype.init;var p=new s,b=a(document);p.render();var v=".layui-tab-title li";b.on("click",v,f.tabClick),b.on("click",f.hideTabMore),a(window).on("resize",f.tabAuto),t(e,p)}); -------------------------------------------------------------------------------- /src/main/resources/static/layui/css/modules/laydate/default/laydate.css: -------------------------------------------------------------------------------- 1 | /** layui-v2.4.5 MIT License By https://www.layui.com */ 2 | .laydate-set-ym,.layui-laydate,.layui-laydate *,.layui-laydate-list{box-sizing:border-box}html #layuicss-laydate{display:none;position:absolute;width:1989px}.layui-laydate *{margin:0;padding:0}.layui-laydate{position:absolute;z-index:66666666;margin:5px 0;border-radius:2px;font-size:14px;-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-name:laydate-upbit;animation-name:laydate-upbit}.layui-laydate-main{width:272px}.layui-laydate-content td,.layui-laydate-header *,.layui-laydate-list li{transition-duration:.3s;-webkit-transition-duration:.3s}@-webkit-keyframes laydate-upbit{from{-webkit-transform:translate3d(0,20px,0);opacity:.3}to{-webkit-transform:translate3d(0,0,0);opacity:1}}@keyframes laydate-upbit{from{transform:translate3d(0,20px,0);opacity:.3}to{transform:translate3d(0,0,0);opacity:1}}.layui-laydate-static{position:relative;z-index:0;display:inline-block;margin:0;-webkit-animation:none;animation:none}.laydate-ym-show .laydate-next-m,.laydate-ym-show .laydate-prev-m{display:none!important}.laydate-ym-show .laydate-next-y,.laydate-ym-show .laydate-prev-y{display:inline-block!important}.laydate-time-show .laydate-set-ym span[lay-type=month],.laydate-time-show .laydate-set-ym span[lay-type=year],.laydate-time-show .layui-laydate-header .layui-icon,.laydate-ym-show .laydate-set-ym span[lay-type=month]{display:none!important}.layui-laydate-header{position:relative;line-height:30px;padding:10px 70px 5px}.laydate-set-ym span,.layui-laydate-header i{padding:0 5px;cursor:pointer}.layui-laydate-header *{display:inline-block;vertical-align:bottom}.layui-laydate-header i{position:absolute;top:10px;color:#999;font-size:18px}.layui-laydate-header i.laydate-prev-y{left:15px}.layui-laydate-header i.laydate-prev-m{left:45px}.layui-laydate-header i.laydate-next-y{right:15px}.layui-laydate-header i.laydate-next-m{right:45px}.laydate-set-ym{width:100%;text-align:center;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.laydate-time-text{cursor:default!important}.layui-laydate-content{position:relative;padding:10px;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-laydate-content table{border-collapse:collapse;border-spacing:0}.layui-laydate-content td,.layui-laydate-content th{width:36px;height:30px;padding:5px;text-align:center}.layui-laydate-content td{position:relative;cursor:pointer}.laydate-day-mark{position:absolute;left:0;top:0;width:100%;height:100%;line-height:30px;font-size:12px;overflow:hidden}.laydate-day-mark::after{position:absolute;content:'';right:2px;top:2px;width:5px;height:5px;border-radius:50%}.layui-laydate-footer{position:relative;height:46px;line-height:26px;padding:10px 20px}.layui-laydate-footer span{margin-right:15px;display:inline-block;cursor:pointer;font-size:12px}.layui-laydate-footer span:hover{color:#5FB878}.laydate-footer-btns{position:absolute;right:10px;top:10px}.laydate-footer-btns span{height:26px;line-height:26px;margin:0 0 0 -1px;padding:0 10px;border:1px solid #C9C9C9;background-color:#fff;white-space:nowrap;vertical-align:top;border-radius:2px}.layui-laydate-list>li,.layui-laydate-range .layui-laydate-main{display:inline-block;vertical-align:middle}.layui-laydate-list{position:absolute;left:0;top:0;width:100%;height:100%;padding:10px;background-color:#fff}.layui-laydate-list>li{position:relative;width:33.3%;height:36px;line-height:36px;margin:3px 0;text-align:center;cursor:pointer}.laydate-month-list>li{width:25%;margin:17px 0}.laydate-time-list>li{height:100%;margin:0;line-height:normal;cursor:default}.laydate-time-list p{position:relative;top:-4px;line-height:29px}.laydate-time-list ol{height:181px;overflow:hidden}.laydate-time-list>li:hover ol{overflow-y:auto}.laydate-time-list ol li{width:130%;padding-left:33px;line-height:30px;text-align:left;cursor:pointer}.layui-laydate-hint{position:absolute;top:115px;left:50%;width:250px;margin-left:-125px;line-height:20px;padding:15px;text-align:center;font-size:12px}.layui-laydate-range{width:546px}.layui-laydate-range .laydate-main-list-0 .laydate-next-m,.layui-laydate-range .laydate-main-list-0 .laydate-next-y,.layui-laydate-range .laydate-main-list-1 .laydate-prev-m,.layui-laydate-range .laydate-main-list-1 .laydate-prev-y{display:none}.layui-laydate-range .laydate-main-list-1 .layui-laydate-content{border-left:1px solid #e2e2e2}.layui-laydate,.layui-laydate-hint{border:1px solid #d2d2d2;box-shadow:0 2px 4px rgba(0,0,0,.12);background-color:#fff;color:#666}.layui-laydate-header{border-bottom:1px solid #e2e2e2}.layui-laydate-header i:hover,.layui-laydate-header span:hover{color:#5FB878}.layui-laydate-content{border-top:none 0;border-bottom:none 0}.layui-laydate-content th{font-weight:400;color:#333}.layui-laydate-content td{color:#666}.layui-laydate-content td.laydate-selected{background-color:#00F7DE}.laydate-selected:hover{background-color:#00F7DE!important}.layui-laydate-content td:hover,.layui-laydate-list li:hover{background-color:#eaeaea;color:#333}.laydate-time-list li ol{margin:0;padding:0;border:1px solid #e2e2e2;border-left-width:0}.laydate-time-list li:first-child ol{border-left-width:1px}.laydate-time-list>li:hover{background:0 0}.layui-laydate-content .laydate-day-next,.layui-laydate-content .laydate-day-prev{color:#d2d2d2}.laydate-selected.laydate-day-next,.laydate-selected.laydate-day-prev{background-color:#f8f8f8!important}.layui-laydate-footer{border-top:1px solid #e2e2e2}.layui-laydate-hint{color:#FF5722}.laydate-day-mark::after{background-color:#5FB878}.layui-laydate-content td.layui-this .laydate-day-mark::after{display:none}.layui-laydate-footer span[lay-type=date]{color:#5FB878}.layui-laydate .layui-this{background-color:#009688!important;color:#fff!important}.layui-laydate .laydate-disabled,.layui-laydate .laydate-disabled:hover{background:0 0!important;color:#d2d2d2!important;cursor:not-allowed!important;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.laydate-theme-molv{border:none}.laydate-theme-molv.layui-laydate-range{width:548px}.laydate-theme-molv .layui-laydate-main{width:274px}.laydate-theme-molv .layui-laydate-header{border:none;background-color:#009688}.laydate-theme-molv .layui-laydate-header i,.laydate-theme-molv .layui-laydate-header span{color:#f6f6f6}.laydate-theme-molv .layui-laydate-header i:hover,.laydate-theme-molv .layui-laydate-header span:hover{color:#fff}.laydate-theme-molv .layui-laydate-content{border:1px solid #e2e2e2;border-top:none;border-bottom:none}.laydate-theme-molv .laydate-main-list-1 .layui-laydate-content{border-left:none}.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li,.laydate-theme-grid .layui-laydate-content td,.laydate-theme-grid .layui-laydate-content thead,.laydate-theme-molv .layui-laydate-footer{border:1px solid #e2e2e2}.laydate-theme-grid .laydate-selected,.laydate-theme-grid .laydate-selected:hover{background-color:#f2f2f2!important;color:#009688!important}.laydate-theme-grid .laydate-selected.laydate-day-next,.laydate-theme-grid .laydate-selected.laydate-day-prev{color:#d2d2d2!important}.laydate-theme-grid .laydate-month-list,.laydate-theme-grid .laydate-year-list{margin:1px 0 0 1px}.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li{margin:0 -1px -1px 0}.laydate-theme-grid .laydate-year-list>li{height:43px;line-height:43px}.laydate-theme-grid .laydate-month-list>li{height:71px;line-height:71px} --------------------------------------------------------------------------------