├── chat ├── README.md ├── test │ ├── helper.js │ ├── core │ │ └── weixin │ │ │ └── core-module.test.js │ ├── app-weixin.test.js │ └── states │ │ └── chat-weixin │ │ └── chat-weixin-controller.test.js ├── public │ ├── img │ │ ├── fenge.png │ │ ├── czl_logo.jpg │ │ ├── download.png │ │ ├── face │ │ │ ├── ee_1.png │ │ │ ├── ee_10.png │ │ │ ├── ee_11.png │ │ │ ├── ee_12.png │ │ │ ├── ee_13.png │ │ │ ├── ee_14.png │ │ │ ├── ee_15.png │ │ │ ├── ee_16.png │ │ │ ├── ee_17.png │ │ │ ├── ee_18.png │ │ │ ├── ee_19.png │ │ │ ├── ee_2.png │ │ │ ├── ee_20.png │ │ │ ├── ee_21.png │ │ │ ├── ee_22.png │ │ │ ├── ee_23.png │ │ │ ├── ee_24.png │ │ │ ├── ee_25.png │ │ │ ├── ee_26.png │ │ │ ├── ee_27.png │ │ │ ├── ee_28.png │ │ │ ├── ee_29.png │ │ │ ├── ee_3.png │ │ │ ├── ee_30.png │ │ │ ├── ee_31.png │ │ │ ├── ee_32.png │ │ │ ├── ee_33.png │ │ │ ├── ee_34.png │ │ │ ├── ee_35.png │ │ │ ├── ee_36.png │ │ │ ├── ee_37.png │ │ │ ├── ee_38.png │ │ │ ├── ee_39.png │ │ │ ├── ee_4.png │ │ │ ├── ee_40.png │ │ │ ├── ee_41.png │ │ │ ├── ee_42.png │ │ │ ├── ee_43.png │ │ │ ├── ee_5.png │ │ │ ├── ee_6.png │ │ │ ├── ee_7.png │ │ │ ├── ee_8.png │ │ │ └── ee_9.png │ │ ├── car_loading.gif │ │ ├── car_loading2.gif │ │ ├── default_user.jpg │ │ ├── msg_loading.gif │ │ ├── default_service.png │ │ ├── startup_320_480.png │ │ ├── default_user_xxyh.jpg │ │ ├── startup_1242_2148.png │ │ ├── startup_640_1136.png │ │ ├── startup_750_1294.png │ │ └── default_user_lechebang.png │ ├── fonts │ │ ├── materialdesignicons-webfont.eot │ │ ├── materialdesignicons-webfont.ttf │ │ ├── materialdesignicons-webfont.woff │ │ └── materialdesignicons-webfont.woff2 │ ├── css │ │ ├── color.css │ │ ├── channel.css │ │ └── app.css │ └── index.html ├── source │ ├── states │ │ ├── chat │ │ │ ├── bottom_sheet │ │ │ │ ├── upload-toast-template.html │ │ │ │ ├── send-other-message-template.html │ │ │ │ ├── upload-tosat-controller.js │ │ │ │ └── send-other-message-controller.js │ │ │ ├── chat-module.js │ │ │ ├── dialog │ │ │ │ ├── error-dialog-template.html │ │ │ │ ├── img-dialog-controller.js │ │ │ │ ├── error-dialog-controller.js │ │ │ │ └── img-dialog-template.html │ │ │ ├── chat-route.js │ │ │ ├── chat-value.js │ │ │ ├── chat-template-2.html │ │ │ ├── chat-template.html │ │ │ └── chat-controller.js │ │ ├── preview │ │ │ ├── preview-module.js │ │ │ ├── preview-route.js │ │ │ ├── preview-template.html │ │ │ └── preview-controller.js │ │ ├── login │ │ │ ├── login-module.js │ │ │ ├── login-route.js │ │ │ ├── login-template.html │ │ │ └── login-controller.js │ │ └── chat-weixin │ │ │ ├── chat-module.js │ │ │ ├── chat-route.js │ │ │ ├── chat-value.js │ │ │ ├── chat-weixin-template.html │ │ │ └── chat-weixin-controller.js │ ├── app-weixin.js │ ├── app-default.js │ ├── components │ │ ├── face │ │ │ ├── face-weixin-template.html │ │ │ ├── face-template.html │ │ │ └── face-directive.js │ │ ├── btn_back │ │ │ └── btn-back-directive.js │ │ ├── menu_left │ │ │ ├── menu-left-template.html │ │ │ └── menu-left-directive.js │ │ ├── loading │ │ │ └── http-loading.js │ │ └── btn_audio │ │ │ └── btn-audio-directive.js │ ├── core │ │ ├── weixin │ │ │ ├── core-router.js │ │ │ ├── core-module.js │ │ │ └── core-controller.js │ │ └── default │ │ │ ├── core-router.js │ │ │ ├── core-theme.js │ │ │ ├── core-module.js │ │ │ └── core-controller.js │ ├── filter │ │ ├── format-date.js │ │ ├── format-user-avatar.js │ │ └── format-message.js │ ├── service │ │ ├── UploadService.js │ │ ├── ApiConfig.js │ │ ├── UserService.js │ │ ├── QaService.js │ │ ├── WXService.js │ │ └── SocketService.js │ └── lib │ │ ├── Recorderjs │ │ ├── recorder.js │ │ ├── example_simple_exportwav.html │ │ ├── README.md │ │ └── recorderWorker.js │ │ ├── tarsocial │ │ └── tarsocial-monitor-v1002.js │ │ ├── qiniu │ │ └── qupload.js │ │ └── weixin │ │ └── jweixin-1.0.0.js ├── config.yaml ├── package.json ├── karma.conf.js ├── gulpfile.js └── config.js ├── .gitignore └── README.md /chat/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /chat/test/helper.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/11/2. 3 | */ 4 | import 'angular-mocks' -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | Thumbs.db 3 | bin 4 | .idea 5 | env.* 6 | jspm_packages 7 | node_modules 8 | chat/dist -------------------------------------------------------------------------------- /chat/public/img/fenge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/fenge.png -------------------------------------------------------------------------------- /chat/public/img/czl_logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/czl_logo.jpg -------------------------------------------------------------------------------- /chat/public/img/download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/download.png -------------------------------------------------------------------------------- /chat/source/states/chat/bottom_sheet/upload-toast-template.html: -------------------------------------------------------------------------------- 1 | 2 | 正在上传... 3 | -------------------------------------------------------------------------------- /chat/public/img/face/ee_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_1.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_10.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_11.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_12.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_13.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_14.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_15.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_16.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_17.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_18.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_19.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_2.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_20.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_21.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_22.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_23.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_24.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_25.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_26.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_27.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_28.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_29.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_3.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_30.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_31.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_32.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_33.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_34.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_35.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_36.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_37.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_37.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_38.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_39.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_4.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_40.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_41.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_41.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_42.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_42.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_43.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_43.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_5.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_6.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_7.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_8.png -------------------------------------------------------------------------------- /chat/public/img/face/ee_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/face/ee_9.png -------------------------------------------------------------------------------- /chat/public/img/car_loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/car_loading.gif -------------------------------------------------------------------------------- /chat/public/img/car_loading2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/car_loading2.gif -------------------------------------------------------------------------------- /chat/public/img/default_user.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/default_user.jpg -------------------------------------------------------------------------------- /chat/public/img/msg_loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/msg_loading.gif -------------------------------------------------------------------------------- /chat/public/img/default_service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/default_service.png -------------------------------------------------------------------------------- /chat/public/img/startup_320_480.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/startup_320_480.png -------------------------------------------------------------------------------- /chat/public/img/default_user_xxyh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/default_user_xxyh.jpg -------------------------------------------------------------------------------- /chat/public/img/startup_1242_2148.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/startup_1242_2148.png -------------------------------------------------------------------------------- /chat/public/img/startup_640_1136.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/startup_640_1136.png -------------------------------------------------------------------------------- /chat/public/img/startup_750_1294.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/startup_750_1294.png -------------------------------------------------------------------------------- /chat/source/states/preview/preview-module.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var PreviewModule = angular.module('preview',[]) 4 | 5 | export default PreviewModule; -------------------------------------------------------------------------------- /chat/public/img/default_user_lechebang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/img/default_user_lechebang.png -------------------------------------------------------------------------------- /chat/public/fonts/materialdesignicons-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/fonts/materialdesignicons-webfont.eot -------------------------------------------------------------------------------- /chat/public/fonts/materialdesignicons-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/fonts/materialdesignicons-webfont.ttf -------------------------------------------------------------------------------- /chat/public/fonts/materialdesignicons-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/fonts/materialdesignicons-webfont.woff -------------------------------------------------------------------------------- /chat/public/fonts/materialdesignicons-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjj5855/jspm-angular-material/master/chat/public/fonts/materialdesignicons-webfont.woff2 -------------------------------------------------------------------------------- /chat/source/states/chat/chat-module.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/9/28. 3 | */ 4 | 5 | var ChatModule = angular.module('chat',[]) 6 | 7 | export default ChatModule; -------------------------------------------------------------------------------- /chat/source/states/login/login-module.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/11/5. 3 | */ 4 | 5 | var LoginModule = angular.module('login',['ngMaterial']); 6 | 7 | export default LoginModule; -------------------------------------------------------------------------------- /chat/source/states/chat-weixin/chat-module.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/9/28. 3 | */ 4 | 5 | var ChatModule; 6 | 7 | ChatModule = angular.module('chat',[]) 8 | 9 | export default ChatModule; -------------------------------------------------------------------------------- /chat/source/states/chat/dialog/error-dialog-template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

5 |
6 |
7 |
-------------------------------------------------------------------------------- /chat/source/states/chat/dialog/img-dialog-controller.js: -------------------------------------------------------------------------------- 1 | 2 | function ImgDialogCtrl($scope,$mdDialog){ 3 | $scope.closeDialog = function() { 4 | $mdDialog.hide(); 5 | } 6 | } 7 | 8 | ImgDialogCtrl.$inject = ['$scope','$mdDialog']; 9 | 10 | export default ImgDialogCtrl -------------------------------------------------------------------------------- /chat/public/css/color.css: -------------------------------------------------------------------------------- 1 | .bg-gray{ 2 | background-color: #f1f1f1!important; 3 | } 4 | .c-primary{ 5 | color: rgb(33,150,243) !important 6 | } 7 | .c-black{ 8 | color: #1f1f1f!important; 9 | } 10 | .c-gray{ 11 | color: gray; 12 | } 13 | .c-green{ 14 | color: #88CE44; 15 | } -------------------------------------------------------------------------------- /chat/source/states/chat/dialog/error-dialog-controller.js: -------------------------------------------------------------------------------- 1 | 2 | function ErrorDialogCtrl($scope,$mdDialog){ 3 | $scope.closeDialog = function() { 4 | $mdDialog.hide(); 5 | } 6 | } 7 | 8 | ErrorDialogCtrl.$inject = ['$scope','$mdDialog']; 9 | 10 | export default ErrorDialogCtrl -------------------------------------------------------------------------------- /chat/source/app-weixin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/9/23. 3 | */ 4 | 5 | import 'jquery' 6 | import 'angular'; 7 | import 'public/css/materialdesignicons.css!' 8 | import 'public/css/app.css!' 9 | 10 | import AppModule from './core/weixin/core-module' 11 | 12 | 13 | export default AppModule -------------------------------------------------------------------------------- /chat/test/core/weixin/core-module.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/11/2. 3 | */ 4 | import 'test/helper'; 5 | import core from 'source/core/weixin/core-module' 6 | 7 | describe('[模块]:CoreModule', () => { 8 | it('具有正确的模块名称', () => { 9 | expect(core.name).to.equal('myApp') 10 | }) 11 | }) -------------------------------------------------------------------------------- /chat/source/states/chat/chat-route.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/9/28. 3 | */ 4 | import ChatTpl from './chat-template.html!text'; 5 | import ChatCtrl from './chat-controller'; 6 | 7 | var ChatRoute = { 8 | template : ChatTpl, 9 | controller : 'ChatCtrl' 10 | }; 11 | export default ChatRoute; -------------------------------------------------------------------------------- /chat/source/app-default.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/9/23. 3 | */ 4 | 5 | import 'jquery' 6 | import 'angular'; 7 | import 'public/css/materialdesignicons.css!' 8 | import 'public/css/app.css!' 9 | import 'public/css/channel.css!' 10 | 11 | import AppModule from './core/default/core-module' 12 | 13 | export default AppModule -------------------------------------------------------------------------------- /chat/source/components/face/face-weixin-template.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
-------------------------------------------------------------------------------- /chat/source/states/chat-weixin/chat-route.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/9/28. 3 | */ 4 | 5 | import ChatWeiXinTpl from './chat-weixin-template.html!text'; 6 | 7 | import ChatWeiXinCtrl from './chat-weixin-controller'; 8 | 9 | var ChatRoute = {}; 10 | 11 | ChatRoute = { 12 | template: ChatWeiXinTpl, 13 | controller: 'ChatWeiXinCtrl' 14 | } 15 | 16 | export default ChatRoute; -------------------------------------------------------------------------------- /chat/test/app-weixin.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/11/2. 3 | */ 4 | import 'test/helper' 5 | import $ from 'jquery' 6 | import 'angular'; 7 | 8 | describe('[应用]:Angular Application 初始化', () => { 9 | it('检查 jquery 有没有引入', () => { 10 | expect($).to.be.an.object 11 | }) 12 | it('检查 angular 有没有引入', () => { 13 | expect(angular).to.be.an.object 14 | }) 15 | }); -------------------------------------------------------------------------------- /chat/source/states/chat/dialog/img-dialog-template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 |
7 |
-------------------------------------------------------------------------------- /chat/source/states/preview/preview-route.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/9/28. 3 | */ 4 | import PreviewTpl from './preview-template.html!text'; 5 | import PreviewCtrl from './preview-controller'; 6 | 7 | var PreviewRoute = { 8 | template : PreviewTpl, 9 | controller : 'PreviewCtrl', 10 | //previewDetail:['$route',function($route){ 11 | // console.log($route.current.params) 12 | //}] 13 | }; 14 | export default PreviewRoute; -------------------------------------------------------------------------------- /chat/source/core/weixin/core-router.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/9/24. 3 | */ 4 | import ChatRoute from 'source/states/chat-weixin/chat-route' 5 | 6 | function CoreRouter($routeProvider,$locationProvider) { 7 | 8 | $routeProvider 9 | .when('/',ChatRoute) 10 | .otherwise({redirectTo: '/'}); 11 | //$locationProvider.html5Mode(true); 12 | } 13 | 14 | CoreRouter.$inject = ['$routeProvider','$locationProvider']; 15 | 16 | export default CoreRouter; -------------------------------------------------------------------------------- /chat/source/states/login/login-route.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/11/5. 3 | */ 4 | import LoginCtrl from './login-controller'; 5 | import LoginTpl from './login-template.html!text'; 6 | 7 | var LoginRoute = { 8 | template : LoginTpl, 9 | controller : 'LoginCtrl', 10 | resolve:{ 11 | changeClass:['$rootScope',function($rootScope){ 12 | $rootScope.pageClass = 'loginpage' 13 | }] 14 | } 15 | }; 16 | 17 | export default LoginRoute; -------------------------------------------------------------------------------- /chat/source/states/preview/preview-template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 |
8 | 9 |
10 |
-------------------------------------------------------------------------------- /chat/source/components/face/face-template.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /chat/source/core/default/core-router.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/9/24. 3 | */ 4 | import ChatRoute from 'source/states/chat/chat-route'; 5 | import PreviewRoute from 'source/states/preview/preview-route'; 6 | 7 | function CoreRouter($routeProvider,$locationProvider) { 8 | 9 | $routeProvider 10 | .when('/',ChatRoute) 11 | .when('/preview',PreviewRoute) 12 | .otherwise({redirectTo: '/'}); 13 | //$locationProvider.html5Mode(true); 14 | } 15 | 16 | CoreRouter.$inject = ['$routeProvider','$locationProvider']; 17 | 18 | export default CoreRouter; -------------------------------------------------------------------------------- /chat/source/states/chat/bottom_sheet/send-other-message-template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
图片
7 |
8 |
9 |
10 |
11 | 12 | -------------------------------------------------------------------------------- /chat/source/states/chat/bottom_sheet/upload-tosat-controller.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/11/17. 3 | */ 4 | 5 | 6 | function UploadToastCtrl($scope, $mdToast) { 7 | $scope.closeToast = function() { 8 | $mdToast.hide(); 9 | }; 10 | $scope.$on('img_upload_success',function(event,data){ 11 | $mdToast.hide(); 12 | $mdToast.show( 13 | $mdToast.simple() 14 | .content('上传成功!') 15 | .position('top') 16 | .hideDelay(1000) 17 | ); 18 | }); 19 | } 20 | 21 | UploadToastCtrl.$inject = ['$scope','$mdToast'] 22 | 23 | export default UploadToastCtrl; -------------------------------------------------------------------------------- /chat/source/components/btn_back/btn-back-directive.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/10/8. 3 | * 4 | */ 5 | export default angular.module('chat') 6 | .directive('cmBackBtn',['$window',function($window){ 7 | return { 8 | restrict: 'AE', 9 | replace: true, 10 | scope:true, 11 | link : function(scope,element,attrs){ 12 | 13 | function back(){ 14 | $window.history.back() 15 | } 16 | 17 | angular.element(element).on('click',function(){ 18 | back(); 19 | }) 20 | } 21 | } 22 | }]); -------------------------------------------------------------------------------- /chat/source/filter/format-date.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/10/10. 3 | */ 4 | 5 | angular.module('format_date',[]) 6 | .filter('format_date',['$rootScope','$filter',function ($rootScope,$filter) { 7 | return function (text,isHour) { 8 | 9 | if(typeof text == 'number'){ 10 | text = $filter('date')(new Date(text),'yyyy-MM-dd HH:mm:ss'); 11 | } 12 | if(text && text !='' && text != undefined) { 13 | if (isHour) { 14 | text = text.substr(text.length - 8, 8); 15 | } else { 16 | text = text.substr(text.length - 14, 14); 17 | } 18 | } 19 | return text; 20 | } 21 | }] 22 | ) -------------------------------------------------------------------------------- /chat/source/states/chat-weixin/chat-value.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/9/28. 3 | */ 4 | 5 | var chatValue = { 6 | 7 | //type 1=文本 | 2=声音 | 3=图片 8 | message : { 9 | content : '', 10 | type : 1 11 | }, 12 | open_face_status:false, 13 | open_audio_status:false, 14 | user_info : { 15 | name : 'user', 16 | avatar : '/chat/public/img/default_user.jpg' 17 | }, 18 | service_info : { 19 | name : 'admin', 20 | avatar : '/chat/public/img/default_service.png' 21 | }, 22 | page : 1, 23 | page_size : 10, 24 | timestamp : '', 25 | msg_list : [] 26 | }; 27 | 28 | export default angular.module('chat').value('chat.value',chatValue); -------------------------------------------------------------------------------- /chat/test/states/chat-weixin/chat-weixin-controller.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/11/3. 3 | */ 4 | import 'test/helper' 5 | 6 | describe('ChatWeiXinCtrl', function() { 7 | var scope; 8 | //我们会在测试中使用这个scope 9 | var ctrl; 10 | 11 | //模拟我们的Application模块并注入我们自己的依赖 12 | beforeEach(angular.mock.module('myApp')); 13 | 14 | //模拟Controller,并且包含 $rootScope 和 $controller 15 | beforeEach(angular.mock.inject(function($rootScope, $controller){ 16 | 17 | //创建一个空的 scope 18 | scope = $rootScope.$new(); 19 | 20 | //声明 Controller并且注入已创建的空的 scope 21 | ctrl = $controller('ChatWeiXinCtrl', {$scope: scope}); 22 | })) 23 | 24 | // 测试从这里开始 25 | it('初始化 聊天页面的页码 为 1', function(){ 26 | expect(scope).to.have.property('page').equal(1); 27 | }); 28 | 29 | }); -------------------------------------------------------------------------------- /chat/source/components/menu_left/menu-left-template.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |

5 | Angular Material 6 |

7 |
8 | 9 | 10 | Index 11 |
12 | 13 | Home 14 |
15 | 16 | Chat 17 |
18 | 19 | Theme 20 | 21 |
22 |
23 |
-------------------------------------------------------------------------------- /chat/source/core/default/core-theme.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/10/7. 3 | */ 4 | 5 | 6 | function CoreTheme($mdThemingProvider) { 7 | 8 | $mdThemingProvider.theme('default') 9 | .primaryPalette('blue',{ 10 | 'default' : '500', 11 | 'hue-1' : '900', 12 | 'hue-2' : 'A100', 13 | 'hue-3' : '400' 14 | }) 15 | .accentPalette('green',{ 16 | 'default' : '600', 17 | 'hue-1' : '900', 18 | 'hue-2' : 'A100', 19 | 'hue-3' : '400' 20 | }) 21 | .warnPalette('deep-orange',{ 22 | 'default' : '500', 23 | }); 24 | $mdThemingProvider.alwaysWatchTheme(true) 25 | } 26 | 27 | CoreTheme.$inject = ['$mdThemingProvider']; 28 | 29 | export default CoreTheme; -------------------------------------------------------------------------------- /chat/source/states/login/login-template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 登录 15 | 16 | -------------------------------------------------------------------------------- /chat/source/states/chat/chat-value.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/9/28. 3 | */ 4 | 5 | var chatValue = { 6 | 7 | //type 1=文本 | 2=声音 | 3=图片 8 | message : { 9 | content : '', 10 | type : 1 11 | }, 12 | open_face_status:false, 13 | open_audio_status:false, 14 | user_info : { 15 | name : 'user', 16 | avatar : '/chat/public/img/default_user.jpg' 17 | }, 18 | service_info : { 19 | name : 'admin', 20 | avatar : '/chat/public/img/default_service.png' 21 | }, 22 | page : 1, 23 | page_size : 10, 24 | timestamp : '', 25 | msg_list : [], 26 | is_loading_history : true, 27 | userInfo : {}, 28 | showTopToolBar : false, 29 | showTopTitle : false, 30 | scroll_top : 0, 31 | }; 32 | 33 | export default angular.module('chat').value('chat.value',chatValue); -------------------------------------------------------------------------------- /chat/source/filter/format-user-avatar.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/10/10. 3 | */ 4 | 5 | angular.module('format_avatar',[]) 6 | .filter('format_avatar',['$rootScope','$filter',function ($rootScope,$filter) { 7 | return function (avatar,channel_sign) { 8 | 9 | if(avatar!=''){ 10 | return avatar; 11 | } 12 | 13 | switch(channel_sign){ 14 | case'czl_xxyh': 15 | avatar = '/chat/public/img/default_user_xxyh.jpg'; 16 | break; 17 | case'czl_lechebang': 18 | avatar = '/chat/public/img/default_user_lechebang.jpg'; 19 | break; 20 | default: 21 | avatar = '/chat/public/img/default_user.jpg'; 22 | break; 23 | } 24 | return avatar; 25 | } 26 | }] 27 | ) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jspm-angular-material 2 | 使用jspm 快速构建 Material Design 设计模式的 angular 应用 3 | 4 | 示例 : 请在微信中打开 5 | 6 | 注意:代码中没有env.js 需要自行添加到 chat/source/env.js 代码如下 7 | 8 | export default angular.module('env',[]) 9 | .service('env',function(){ 10 | return { 11 | APP_ID : "你的微信公众号ID", 12 | APP_HOST : "你的微信网页授权地址", 13 | BASE_HOST : "你的API后台地址", 14 | IM_HOST : "你的IM后台地址" 15 | } 16 | }); 17 | 18 | 0.目前只有chat这个项目 前往目录 19 | 20 | cd chat 21 | 22 | 1.全局安装jspm 23 | 24 | npm install jspm -g 25 | 26 | 2.安装依赖包 27 | 28 | jspm install 29 | 30 | 3.安装开发和构建包 31 | 32 | npm install 33 | 34 | 4.构建开发项目 35 | 36 | 修改 public/index.html 中的 System.import("source/app-default 或 source/app-weixin"); 调试不同页面 37 | 38 | gulp 39 | 40 | 5.开发完成后 41 | 42 | 打包weixin页面 43 | 44 | gulp weixin 45 | 46 | 打包default页面 47 | 48 | gulp app 49 | 50 | 打包所有页面 51 | 52 | gulp all -------------------------------------------------------------------------------- /chat/source/core/weixin/core-module.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/9/24. 3 | */ 4 | import $ from 'jquery' 5 | import 'angular-route'; 6 | import 'angular-resource' 7 | import 'source/service/ApiConfig' 8 | import 'source/env' 9 | import 'source/filter/format-message' 10 | import 'source/filter/format-date' 11 | 12 | import ChatModule from 'source/states/chat-weixin/chat-module' 13 | 14 | import WXModule from 'source/service/WXService' 15 | import SocketModule from 'source/service/SocketService' 16 | import UserModule from 'source/service/UserService' 17 | 18 | import CoreRouter from 'source/core/weixin/core-router' 19 | import CoreCtrl from 'source/core/weixin/core-controller' 20 | 21 | 22 | var CoreModule = angular.module('myApp',[ 23 | 'ngRoute', 24 | 'ngResource', 25 | 26 | 'env','apiConfig', 27 | WXModule.name,SocketModule.name,UserModule.name, 28 | 'format_msg','format_date', 29 | ChatModule.name, 30 | ]) 31 | .config(CoreRouter) 32 | .controller('myAppCtrl',CoreCtrl); 33 | 34 | 35 | export default CoreModule -------------------------------------------------------------------------------- /chat/public/css/channel.css: -------------------------------------------------------------------------------- 1 | /*2015-12-02 乐车帮 样式*/ 2 | .czl_lechebang .md-button.md-accent{ 3 | color: rgb(245,245,249) !important; 4 | } 5 | .czl_lechebang .md-button.md-fab.md-accent{ 6 | background-color: rgb(245,245,249) !important; 7 | } 8 | .czl_lechebang .md-button.md-fab.md-accent md-icon{ 9 | color: rgb(102,102,102) !important; 10 | } 11 | .czl_lechebang .md-button.md-accent md-icon{ 12 | color: #35c816 !important; 13 | } 14 | .czl_lechebang md-toolbar.md-accent{ 15 | background-color: rgb(245,245,249) !important; 16 | color: rgb(102,102,102) !important; 17 | } 18 | .czl_lechebang .direct-chat-img{ 19 | border-radius: 0; 20 | background-color: #fff; 21 | } 22 | .czl_lechebang md-toolbar:not(.md-menu-toolbar) md-icon { 23 | color: rgba(102,102,102,0.87); 24 | } 25 | .czl_lechebang #message_box{ 26 | background-color: rgb(239,239,244) !important;; 27 | } 28 | .czl_lechebang[data-loading]{ 29 | /*position: fixed;*/ 30 | /*background: rgba(255,255,255,.9);*/ 31 | /*border:1px solid transparent;*/ 32 | /*border-radius: 15px;*/ 33 | } 34 | /*乐车帮 样式 [结束]*/ -------------------------------------------------------------------------------- /chat/config.yaml: -------------------------------------------------------------------------------- 1 | # config.yaml 2 | --- 3 | browserSync: &browserSync 4 | files: 5 | - "public/**" 6 | - "source/**" 7 | watchOptions: 8 | debounceDelay: 3000 9 | server: 10 | baseDir: "public" 11 | routes: 12 | "/dist": "./dist/" 13 | "/public": "./public/" 14 | "/build.js": "./build.js" 15 | "/default.js": "./default.js" 16 | "/weixin.js": "./weixin.js" 17 | "/config.js": "./config.js" 18 | "/jspm_packages": "./jspm_packages/" 19 | "/source": "./source/" 20 | "/chat/public": "./public/" 21 | # middleware: [] 22 | startPath: "/" 23 | host: "127.0.0.1" 24 | port: 3000 25 | # open: false 26 | # notify: false 27 | # online: false 28 | # tunnel: false 29 | # tunnel: "jspm-angular-demo" 30 | # logLevel: "info" 31 | # logPrefix: "jspm-angular-demo" 32 | # logConnections: false 33 | # logFileChanges: false 34 | 35 | # proxyURL: "http://your.endpoint.api/" 36 | # proxyOptions: &proxyOptions 37 | # route: "/api" 38 | # via: "nightire@localhost" 39 | # cookieRewrite: "hostname" 40 | # reserveHost: false 41 | -------------------------------------------------------------------------------- /chat/source/service/UploadService.js: -------------------------------------------------------------------------------- 1 | 2 | export default angular.module('Upload',['ngRoute','ngResource']) 3 | .config(['$resourceProvider','$httpProvider', function($resourceProvider,$httpProvider) { 4 | 5 | $httpProvider.defaults.headers.common = { 6 | 'Accept':'application/json, text/javascript, */*; q=0.01', 7 | 'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8', 8 | }; 9 | $httpProvider.defaults.headers.put['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; 10 | $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; 11 | 12 | }]) 13 | .service('Upload',['$rootScope','$cookies','$http','$resource','apiConfig', 14 | function($rootScope,$cookies,$http,$resource,apiConfig){ 15 | var service_host = apiConfig.service_host; 16 | 17 | return $resource(service_host+'upload/upload-token',{},{ 18 | get: { 19 | method:'GET', 20 | params: apiConfig.authParams, 21 | } 22 | }); 23 | }]); -------------------------------------------------------------------------------- /chat/source/components/loading/http-loading.js: -------------------------------------------------------------------------------- 1 | 2 | import $ from 'jquery' 3 | 4 | export default angular.module('loading',[]) 5 | .directive('loading',['$http','$rootScope',function($http,$rootScope){ 6 | return { 7 | restrict: 'A', 8 | link: function (scope, elm, attrs) 9 | { 10 | let top = ($(window).height()-102)/2; 11 | let left = ($(window).width()-102)/2; 12 | $(elm).css('top',top+'px'); 13 | $(elm).css('left',left+'px'); 14 | 15 | scope.isLoading = function () { 16 | return $http.pendingRequests.length > 0; 17 | }; 18 | 19 | scope.$watch(scope.isLoading, function (v) 20 | { 21 | if(v){ 22 | if($rootScope.hide_http_loading){ 23 | return; 24 | } 25 | $(elm).show(); 26 | }else{ 27 | $(elm).hide(); 28 | } 29 | }); 30 | } 31 | }; 32 | }]); -------------------------------------------------------------------------------- /chat/source/states/login/login-controller.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/11/5. 3 | */ 4 | 5 | import $ from 'jquery' 6 | 7 | 8 | function LoginCtrl($scope,$timeout,$interval,$location,$cookies){ 9 | 10 | $scope.loginInfo = { 11 | phone:'', 12 | code :'' 13 | } 14 | $scope.auth_code_text = '获取验证码'; 15 | 16 | $scope.getAuthCode = getAuthCode; 17 | $scope.webLogin = webLogin; 18 | 19 | function getAuthCode(){ 20 | $('#getAuthCode_btn').attr('disabled','disabled'); 21 | $timeout(()=>{ 22 | $('#getAuthCode_btn').removeAttr('disabled'); 23 | $scope.auth_code_text = '获取验证码'; 24 | },60e3) 25 | let i = 59; 26 | $scope.auth_code_text = '60秒后可再次获取'; 27 | $interval(()=>{ 28 | $scope.auth_code_text = i+'秒后可再次获取'; 29 | i--; 30 | },1e3,59) 31 | 32 | } 33 | 34 | function webLogin(){ 35 | $cookies.putObject('user_login_cookie','123456',{expires: 0,'path':'/'}); 36 | $location.path('/'); 37 | } 38 | } 39 | 40 | LoginCtrl.$inject = ['$scope','$timeout','$interval','$location','$cookies']; 41 | 42 | 43 | export default angular.module('login') 44 | .controller('LoginCtrl',LoginCtrl) 45 | -------------------------------------------------------------------------------- /chat/source/core/weixin/core-controller.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/10/15. 3 | */ 4 | 5 | import $ from 'jquery' 6 | 7 | 8 | function myAppCtrl($rootScope,$routeParams){ 9 | 10 | $rootScope.is_weixn = window.is_weixn(); 11 | 12 | 13 | 14 | //页面加载完成后自适应屏幕 15 | $rootScope.$on('$viewContentLoaded', function() { 16 | autoSetMessageBoxHeight(); 17 | }); 18 | $(window).resize(function(){ 19 | autoSetMessageBoxHeight(); 20 | }) 21 | 22 | function autoSetMessageBoxHeight(){ 23 | var el = $("#message_box"); 24 | if(el.length == 1){ 25 | $rootScope.winheight= $(window).height(); 26 | $rootScope.winwidth = $(window).width(); 27 | $rootScope.header = $(".cm-toolbar:first").height(); 28 | $rootScope.bottom = 49; 29 | $(el[0]).css('height',$rootScope.winheight-$rootScope.header-$rootScope.bottom+'px'); 30 | 31 | $("#message_input").css('width',$rootScope.winwidth-48-48-52-13); 32 | $("#audio_input").css('width',$rootScope.winwidth-48-52-10); 33 | } 34 | $("body").css('background','#fff'); 35 | } 36 | 37 | } 38 | 39 | myAppCtrl.$inject = ['$rootScope','$routeParams']; 40 | 41 | export default myAppCtrl; -------------------------------------------------------------------------------- /chat/source/core/default/core-module.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/9/24. 3 | */ 4 | import $ from 'jquery' 5 | import 'angular-route'; 6 | import 'angular-resource' 7 | import 'angular-material' 8 | import 'angular-cookies' 9 | import 'angular-local-storage' 10 | import 'source/service/ApiConfig' 11 | import 'source/env' 12 | import 'source/filter/format-message' 13 | import 'source/filter/format-date' 14 | import 'source/filter/format-user-avatar' 15 | 16 | import 'source/components/loading/http-loading' 17 | 18 | import ChatModule from 'source/states/chat/chat-module' 19 | import PreviewModule from 'source/states/preview/preview-module' 20 | 21 | import SocketModule from 'source/service/SocketService' 22 | import UserModule from 'source/service/UserService' 23 | import UploadModule from 'source/service/UploadService' 24 | 25 | import CoreRouter from 'source/core/default/core-router' 26 | import CoreCtrl from 'source/core/default/core-controller' 27 | 28 | 29 | var CoreModule = angular.module('myApp',[ 30 | 'ngRoute', 31 | 'ngResource', 32 | 'ngMaterial', 33 | 'ngCookies', 34 | 'LocalStorageModule','angularQFileUpload','loading', 35 | 'env','apiConfig', 36 | SocketModule.name,UserModule.name,UploadModule.name, 37 | 'format_msg','format_date','format_avatar', 38 | ChatModule.name,PreviewModule.name, 39 | ]) 40 | .config(CoreRouter) 41 | .controller('myAppCtrl',CoreCtrl); 42 | 43 | 44 | export default CoreModule -------------------------------------------------------------------------------- /chat/source/service/ApiConfig.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/9/25. 3 | */ 4 | 5 | 6 | export default angular.module('apiConfig',[]) 7 | .service('apiConfig',['$rootScope','env',function($rootScope,env){ 8 | var base_host = env.BASE_HOST; 9 | var api_service_path = 'service/'; 10 | var im_host = env.IM_HOST; 11 | $rootScope.client_id = env.CLIENT_ID; 12 | $rootScope.client_secre = env.CLIENT_SECRE; 13 | 14 | var app_id = env.APP_ID; 15 | var app_host = env.APP_HOST; 16 | 17 | return { 18 | authParams: { 19 | client_id : $rootScope.client_id, 20 | user_secret:$rootScope.user_secret 21 | }, 22 | client_id : $rootScope.client_id, 23 | user_secret:$rootScope.user_secret, 24 | client_secre:$rootScope.client_secre, 25 | 26 | base_host:base_host, 27 | mobile_host:base_host+'mobile/', 28 | service_host:base_host+'service/', 29 | chat_host:base_host+'chat/', 30 | wx_host:base_host+'wechat/', 31 | im_host:im_host, 32 | 33 | app_id:app_id, 34 | app_host:app_host, 35 | 36 | qiniu_qa_host:'http://7xkkt4.com2.z0.glb.qiniucdn.com/', 37 | qiniu_im_host:'http://7xkz66.com2.z0.glb.qiniucdn.com/', 38 | qiniu_wiki_host:'http://7xkz65.com2.z0.glb.qiniucdn.com/', 39 | qiniu_avatar_host:'http://7xl1vx.com2.z0.glb.qiniucdn.com/', 40 | } 41 | }]); -------------------------------------------------------------------------------- /chat/source/components/menu_left/menu-left-directive.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/10/8. 3 | */ 4 | 5 | import LeftMenuTpl from './menu-left-template.html!text' 6 | 7 | export default angular.module('index') 8 | .directive('menuLeft',[function(){ 9 | return { 10 | restrict: 'E', 11 | replace: true, 12 | transclude:true, 13 | scope:{ 14 | }, 15 | template: LeftMenuTpl, 16 | link : function(scope, element, attrs){ 17 | 18 | } 19 | } 20 | }]) 21 | .directive('menuLeftBtn',['$mdUtil','$mdSidenav','$log', function($mdUtil,$mdSidenav,$log){ 22 | /** 23 | * Build handler to open/close a SideNav; when animation finishes 24 | * report completion in console 25 | */ 26 | function toggler(navID) { 27 | var debounceFn = $mdUtil.debounce(function(){ 28 | $mdSidenav(navID) 29 | .toggle() 30 | .then(function () { 31 | $log.debug("toggle " + navID + " is done"); 32 | }); 33 | },200); 34 | return debounceFn; 35 | } 36 | 37 | return { 38 | restrict: 'A', 39 | compile : function(element, attrs){ 40 | var toggleLeft = toggler('left'); 41 | angular.element(element).on('click',function(){ 42 | toggleLeft(); 43 | }); 44 | } 45 | } 46 | }]) -------------------------------------------------------------------------------- /chat/source/service/UserService.js: -------------------------------------------------------------------------------- 1 | 2 | export default 3 | angular.module('User',['ngRoute','ngResource']) 4 | .config(['$resourceProvider','$httpProvider', function($resourceProvider,$httpProvider) { 5 | 6 | $httpProvider.defaults.headers.common = { 7 | 'Accept':'application/json, text/javascript, */*; q=0.01', 8 | 'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8', 9 | }; 10 | $httpProvider.defaults.headers.put['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; 11 | $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; 12 | 13 | }]) 14 | .service('User',['$rootScope','$http','$resource','apiConfig', 15 | function($rootScope,$http,$resource,apiConfig){ 16 | var wechat_host = apiConfig.wx_host; 17 | let mobile_host = apiConfig.mobile_host; 18 | 19 | return $resource(wechat_host+'callback/userinfobycode',{},{ 20 | getUserInfoByCode:{ 21 | url:wechat_host+'callback/userinfobycode', 22 | method:'GET', 23 | params: apiConfig.authParams, 24 | }, 25 | getHistoryMsg:{ 26 | url:wechat_host+'user/historymsg', 27 | method:'GET', 28 | params: apiConfig.authParams, 29 | }, 30 | getUserInfoByThirdApp:{ 31 | url:mobile_host+'passport/login', 32 | method:'POST', 33 | } 34 | }); 35 | }]); -------------------------------------------------------------------------------- /chat/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "jspm": { 3 | "dependencies": { 4 | "angular": "github:angular/bower-angular@1.4.6", 5 | "angular-cookies": "github:angular/bower-angular-cookies@1.4.6", 6 | "angular-local-storage": "npm:angular-local-storage@0.2.2", 7 | "angular-material": "npm:angular-material@0.11.0", 8 | "angular-mocks": "github:angular/bower-angular-mocks@1.4.6", 9 | "angular-resource": "github:angular/bower-angular-resource@1.4.6", 10 | "angular-route": "github:angular/bower-angular-route@1.4.6", 11 | "clean-css": "npm:clean-css@3.4.4", 12 | "css": "github:systemjs/plugin-css@0.1.17", 13 | "jquery": "npm:jquery@2.1.4", 14 | "mdi": "npm:mdi@1.2.65", 15 | "process": "github:jspm/nodelibs-process@0.1.2", 16 | "text": "github:systemjs/plugin-text@0.0.2", 17 | "traceur": "npm:traceur@0.0.92" 18 | }, 19 | "devDependencies": { 20 | "babel": "npm:babel-core@5.8.24", 21 | "babel-runtime": "npm:babel-runtime@5.8.24", 22 | "core-js": "npm:core-js@1.1.4", 23 | "traceur-runtime": "github:jmcriffey/bower-traceur-runtime@0.0.92" 24 | } 25 | }, 26 | "devDependencies": { 27 | "browser-sync": "2.9.6", 28 | "chai": "3.4.0", 29 | "chai-as-promised": "5.1.0", 30 | "gulp": "3.9.0", 31 | "gulp-clean": "0.3.1", 32 | "gulp-concat": "2.6.0", 33 | "gulp-html-replace": "1.5.1", 34 | "gulp-uglify": "1.2.0", 35 | "jasmine-core": "2.3.4", 36 | "js-yaml": "3.4.2", 37 | "karma": "0.13.14", 38 | "karma-chai": "0.1.0", 39 | "karma-chai-as-promised": "0.1.2", 40 | "karma-chrome-launcher": "0.2.1", 41 | "karma-jasmine": "0.3.6", 42 | "karma-jspm": "2.0.2", 43 | "karma-mocha": "0.2.0", 44 | "karma-mocha-reporter": "1.1.1", 45 | "karma-sinon-chai": "1.1.0", 46 | "mocha": "2.3.3" 47 | }, 48 | "dependencies": { 49 | "jspm": "0.16.13" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /chat/source/states/preview/preview-controller.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/12/3. 3 | */ 4 | import $ from 'jquery'; 5 | 6 | import 'source/components/btn_back/btn-back-directive' 7 | 8 | export default angular.module('preview') 9 | .controller('PreviewCtrl',['$scope','$routeParams','$rootScope','$timeout', 10 | function($scope,$routeParams,$rootScope,$timeout){ 11 | $scope.pageClass = 'page'; 12 | $("#preview_box").css('height',$rootScope.winheight+'px') 13 | 14 | $scope.isSamllImg = true; 15 | $scope.toggleImg = toggleImg; 16 | 17 | init(); 18 | 19 | ////////////////////////////////////////////// 20 | function init(){ 21 | autoMarginTop(); 22 | } 23 | 24 | function toggleImg(){ 25 | $scope.isSamllImg = !$scope.isSamllImg; 26 | autoMarginTop(); 27 | } 28 | 29 | function autoMarginTop(){ 30 | $timeout(()=>{ 31 | let img_height = $("#preview_img")[0].height; 32 | let margin_top = Math.abs($rootScope.winheight-img_height)/2; 33 | 34 | if($scope.isSamllImg){ 35 | //设置顶部距离 36 | if(img_height == 0){ 37 | $("#preview_img").css('margin-top','50%'); 38 | }else{ 39 | if(img_height>$rootScope.winheight){ 40 | $("#preview_img").css('margin-top',0); 41 | }else{ 42 | $("#preview_img").css('margin-top',margin_top+'px'); 43 | } 44 | } 45 | }else{ 46 | if(img_height>$rootScope.winheight){ 47 | $("#preview_img").css('margin-top',0); 48 | }else{ 49 | $("#preview_img").css('margin-top',margin_top+'px'); 50 | } 51 | } 52 | },100) 53 | } 54 | }]) -------------------------------------------------------------------------------- /chat/source/service/QaService.js: -------------------------------------------------------------------------------- 1 | 2 | export default 3 | angular.module('Qa',['ngRoute','ngResource']) 4 | .config(['$resourceProvider','$httpProvider', function($resourceProvider,$httpProvider) { 5 | 6 | $httpProvider.defaults.headers.common = { 7 | 'Accept':'application/json, text/javascript, */*; q=0.01', 8 | 'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8', 9 | }; 10 | $httpProvider.defaults.headers.put['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; 11 | $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; 12 | 13 | }]) 14 | .service('Qa',['$rootScope','$http','$resource','apiConfig', 15 | function($rootScope,$http,$resource,apiConfig){ 16 | var service_host = apiConfig.mobile_host; 17 | 18 | return $resource(service_host+'qa/:qa_id',{},{ 19 | create:{ 20 | url:service_host+'qa/create', 21 | method:'GET', 22 | params: apiConfig.authParams, 23 | }, 24 | get: { 25 | method:'GET', 26 | params: apiConfig.authParams, 27 | }, 28 | edit: { 29 | url:service_host+'qa/:qa_id/edit', 30 | method:'GET', 31 | params: apiConfig.authParams, 32 | }, 33 | save: { 34 | method:'POST', 35 | params: apiConfig.authParams, 36 | }, 37 | query: { 38 | url:service_host+'qa/list', 39 | method: "GET", 40 | params: apiConfig.authParams, 41 | isArray: false 42 | }, 43 | update: { 44 | method:'POST', 45 | params: apiConfig.authParams, 46 | }, 47 | remove: { 48 | method:'POST', 49 | params: apiConfig.authParams, 50 | } 51 | }); 52 | }]); -------------------------------------------------------------------------------- /chat/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Mon Nov 02 2015 15:10:07 GMT+0800 (CST) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: '', 9 | 10 | 11 | // frameworks to use 12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 13 | frameworks: [ 14 | 'chai-as-promised', 15 | 'sinon-chai', 16 | 'mocha', 17 | 'jspm' 18 | ], 19 | 20 | // list of files / patterns to load in the browser 21 | //files: [], 22 | jspm: { 23 | paths:{ 24 | 'test/*':'base/test/*', 25 | 'source/*':'base/source/*', 26 | 'public/*':'base/public/*', 27 | "github:*": "base/jspm_packages/github/*", 28 | "npm:*": "base/jspm_packages/npm/*", 29 | 'node_modules/*':"base/node_modules/*", 30 | //'*':"base/*", 31 | }, 32 | loadFiles: [ 33 | 'test/**/*.js' 34 | ], 35 | serveFiles: [ 36 | 'public/**', 37 | 'source/**/*.html', 38 | 'source/**/*.js' 39 | ], 40 | }, 41 | reports: [ 42 | 'mocha' 43 | ], 44 | 45 | // list of files to exclude 46 | exclude: [ 47 | ], 48 | 49 | 50 | // preprocess matching files before serving them to the browser 51 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 52 | preprocessors: { 53 | }, 54 | 55 | 56 | // test results reporter to use 57 | // possible values: 'dots', 'progress' 58 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 59 | reporters: ['progress'], 60 | 61 | 62 | // web server port 63 | port: 9876, 64 | 65 | 66 | // enable / disable colors in the output (reporters and logs) 67 | colors: true, 68 | 69 | 70 | // level of logging 71 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 72 | logLevel: config.LOG_INFO, 73 | 74 | 75 | // enable / disable watching file and executing tests whenever any file changes 76 | autoWatch: true, 77 | 78 | 79 | // start these browsers 80 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 81 | browsers: ['Chrome'], 82 | 83 | 84 | // Continuous Integration mode 85 | // if true, Karma captures browsers, runs the tests and exits 86 | singleRun: false, 87 | 88 | // Concurrency level 89 | // how many browser should be started simultanous 90 | concurrency: Infinity 91 | }) 92 | } 93 | -------------------------------------------------------------------------------- /chat/source/lib/Recorderjs/recorder.js: -------------------------------------------------------------------------------- 1 | (function(window){ 2 | 3 | var WORKER_PATH = 'source/lib/Recorderjs/recorderWorker.js'; 4 | 5 | var Recorder = function(source, cfg){ 6 | var config = cfg || {}; 7 | var bufferLen = config.bufferLen || 4096; 8 | var numChannels = config.numChannels || 2; 9 | this.context = source.context; 10 | this.node = (this.context.createScriptProcessor || 11 | this.context.createJavaScriptNode).call(this.context, 12 | bufferLen, numChannels, numChannels); 13 | var worker = new Worker(config.workerPath || WORKER_PATH); 14 | worker.postMessage({ 15 | command: 'init', 16 | config: { 17 | sampleRate: this.context.sampleRate, 18 | numChannels: numChannels 19 | } 20 | }); 21 | var recording = false, 22 | currCallback; 23 | 24 | this.node.onaudioprocess = function(e){ 25 | if (!recording) return; 26 | var buffer = []; 27 | for (var channel = 0; channel < numChannels; channel++){ 28 | buffer.push(e.inputBuffer.getChannelData(channel)); 29 | } 30 | worker.postMessage({ 31 | command: 'record', 32 | buffer: buffer 33 | }); 34 | } 35 | 36 | this.configure = function(cfg){ 37 | for (var prop in cfg){ 38 | if (cfg.hasOwnProperty(prop)){ 39 | config[prop] = cfg[prop]; 40 | } 41 | } 42 | } 43 | 44 | this.record = function(){ 45 | recording = true; 46 | } 47 | 48 | this.stop = function(){ 49 | recording = false; 50 | } 51 | 52 | this.clear = function(){ 53 | worker.postMessage({ command: 'clear' }); 54 | } 55 | 56 | this.getBuffer = function(cb) { 57 | currCallback = cb || config.callback; 58 | worker.postMessage({ command: 'getBuffer' }) 59 | } 60 | 61 | this.exportWAV = function(cb, type){ 62 | currCallback = cb || config.callback; 63 | type = type || config.type || 'audio/wav'; 64 | if (!currCallback) throw new Error('Callback not set'); 65 | worker.postMessage({ 66 | command: 'exportWAV', 67 | type: type 68 | }); 69 | } 70 | 71 | worker.onmessage = function(e){ 72 | var blob = e.data; 73 | currCallback(blob); 74 | } 75 | 76 | source.connect(this.node); 77 | this.node.connect(this.context.destination); //this should not be necessary 78 | }; 79 | 80 | Recorder.forceDownload = function(blob, filename){ 81 | var url = (window.URL || window.webkitURL).createObjectURL(blob); 82 | var link = window.document.createElement('a'); 83 | link.href = url; 84 | link.download = filename || 'output.wav'; 85 | var click = document.createEvent("Event"); 86 | click.initEvent("click", true, true); 87 | link.dispatchEvent(click); 88 | } 89 | 90 | window.Recorder = Recorder; 91 | 92 | })(window); 93 | -------------------------------------------------------------------------------- /chat/source/core/default/core-controller.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/10/15. 3 | */ 4 | 5 | import $ from 'jquery' 6 | 7 | import ErrorDialogCtrl from 'source/states/chat/dialog/error-dialog-controller'; 8 | import ErrorDialogHtml from 'source/states/chat/dialog/error-dialog-template.html!text' 9 | 10 | function myAppCtrl($rootScope,$timeout,$mdDialog,$scope){ 11 | 12 | $rootScope.is_weixn = window.is_weixn(); 13 | $rootScope.isAndroid = navigator.userAgent.match(/Android/i) ? true: false; 14 | $rootScope.isBlackBerry = navigator.userAgent.match(/BlackBerry/i) ? true: false; 15 | $rootScope.isiPhone = navigator.userAgent.match(/iPhone/i) ? true: false; 16 | $rootScope.isWindows = navigator.userAgent.match(/IEMobile/i) ? true: false; 17 | $rootScope.autoSetMessageBoxHeight = autoSetMessageBoxHeight; 18 | $rootScope.errorDialog = errorDialog; 19 | 20 | getSysVersion();//获取系统版本 21 | 22 | //页面加载完成后自适应屏幕 23 | $rootScope.$on('$viewContentLoaded', function() { 24 | $timeout(()=>{ 25 | autoSetMessageBoxHeight() 26 | },1e1) 27 | }); 28 | $(window).resize(function(){ 29 | autoSetMessageBoxHeight(); 30 | }) 31 | 32 | function autoSetMessageBoxHeight(){ 33 | var el = $("#message_box"); 34 | if(el.length == 1){ 35 | $rootScope.winheight= $(window).height(); 36 | $rootScope.winwidth = $(window).width(); 37 | $rootScope.header = $("#cm-header").height(); 38 | $rootScope.topToolbar = $("md-toolbar:first").height(); 39 | $rootScope.bottom = 49; 40 | $(el[0]).css('height',$rootScope.winheight-$rootScope.header-$rootScope.topToolbar-$rootScope.bottom+'px'); 41 | 42 | $("#message_input").css('width',$rootScope.winwidth-48-48-13); 43 | } 44 | $("body").css('background','#f1f1f1'); 45 | } 46 | 47 | function getSysVersion(){ 48 | if($rootScope.isAndroid){ 49 | var str = navigator.userAgent.match(/Android ([\d.]+)/); 50 | for(let i=0;i0){ 52 | $rootScope.sys_version = parseFloat(str[i]); 53 | } 54 | } 55 | }else if($rootScope.isiPhone){ 56 | var str = navigator.userAgent.match(/iPhone OS ([\d_]+) /); 57 | for(let i=0;i0){ 59 | $rootScope.sys_version = parseFloat(str[i]); 60 | } 61 | } 62 | } 63 | } 64 | 65 | function errorDialog(msg){ 66 | $scope.error_msg = msg; 67 | $mdDialog.show({ 68 | clickOutsideToClose: true, 69 | scope: $scope, 70 | preserveScope: true, 71 | template: ErrorDialogHtml, 72 | controller:ErrorDialogCtrl 73 | }); 74 | } 75 | } 76 | 77 | myAppCtrl.$inject = ['$rootScope','$timeout','$mdDialog','$scope']; 78 | 79 | export default myAppCtrl; -------------------------------------------------------------------------------- /chat/source/components/face/face-directive.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/9/30. 3 | */ 4 | 5 | import FaceWeiXinTemplate from './face-weixin-template.html!text' 6 | 7 | export default angular.module('chat') 8 | .directive('face',['$rootScope',function($rootScope){ 9 | return { 10 | restrict: 'AE', 11 | replace: false, 12 | transclude:true, 13 | scope:{ 14 | }, 15 | template: FaceWeiXinTemplate, 16 | link : function(scope, element, attrs){ 17 | scope.face_list = [ 18 | 19 | {name:'[blush]',img:'ee_1.png'}, 20 | {name:'[relieved]',img:'ee_2.png'}, 21 | {name:'[heart_eyes]',img:'ee_3.png'}, 22 | {name:'[hushed]',img:'ee_4.png'}, 23 | {name:'[kissing_closed_eyes]',img:'ee_5.png'}, 24 | {name:'[stuck_out_tongue_winking_eye]',img:'ee_6.png'}, 25 | {name:'[stuck_out_tongue_closed_eyes]',img:'ee_7.png'}, 26 | {name:'[sleepy]',img:'ee_8.png'}, 27 | {name:'[sob]',img:'ee_9.png'}, 28 | {name:'[joy]',img:'ee_10.png'}, 29 | {name:'[grin]',img:'ee_11.png'}, 30 | {name:'[smiley]',img:'ee_12.png'}, 31 | {name:'[sweat]',img:'ee_13.png'}, 32 | {name:'[confounded]',img:'ee_14.png'}, 33 | {name:'[kissing_heart]',img:'ee_15.png'}, 34 | {name:'[angry]',img:'ee_16.png'}, 35 | {name:'[flushed]',img:'ee_17.png'}, 36 | {name:'[mask]',img:'ee_18.png'}, 37 | {name:'[astonished]',img:'ee_19.png'}, 38 | {name:'[rage]',img:'ee_20.png'}, 39 | {name:'[zzz]',img:'ee_21.png'}, 40 | {name:'[iphone]',img:'ee_22.png'}, 41 | {name:'[beers]',img:'ee_23.png'}, 42 | {name:'[punch]',img:'ee_24.png'}, 43 | {name:'[ok_hand]',img:'ee_25.png'}, 44 | {name:'[+1]',img:'ee_26.png'}, 45 | {name:'[thumbsdown]',img:'ee_27.png'}, 46 | {name:'[clap]',img:'ee_28.png'}, 47 | {name:'[pray]',img:'ee_29.png'}, 48 | {name:'[broken_heart]',img:'ee_30.png'}, 49 | {name:'[rose]',img:'ee_31.png'}, 50 | {name:'[bikini]',img:'ee_32.png'}, 51 | {name:'[dress]',img:'ee_33.png'}, 52 | {name:'[womans_hat]',img:'ee_34.png'}, 53 | {name:'[shirt]',img:'ee_35.png'}, 54 | {name:'[high_heel]',img:'ee_36.png'}, 55 | {name:'[boot]',img:'ee_37.png'}, 56 | {name:'[boy]',img:'ee_38.png'}, 57 | {name:'[girl]',img:'ee_39.png'}, 58 | {name:'[man]',img:'ee_40.png'}, 59 | {name:'[woman]',img:'ee_41.png'}, 60 | {name:'[skull]',img:'ee_42.png'}, 61 | {name:'[fire]',img:'ee_43.png'} 62 | 63 | ]; 64 | scope.click_face = click_face; 65 | 66 | function click_face(face_name){ 67 | $rootScope.$broadcast('face_inputting',{face_name:face_name}); 68 | } 69 | }, 70 | } 71 | }]) -------------------------------------------------------------------------------- /chat/public/index.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 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 55 | 56 | 57 | 58 | 61 | 62 | 63 | 64 | 65 | 66 | 67 |
69 | 70 |
71 | 72 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /chat/source/lib/Recorderjs/example_simple_exportwav.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Live input record and playback 7 | 11 | 12 | 13 | 14 |

Recorder.js simple WAV export example

15 | 16 |

Make sure you are using a recent version of Google Chrome.

17 |

Also before you enable microphone input either plug in headphones or turn the volume down if you want to avoid ear splitting feedback!

18 | 19 | 20 | 21 | 22 |

Recordings

23 | 24 | 25 |

Log

26 |

 27 | 
 28 |   
104 | 
105 |   
106 | 
107 | 
108 | 


--------------------------------------------------------------------------------
/chat/gulpfile.js:
--------------------------------------------------------------------------------
  1 | // gulpfile.js
  2 | var fs          = require('fs');
  3 | var yaml        = require('js-yaml');
  4 | // var _           = require('lodash');
  5 | var gulp        = require('gulp');
  6 | // var proxy       = require('proxy-middleware');
  7 | // var url         = require('url');
  8 | var browserSync = require('browser-sync');
  9 | 
 10 | var clean = require('gulp-clean');
 11 | var concat  = require('gulp-concat');
 12 | var uglify  = require('gulp-uglify');
 13 | var htmlreplace = require('gulp-html-replace');//页面替换
 14 | 
 15 |     try {
 16 |     var options = yaml.safeLoad(fs.readFileSync('./config.yaml', 'utf-8'));
 17 | } catch (error) {
 18 |     throw new Error(error);
 19 | }
 20 | 
 21 | var taskDependencies = (function() {
 22 |     gulp.task('server', function() {
 23 |         // var proxyMiddleware = proxy(
 24 |         //     _.assign(url.parse(options.proxyURL), options.proxyOptions)
 25 |         // );
 26 |         // options.browserSync.server.middleware.push(proxyMiddleware);
 27 |         browserSync(options.browserSync);
 28 |     });
 29 | 
 30 |     return ['server'];
 31 | }());
 32 | 
 33 | gulp.task('default', taskDependencies, function() {
 34 |     // Default Task Denifition
 35 | });
 36 | 
 37 | /**
 38 |  *  minify: Use minification, defaults to true.
 39 |     mangle: Use mangling with minification, defaults to true.
 40 |     lowResSourceMaps: Use faster low-resolution source maps, defaults to true.
 41 |     sourceMaps: Use source maps, defaults to true.
 42 |  */
 43 | 
 44 | var jspm = require('jspm');
 45 | 
 46 | //清空dist
 47 | gulp.task('clean', function() {
 48 |     return gulp.src(['./dist/default'], {read: false})
 49 |         .pipe(clean({force: true}));
 50 | });
 51 | 
 52 | 
 53 | gulp.task('weinxinclean', function() {
 54 |     return gulp.src(['./dist/weixin'], {read: false})
 55 |         .pipe(clean({force: true}));
 56 | })
 57 | 
 58 | gulp.task('weixin',['weinxinclean'],function(){
 59 |     var v = new Date().getTime();
 60 |     console.log('开始任务');
 61 |     jspm.setPackagePath('./');
 62 |     console.log('设置包路径');
 63 |     jspm.bundleSFX('./source/app-weixin.js','./dist/weixin/weixin-'+v+'.js',{
 64 |         sourceMaps:false,
 65 |         minify:true
 66 |     }).then(function(){
 67 |         console.log('打包weixin.js完成');
 68 | 
 69 |         gulp.src('./public/index.html')
 70 |             .pipe(htmlreplace({
 71 |                 app_js:{
 72 |                     src: null,
 73 |                     tpl: ''
 74 |                 }
 75 |             }))
 76 |             .pipe(gulp.dest('./dist/weixin'))
 77 | 
 78 |         console.log('执行成功!');
 79 |     })
 80 | });
 81 | 
 82 | gulp.task('appclean', function() {
 83 |     return gulp.src(['./dist/default'], {read: false})
 84 |         .pipe(clean({force: true}));
 85 | })
 86 | 
 87 | gulp.task('app',['appclean'],function(){
 88 |     var v = new Date().getTime();
 89 |     console.log('开始任务');
 90 |     jspm.setPackagePath('./');
 91 |     console.log('设置包路径');
 92 |     jspm.bundleSFX('./source/app-default.js','./dist/default/default-'+v+'.js',{
 93 |         sourceMaps:false,
 94 |         minify:true
 95 |     }).then(function(){
 96 |         console.log('打包default.js完成');
 97 | 
 98 |         gulp.src('./public/index.html')
 99 |             .pipe(htmlreplace({
100 |                 app_js:{
101 |                     src: null,
102 |                     tpl: ''
103 |                 }
104 |             }))
105 |             .pipe(gulp.dest('./dist/default'))
106 | 
107 |         console.log('执行成功!');
108 |     })
109 | });
110 | 
111 | gulp.task('all',['app','weixin'],function(){
112 | 
113 | })


--------------------------------------------------------------------------------
/chat/source/lib/Recorderjs/README.md:
--------------------------------------------------------------------------------
 1 | # Recorder.js
 2 | 
 3 | ## A plugin for recording/exporting the output of Web Audio API nodes
 4 | 
 5 | ### Syntax
 6 | #### Constructor
 7 |     var rec = new Recorder(source [, config])
 8 | 
 9 | Creates a recorder instance.
10 | 
11 | - **source** - The node whose output you wish to capture
12 | - **config** - (*optional*) A configuration object (see **config** section below)
13 | 
14 | ---------
15 | #### Config
16 | 
17 | - **workerPath** - Path to recorder.js worker script. Defaults to 'js/recorderjs/recorderWorker.js'
18 | - **bufferLen** - The length of the buffer that the internal JavaScriptNode uses to capture the audio. Can be tweaked if experiencing performance issues. Defaults to 4096.
19 | - **callback** - A default callback to be used with `exportWAV`.
20 | - **type** - The type of the Blob generated by `exportWAV`. Defaults to 'audio/wav'.
21 | 
22 | ---------
23 | #### Instance Methods
24 | 
25 |     rec.record()
26 |     rec.stop()
27 | 
28 | Pretty self-explanatory... **record** will begin capturing audio and **stop** will cease capturing audio. Subsequent calls to **record** will add to the current recording.
29 | 
30 |     rec.clear()
31 | 
32 | This will clear the recording.
33 | 
34 |     rec.exportWAV([callback][, type])
35 | 
36 | This will generate a Blob object containing the recording in WAV format. The callback will be called with the Blob as its sole argument. If a callback is not specified, the default callback (as defined in the config) will be used. If no default has been set, an error will be thrown.
37 | 
38 | In addition, you may specify the type of Blob to be returned (defaults to 'audio/wav').
39 | 
40 |     rec.getBuffer([callback])
41 | 
42 | This will pass the recorded stereo buffer (as an array of two Float32Arrays, for the separate left and right channels) to the callback. It can be played back by creating a new source buffer and setting these buffers as the separate channel data:
43 | 
44 | 	function getBufferCallback( buffers ) {
45 | 		var newSource = audioContext.createBufferSource();
46 | 		var newBuffer = audioContext.createBuffer( 2, buffers[0].length, audioContext.sampleRate );
47 | 		newBuffer.getChannelData(0).set(buffers[0]);
48 | 		newBuffer.getChannelData(1).set(buffers[1]);
49 | 		newSource.buffer = newBuffer;
50 | 
51 | 		newSource.connect( audioContext.destination );
52 | 		newSource.start(0);
53 | 	}
54 | 
55 | This sample code will play back the stereo buffer.
56 | 
57 | 
58 |     rec.configure(config)
59 | 
60 | This will set the configuration for Recorder by passing in a config object.
61 | 
62 | #### Utility Methods (static)
63 | 
64 |     Recorder.forceDownload(blob[, filename])
65 | 
66 | This method will force a download using the new anchor link *download* attribute. Filename defaults to 'output.wav'.
67 | 
68 | ## License (MIT)
69 | 
70 | Copyright © 2013 Matt Diamond
71 | 
72 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
73 | 
74 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
75 | 
76 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


--------------------------------------------------------------------------------
/chat/source/states/chat/bottom_sheet/send-other-message-controller.js:
--------------------------------------------------------------------------------
 1 | /**
 2 |  * Created by yangjiajun on 15/9/30.
 3 |  */
 4 | import 'source/lib/qiniu/qupload'
 5 | import UploadToast from './upload-toast-template.html!text'
 6 | import UploadToastCtrl from './upload-tosat-controller'
 7 | 
 8 | function SendOtherMessageCtrl($scope, $mdBottomSheet,$rootScope,apiConfig,UploadService,$qupload,$mdToast) {
 9 | 
10 |         var qiniu_im_host = apiConfig.qiniu_im_host;
11 |         $scope.selectFiles = [];
12 | 
13 | 
14 |         var start = function (index) {
15 |             $mdBottomSheet.hide();
16 |             $rootScope.hide_http_loading = true;
17 |             $mdToast.show({
18 |                 controller: UploadToastCtrl,
19 |                 template: UploadToast,
20 |                 hideDelay: 60e3,
21 |                 position: 'top'
22 |             });
23 |             var key = new Date().getTime()+'';
24 |             $scope.selectFiles[index].upload = $qupload.upload({
25 |                 //key: $filter('date')(new Date(),'yyyy-MM-dd HH:mm:ss')+'_'+$rootScope.talkUser.user_uin,//按用户名称和发送时间命名 方便数据迁移
26 |                 key: key,//按用户名称和发送时间命名 方便数据迁移
27 |                 file: $scope.selectFiles[index].file,
28 |                 token:$scope.uploadToken,
29 |             });
30 |             $scope.selectFiles[index].upload.then(function (response) {
31 |                 //上传成功 发送图片
32 |                 var img_url = qiniu_im_host+response.key;
33 |                 $rootScope.$broadcast('img_upload_success',{img_url:img_url});
34 |                 $scope.selectFiles.splice(index,1);
35 |                 $rootScope.hide_http_loading = false;
36 |             }, function (response) {
37 |                 //toaster.pop('error','上传失败!');
38 |                 $scope.selectFiles.splice(index,1);
39 |                 $rootScope.hide_http_loading = false;
40 |             }, function (evt) {
41 |                 $mdToast.updateContent(Math.floor(100 * evt.loaded / evt.totalSize));
42 |             });
43 |         };
44 | 
45 | 
46 |         $scope.convertBase64UrlToBlob = function(urlData){
47 |             var bytes=window.atob(urlData.split(',')[1]);        //去掉url的头,并转换为byte
48 | 
49 |             //处理异常,将ascii码小于0的转换为大于0
50 |             var ab = new ArrayBuffer(bytes.length);
51 |             var ia = new Uint8Array(ab);
52 |             for (var i = 0; i < bytes.length; i++) {
53 |                 ia[i] = bytes.charCodeAt(i);
54 |             }
55 | 
56 |             return new Blob( [ab] , {type : 'image/png'});
57 |         }
58 | 
59 |         $scope.onFileSelect = function ($files) {
60 |             var offsetx = $scope.selectFiles.length;
61 |             $scope.getUpToken().then(function(){
62 |                 for (var i = 0; i < $files.length; i++) {
63 |                     if(!($files[i].type == 'image/png' || $files[i].type == 'image/jpg' || $files[i].type == 'image/jpeg')){
64 |                         $rootScope.errorDialog("只支持jpg,jpeg,png格式!");
65 |                         $mdBottomSheet.hide();
66 |                         continue;
67 |                     }
68 |                     $scope.selectFiles[i + offsetx] = {
69 |                         file: $files[i]
70 |                     };
71 |                     start(i + offsetx);
72 |                 }
73 |             })
74 | 
75 |         };
76 | 
77 |         $scope.getUpToken = function(){
78 |             //that.value = null;
79 |             return new Promise(function(resolve,reject){
80 |                 UploadService.get({type:'im'}).$promise.then(function(data){
81 |                     if(data && data.code == 200){
82 |                         $scope.uploadToken = data.data.upload_token;
83 |                         resolve()
84 |                     }else{
85 |                         reject()
86 |                     }
87 |                 }).catch(function(){
88 |                     reject()
89 |                 })
90 |             })
91 |         };
92 | 
93 |     }
94 | 
95 | SendOtherMessageCtrl.$inject = ['$scope','$mdBottomSheet','$rootScope','apiConfig','Upload','$qupload','$mdToast'];
96 | 
97 | export default SendOtherMessageCtrl


--------------------------------------------------------------------------------
/chat/source/components/btn_audio/btn-audio-directive.js:
--------------------------------------------------------------------------------
  1 | /**
  2 |  * Created by yangjiajun on 15/10/8.
  3 |  *
  4 |  */
  5 | 
  6 | //语音
  7 | import 'source/lib/Recorderjs/recorder'
  8 | import 'source/lib/Recorderjs/recorderWorker'
  9 | 
 10 | export default angular.module('chat')
 11 |     .directive('cmAudioBtn',['$rootScope',function($rootScope){
 12 |         var audio_context;
 13 | 
 14 |         function startUserMedia(stream) {
 15 |             var input = audio_context.createMediaStreamSource(stream);
 16 |             console.log('Media stream created.');
 17 |             // Uncomment if you want the audio to feedback directly
 18 |             //input.connect(audio_context.destination);
 19 |             //__log('Input connected to audio context destination.');
 20 | 
 21 |             $rootScope.recorder = new Recorder(input);
 22 |             console.log('Recorder initialised.');
 23 |         }
 24 | 
 25 |         return {
 26 |             restrict: 'AE',
 27 |             replace: true,
 28 |             scope:{
 29 |                 ngModel:'='
 30 |             },
 31 |             link : function($scope,element,attrs){
 32 | 
 33 |                 element.on('click',function(){
 34 |                     console.log($scope.ngModel);
 35 |                     $scope.ngModel = !$scope.ngModel;
 36 |                     $rootScope.$apply($scope.ngModel);
 37 |                     if(angular.isUndefined($rootScope.recorder)){
 38 |                         try {
 39 |                             // webkit shim
 40 |                             window.AudioContext = window.AudioContext || window.webkitAudioContext;
 41 |                             navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia;
 42 |                             window.URL = window.URL || window.webkitURL;
 43 | 
 44 |                             audio_context = new AudioContext;
 45 |                             console.log('Audio context set up.');
 46 |                             console.log('navigator.getUserMedia ' + (navigator.getUserMedia ? 'available.' : 'not present!'));
 47 |                         } catch (e) {
 48 |                             alert('No web audio support in this browser!');
 49 |                         }
 50 | 
 51 |                         navigator.getUserMedia({audio: true}, startUserMedia, function(e) {
 52 |                             $scope.status = false;
 53 |                             alert('未找到在线的音频输入设备: ' + e);
 54 |                         });
 55 |                     }
 56 |                 })
 57 | 
 58 | 
 59 |             }
 60 |         }
 61 |     }])
 62 |     .directive('cmAudioInputBtn',['$rootScope',function($rootScope){
 63 |         return {
 64 |             restrict: 'E',
 65 |             replace: false,
 66 |             scope:true,
 67 |             link : function($scope,element,attrs){
 68 |                 $scope.startRecording = startRecording;
 69 |                 $scope.stopRecording = stopRecording;
 70 | 
 71 |                 element.on('mousedown',function(){
 72 |                     startRecording()
 73 |                     console.log('正在录音。。。')
 74 |                 })
 75 | 
 76 |                 element.on('mouseup',function(){
 77 |                     stopRecording()
 78 |                     console.log('结束录音。。。')
 79 |                 })
 80 | 
 81 |                 function startRecording(button){
 82 |                     $rootScope.recorder && $rootScope.recorder.record();
 83 |                 }
 84 | 
 85 |                 function stopRecording(button) {
 86 |                     $rootScope.recorder && $rootScope.recorder.stop();
 87 |                     // create WAV download link using audio data blob
 88 |                     var audioUrl = createDownloadLink();
 89 | 
 90 | 
 91 |                     $rootScope.recorder.clear();
 92 |                 }
 93 | 
 94 |                 function createDownloadLink() {
 95 |                     $rootScope.recorder && $rootScope.recorder.exportWAV(function(blob) {
 96 |                         var audioUrl = URL.createObjectURL(blob);
 97 |                         $scope.$emit('audio_inputting',audioUrl);
 98 |                         console.log('完成录音。。。')
 99 |                     });
100 |                 }
101 |             }
102 |         }
103 |     }]);


--------------------------------------------------------------------------------
/chat/source/lib/Recorderjs/recorderWorker.js:
--------------------------------------------------------------------------------
  1 | var recLength = 0,
  2 |   recBuffers = [],
  3 |   sampleRate,
  4 |   numChannels;
  5 | 
  6 | this.onmessage = function(e){
  7 |   switch(e.data.command){
  8 |     case 'init':
  9 |       init(e.data.config);
 10 |       break;
 11 |     case 'record':
 12 |       record(e.data.buffer);
 13 |       break;
 14 |     case 'exportWAV':
 15 |       exportWAV(e.data.type);
 16 |       break;
 17 |     case 'getBuffer':
 18 |       getBuffer();
 19 |       break;
 20 |     case 'clear':
 21 |       clear();
 22 |       break;
 23 |   }
 24 | };
 25 | 
 26 | function init(config){
 27 |   sampleRate = config.sampleRate;
 28 |   numChannels = config.numChannels;
 29 |   initBuffers();
 30 | }
 31 | 
 32 | function record(inputBuffer){
 33 |   for (var channel = 0; channel < numChannels; channel++){
 34 |     recBuffers[channel].push(inputBuffer[channel]);
 35 |   }
 36 |   recLength += inputBuffer[0].length;
 37 | }
 38 | 
 39 | function exportWAV(type){
 40 |   var buffers = [];
 41 |   for (var channel = 0; channel < numChannels; channel++){
 42 |     buffers.push(mergeBuffers(recBuffers[channel], recLength));
 43 |   }
 44 |   if (numChannels === 2){
 45 |       var interleaved = interleave(buffers[0], buffers[1]);
 46 |   } else {
 47 |       var interleaved = buffers[0];
 48 |   }
 49 |   var dataview = encodeWAV(interleaved);
 50 |   var audioBlob = new Blob([dataview], { type: type });
 51 | 
 52 |   this.postMessage(audioBlob);
 53 | }
 54 | 
 55 | function getBuffer(){
 56 |   var buffers = [];
 57 |   for (var channel = 0; channel < numChannels; channel++){
 58 |     buffers.push(mergeBuffers(recBuffers[channel], recLength));
 59 |   }
 60 |   this.postMessage(buffers);
 61 | }
 62 | 
 63 | function clear(){
 64 |   recLength = 0;
 65 |   recBuffers = [];
 66 |   initBuffers();
 67 | }
 68 | 
 69 | function initBuffers(){
 70 |   for (var channel = 0; channel < numChannels; channel++){
 71 |     recBuffers[channel] = [];
 72 |   }
 73 | }
 74 | 
 75 | function mergeBuffers(recBuffers, recLength){
 76 |   var result = new Float32Array(recLength);
 77 |   var offset = 0;
 78 |   for (var i = 0; i < recBuffers.length; i++){
 79 |     result.set(recBuffers[i], offset);
 80 |     offset += recBuffers[i].length;
 81 |   }
 82 |   return result;
 83 | }
 84 | 
 85 | function interleave(inputL, inputR){
 86 |   var length = inputL.length + inputR.length;
 87 |   var result = new Float32Array(length);
 88 | 
 89 |   var index = 0,
 90 |     inputIndex = 0;
 91 | 
 92 |   while (index < length){
 93 |     result[index++] = inputL[inputIndex];
 94 |     result[index++] = inputR[inputIndex];
 95 |     inputIndex++;
 96 |   }
 97 |   return result;
 98 | }
 99 | 
100 | function floatTo16BitPCM(output, offset, input){
101 |   for (var i = 0; i < input.length; i++, offset+=2){
102 |     var s = Math.max(-1, Math.min(1, input[i]));
103 |     output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
104 |   }
105 | }
106 | 
107 | function writeString(view, offset, string){
108 |   for (var i = 0; i < string.length; i++){
109 |     view.setUint8(offset + i, string.charCodeAt(i));
110 |   }
111 | }
112 | 
113 | function encodeWAV(samples){
114 |   var buffer = new ArrayBuffer(44 + samples.length * 2);
115 |   var view = new DataView(buffer);
116 | 
117 |   /* RIFF identifier */
118 |   writeString(view, 0, 'RIFF');
119 |   /* RIFF chunk length */
120 |   view.setUint32(4, 36 + samples.length * 2, true);
121 |   /* RIFF type */
122 |   writeString(view, 8, 'WAVE');
123 |   /* format chunk identifier */
124 |   writeString(view, 12, 'fmt ');
125 |   /* format chunk length */
126 |   view.setUint32(16, 16, true);
127 |   /* sample format (raw) */
128 |   view.setUint16(20, 1, true);
129 |   /* channel count */
130 |   view.setUint16(22, numChannels, true);
131 |   /* sample rate */
132 |   view.setUint32(24, sampleRate, true);
133 |   /* byte rate (sample rate * block align) */
134 |   view.setUint32(28, sampleRate * 4, true);
135 |   /* block align (channel count * bytes per sample) */
136 |   view.setUint16(32, numChannels * 2, true);
137 |   /* bits per sample */
138 |   view.setUint16(34, 16, true);
139 |   /* data chunk identifier */
140 |   writeString(view, 36, 'data');
141 |   /* data chunk length */
142 |   view.setUint32(40, samples.length * 2, true);
143 | 
144 |   floatTo16BitPCM(view, 44, samples);
145 | 
146 |   return view;
147 | }
148 | 


--------------------------------------------------------------------------------
/chat/source/filter/format-message.js:
--------------------------------------------------------------------------------
  1 | /**
  2 |  * Created by yangjiajun on 15/10/10.
  3 |  */
  4 | 
  5 | angular.module('format_msg',[])
  6 |     .filter('format_msg',['$sce','$rootScope',function($sce,$rootScope){
  7 |         var face_list = {
  8 |             '[blush]': 'ee_1.png',
  9 |             '[relieved]': 'ee_2.png',
 10 |             '[heart_eyes]': 'ee_3.png',
 11 |             '[hushed]': 'ee_4.png',
 12 |             '[kissing_closed_eyes]': 'ee_5.png',
 13 |             '[stuck_out_tongue_winking_eye]': 'ee_6.png',
 14 |             '[stuck_out_tongue_closed_eyes]': 'ee_7.png',
 15 |             '[sleepy]': 'ee_8.png',
 16 |             '[sob]': 'ee_9.png',
 17 |             '[joy]': 'ee_10.png',
 18 |             '[grin]': 'ee_11.png',
 19 |             '[smiley]': 'ee_12.png',
 20 |             '[sweat]': 'ee_13.png',
 21 |             '[confounded]': 'ee_14.png',
 22 |             '[kissing_heart]': 'ee_15.png',
 23 |             '[angry]': 'ee_16.png',
 24 |             '[flushed]': 'ee_17.png',
 25 |             '[mask]': 'ee_18.png',
 26 |             '[astonished]': 'ee_19.png',
 27 |             '[rage]': 'ee_20.png',
 28 |             '[zzz]': 'ee_21.png',
 29 |             '[iphone]': 'ee_22.png',
 30 |             '[beers]': 'ee_23.png',
 31 |             '[punch]': 'ee_24.png',
 32 |             '[ok_hand]': 'ee_25.png',
 33 |             '[+1]': 'ee_26.png',
 34 |             '[thumbsdown]': 'ee_27.png',
 35 |             '[clap]': 'ee_28.png',
 36 |             '[pray]': 'ee_29.png',
 37 |             '[broken_heart]': 'ee_30.png',
 38 |             '[rose]': 'ee_31.png',
 39 |             '[bikini]': 'ee_32.png',
 40 |             '[dress]': 'ee_33.png',
 41 |             '[womans_hat]': 'ee_34.png',
 42 |             '[shirt]': 'ee_35.png',
 43 |             '[high_heel]': 'ee_36.png',
 44 |             '[boot]': 'ee_37.png',
 45 |             '[boy]': 'ee_38.png',
 46 |             '[girl]': 'ee_39.png',
 47 |             '[man]': 'ee_40.png',
 48 |             '[woman]': 'ee_41.png',
 49 |             '[skull]': 'ee_42.png',
 50 |             '[fire]': 'ee_43.png',
 51 |             //兼容客户端 传的标识不一样
 52 |             '[smile]': 'ee_12.png'
 53 |         }
 54 | 
 55 |         return function (text,type) {
 56 |             type = type+'';
 57 |             switch (type){
 58 |                 case '1'://文本
 59 |                     if(text && text !='' && text != undefined){
 60 |                         text = text.replace(/\n/g,function(a,b){
 61 |                             return '
'; 62 | }); 63 | text = text.replace(/\[.+?\]/g,function(a,b){ 64 | return ''; 65 | }); 66 | text = text.replace(/<\(.+?\)>/g,function(a,b){ 67 | if(a.length>4){ 68 | var baike = a.replace('<(','').replace(')>',''); 69 | return ''+baike+'' 70 | } 71 | return a; 72 | }); 73 | } 74 | break; 75 | case '2'://语音 76 | text = ''; 77 | break; 78 | case '3'://图片 79 | text = ''; 80 | break; 81 | case '4'://用户分享行为 82 | text = text.toString(); 83 | switch(text){ 84 | case "show": 85 | text = "客户端弹出了分享框!"; 86 | break; 87 | case"qq": 88 | text = "用户分享到了QQ"; 89 | break; 90 | case"wx": 91 | text = "用户分享到了好友"; 92 | break; 93 | case"pyq": 94 | text = "用户分享到了朋友圈"; 95 | break; 96 | case"cancel": 97 | text = "用户取消了分享"; 98 | break; 99 | default : 100 | break; 101 | } 102 | text = "系统消息:"+text; 103 | break; 104 | default : 105 | 106 | break; 107 | } 108 | return $sce.trustAsHtml(text); 109 | } 110 | }]); -------------------------------------------------------------------------------- /chat/source/states/chat-weixin/chat-weixin-template.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | 选车用车养车,专业技师,即时解答

4 |

5 | 在线时间 08:00-24:00 6 | 7 |

8 |
9 |
10 | 11 |
12 |
点击获取聊天记录
13 |
没有聊天记录了
14 | 15 | 16 |
17 |
18 | 19 |
20 |
21 | {{msg.created_at|format_date}} 22 | 23 |
24 | 25 | message user image 26 |
27 | 28 |
29 |
30 | 31 | 32 |
33 |
34 | {{msg.created_at|format_date}} 35 | 36 |
37 | message user image 38 |
39 | 40 |
41 | 42 |
43 |
44 |
45 | 46 |
47 |
48 | 49 | 50 | 51 |
52 | 53 | 54 |
55 | 59 |
60 | 61 | 62 |
63 | 64 |
65 | 66 | 67 | 70 | 71 | 72 | 75 | 76 | 77 | 81 |
82 | 83 | 84 | 85 | 86 | 87 |
88 |
89 | 90 | 91 | 92 |
93 |
-------------------------------------------------------------------------------- /chat/source/service/WXService.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/10/14. 3 | */ 4 | 5 | //微信jssdk 6 | import wx from 'source/lib/weixin/jweixin-1.0.0' 7 | //import 'source/lib/tarsocial/tarsocial-monitor-v1002' 8 | 9 | export default angular.module('WX',[]) 10 | .config(['$httpProvider', function($httpProvider) { 11 | 12 | $httpProvider.defaults.headers.common = { 13 | 'Accept':'application/json, text/javascript, */*; q=0.01', 14 | 'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8', 15 | }; 16 | $httpProvider.defaults.headers.put['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; 17 | $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; 18 | 19 | }]) 20 | .service('wxService',['$rootScope','apiConfig','$http',function($rootScope,apiConfig,$http){ 21 | 22 | var weixin = {}; 23 | weixin.init = setWXShare; 24 | 25 | function setWXShare(data,wxUserInfo) { 26 | 27 | 28 | var shareText = { 29 | title: data.title, 30 | desc: data.desc, 31 | link: data.link, 32 | shareLink:data.shareLink 33 | }; 34 | 35 | function loadWXTicket(shareText, callback) { 36 | $http({ 37 | url:apiConfig.base_host+'wechat/callback/sign', 38 | params:{link: shareText.link}, 39 | method:'GET' 40 | }).success(function(data,header,config,status){ 41 | callback(data.data); 42 | }).error(function(data,header,config,status){ 43 | console.log('error'); 44 | }); 45 | } 46 | 47 | loadWXTicket(shareText, function (ticket) { 48 | wx.config({ 49 | debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
 50 | appId: ticket.appid, // 必填,公众号的唯一标识
 51 | timestamp: ticket.timestamp, // 必填,生成签名的时间戳
 52 | nonceStr: ticket.noncestr, // 必填,生成签名的随机串
 53 | signature: ticket.signature,// 必填,签名,见附录1
 54 | jsApiList: [ 55 | "onMenuShareTimeline", 56 | "onMenuShareAppMessage", 57 | "previewImage", 58 | "getLocation" 59 | ] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
 60 | }); 61 | // 要显示的菜单项,所有menu项见附录3 62 | wx.showMenuItems({ 63 | menuList: [ 64 | 'menuItem:share:appMessage', 65 | 'menuItem:share:timeline', 66 | 'menuItem:favorite' 67 | ] 68 | }); 69 | // 要隐藏的菜单项,只能隐藏“传播类”和“保护类”按钮,所有menu项见附录3 70 | wx.hideMenuItems({ 71 | menuList: [ 72 | 'menuItem:share:qq', 73 | 'menuItem:share:weiboApp', 74 | 'menuItem:share:facebook', 75 | 'menuItem:share:QZone', 76 | 'menuItem:copyUrl', 77 | 'menuItem:originPage', 78 | 'menuItem:openWithQQBrowser', 79 | 'menuItem:openWithSafari' 80 | ] 81 | }); 82 | wx.ready(function () { 83 | 84 | var shareData64 = { 85 | title: shareText.title, // 分享标题
 86 | desc: shareText.desc, // 分享描述
 87 | link: shareText.shareLink, // 分享链接
 88 | imgUrl: 'http://7xl1vx.com2.z0.glb.qiniucdn.com/blue_share.jpg', // 分享图标
 89 | type: 'link', // 分享类型,music、video或link,不填默认为link
 90 | dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
 91 | success: function () { 92 | // 用户确认分享后执行的回调函数
 93 | console.log("用户分享成功"); 94 | }, 95 | cancel: function () { 96 | // 用户取消分享后执行的回调函数
 97 | console.log("用户取消分享后执行的回调函数"); 98 | } 99 | }; 100 | 101 | //分享给好友
 102 | wx.onMenuShareAppMessage(shareData64); 103 | //分享到朋友圈
 104 | wx.onMenuShareTimeline(shareData64); 105 | 106 | wx.getLocation({ 107 | type: 'wgs84', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02' 108 | success: function (res) { 109 | var latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90 110 | var longitude = res.longitude; // 经度,浮点数,范围为180 ~ -180。 111 | var speed = res.speed; // 速度,以米/每秒计 112 | var accuracy = res.accuracy; // 位置精度 113 | 114 | weixin.latitude = latitude+':'+longitude; 115 | console.log(weixin.latitude); 116 | } 117 | }); 118 | 119 | weixin.previewImage = function(imgUrl){ 120 | wx.previewImage({ 121 | current: imgUrl, // 当前显示图片的http链接 122 | urls: [imgUrl] // 需要预览的图片http链接列表 123 | }); 124 | } 125 | 126 | }) 127 | }); 128 | } 129 | 130 | 131 | return weixin; 132 | }]) -------------------------------------------------------------------------------- /chat/source/service/SocketService.js: -------------------------------------------------------------------------------- 1 | 2 | import io from 'source/lib/socket-client/socket.io-1.2.0' 3 | 4 | 5 | 6 | export default angular.module('socket',[]) 7 | .service('socket',['$rootScope','apiConfig','$timeout',function($rootScope,apiConfig,$timeout){ 8 | 9 | if(angular.isUndefined($rootScope.isLinkedToSocket)){ 10 | $rootScope.isLinkedToSocket = false; 11 | } 12 | 13 | if(!$rootScope.isLinkedToSocket) { 14 | var socket = {}; 15 | } 16 | 17 | var im = { 18 | cmd_login : 'CMD_USER_LOGIN',//登录 19 | 20 | cmd_logout: 'CMD_USER_LOGOUT',//登出 21 | 22 | cmd_chat_msg:'CMD_USER_CHAT_MSG',//聊天消息 23 | 24 | cmd_chat_msg_ask: 'CMD_USER_CHAT_MSG_ACK',//聊天消息收到 25 | 26 | cmd_user_in_chat: 'CMD_USER_ENTER_CHAT_WINDOW',//用户进入聊天页面 27 | 28 | cmd_create_session_notify: 'CMD_USER_CREATE_SESSION_NOTIFY',//创建会话 29 | 30 | cmd_keep_live: 'CMD_USER_KEEPLIVE',//心跳包 31 | 32 | cmd_kick_user: 'CMD_USER_KICK_USER_NOTIFY',//相同用户踢掉通知 33 | 34 | cmd_chat_msg_notify : 'CMD_USER_CHAT_MSG_NOTIFY',//客服消息收到通知IM服务器 35 | 36 | }; 37 | return { 38 | im : im, 39 | on: function(eventName, callback) { 40 | socket.on(eventName, function() { 41 | 42 | var args = arguments; 43 | $rootScope.$apply(function(){ 44 | callback.apply(socket, args); 45 | }); 46 | }); 47 | }, 48 | 49 | emit: function(eventName, data, callback) { 50 | socket.emit(eventName, data, function() { 51 | var args = arguments; 52 | $rootScope.$apply(function() { 53 | if(callback) { 54 | callback.apply(socket, args); 55 | } 56 | }); 57 | }) 58 | }, 59 | 60 | close: function(){ 61 | socket.close(); 62 | }, 63 | 64 | connect: function(){ 65 | var self = this; 66 | return new Promise(function(resolve,reject){ 67 | 68 | if($rootScope.isLinkedToSocket == true){ 69 | resolve(); 70 | return; 71 | } 72 | console.log('还没连上socket'+$rootScope.isLinkedToSocket); 73 | socket = io(apiConfig.im_host); 74 | 75 | self.initListen(); 76 | 77 | //socket连接成功 78 | socket.on('connect',function(){ 79 | console.info("socket连接成功"); 80 | $rootScope.isLinkedToSocket = true; 81 | $rootScope.isLoginIM = false; 82 | resolve(); 83 | }); 84 | 85 | //socket连接断开,直接关闭socket 86 | socket.on('disconnect',function(){ 87 | $rootScope.isLinkedToSocket = false; 88 | $rootScope.isLoginIM = false; 89 | $rootScope.$apply(); 90 | this.close(); 91 | alert('连接断开,请刷新浏览器重试'); 92 | console.error("socket连接断开"); 93 | //重连socket 94 | self.connect(); 95 | reject(); 96 | }); 97 | 98 | }); 99 | }, 100 | 101 | //登陆 102 | loginIM: function(userInfo){ 103 | if($rootScope.isLoginIM == true){ 104 | return true; 105 | } 106 | //var userInfo = { 107 | // 'uin': 4283, 108 | // 'nick':'15900804441', 109 | // 'pic': '', 110 | // 'location':'', 111 | // 'address':'', 112 | // 'token':'iC2TC\/JIadWAAlOew7Eb0A==', 113 | // 'client_type': 3, 114 | // 'client_id':'', 115 | // 'client_ver':'', 116 | // 'channel': '',//渠道 117 | // 'latitude':'' 118 | //}; 119 | $timeout(()=>{ 120 | console.log('正在登陆'); 121 | socket.emit(im.cmd_login,userInfo?userInfo:$rootScope.loginInfo); 122 | },1000) 123 | }, 124 | inChatWindow(){ 125 | socket.emit(im.cmd_user_in_chat,{}); 126 | }, 127 | //登出 128 | logoutIM: function(){ 129 | socket.emit(im.cmd_logout,{}); 130 | }, 131 | //发消息 132 | sendMsg : function(msg){ 133 | socket.emit(im.cmd_chat_msg,msg); 134 | }, 135 | //初始化 监听 136 | initListen:function(){ 137 | //登陆 138 | socket.on(im.cmd_login,(data)=>{ 139 | if(data && data.err_code == 0){ 140 | if(angular.isUndefined($rootScope.isLoginIM)){ 141 | $rootScope.isLoginIM = true; 142 | }else{ 143 | $rootScope.isLoginIM = true; 144 | } 145 | } 146 | $rootScope.$broadcast(im.cmd_login,data) 147 | }) 148 | //进入聊天框 149 | socket.on(im.cmd_user_in_chat,(data)=>{ 150 | $rootScope.$broadcast(im.cmd_user_in_chat,data); 151 | }); 152 | //登出 153 | socket.on(im.cmd_logout,(data)=>{ 154 | $rootScope.$broadcast(im.cmd_logout,data) 155 | }) 156 | 157 | //接收到消息 158 | socket.on(im.cmd_chat_msg,(msg)=>{ 159 | $rootScope.$broadcast(im.cmd_chat_msg,msg); 160 | let time = new Date().getTime(); 161 | socket.emit(im.cmd_chat_msg_notify,{ 162 | msg_id : msg.msg_id, 163 | push_status : 1, 164 | read_status : 1, 165 | create_time : time 166 | }) 167 | }); 168 | //发送消息的反馈 169 | socket.on(im.cmd_chat_msg_ask,(ask)=>{ 170 | $rootScope.$broadcast(im.cmd_chat_msg_ask,ask); 171 | }); 172 | //被踢原因 173 | socket.on(im.cmd_kick_user,(season)=>{ 174 | $rootScope.$broadcast(im.cmd_kick_user,season); 175 | }); 176 | } 177 | }; 178 | }]); 179 | -------------------------------------------------------------------------------- /chat/source/states/chat/chat-template-2.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 |

7 | 车知了-在线问答 8 |

9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 |

17 | 车知了,用车问题即时解答

18 |

19 | 在线时间 08:00-24:00 20 |

21 |
22 |
23 |
点击获取聊天记录
24 |
没有聊天记录了
25 | 26 |
27 |
28 | 29 |
30 |
31 | {{msg.created_at|format_date}} 32 |
33 | 34 | message user image 35 |
36 | 37 |
38 |
39 | 40 | 41 |
42 |
43 | {{msg.created_at|format_date}} 44 |
45 | message user image 46 |
47 | 48 |
49 |
50 |
51 |
52 | 53 |
54 |
55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 |
81 | 84 |
85 | 86 | 87 | 88 | 89 | 90 | 91 |
92 | 93 | 95 | 96 | 97 |
98 |
99 | 100 | 101 | 102 | 103 |
104 | 105 | 106 | 107 |

技师资料

108 |
109 | 110 |
111 | 112 |
113 | 114 |
115 | 116 | 117 | 119 | 120 | 121 | 122 | 124 | 125 | 126 | 127 | 129 | 130 | 131 | 132 | 134 | 135 |
136 |
137 |
138 | 139 | -------------------------------------------------------------------------------- /chat/source/states/chat/chat-template.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 |

7 | 车知了-在线问答 8 |

9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 |

17 | 车知了,用车问题即时解答

18 |

19 | 在线时间 08:00-24:00 20 |

21 |
22 | 23 | 24 |
点击获取聊天记录
25 |
没有聊天记录了
26 | 27 |
28 |
29 | 30 |
31 |
32 | {{msg.created_at|format_date}} 33 |
34 | 35 | message user image 36 |
37 | 38 |
39 |
40 | 41 | 42 |
43 |
44 | {{msg.created_at|format_date}} 45 |
46 | message user image 47 |
48 | 49 |
50 |
51 |
52 |
53 | 54 |
55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
80 | 83 |
84 | 85 | 86 | 87 | 88 | 89 | 90 |
91 | 92 | 94 | 95 | 96 |
97 |
98 | 99 | 100 | 101 | 102 |
103 | 104 | 105 | 106 |

技师资料

107 |
108 | 109 |
110 | 111 |
112 | 113 |
114 | 115 | 116 | 118 | 119 | 120 | 121 | 123 | 124 | 125 | 126 | 128 | 129 | 130 | 131 | 133 | 134 |
135 |
136 |
137 | 138 | -------------------------------------------------------------------------------- /chat/source/lib/tarsocial/tarsocial-monitor-v1002.js: -------------------------------------------------------------------------------- 1 | function TarMonitor(){function start(){var posturl="http://slb2.tarsocial.com/in/wxs",encrypturl="http://www.h5mo.com/api/encrypt",params=getUrlArgMap(),tar_foid=params.tar_foid,tar_from=params.from;("undefined"==typeof tar_foid||null==tar_foid||""==tar_foid)&&(tar_foid="root"),("undefined"==typeof tar_oid||null==tar_oid)&&(tar_oid=""),("undefined"==typeof tar_nickname||null==tar_nickname)&&(tar_nickname=""),("undefined"==typeof tar_sex||null==tar_sex)&&(tar_sex=""),("undefined"==typeof tar_province||null==tar_province)&&(tar_province=""),("undefined"==typeof tar_city||null==tar_city)&&(tar_city=""),("undefined"==typeof tar_country||null==tar_country)&&(tar_country=""),("undefined"==typeof tar_headimgurl||null==tar_headimgurl)&&(tar_headimgurl=""),("undefined"==typeof tar_from||null==tar_from)&&(tar_from=""),("undefined"==typeof tar_unionid||null==tar_unionid)&&(tar_unionid=""),("undefined"==typeof tar_url||null==tar_url)&&(tar_url=""),("undefined"==typeof tar_refer||null==tar_refer)&&(tar_refer=""),("undefined"==typeof tar_width||null==tar_width)&&(tar_width=""),("undefined"==typeof tar_height||null==tar_height)&&(tar_height=""),Ajax.request(encrypturl,{method:"POST",data:{tar_eventid:tar_event,tar_oid:tar_oid},success:function(r){var ret=eval("("+r.response+")");tar_encrypt=ret.encrypt,tar_sharedata=ret.sharedata}}),Ajax.request(posturl,{method:"POST",data:{tar_uuid:tar_uuid,tar_event:tar_event,tar_oid:tar_oid,tar_foid:tar_foid,tar_nickname:tar_nickname,tar_sex:tar_sex,tar_province:tar_province,tar_city:tar_city,tar_country:tar_country,tar_headimgurl:tar_headimgurl,tar_from:tar_from,tar_unionid:tar_unionid,tar_url:tar_url,tar_refer:tar_refer,tar_width:tar_width,tar_height:tar_height}})}function getUrlArgMap(){for(var a=new Object,b=location.search.substring(1),c=b.split("&"),d=0;d0?d:tar_oid;return/\?/i.test(a.link)?/tar_foid/.test(a.link)?a.link.replace(/tar_foid=[^\?\&\#]*/,"tar_foid="+f):a.link=a.link+"&tar_foid="+f:a.link=a.link+"?tar_foid="+f,tar_foid=d,e&&(e.share_img&&(a.imgUrl=e.share_img),e.share_desc&&(a.desc=e.share_desc),e.share_title&&(a.title=e.share_title)),a},Ajax=function(){function a(a,d){function e(){}var f=d.async!==!1,g=d.method||"GET",h=d.data||null,i=d.success||e,j=d.failure||e;g=g.toUpperCase(),"GET"==g&&h&&(h=c(h),a+=(-1==a.indexOf("?")?"?":"&")+h,h=null);var k=window.XMLHttpRequest?new XMLHttpRequest:new ActiveXObject("Microsoft.XMLHTTP");return k.onreadystatechange=function(){b(k,i,j)},k.open(g,a,f),"POST"==g&&(h=c(h),k.setRequestHeader("Content-type","application/x-www-form-urlencoded;")),k.send(h),k}function b(a,b,c){if(4==a.readyState){var d=a.status;d>=200&&300>d?b(a):c(a)}}function c(a){if("string"==typeof a||null==a)return a;if("object"==typeof a){var b="";for(var c in a)b="&"+c+"="+a[c]+b;return b.substr(1)}return a.toString()}return{request:a}}()}function setCookieAdv(a,b,c){var d=new Date;d.setDate(d.getDate()+c),document.cookie=a+"="+escape(b)+(null==c?"":";expires="+d.toGMTString())}function getCookieAdv(a){if(document.cookie.length>0&&(c_start=document.cookie.indexOf(a+"="),-1!=c_start)){c_start=c_start+a.length+1,c_end=document.cookie.indexOf(";",c_start),-1==c_end&&(c_end=document.cookie.length);var b=unescape(document.cookie.substring(c_start,c_end));return b}return""}var tar=new TarMonitor; -------------------------------------------------------------------------------- /chat/source/lib/qiniu/qupload.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /**! 3 | * AngularJS qiniu cloud storage large file upload service with support resumble,progress 4 | * @author icattlecoder 5 | * @version 0.0.1 6 | */ 7 | 8 | (function () { 9 | var angularQFileUpload = angular.module('angularQFileUpload', ['LocalStorageModule']); 10 | 11 | angularQFileUpload.service('$qupload', ['$http', '$q', 'localStorageService', 12 | 13 | function ($http, $q, localStorageService) { 14 | 15 | function utf16to8(str) { 16 | var out, i, len, c; 17 | out = ''; 18 | len = str.length; 19 | for (i = 0; i < len; i++) { 20 | c = str.charCodeAt(i); 21 | if ((c >= 0x0001) && (c <= 0x007F)) { 22 | out += str.charAt(i); 23 | } else if (c > 0x07FF) { 24 | out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F)); 25 | out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F)); 26 | out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F)); 27 | } else { 28 | out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F)); 29 | out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F)); 30 | } 31 | } 32 | return out; 33 | } 34 | 35 | /* 36 | * Interfaces: 37 | * b64 = base64encode(data); 38 | */ 39 | var base64EncodeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'; 40 | 41 | function base64encode(str) { 42 | var out, i, len; 43 | var c1, c2, c3; 44 | len = str.length; 45 | i = 0; 46 | out = ''; 47 | while (i < len) { 48 | c1 = str.charCodeAt(i++) & 0xff; 49 | if (i == len) { 50 | out += base64EncodeChars.charAt(c1 >> 2); 51 | out += base64EncodeChars.charAt((c1 & 0x3) << 4); 52 | out += '=='; 53 | break; 54 | } 55 | c2 = str.charCodeAt(i++); 56 | if (i == len) { 57 | out += base64EncodeChars.charAt(c1 >> 2); 58 | out += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)); 59 | out += base64EncodeChars.charAt((c2 & 0xF) << 2); 60 | out += '='; 61 | break; 62 | } 63 | c3 = str.charCodeAt(i++); 64 | out += base64EncodeChars.charAt(c1 >> 2); 65 | out += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)); 66 | out += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6)); 67 | out += base64EncodeChars.charAt(c3 & 0x3F); 68 | } 69 | return out; 70 | } 71 | 72 | 73 | var uploadEndPoint = 'http://up.qiniu.com'; 74 | 75 | var defaultsSetting = { 76 | chunkSize: 1024 * 1024 * 4, 77 | mkblkEndPoint: uploadEndPoint + '/mkblk/', 78 | mkfileEndPoint: uploadEndPoint + '/mkfile/', 79 | maxRetryTimes: 3 80 | }; 81 | 82 | //Is support qiniu resumble upload 83 | this.support = ( 84 | typeof File !== 'undefined' && 85 | typeof Blob !== 'undefined' && 86 | typeof FileList !== 'undefined' && 87 | (!!Blob.prototype.slice || !!Blob.prototype.webkitSlice || !!Blob.prototype.mozSlice || 88 | false 89 | ) 90 | ); 91 | if (!this.support) { 92 | return null; 93 | } 94 | 95 | var fileHashKeyFunc = function (file) { 96 | return file.name + file.lastModified + file.size + file.type; 97 | }; 98 | 99 | this.upload = function (config) { 100 | var deferred = $q.defer(); 101 | var promise = deferred.promise; 102 | 103 | var file = config.file; 104 | if (!file) { 105 | return; 106 | } 107 | 108 | var fileHashKey = fileHashKeyFunc(file); 109 | var blockRet = localStorageService.get(fileHashKey); 110 | if (!blockRet) { 111 | blockRet = []; 112 | } 113 | var blkCount = (file.size + ((1 << 22) - 1)) >> 22; 114 | 115 | var getChunck = function (file, startByte, endByte) { 116 | return file[(file.slice ? 'slice' : (file.mozSlice ? 'mozSlice' : (file.webkitSlice ? 'webkitSlice' : 'slice')))](startByte, endByte); 117 | }; 118 | 119 | var getBlkSize = function (file, blkCount, blkIndex) { 120 | 121 | if (blkIndex === blkCount - 1) { 122 | return file.size - 4194304 * blkIndex; 123 | } else { 124 | return 4194304; 125 | } 126 | }; 127 | 128 | var mkfile = function (file, blockRet) { 129 | if (blockRet.length === 0) { 130 | return; 131 | } 132 | var body = ''; 133 | var b; 134 | for (var i = 0; i < blockRet.length - 1; i++) { 135 | b = angular.fromJson(blockRet[i]); 136 | body += (b.ctx + ','); 137 | } 138 | b = angular.fromJson(blockRet[blockRet.length - 1]); 139 | body += b.ctx; 140 | 141 | var url = defaultsSetting.mkfileEndPoint + file.size; 142 | if (config && config.key) { 143 | url += ("/key/" + base64encode(utf16to8(config.key))); 144 | } 145 | $http({ 146 | url: url, 147 | method: 'POST', 148 | data: body, 149 | headers: { 150 | 'Authorization': 'UpToken ' + config.token, 151 | 'Content-Type': 'text/plain' 152 | } 153 | }).success(function (e) { 154 | deferred.resolve(e); 155 | localStorageService.remove(fileHashKey); 156 | }).error(function (e) { 157 | deferred.reject(e); 158 | }); 159 | }; 160 | var xhr; 161 | 162 | var mkblk = function (file, i, retry) { 163 | if (i === blkCount) { 164 | mkfile(file, blockRet); 165 | return; 166 | } 167 | if (!retry) { 168 | deferred.reject('max retried,still failure'); 169 | return; 170 | } 171 | var blkSize = getBlkSize(file, blkCount, i); 172 | var offset = i * 4194304; 173 | var chunck = getChunck(file, offset, offset + blkSize); 174 | 175 | xhr = new XMLHttpRequest(); 176 | xhr.open('POST', defaultsSetting.mkblkEndPoint + blkSize, true); 177 | xhr.setRequestHeader('Authorization', 'UpToken ' + config.token); 178 | 179 | xhr.upload.addEventListener('progress', function (evt) { 180 | if (evt.lengthComputable) { 181 | var nevt = { 182 | totalSize: file.size, 183 | loaded: evt.loaded + offset 184 | }; 185 | deferred.notify(nevt); 186 | } 187 | }); 188 | 189 | xhr.upload.onerror = function () { 190 | mkblk(config.file, i, --retry); 191 | }; 192 | 193 | xhr.onreadystatechange = function (response) { 194 | if (response && xhr.readyState === 4 && xhr.status === 200) { 195 | if (xhr.status === 200) { 196 | blockRet[i] = xhr.responseText; 197 | localStorageService.set(fileHashKey, blockRet); 198 | mkblk(config.file, ++i, defaultsSetting.maxRetryTimes); 199 | } else { 200 | mkblk(config.file, i, --retry); 201 | } 202 | } 203 | }; 204 | xhr.send(chunck); 205 | }; 206 | 207 | 208 | mkblk(config.file, blockRet.length, defaultsSetting.maxRetryTimes); 209 | promise.abort = function () { 210 | xhr.abort(); 211 | localStorageService.remove(fileHashKey); 212 | }; 213 | 214 | promise.pause = function () { 215 | xhr.abort(); 216 | }; 217 | 218 | return promise; 219 | }; 220 | } 221 | ]); 222 | })(); 223 | 224 | angular.module('angularQFileUpload').directive('ngFileSelect', ['$parse', '$timeout', 225 | function ($parse, $timeout) { 226 | return function (scope, elem, attr) { 227 | var fn = $parse(attr['ngFileSelect']); 228 | if (elem[0].tagName.toLowerCase() !== 'input' || (elem.attr('type') && elem.attr('type').toLowerCase()) !== 'file') { 229 | var fileElem = angular.element(''); 230 | for (var i = 0; i < elem[0].attributes.length; i++) { 231 | fileElem.attr(elem[0].attributes[i].name, elem[0].attributes[i].value); 232 | } 233 | if (elem.attr('data-multiple')) fileElem.attr('multiple', 'true'); 234 | fileElem.css('top', 0).css('bottom', 0).css('left', 0).css('right', 0).css('width', '100%'). 235 | css('opacity', 0).css('position', 'absolute').css('filter', 'alpha(opacity=0)'); 236 | elem.append(fileElem); 237 | if (elem.css('position') === '' || elem.css('position') === 'static') { 238 | elem.css('position', 'relative'); 239 | } 240 | elem = fileElem; 241 | } 242 | elem.bind('change', function (evt) { 243 | var files = [], 244 | fileList, i; 245 | fileList = evt.__files_ || evt.target.files; 246 | if (fileList !== null) { 247 | for (i = 0; i < fileList.length; i++) { 248 | files.push(fileList.item(i)); 249 | } 250 | } 251 | $timeout(function () { 252 | fn(scope, { 253 | $files: files, 254 | $event: evt 255 | }); 256 | }); 257 | }); 258 | }; 259 | } 260 | ]); -------------------------------------------------------------------------------- /chat/source/lib/weixin/jweixin-1.0.0.js: -------------------------------------------------------------------------------- 1 | !function(a,b){"function"==typeof define&&(define.amd||define.cmd)?define(function(){return b(a)}):b(a,!0)}(this,function(a,b){function c(b,c,d){a.WeixinJSBridge?WeixinJSBridge.invoke(b,e(c),function(a){g(b,a,d)}):j(b,d)}function d(b,c,d){a.WeixinJSBridge?WeixinJSBridge.on(b,function(a){d&&d.trigger&&d.trigger(a),g(b,a,c)}):d?j(b,d):j(b,c)}function e(a){return a=a||{},a.appId=z.appId,a.verifyAppId=z.appId,a.verifySignType="sha1",a.verifyTimestamp=z.timestamp+"",a.verifyNonceStr=z.nonceStr,a.verifySignature=z.signature,a}function f(a){return{timeStamp:a.timestamp+"",nonceStr:a.nonceStr,"package":a.package,paySign:a.paySign,signType:a.signType||"SHA1"}}function g(a,b,c){var d,e,f;switch(delete b.err_code,delete b.err_desc,delete b.err_detail,d=b.errMsg,d||(d=b.err_msg,delete b.err_msg,d=h(a,d),b.errMsg=d),c=c||{},c._complete&&(c._complete(b),delete c._complete),d=b.errMsg||"",z.debug&&!c.isInnerInvoke&&alert(JSON.stringify(b)),e=d.indexOf(":"),f=d.substring(e+1)){case"ok":c.success&&c.success(b);break;case"cancel":c.cancel&&c.cancel(b);break;default:c.fail&&c.fail(b)}c.complete&&c.complete(b)}function h(a,b){var e,f,c=a,d=p[c];return d&&(c=d),e="ok",b&&(f=b.indexOf(":"),e=b.substring(f+1),"confirm"==e&&(e="ok"),"failed"==e&&(e="fail"),-1!=e.indexOf("failed_")&&(e=e.substring(7)),-1!=e.indexOf("fail_")&&(e=e.substring(5)),e=e.replace(/_/g," "),e=e.toLowerCase(),("access denied"==e||"no permission to execute"==e)&&(e="permission denied"),"config"==c&&"function not exist"==e&&(e="ok"),""==e&&(e="fail")),b=c+":"+e}function i(a){var b,c,d,e;if(a){for(b=0,c=a.length;c>b;++b)d=a[b],e=o[d],e&&(a[b]=e);return a}}function j(a,b){if(!(!z.debug||b&&b.isInnerInvoke)){var c=p[a];c&&(a=c),b&&b._complete&&delete b._complete,console.log('"'+a+'",',b||"")}}function k(){if(!("6.0.2">w||y.systemType<0)){var b=new Image;y.appId=z.appId,y.initTime=x.initEndTime-x.initStartTime,y.preVerifyTime=x.preVerifyEndTime-x.preVerifyStartTime,C.getNetworkType({isInnerInvoke:!0,success:function(a){y.networkType=a.networkType;var c="https://open.weixin.qq.com/sdk/report?v="+y.version+"&o="+y.isPreVerifyOk+"&s="+y.systemType+"&c="+y.clientVersion+"&a="+y.appId+"&n="+y.networkType+"&i="+y.initTime+"&p="+y.preVerifyTime+"&u="+y.url;b.src=c}})}}function l(){return(new Date).getTime()}function m(b){t&&(a.WeixinJSBridge?b():q.addEventListener&&q.addEventListener("WeixinJSBridgeReady",b,!1))}function n(){C.invoke||(C.invoke=function(b,c,d){a.WeixinJSBridge&&WeixinJSBridge.invoke(b,e(c),d)},C.on=function(b,c){a.WeixinJSBridge&&WeixinJSBridge.on(b,c)})}var o,p,q,r,s,t,u,v,w,x,y,z,A,B,C;if(!a.jWeixin)return o={config:"preVerifyJSAPI",onMenuShareTimeline:"menu:share:timeline",onMenuShareAppMessage:"menu:share:appmessage",onMenuShareQQ:"menu:share:qq",onMenuShareWeibo:"menu:share:weiboApp",onMenuShareQZone:"menu:share:QZone",previewImage:"imagePreview",getLocation:"geoLocation",openProductSpecificView:"openProductViewWithPid",addCard:"batchAddCard",openCard:"batchViewCard",chooseWXPay:"getBrandWCPayRequest"},p=function(){var b,a={};for(b in o)a[o[b]]=b;return a}(),q=a.document,r=q.title,s=navigator.userAgent.toLowerCase(),t=-1!=s.indexOf("micromessenger"),u=-1!=s.indexOf("android"),v=-1!=s.indexOf("iphone")||-1!=s.indexOf("ipad"),w=function(){var a=s.match(/micromessenger\/(\d+\.\d+\.\d+)/)||s.match(/micromessenger\/(\d+\.\d+)/);return a?a[1]:""}(),x={initStartTime:l(),initEndTime:0,preVerifyStartTime:0,preVerifyEndTime:0},y={version:1,appId:"",initTime:0,preVerifyTime:0,networkType:"",isPreVerifyOk:1,systemType:v?1:u?2:-1,clientVersion:w,url:encodeURIComponent(location.href)},z={},A={_completes:[]},B={state:0,res:{}},m(function(){x.initEndTime=l()}),C={config:function(a){z=a,j("config",a);var b=z.check===!1?!1:!0;m(function(){var a,d,e;if(b)c(o.config,{verifyJsApiList:i(z.jsApiList)},function(){A._complete=function(a){x.preVerifyEndTime=l(),B.state=1,B.res=a},A.success=function(){y.isPreVerifyOk=0},A.fail=function(a){A._fail?A._fail(a):B.state=-1};var a=A._completes;return a.push(function(){z.debug||k()}),A.complete=function(){for(var c=0,d=a.length;d>c;++c)a[c]();A._completes=[]},A}()),x.preVerifyStartTime=l();else{for(B.state=1,a=A._completes,d=0,e=a.length;e>d;++d)a[d]();A._completes=[]}}),z.beta&&n()},ready:function(a){0!=B.state?a():(A._completes.push(a),!t&&z.debug&&a())},error:function(a){"6.0.2">w||(-1==B.state?a(B.res):A._fail=a)},checkJsApi:function(a){var b=function(a){var c,d,b=a.checkResult;for(c in b)d=p[c],d&&(b[d]=b[c],delete b[c]);return a};c("checkJsApi",{jsApiList:i(a.jsApiList)},function(){return a._complete=function(a){if(u){var c=a.checkResult;c&&(a.checkResult=JSON.parse(c))}a=b(a)},a}())},onMenuShareTimeline:function(a){d(o.onMenuShareTimeline,{complete:function(){c("shareTimeline",{title:a.title||r,desc:a.title||r,img_url:a.imgUrl||"",link:a.link||location.href,type:a.type||"link",data_url:a.dataUrl||""},a)}},a)},onMenuShareAppMessage:function(a){d(o.onMenuShareAppMessage,{complete:function(){c("sendAppMessage",{title:a.title||r,desc:a.desc||"",link:a.link||location.href,img_url:a.imgUrl||"",type:a.type||"link",data_url:a.dataUrl||""},a)}},a)},onMenuShareQQ:function(a){d(o.onMenuShareQQ,{complete:function(){c("shareQQ",{title:a.title||r,desc:a.desc||"",img_url:a.imgUrl||"",link:a.link||location.href},a)}},a)},onMenuShareWeibo:function(a){d(o.onMenuShareWeibo,{complete:function(){c("shareWeiboApp",{title:a.title||r,desc:a.desc||"",img_url:a.imgUrl||"",link:a.link||location.href},a)}},a)},onMenuShareQZone:function(a){d(o.onMenuShareQZone,{complete:function(){c("shareQZone",{title:a.title||r,desc:a.desc||"",img_url:a.imgUrl||"",link:a.link||location.href},a)}},a)},startRecord:function(a){c("startRecord",{},a)},stopRecord:function(a){c("stopRecord",{},a)},onVoiceRecordEnd:function(a){d("onVoiceRecordEnd",a)},playVoice:function(a){c("playVoice",{localId:a.localId},a)},pauseVoice:function(a){c("pauseVoice",{localId:a.localId},a)},stopVoice:function(a){c("stopVoice",{localId:a.localId},a)},onVoicePlayEnd:function(a){d("onVoicePlayEnd",a)},uploadVoice:function(a){c("uploadVoice",{localId:a.localId,isShowProgressTips:0==a.isShowProgressTips?0:1},a)},downloadVoice:function(a){c("downloadVoice",{serverId:a.serverId,isShowProgressTips:0==a.isShowProgressTips?0:1},a)},translateVoice:function(a){c("translateVoice",{localId:a.localId,isShowProgressTips:0==a.isShowProgressTips?0:1},a)},chooseImage:function(a){c("chooseImage",{scene:"1|2",count:a.count||9,sizeType:a.sizeType||["original","compressed"],sourceType:a.sourceType||["album","camera"]},function(){return a._complete=function(a){if(u){var b=a.localIds;b&&(a.localIds=JSON.parse(b))}},a}())},previewImage:function(a){c(o.previewImage,{current:a.current,urls:a.urls},a)},uploadImage:function(a){c("uploadImage",{localId:a.localId,isShowProgressTips:0==a.isShowProgressTips?0:1},a)},downloadImage:function(a){c("downloadImage",{serverId:a.serverId,isShowProgressTips:0==a.isShowProgressTips?0:1},a)},getNetworkType:function(a){var b=function(a){var c,d,e,b=a.errMsg;if(a.errMsg="getNetworkType:ok",c=a.subtype,delete a.subtype,c)a.networkType=c;else switch(d=b.indexOf(":"),e=b.substring(d+1)){case"wifi":case"edge":case"wwan":a.networkType=e;break;default:a.errMsg="getNetworkType:fail"}return a};c("getNetworkType",{},function(){return a._complete=function(a){a=b(a)},a}())},openLocation:function(a){c("openLocation",{latitude:a.latitude,longitude:a.longitude,name:a.name||"",address:a.address||"",scale:a.scale||28,infoUrl:a.infoUrl||""},a)},getLocation:function(a){a=a||{},c(o.getLocation,{type:a.type||"wgs84"},function(){return a._complete=function(a){delete a.type},a}())},hideOptionMenu:function(a){c("hideOptionMenu",{},a)},showOptionMenu:function(a){c("showOptionMenu",{},a)},closeWindow:function(a){a=a||{},c("closeWindow",{immediate_close:a.immediateClose||0},a)},hideMenuItems:function(a){c("hideMenuItems",{menuList:a.menuList},a)},showMenuItems:function(a){c("showMenuItems",{menuList:a.menuList},a)},hideAllNonBaseMenuItem:function(a){c("hideAllNonBaseMenuItem",{},a)},showAllNonBaseMenuItem:function(a){c("showAllNonBaseMenuItem",{},a)},scanQRCode:function(a){a=a||{},c("scanQRCode",{needResult:a.needResult||0,scanType:a.scanType||["qrCode","barCode"]},function(){return a._complete=function(a){var b,c;v&&(b=a.resultStr,b&&(c=JSON.parse(b),a.resultStr=c&&c.scan_code&&c.scan_code.scan_result))},a}())},openProductSpecificView:function(a){c(o.openProductSpecificView,{pid:a.productId,view_type:a.viewType||0,ext_info:a.extInfo},a)},addCard:function(a){var e,f,g,h,b=a.cardList,d=[];for(e=0,f=b.length;f>e;++e)g=b[e],h={card_id:g.cardId,card_ext:g.cardExt},d.push(h);c(o.addCard,{card_list:d},function(){return a._complete=function(a){var c,d,e,b=a.card_list;if(b){for(b=JSON.parse(b),c=0,d=b.length;d>c;++c)e=b[c],e.cardId=e.card_id,e.cardExt=e.card_ext,e.isSuccess=e.is_succ?!0:!1,delete e.card_id,delete e.card_ext,delete e.is_succ;a.cardList=b,delete a.card_list}},a}())},chooseCard:function(a){c("chooseCard",{app_id:z.appId,location_id:a.shopId||"",sign_type:a.signType||"SHA1",card_id:a.cardId||"",card_type:a.cardType||"",card_sign:a.cardSign,time_stamp:a.timestamp+"",nonce_str:a.nonceStr},function(){return a._complete=function(a){a.cardList=a.choose_card_info,delete a.choose_card_info},a}())},openCard:function(a){var e,f,g,h,b=a.cardList,d=[];for(e=0,f=b.length;f>e;++e)g=b[e],h={card_id:g.cardId,code:g.code},d.push(h);c(o.openCard,{card_list:d},a)},chooseWXPay:function(a){c(o.chooseWXPay,f(a),a)}},b&&(a.wx=a.jWeixin=C),C}); -------------------------------------------------------------------------------- /chat/config.js: -------------------------------------------------------------------------------- 1 | System.config({ 2 | baseURL: "/", 3 | defaultJSExtensions: true, 4 | transpiler: "babel", 5 | babelOptions: { 6 | "optional": [ 7 | "runtime", 8 | "optimisation.modules.system" 9 | ] 10 | }, 11 | paths: { 12 | "github:*": "jspm_packages/github/*", 13 | "npm:*": "jspm_packages/npm/*" 14 | }, 15 | minify: true, 16 | sourceMaps: false, 17 | 18 | map: { 19 | "angular": "github:angular/bower-angular@1.4.6", 20 | "angular-cookies": "github:angular/bower-angular-cookies@1.4.6", 21 | "angular-local-storage": "npm:angular-local-storage@0.2.2", 22 | "angular-material": "npm:angular-material@0.11.0", 23 | "angular-mocks": "github:angular/bower-angular-mocks@1.4.6", 24 | "angular-resource": "github:angular/bower-angular-resource@1.4.6", 25 | "angular-route": "github:angular/bower-angular-route@1.4.6", 26 | "babel": "npm:babel-core@5.8.25", 27 | "babel-runtime": "npm:babel-runtime@5.8.24", 28 | "clean-css": "npm:clean-css@3.4.4", 29 | "core-js": "npm:core-js@1.1.4", 30 | "css": "github:systemjs/plugin-css@0.1.17", 31 | "jquery": "npm:jquery@2.1.4", 32 | "mdi": "npm:mdi@1.2.65", 33 | "process": "github:jspm/nodelibs-process@0.1.2", 34 | "text": "github:systemjs/plugin-text@0.0.2", 35 | "traceur": "npm:traceur@0.0.92", 36 | "traceur-runtime": "github:jmcriffey/bower-traceur-runtime@0.0.92", 37 | "github:angular/bower-angular-animate@1.4.6": { 38 | "angular": "github:angular/bower-angular@1.4.6" 39 | }, 40 | "github:angular/bower-angular-aria@1.4.6": { 41 | "angular": "github:angular/bower-angular@1.4.6" 42 | }, 43 | "github:angular/bower-angular-cookies@1.4.6": { 44 | "angular": "github:angular/bower-angular@1.4.6" 45 | }, 46 | "github:angular/bower-angular-mocks@1.4.6": { 47 | "angular": "github:angular/bower-angular@1.4.6" 48 | }, 49 | "github:angular/bower-angular-route@1.4.6": { 50 | "angular": "github:angular/bower-angular@1.4.6" 51 | }, 52 | "github:jspm/nodelibs-assert@0.1.0": { 53 | "assert": "npm:assert@1.3.0" 54 | }, 55 | "github:jspm/nodelibs-buffer@0.1.0": { 56 | "buffer": "npm:buffer@3.5.1" 57 | }, 58 | "github:jspm/nodelibs-events@0.1.1": { 59 | "events": "npm:events@1.0.2" 60 | }, 61 | "github:jspm/nodelibs-http@1.7.1": { 62 | "Base64": "npm:Base64@0.2.1", 63 | "events": "github:jspm/nodelibs-events@0.1.1", 64 | "inherits": "npm:inherits@2.0.1", 65 | "stream": "github:jspm/nodelibs-stream@0.1.0", 66 | "url": "github:jspm/nodelibs-url@0.1.0", 67 | "util": "github:jspm/nodelibs-util@0.1.0" 68 | }, 69 | "github:jspm/nodelibs-https@0.1.0": { 70 | "https-browserify": "npm:https-browserify@0.0.0" 71 | }, 72 | "github:jspm/nodelibs-os@0.1.0": { 73 | "os-browserify": "npm:os-browserify@0.1.2" 74 | }, 75 | "github:jspm/nodelibs-path@0.1.0": { 76 | "path-browserify": "npm:path-browserify@0.0.0" 77 | }, 78 | "github:jspm/nodelibs-process@0.1.2": { 79 | "process": "npm:process@0.11.2" 80 | }, 81 | "github:jspm/nodelibs-querystring@0.1.0": { 82 | "querystring": "npm:querystring@0.2.0" 83 | }, 84 | "github:jspm/nodelibs-stream@0.1.0": { 85 | "stream-browserify": "npm:stream-browserify@1.0.0" 86 | }, 87 | "github:jspm/nodelibs-url@0.1.0": { 88 | "url": "npm:url@0.10.3" 89 | }, 90 | "github:jspm/nodelibs-util@0.1.0": { 91 | "util": "npm:util@0.10.3" 92 | }, 93 | "github:jspm/nodelibs-vm@0.1.0": { 94 | "vm-browserify": "npm:vm-browserify@0.0.4" 95 | }, 96 | "npm:amdefine@1.0.0": { 97 | "fs": "github:jspm/nodelibs-fs@0.1.2", 98 | "module": "github:jspm/nodelibs-module@0.1.0", 99 | "path": "github:jspm/nodelibs-path@0.1.0", 100 | "process": "github:jspm/nodelibs-process@0.1.2" 101 | }, 102 | "npm:angular-material@0.11.0": { 103 | "angular": "github:angular/bower-angular@1.4.6", 104 | "angular-animate": "github:angular/bower-angular-animate@1.4.6", 105 | "angular-aria": "github:angular/bower-angular-aria@1.4.6", 106 | "css": "github:systemjs/plugin-css@0.1.17" 107 | }, 108 | "npm:assert@1.3.0": { 109 | "util": "npm:util@0.10.3" 110 | }, 111 | "npm:babel-runtime@5.8.24": { 112 | "process": "github:jspm/nodelibs-process@0.1.2" 113 | }, 114 | "npm:brace-expansion@1.1.1": { 115 | "balanced-match": "npm:balanced-match@0.2.1", 116 | "concat-map": "npm:concat-map@0.0.1" 117 | }, 118 | "npm:buffer@3.5.1": { 119 | "base64-js": "npm:base64-js@0.0.8", 120 | "ieee754": "npm:ieee754@1.1.6", 121 | "is-array": "npm:is-array@1.0.1" 122 | }, 123 | "npm:clean-css@3.4.4": { 124 | "buffer": "github:jspm/nodelibs-buffer@0.1.0", 125 | "commander": "npm:commander@2.8.1", 126 | "fs": "github:jspm/nodelibs-fs@0.1.2", 127 | "http": "github:jspm/nodelibs-http@1.7.1", 128 | "https": "github:jspm/nodelibs-https@0.1.0", 129 | "os": "github:jspm/nodelibs-os@0.1.0", 130 | "path": "github:jspm/nodelibs-path@0.1.0", 131 | "process": "github:jspm/nodelibs-process@0.1.2", 132 | "source-map": "npm:source-map@0.4.4", 133 | "url": "github:jspm/nodelibs-url@0.1.0", 134 | "util": "github:jspm/nodelibs-util@0.1.0" 135 | }, 136 | "npm:commander@2.6.0": { 137 | "child_process": "github:jspm/nodelibs-child_process@0.1.0", 138 | "events": "github:jspm/nodelibs-events@0.1.1", 139 | "path": "github:jspm/nodelibs-path@0.1.0", 140 | "process": "github:jspm/nodelibs-process@0.1.2" 141 | }, 142 | "npm:commander@2.8.1": { 143 | "child_process": "github:jspm/nodelibs-child_process@0.1.0", 144 | "events": "github:jspm/nodelibs-events@0.1.1", 145 | "fs": "github:jspm/nodelibs-fs@0.1.2", 146 | "graceful-readlink": "npm:graceful-readlink@1.0.1", 147 | "path": "github:jspm/nodelibs-path@0.1.0", 148 | "process": "github:jspm/nodelibs-process@0.1.2" 149 | }, 150 | "npm:core-js@1.1.4": { 151 | "fs": "github:jspm/nodelibs-fs@0.1.2", 152 | "process": "github:jspm/nodelibs-process@0.1.2", 153 | "systemjs-json": "github:systemjs/plugin-json@0.1.0" 154 | }, 155 | "npm:core-util-is@1.0.1": { 156 | "buffer": "github:jspm/nodelibs-buffer@0.1.0" 157 | }, 158 | "npm:glob@4.3.5": { 159 | "assert": "github:jspm/nodelibs-assert@0.1.0", 160 | "events": "github:jspm/nodelibs-events@0.1.1", 161 | "fs": "github:jspm/nodelibs-fs@0.1.2", 162 | "inflight": "npm:inflight@1.0.4", 163 | "inherits": "npm:inherits@2.0.1", 164 | "minimatch": "npm:minimatch@2.0.10", 165 | "once": "npm:once@1.3.2", 166 | "path": "github:jspm/nodelibs-path@0.1.0", 167 | "process": "github:jspm/nodelibs-process@0.1.2", 168 | "util": "github:jspm/nodelibs-util@0.1.0" 169 | }, 170 | "npm:graceful-readlink@1.0.1": { 171 | "fs": "github:jspm/nodelibs-fs@0.1.2" 172 | }, 173 | "npm:https-browserify@0.0.0": { 174 | "http": "github:jspm/nodelibs-http@1.7.1" 175 | }, 176 | "npm:inflight@1.0.4": { 177 | "once": "npm:once@1.3.2", 178 | "process": "github:jspm/nodelibs-process@0.1.2", 179 | "wrappy": "npm:wrappy@1.0.1" 180 | }, 181 | "npm:inherits@2.0.1": { 182 | "util": "github:jspm/nodelibs-util@0.1.0" 183 | }, 184 | "npm:jquery@2.1.4": { 185 | "process": "github:jspm/nodelibs-process@0.1.2" 186 | }, 187 | "npm:minimatch@2.0.10": { 188 | "brace-expansion": "npm:brace-expansion@1.1.1", 189 | "path": "github:jspm/nodelibs-path@0.1.0" 190 | }, 191 | "npm:once@1.3.2": { 192 | "wrappy": "npm:wrappy@1.0.1" 193 | }, 194 | "npm:os-browserify@0.1.2": { 195 | "os": "github:jspm/nodelibs-os@0.1.0" 196 | }, 197 | "npm:path-browserify@0.0.0": { 198 | "process": "github:jspm/nodelibs-process@0.1.2" 199 | }, 200 | "npm:process@0.11.2": { 201 | "assert": "github:jspm/nodelibs-assert@0.1.0" 202 | }, 203 | "npm:punycode@1.3.2": { 204 | "process": "github:jspm/nodelibs-process@0.1.2" 205 | }, 206 | "npm:readable-stream@1.1.13": { 207 | "buffer": "github:jspm/nodelibs-buffer@0.1.0", 208 | "core-util-is": "npm:core-util-is@1.0.1", 209 | "events": "github:jspm/nodelibs-events@0.1.1", 210 | "inherits": "npm:inherits@2.0.1", 211 | "isarray": "npm:isarray@0.0.1", 212 | "process": "github:jspm/nodelibs-process@0.1.2", 213 | "stream-browserify": "npm:stream-browserify@1.0.0", 214 | "string_decoder": "npm:string_decoder@0.10.31" 215 | }, 216 | "npm:rsvp@3.1.0": { 217 | "process": "github:jspm/nodelibs-process@0.1.2" 218 | }, 219 | "npm:semver@2.3.2": { 220 | "process": "github:jspm/nodelibs-process@0.1.2" 221 | }, 222 | "npm:source-map-support@0.2.10": { 223 | "assert": "github:jspm/nodelibs-assert@0.1.0", 224 | "buffer": "github:jspm/nodelibs-buffer@0.1.0", 225 | "child_process": "github:jspm/nodelibs-child_process@0.1.0", 226 | "fs": "github:jspm/nodelibs-fs@0.1.2", 227 | "http": "github:jspm/nodelibs-http@1.7.1", 228 | "path": "github:jspm/nodelibs-path@0.1.0", 229 | "process": "github:jspm/nodelibs-process@0.1.2", 230 | "querystring": "github:jspm/nodelibs-querystring@0.1.0", 231 | "source-map": "npm:source-map@0.1.32" 232 | }, 233 | "npm:source-map@0.1.32": { 234 | "amdefine": "npm:amdefine@1.0.0", 235 | "fs": "github:jspm/nodelibs-fs@0.1.2", 236 | "path": "github:jspm/nodelibs-path@0.1.0", 237 | "process": "github:jspm/nodelibs-process@0.1.2" 238 | }, 239 | "npm:source-map@0.4.4": { 240 | "amdefine": "npm:amdefine@1.0.0", 241 | "process": "github:jspm/nodelibs-process@0.1.2" 242 | }, 243 | "npm:stream-browserify@1.0.0": { 244 | "events": "github:jspm/nodelibs-events@0.1.1", 245 | "inherits": "npm:inherits@2.0.1", 246 | "readable-stream": "npm:readable-stream@1.1.13" 247 | }, 248 | "npm:string_decoder@0.10.31": { 249 | "buffer": "github:jspm/nodelibs-buffer@0.1.0" 250 | }, 251 | "npm:traceur@0.0.92": { 252 | "buffer": "github:jspm/nodelibs-buffer@0.1.0", 253 | "commander": "npm:commander@2.6.0", 254 | "fs": "github:jspm/nodelibs-fs@0.1.2", 255 | "glob": "npm:glob@4.3.5", 256 | "module": "github:jspm/nodelibs-module@0.1.0", 257 | "path": "github:jspm/nodelibs-path@0.1.0", 258 | "process": "github:jspm/nodelibs-process@0.1.2", 259 | "rsvp": "npm:rsvp@3.1.0", 260 | "semver": "npm:semver@2.3.2", 261 | "source-map-support": "npm:source-map-support@0.2.10", 262 | "systemjs-json": "github:systemjs/plugin-json@0.1.0", 263 | "vm": "github:jspm/nodelibs-vm@0.1.0" 264 | }, 265 | "npm:url@0.10.3": { 266 | "assert": "github:jspm/nodelibs-assert@0.1.0", 267 | "punycode": "npm:punycode@1.3.2", 268 | "querystring": "npm:querystring@0.2.0", 269 | "util": "github:jspm/nodelibs-util@0.1.0" 270 | }, 271 | "npm:util@0.10.3": { 272 | "inherits": "npm:inherits@2.0.1", 273 | "process": "github:jspm/nodelibs-process@0.1.2" 274 | }, 275 | "npm:vm-browserify@0.0.4": { 276 | "indexof": "npm:indexof@0.0.1" 277 | } 278 | } 279 | }); 280 | -------------------------------------------------------------------------------- /chat/source/states/chat-weixin/chat-weixin-controller.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/9/28. 3 | */ 4 | 5 | import './chat-value' 6 | import 'source/filter/format-message' 7 | import $ from 'jquery' 8 | 9 | //表情控件 10 | import CmFace from 'source/components/face/face-directive' 11 | //返回按钮指令 12 | import 'source/components/btn_back/btn-back-directive' 13 | 14 | 15 | export default angular.module('chat') 16 | .controller('ChatWeiXinCtrl',['$rootScope','$scope','$routeParams','$timeout','$window','chat.value','$log','$filter','wxService','socket','User','$location','apiConfig', 17 | function($rootScope,$scope,$routeParams,$timeout,$window,value,$log,$filter,wxService,socketService,UserService,$location,apiConfig){ 18 | var from = getUrlVar('state'); 19 | var share_link = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid='+apiConfig.app_id+'&redirect_uri=http%3A%2F%2F'+apiConfig.app_host+'%2Fchat%2Fdist%2Fweixin%2Findex.html&response_type=code&scope=snsapi_userinfo&state='+from+'#wechat_redirect'; 20 | 21 | $scope.open_face_status = value.open_face_status; 22 | $scope.open_audio_status = value.open_audio_status; 23 | $scope.message = value.message; 24 | $scope.msg_list = value.msg_list; 25 | $scope.service_info = value.service_info; 26 | $scope.user_info = value.user_info; 27 | 28 | $scope.page = value.page; 29 | $scope.timestamp = value.timestamp = new Date().getTime(); 30 | 31 | $scope.gotoBottom = gotoBottom; 32 | $scope.sendMessage = sendMessage; 33 | $scope.showFace = showFace; 34 | $scope.hideFace = hideFace; 35 | $scope.toggleAd = toggleAd; 36 | $scope.loadHistoryMsg = loadHistoryMsg; 37 | $scope.is_loading_history = true; 38 | $scope.preview = preview; 39 | $scope.keypressInChatInput = keypressInChatInput; 40 | 41 | $scope.code = getUrlVar('code'); 42 | 43 | 44 | 45 | if($scope.code){ 46 | 47 | let code = $scope.code; 48 | 49 | //ajax访问后台 获取用户信息 50 | UserService.getUserInfoByCode({code:code,state:from}).$promise.then( 51 | function(data){ 52 | if(data && data.code==200){ 53 | $scope.userInfo = data.data; 54 | /** 55 | * 初始化微信分享 需要获得微信用户信息 56 | */ 57 | share_link = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid='+apiConfig.app_id+'&redirect_uri=http%3A%2F%2F'+apiConfig.app_host+'%2Fchat%2Fdist%2Fweixin%2Findex.html&response_type=code&scope=snsapi_userinfo&state='+$scope.userInfo.user_id+'#wechat_redirect'; 58 | wxService.init({ 59 | title:"车知了--你身边懂车的朋友", 60 | desc:"用车问题专业技师一对一解答,一键提问一分钟响应", 61 | link:document.URL, 62 | shareLink:share_link 63 | },$scope.userInfo.wx_userInfo); 64 | 65 | //获取用户信息后 登陆IM 66 | socketService.connect().then( 67 | function(){ 68 | $rootScope.loginInfo = { 69 | 'uin': $scope.userInfo.user_id, 70 | 'nick':$scope.userInfo.nickname, 71 | 'pic': $scope.userInfo.user_avatar, 72 | 'location':'', 73 | 'address':'', 74 | 'token':$scope.userInfo.user_token, 75 | 'client_type': 3, 76 | 'client_id':'', 77 | 'client_ver':'1.0.0', 78 | 'channel': $scope.userInfo.channel_sign,//渠道 79 | 'latitude':angular.isDefined(wxService.latitude)?wxService.latitude:'' 80 | } 81 | socketService.loginIM($rootScope.loginInfo); 82 | data.data.user_avatar !=''?value.user_info.avatar = data.data.user_avatar:''; 83 | value.user_info.name = $scope.userInfo.nickname; 84 | $rootScope.$apply('user_info'); 85 | }, 86 | function(){ 87 | $rootScope.isLinkedToSocket = false; 88 | alert('连接断开'); 89 | console.log('连接断开'); 90 | } 91 | ) 92 | }else{ 93 | window.location.href = share_link; 94 | } 95 | 96 | } 97 | ); 98 | 99 | 100 | }else if(angular.isUndefined($scope.code)){ 101 | console.log('授权失败!'); 102 | window.location.href = share_link; 103 | 104 | //获取用户信息后 登陆IM 105 | //socketService.connect().then( 106 | // function(){ 107 | // $scope.userInfo = { 108 | // address: "", 109 | // alpha_id: "Gsj", 110 | // answer_number: 0, 111 | // appoint_number: 0, 112 | // car_number: "", 113 | // car_type_name: "", 114 | // gender: 1, 115 | // gender_str: "男", 116 | // nickname: "杨佳军", 117 | // realname: "", 118 | // telephone: "", 119 | // channel_sign:'czl_weixin', 120 | // user_allow_login: true, 121 | // user_avatar: "http://wx.qlogo.cn/mmopen/wJibWkqN1bUO2ozCTUD2e0k9AIsot7OdRLPt9UbRyaFa4I6cvaqXWyUrczoZn5gkOSngAJKWj8JAicRibZV6SVr9xjYPLqZ7qUZ/0", 122 | // user_id: 35754, 123 | // user_token: "9vEqDHX9wZo/Gz4Gpc2lmw==", 124 | // } 125 | // 126 | // $rootScope.loginInfo = { 127 | // 'uin': $scope.userInfo.user_id, 128 | // 'nick':$scope.userInfo.nickname, 129 | // 'pic': $scope.userInfo.user_avatar, 130 | // 'location':'', 131 | // 'address':'', 132 | // 'token':$scope.userInfo.user_token, 133 | // 'client_type': 3, 134 | // 'client_id':'', 135 | // 'client_ver':'1.0.0', 136 | // 'channel': $scope.userInfo.channel_sign,//渠道 137 | // 'latitude':angular.isDefined(wxService.latitude)?wxService.latitude:'' 138 | // } 139 | // socketService.loginIM($rootScope.loginInfo); 140 | // value.user_info.avatar = $scope.userInfo.user_avatar; 141 | // value.user_info.name = $scope.userInfo.nickname; 142 | // $rootScope.$apply('user_info'); 143 | // }, 144 | // function(){ 145 | // $rootScope.isLinkedToSocket = false; 146 | // alert('连接断开'); 147 | // console.log('连接断开'); 148 | // } 149 | //) 150 | } 151 | 152 | $scope.$on(socketService.im.cmd_login,function(event,data){ 153 | console.log('登陆成功',$rootScope.loginInfo); 154 | //发送用户进框事件 155 | //$timeout(()=>{ 156 | // socketService.inChatWindow(); 157 | //},1000); 158 | let msg_id = new Date().getTime(); 159 | value.msg_list.push({ 160 | "msg_id": msg_id, 161 | "from": 1, 162 | "type": 1, 163 | "content": '您好,想了解汽车哪方面内容呢?', 164 | "created_at": msg_id, 165 | "updated_at": msg_id 166 | }); 167 | //获取用户聊天记录 168 | loadHistoryMsg(); 169 | }); 170 | 171 | /** 172 | * 接收欢迎语 173 | */ 174 | $scope.$on(socketService.im.cmd_user_in_chat,function(event,data){ 175 | if(data.working == 0){ 176 | let msg_id = new Date().getTime(); 177 | value.msg_list.push({ 178 | "msg_id": msg_id, 179 | "from": 1, 180 | "type": 1, 181 | "content": data.welcome, 182 | "created_at": data.time, 183 | "updated_at": data.time 184 | }); 185 | } 186 | }); 187 | 188 | $scope.$on(socketService.im.cmd_chat_msg,function(event,msg){ 189 | value.msg_list.push({ 190 | "msg_id": msg.msg_id, 191 | "from": 1, 192 | "type": parseInt(msg.type), 193 | "content": msg.content, 194 | "created_at": msg.time, 195 | "updated_at": msg.time 196 | }); 197 | $rootScope.$apply('msg_list'); 198 | gotoBottom(); 199 | }); 200 | 201 | $scope.$on(socketService.im.cmd_chat_msg_ask,function(event,msg){ 202 | console.log(msg); 203 | for(let i=value.msg_list.length-1;i>=0;i--){ 204 | if(msg.msg_id == value.msg_list[i].msg_id){ 205 | $rootScope.$apply(function(){ 206 | value.msg_list[i].push_status = true; 207 | }) 208 | break; 209 | } 210 | } 211 | }); 212 | 213 | /** 214 | * 监听表情控件的输入表情事件 215 | */ 216 | $scope.$on('face_inputting',face_inputting); 217 | 218 | 219 | //绑定回车按键 220 | function keypressInChatInput($event){ 221 | if($scope.message.content.trim() != '' && $event.keyCode==13 && $event.altKey == false && $event.ctrlKey==false && $event.shiftKey==false ){ 222 | $event.preventDefault(); 223 | $event.stopPropagation(); 224 | $scope.sendMessage($scope.message.content,1); 225 | return; 226 | } 227 | } 228 | 229 | /** 230 | * 只是上拉加载聊天历史 231 | */ 232 | function loadHistoryMsg(){ 233 | var prams = { 234 | page : value.page, 235 | timestamp : value.timestamp, 236 | user_id : $scope.userInfo.user_id, 237 | alpha_id : $scope.userInfo.alpha_id 238 | }; 239 | $scope.is_loading_history = true; 240 | return new Promise(function(){ 241 | UserService.getHistoryMsg(prams).$promise.then( 242 | function(data){ 243 | if(data.data.length==0){ 244 | $scope.page = value.page = 0; 245 | return; 246 | } 247 | if(value.msg_list.length == 0){ 248 | for(let i=data.data.length-1;i>=0;i--){ 249 | value.msg_list.push(data.data[i]); 250 | } 251 | }else{ 252 | for(let j=0;j{ 291 | document.getElementById("message_box").scrollTop = document.getElementById("message_box").scrollHeight; 292 | },100) 293 | } 294 | 295 | /** 296 | * 发送文字消息 297 | */ 298 | function sendMessage(message,type){ 299 | if(!$rootScope.isLinkedToSocket){ 300 | alert('连接已断开,请重新进入页面!'); 301 | return; 302 | } 303 | 304 | let time = new Date(); 305 | let date = $filter('date')(time,'yyyy-MM-dd HH:mm:ss'); 306 | let msg = { 307 | "msg_id": time.getTime(), 308 | "from": 0, 309 | "type": type, 310 | "content": message, 311 | "created_at": date, 312 | "updated_at": date, 313 | "push_status" : false 314 | }; 315 | if(type == 1){ 316 | value.message.content = ''; 317 | } 318 | value.msg_list.push(msg); 319 | $scope.gotoBottom(); 320 | hideFace(); 321 | socketService.sendMsg(msg); 322 | } 323 | 324 | /** 325 | * 显示表情 326 | */ 327 | function showFace(){ 328 | $scope.open_face_status = !$scope.open_face_status; 329 | var el = $("#message_box"); 330 | if($scope.open_face_status){ 331 | $(el[0]).css('height',$rootScope.winheight-$rootScope.header-$rootScope.bottom-200); 332 | gotoBottom(); 333 | }else{ 334 | $(el[0]).css('height',$rootScope.winheight-$rootScope.header-$rootScope.bottom); 335 | } 336 | } 337 | 338 | function hideFace(){ 339 | $scope.open_face_status = false; 340 | var el = $("#message_box"); 341 | $(el[0]).css('height',$rootScope.winheight-$rootScope.header-$rootScope.bottom); 342 | } 343 | 344 | /** 345 | * 显示广告 346 | */ 347 | function toggleAd(){ 348 | if($scope.userInfo.channel_sign == 'czl_weixin'){ 349 | if(angular.isUndefined($scope.openAd)){ 350 | $scope.openAd = true; 351 | }else{ 352 | $scope.openAd = !$scope.openAd; 353 | } 354 | } 355 | } 356 | 357 | /** 358 | * 获取get参数 359 | * @returns {Array} 360 | */ 361 | function getUrlVars(){ 362 | var vars = [], hash; 363 | var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); 364 | for(var i = 0; i < hashes.length; i++) 365 | { 366 | hash = hashes[i].split('='); 367 | vars.push(hash[0]); 368 | vars[hash[0]] = hash[1]; 369 | } 370 | return vars; 371 | } 372 | 373 | function getUrlVar(name){ 374 | let value = getUrlVars()[name] 375 | if((name=='code'||name=='state') && angular.isString(value)){ 376 | value = value.replace('#',''); 377 | value = value.replace('/',''); 378 | } 379 | return value; 380 | } 381 | 382 | 383 | }] 384 | ) -------------------------------------------------------------------------------- /chat/public/css/app.css: -------------------------------------------------------------------------------- 1 | @import "color.css"; 2 | *{ 3 | outline: 0; 4 | } 5 | body{ 6 | overflow: hidden; 7 | } 8 | div[ng-view]{ 9 | background-color: #fff; 10 | } 11 | .site-content-toolbar { 12 | background: #f6f6f6 !important; 13 | color: #202020 !important; 14 | z-index: 3; 15 | } 16 | 17 | .dis-block{ 18 | display: block; 19 | } 20 | 21 | .lh-36{ 22 | height: 36px; 23 | line-height: 36px; 24 | } 25 | 26 | .h-200{ 27 | height: 200px; 28 | max-height: 200px; 29 | } 30 | .cm-fab-btn{ 31 | position: absolute!important; 32 | margin-top: -30px!important; 33 | right: 10px!important; 34 | } 35 | .cm-fab-btn.active{ 36 | z-index: 9!important; 37 | -webkit-animation:tobig 1s .2s ease both; 38 | -moz-animation:tobig 1s .2s ease both; 39 | } 40 | /*悬浮按钮 动画*/ 41 | #animation{ 42 | -webkit-animation:tobig 1s .2s ease both; 43 | -moz-animation:tobig 1s .2s ease both;} 44 | @-webkit-keyframes tobig{ 45 | 0%{-webkit-transform:scale(1)} 46 | 100%{-webkit-transform:scale(50)} 47 | } 48 | @-moz-keyframes tobig{ 49 | 0%{-moz-transform:scale(1)} 50 | 100%{-moz-transform:scale(50)} 51 | } 52 | 53 | /*聊天框CSS*/ 54 | /* 55 | * Component: Direct Chat 56 | * ---------------------- 57 | */ 58 | .direct-chat .box-body { 59 | border-bottom-right-radius: 0; 60 | border-bottom-left-radius: 0; 61 | position: relative; 62 | overflow-x: hidden; 63 | padding: 0; 64 | } 65 | .direct-chat.chat-pane-open .direct-chat-contacts { 66 | -webkit-transform: translate(0, 0); 67 | -ms-transform: translate(0, 0); 68 | -o-transform: translate(0, 0); 69 | transform: translate(0, 0); 70 | } 71 | .direct-chat-messages { 72 | -webkit-transform: translate(0, 0); 73 | -ms-transform: translate(0, 0); 74 | -o-transform: translate(0, 0); 75 | transform: translate(0, 0); 76 | padding: 10px; 77 | /*height: 250px;*/ 78 | overflow: auto; 79 | } 80 | .direct-chat-msg, 81 | .direct-chat-text { 82 | display: block; 83 | } 84 | .direct-chat-msg { 85 | margin-bottom: 10px; 86 | } 87 | .direct-chat-msg:before, 88 | .direct-chat-msg:after { 89 | content: " "; 90 | display: table; 91 | } 92 | .direct-chat-msg:after { 93 | clear: both; 94 | } 95 | .direct-chat-messages, 96 | .direct-chat-contacts { 97 | -webkit-transition: -webkit-transform 0.5s ease-in-out; 98 | -moz-transition: -moz-transform 0.5s ease-in-out; 99 | -o-transition: -o-transform 0.5s ease-in-out; 100 | transition: transform 0.5s ease-in-out; 101 | } 102 | .direct-chat-text { 103 | border-radius: 5px; 104 | position: relative; 105 | padding: 5px 10px; 106 | background: #ffffff; 107 | border: 1px solid #eeeeee; 108 | margin: 5px 0 0 50px; 109 | color: #444444; 110 | line-height: 1.2; 111 | } 112 | .direct-chat-text:after, 113 | .direct-chat-text:before { 114 | position: absolute; 115 | right: 100%; 116 | top: 15px; 117 | border: solid transparent; 118 | border-right-color: #ffffff; 119 | content: ' '; 120 | height: 0; 121 | width: 0; 122 | pointer-events: none; 123 | } 124 | .direct-chat-text:after { 125 | border-width: 5px; 126 | margin-top: -5px; 127 | } 128 | .direct-chat-text:before { 129 | border-width: 6px; 130 | margin-top: -6px; 131 | } 132 | .right .direct-chat-text { 133 | margin-right: 50px; 134 | margin-left: 0; 135 | } 136 | .right .direct-chat-text:after, 137 | .right .direct-chat-text:before { 138 | right: auto; 139 | left: 100%; 140 | border-right-color: transparent; 141 | border-left-color: #ffffff; 142 | } 143 | .direct-chat-img { 144 | border-radius: 50%; 145 | float: left; 146 | width: 40px; 147 | height: 40px; 148 | } 149 | .right .direct-chat-img { 150 | float: right; 151 | } 152 | .direct-chat-info { 153 | display: block; 154 | margin-bottom: 2px; 155 | font-size: 12px; 156 | } 157 | .direct-chat-name { 158 | font-weight: 600; 159 | } 160 | .direct-chat-timestamp { 161 | color: #999; 162 | } 163 | .direct-chat-contacts-open .direct-chat-contacts { 164 | -webkit-transform: translate(0, 0); 165 | -ms-transform: translate(0, 0); 166 | -o-transform: translate(0, 0); 167 | transform: translate(0, 0); 168 | } 169 | .direct-chat-contacts { 170 | -webkit-transform: translate(101%, 0); 171 | -ms-transform: translate(101%, 0); 172 | -o-transform: translate(101%, 0); 173 | transform: translate(101%, 0); 174 | position: absolute; 175 | top: 0; 176 | bottom: 0; 177 | height: 250px; 178 | width: 100%; 179 | background: #222d32; 180 | color: #fff; 181 | overflow: auto; 182 | } 183 | .contacts-list > li { 184 | border-bottom: 1px solid rgba(0, 0, 0, 0.2); 185 | padding: 10px; 186 | margin: 0; 187 | } 188 | .contacts-list > li:before, 189 | .contacts-list > li:after { 190 | content: " "; 191 | display: table; 192 | } 193 | .contacts-list > li:after { 194 | clear: both; 195 | } 196 | .contacts-list > li:last-of-type { 197 | border-bottom: none; 198 | } 199 | .contacts-list-img { 200 | border-radius: 50%; 201 | width: 40px; 202 | float: left; 203 | } 204 | .contacts-list-info { 205 | margin-left: 45px; 206 | color: #fff; 207 | } 208 | .contacts-list-name, 209 | .contacts-list-status { 210 | display: block; 211 | } 212 | .contacts-list-name { 213 | font-weight: 600; 214 | } 215 | .contacts-list-status { 216 | font-size: 12px; 217 | } 218 | .contacts-list-date { 219 | color: #aaa; 220 | font-weight: normal; 221 | } 222 | .contacts-list-msg { 223 | color: #999; 224 | } 225 | .direct-chat-danger .right > .direct-chat-text { 226 | background: #dd4b39; 227 | border-color: #dd4b39; 228 | color: #ffffff; 229 | } 230 | .direct-chat-danger .right > .direct-chat-text:after, 231 | .direct-chat-danger .right > .direct-chat-text:before { 232 | border-left-color: #dd4b39; 233 | } 234 | .direct-chat-primary .right > .direct-chat-text { 235 | background: #3c8dbc; 236 | border-color: #3c8dbc; 237 | color: #ffffff; 238 | } 239 | .direct-chat-primary .right > .direct-chat-text:after, 240 | .direct-chat-primary .right > .direct-chat-text:before { 241 | border-left-color: #3c8dbc; 242 | } 243 | .direct-chat-warning .right > .direct-chat-text { 244 | background: #f39c12; 245 | border-color: #f39c12; 246 | color: #ffffff; 247 | } 248 | .direct-chat-warning .right > .direct-chat-text:after, 249 | .direct-chat-warning .right > .direct-chat-text:before { 250 | border-left-color: #f39c12; 251 | } 252 | .direct-chat-info .right > .direct-chat-text { 253 | background: #00c0ef; 254 | border-color: #00c0ef; 255 | color: #ffffff; 256 | } 257 | .direct-chat-info .right > .direct-chat-text:after, 258 | .direct-chat-info .right > .direct-chat-text:before { 259 | border-left-color: #00c0ef; 260 | } 261 | .direct-chat-success .right > .direct-chat-text { 262 | background: #a0e75a; 263 | border-color: #a0e75a; 264 | color: #444444; 265 | } 266 | .direct-chat-success .right > .direct-chat-text:after, 267 | .direct-chat-success .right > .direct-chat-text:before { 268 | border-left-color: #a0e75a; 269 | } 270 | 271 | .direct-chat-info{ 272 | text-align: center; 273 | } 274 | .direct-chat-timestamp{ 275 | font-size: 16px; 276 | } 277 | .direct-chat-text{ 278 | display: inline-block; 279 | max-width: 70%; 280 | margin: 5px 0 0 10px; 281 | } 282 | .right .direct-chat-text { 283 | float: right; 284 | margin-right: 10px; 285 | } 286 | .direct-chat-name{ 287 | position: absolute; 288 | margin-top: -20px; 289 | font-size: 16px; 290 | } 291 | .direct-chat-name.right{ 292 | right: 10px; 293 | } 294 | /**/ 295 | 296 | .mdi.mdi-48px{ 297 | height: 48px; 298 | } 299 | 300 | .mg_0{ 301 | margin: 0!important; 302 | } 303 | 304 | /*2015-10-14 兼容的X5内核的css*/ 305 | body{ 306 | margin: 0; 307 | padding: 0; 308 | } 309 | /*顶部栏*/ 310 | .cm-toolbar { 311 | box-sizing: border-box; 312 | display: block; 313 | position: relative; 314 | z-index: 2; 315 | font-size: 20px; 316 | min-height: 64px; 317 | width: 100%; 318 | } 319 | .cm-toolbar{ 320 | min-height: 56px; 321 | } 322 | /*左边的工具按钮*/ 323 | .cm-toolbar-tools{ 324 | font-size: 20px; 325 | letter-spacing: 0.005em; 326 | box-sizing: border-box; 327 | font-weight: 400; 328 | display: block; 329 | width: 100%; 330 | height: 64px; 331 | max-height: 64px; 332 | padding: 3px 16px 3px 16px; 333 | margin: 0; 334 | } 335 | .cm-toolbar-tools { 336 | height: 56px; 337 | max-height: 56px; 338 | } 339 | /*按钮基本样式*/ 340 | .cm-button { 341 | letter-spacing: .01em; 342 | border-radius: 3px; 343 | box-sizing: border-box; 344 | color: currentColor; 345 | -webkit-user-select: none; 346 | -moz-user-select: none; 347 | -ms-user-select: none; 348 | user-select: none; 349 | position: relative; 350 | border: 0; 351 | display: inline-block; 352 | -webkit-align-items: center; 353 | -ms-flex-align: center; 354 | align-items: center; 355 | padding: 0 6px; 356 | margin: 6px 8px; 357 | line-height: 36px; 358 | min-height: 36px; 359 | background: 0 0; 360 | white-space: nowrap; 361 | min-width: 88px; 362 | text-align: center; 363 | text-transform: uppercase; 364 | font-weight: 500; 365 | font-size: 14px; 366 | font-style: inherit; 367 | font-variant: inherit; 368 | font-family: inherit; 369 | cursor: pointer; 370 | overflow: hidden; 371 | transition: box-shadow .4s cubic-bezier(.25,.8,.25,1),background-color .4s cubic-bezier(.25,.8,.25,1); 372 | } 373 | /*图标按钮*/ 374 | .cm-button.cm-icon-button { 375 | margin: 0 6px; 376 | height: 48px; 377 | min-width: 0; 378 | line-height: 48px; 379 | padding-left: 0; 380 | padding-right: 0; 381 | width: 48px; 382 | border-radius: 50%; 383 | } 384 | .cm-button:disabled,.cm-button.cm-icon-button:disabled{ 385 | color: #b5b5b5; 386 | } 387 | .cm-toolbar-tools .cm-button { 388 | margin-top: 0; 389 | margin-bottom: 0; 390 | } 391 | .cm-toolbar-tools>.cm-button:first-child { 392 | margin-left: -8px; 393 | } 394 | .cm-toolbar-tools>.cm-button:last-child, .cm-toolbar-tools>.cm-menu:last-child { 395 | margin-right: -8px; 396 | } 397 | .cm-button.cm-fab, .cm-chips, .cm-checkbox .cm-label, .cm-icon { 398 | vertical-align: middle; 399 | } 400 | .cm-icon { 401 | margin: auto; 402 | background-repeat: no-repeat no-repeat; 403 | display: inline-block; 404 | fill: currentColor; 405 | height: 24px; 406 | width: 24px; 407 | } 408 | 409 | .cm-toolbar-tools h1, .cm-toolbar-tools h2, .cm-toolbar-tools h3 { 410 | font-size: inherit; 411 | font-weight: inherit; 412 | margin: inherit; 413 | display: inline; 414 | } 415 | .cm-box{ 416 | overflow-y: auto; 417 | } 418 | 419 | .cm-input { 420 | color: rgba(0,0,0,0.87); 421 | border-color: rgba(0,0,0,0.12); 422 | } 423 | .cm-input { 424 | -webkit-order: 2; 425 | -ms-flex-order: 2; 426 | order: 2; 427 | display: block; 428 | margin-top: auto; 429 | background: 0 0; 430 | border-width: 0 0 1px; 431 | line-height: 26px; 432 | -ms-flex-preferred-size: 26px; 433 | border-radius: 0; 434 | padding: 2px 2px 1px; 435 | font-size: 100%; 436 | } 437 | .cm-input:focus{ 438 | outline: 0; 439 | } 440 | .cm-padding{ 441 | padding: 8px; 442 | } 443 | 444 | .inline{ 445 | display: inline; 446 | } 447 | 448 | .tuigunang-box{ 449 | z-index: 10; 450 | color: #fff; 451 | background-color:#000000; 452 | background-color:rgba(0,0,0,0.5); 453 | position: absolute;width: 100%;top: 0px;height: 56px; 454 | } 455 | .tc{ 456 | text-align: center; 457 | } 458 | .direct-chat-loading{ 459 | height: 20px; 460 | margin-top: 10px; 461 | margin-right: 5px; 462 | float: right; 463 | } 464 | 465 | .top-text{ 466 | margin: 0;padding-top: 10px;font-size: 16px;color: #00abec; 467 | } 468 | 469 | .chat-input{ 470 | background: #fff;border-width: 1px;border-radius: 5px; 471 | } 472 | 473 | .border-0{ 474 | border-width: 0; 475 | } 476 | 477 | .cm-bottom-toolbar{ 478 | min-height: 48px;width: 100%;border-width: 1px 0 0 0;border-top-color: #dddddd;border-style: solid; 479 | } 480 | 481 | 482 | /*2015-11-18 flex布局兼容写法*/ 483 | .layout{ 484 | display: -webkit-box; /* 老版本语法: Safari, iOS, Android browser, older WebKit browsers. */ 485 | display: -moz-box; /* 老版本语法: Firefox (buggy) */ 486 | display: -ms-flexbox; /* 混合版本语法: IE 10 */ 487 | display: -webkit-flex; /* 新版本语法: Chrome 21+ */ 488 | display: flex; /* 新版本语法: Opera 12.1, Firefox 22+ */ 489 | } 490 | .layout-column { 491 | -webkit-box-direction: normal; 492 | -webkit-box-orient: vertical; 493 | -moz-flex-direction: column; 494 | -webkit-flex-direction: column; 495 | flex-direction: column; 496 | } 497 | .layout-row { 498 | -webkit-box-direction: normal; 499 | -webkit-box-orient: horizontal; 500 | -moz-flex-direction: row; 501 | -webkit-flex-direction: row; 502 | flex-direction: row; 503 | } 504 | .flex{ 505 | /*-webkit-box-flex: 1.0;*/ 506 | /*-moz-flex-grow: 1;*/ 507 | /*-webkit-flex-grow: 1;*/ 508 | /*flex-grow: 1;*/ 509 | } 510 | 511 | md-dialog md-dialog-content:not([layout=row])>:first-child:not(.md-subheader) { 512 | margin-bottom: -3px; 513 | } 514 | 515 | .preview-img-sm{ 516 | max-width: 100%; 517 | } 518 | 519 | 520 | .login-padding { 521 | padding: 40px; 522 | } 523 | .loginpage.ng-enter, .loginpage.ng-leave { 524 | transition: .4s linear all; 525 | } 526 | .loginpage.ng-enter { 527 | -webkit-animation:fadeInLeftBig .4s 0s ease both; 528 | -moz-animation:fadeInLeftBig .4s 0s ease both; 529 | } 530 | .loginpage.ng-enter.ng-enter-active, .loginpage.ng-leave { 531 | /*position: absolute;*/ 532 | /*width: 100%;*/ 533 | /*transform: translateX(0%);*/ 534 | } 535 | .loginpage.ng-leave.ng-leave-active { 536 | -webkit-animation: fadeOutLeftBig .4s .3s ease both; 537 | -moz-animation: fadeOutLeftBig .4s .3s ease both; 538 | } 539 | 540 | .chatpage.ng-enter, .chatpage.ng-leave { 541 | transition: .4s linear none; 542 | } 543 | .chatpage.ng-enter { 544 | -webkit-animation:fadeInLeftBig .4s 0s ease both; 545 | -moz-animation:fadeInLeftBig .4s 0s ease both; 546 | } 547 | .chatpage.ng-enter.ng-enter-active, .chatpage.ng-leave { 548 | position: absolute; 549 | width: 100%; 550 | /*transform: translateX(0%) ;*/ 551 | } 552 | .chatpage.ng-leave.ng-leave-active { 553 | -webkit-animation: fadeOutLeftBig .4s .3s ease both; 554 | -moz-animation: fadeOutLeftBig .4s .3s ease both; 555 | } 556 | 557 | .page.ng-enter, .page.ng-leave{ 558 | transition:.4s linear none; 559 | } 560 | .page.ng-enter { 561 | -webkit-animation:fadeInRightBig .4s 0s ease both; 562 | -moz-animation:fadeInRightBig .4s 0s ease both; 563 | } 564 | .page.ng-enter.ng-enter-active, .page.ng-leave { 565 | position: absolute; 566 | width: 100%; 567 | /*transform:translateX(0%);*/ 568 | } 569 | .page.ng-leave.ng-leave-active { 570 | -webkit-animation: fadeOutRightBig .4s .3s ease both; 571 | -moz-animation: fadeOutRightBig .4s .3s ease both; 572 | } 573 | /*右边淡入*/ 574 | @-webkit-keyframes fadeInRightBig{ 575 | 0%{opacity:0; 576 | -webkit-transform:translateX(2000px)} 577 | 100%{opacity:1; 578 | -webkit-transform:translateX(0)} 579 | } 580 | @-moz-keyframes fadeInRightBig{ 581 | 0%{opacity:0; 582 | -moz-transform:translateX(2000px)} 583 | 100%{opacity:1; 584 | -moz-transform:translateX(0)} 585 | } 586 | /*右边淡出*/ 587 | @-webkit-keyframes fadeOutRightBig{ 588 | 0%{opacity:1; 589 | -webkit-transform:translateX(0)} 590 | 100%{opacity:0; 591 | -webkit-transform:translateX(2000px)} 592 | } 593 | @-moz-keyframes fadeOutRightBig{ 594 | 0%{opacity:1; 595 | -moz-transform:translateX(0)} 596 | 100%{opacity:0; 597 | -moz-transform:translateX(2000px)} 598 | } 599 | /*左边淡入*/ 600 | @-webkit-keyframes fadeInLeftBig{ 601 | 0%{opacity:0; 602 | -webkit-transform:translateX(-2000px)} 603 | 100%{opacity:1; 604 | -webkit-transform:translateX(0)} 605 | } 606 | @-moz-keyframes fadeInLeftBig{ 607 | 0%{opacity:0; 608 | -moz-transform:translateX(-2000px)} 609 | 100%{opacity:1; 610 | -moz-transform:translateX(0)} 611 | } 612 | /*左边淡出*/ 613 | @-webkit-keyframes fadeOutLeftBig{ 614 | 0%{opacity:1; 615 | -webkit-transform:translateX(0)} 616 | 100%{opacity:0; 617 | -webkit-transform:translateX(-2000px)} 618 | } 619 | @-moz-keyframes fadeOutLeftBig { 620 | 0% { 621 | opacity: 1; 622 | -moz-transform: translateX(0) 623 | } 624 | 100% { 625 | opacity: 0; 626 | -moz-transform: translateX(-2000px) 627 | } 628 | } 629 | @-webkit-keyframes fadeIn{ 630 | 0% { 631 | opacity: 0; 632 | } 633 | 100% { 634 | opacity: 1; 635 | } 636 | } 637 | @-moz-keyframes fadeIn{ 638 | 0% { 639 | opacity: 0; 640 | } 641 | 100% { 642 | opacity: 1; 643 | } 644 | } 645 | @-webkit-keyframes fadeOut{ 646 | 0% { 647 | opacity: 1; 648 | } 649 | 100% { 650 | opacity: 0; 651 | } 652 | } 653 | @-moz-keyframes fadeOut{ 654 | 0% { 655 | opacity: 1; 656 | } 657 | 100% { 658 | opacity: 0; 659 | } 660 | } 661 | 662 | -------------------------------------------------------------------------------- /chat/source/states/chat/chat-controller.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by yangjiajun on 15/9/28. 3 | */ 4 | 5 | import $ from 'jquery' 6 | import './chat-value' 7 | import SendOtherMessageHtml from './bottom_sheet/send-other-message-template.html!text' 8 | import SendOtherMessageCtrl from './bottom_sheet/send-other-message-controller'; 9 | import ImgDialogCtrl from './dialog/img-dialog-controller'; 10 | import ImgDialogHtml from './dialog/img-dialog-template.html!text'; 11 | 12 | import 'source/filter/format-message' 13 | 14 | //表情控件 15 | import CmFace from 'source/components/face/face-directive' 16 | import 'source/components/btn_back/btn-back-directive' 17 | 18 | export default angular.module('chat') 19 | .controller('SendOtherMessageCtrl',SendOtherMessageCtrl) 20 | .controller('ChatCtrl',['$rootScope','$scope','$timeout','$window','chat.value','$mdSidenav','$mdUtil','$mdBottomSheet','$log','$filter','User','socket','$mdToast','$mdDialog','$location', 21 | function($rootScope,$scope,$timeout,$window,value,$mdSidenav,$mdUtil,$mdBottomSheet,$log,$filter,UserService,socketService,$mdToast,$mdDialog,$location){ 22 | $scope.pageClass = 'chatpage'; 23 | $scope.showTopToolBar = value.showTopToolBar; 24 | $scope.showTopTitle = value.showTopTitle; 25 | $scope.is_loading_history = value.is_loading_history; 26 | $scope.error_msg = '服务器错误!'; 27 | $scope.open_face_status = value.open_face_status; 28 | $scope.open_audio_status = value.open_audio_status; 29 | $scope.scroll_top = value.scroll_top; 30 | $scope.message = value.message; 31 | $scope.msg_list = value.msg_list; 32 | $scope.service_info = value.service_info; 33 | $scope.user_info = value.user_info; 34 | $scope.userInfo = value.userInfo; 35 | $scope.page = value.page; 36 | $scope.timestamp = value.timestamp = new Date().getTime(); 37 | $scope.toggleRight = buildToggler('right'); 38 | $scope.toggleFace = toggleFace; 39 | $scope.focusMessageInput = focusMessageInput; 40 | $scope.showGridBottomSheet = showGridBottomSheet; 41 | $scope.gotoBottom = gotoBottom; 42 | $scope.sendMessage = sendMessage; 43 | $scope.keypressInChatInput = keypressInChatInput; 44 | $scope.loadHistoryMsg = loadHistoryMsg; 45 | $scope.preview = preview; 46 | 47 | /** 48 | * 监听表情控件的输入表情事件 49 | */ 50 | $scope.$on('face_inputting',face_inputting); 51 | /** 52 | * 监听语音输入(没用) 53 | */ 54 | $scope.$on('audio_inputting',audio_inputting); 55 | $scope.$on('img_upload_success',handleImgUploadSuccess); 56 | /** 57 | * 登陆成功事件 58 | */ 59 | $scope.$on(socketService.im.cmd_login,function(event,data){ 60 | console.log('登陆成功',$rootScope.loginInfo); 61 | let msg_id = new Date().getTime(); 62 | value.msg_list.push({ 63 | "msg_id": msg_id, 64 | "from": 1, 65 | "type": 1, 66 | "content": '您好,想了解汽车哪方面内容呢?', 67 | "created_at": msg_id, 68 | "updated_at": msg_id 69 | }); 70 | loadHistoryMsg(); 71 | $rootScope.autoSetMessageBoxHeight(); 72 | }); 73 | /** 74 | * 收到消息事件 75 | */ 76 | $scope.$on(socketService.im.cmd_chat_msg,function(event,msg){ 77 | value.msg_list.push({ 78 | "msg_id": msg.msg_id, 79 | "from": 1, 80 | "type": parseInt(msg.type), 81 | "content": msg.content, 82 | "created_at": msg.time, 83 | "updated_at": msg.time 84 | }); 85 | $rootScope.$apply('msg_list'); 86 | gotoBottom(); 87 | }); 88 | /** 89 | * 消息发送反馈事件 90 | */ 91 | $scope.$on(socketService.im.cmd_chat_msg_ask,function(event,msg){ 92 | console.log(msg); 93 | for(let i=value.msg_list.length-1;i>=0;i--){ 94 | if(msg.msg_id == value.msg_list[i].msg_id){ 95 | $rootScope.$apply(function(){ 96 | value.msg_list[i].push_status = true; 97 | }) 98 | break; 99 | } 100 | } 101 | }); 102 | /** 103 | * 接收欢迎语 104 | */ 105 | $scope.$on(socketService.im.cmd_user_in_chat,function(event,data){ 106 | if(data.working == 0){ 107 | let msg_id = new Date().getTime(); 108 | value.msg_list.push({ 109 | "msg_id": msg_id, 110 | "from": 1, 111 | "type": 1, 112 | "content": data.welcome, 113 | "created_at": data.time, 114 | "updated_at": data.time 115 | }); 116 | } 117 | }); 118 | init(); 119 | listenScroll(); 120 | //////////////////////////////////////// 121 | function init(){ 122 | if($rootScope.isLoginIM){ 123 | $timeout(()=>{ 124 | document.getElementById("message_box").scrollTop = value.scroll_top; 125 | },100); 126 | return; 127 | } 128 | 129 | $scope.system_version = getUrlVar('system_version'); 130 | let params = { 131 | uid : getUrlVar('uid'), 132 | channel : getUrlVar('channel'), 133 | device : getUrlVar('device'), 134 | timestamp : getUrlVar('timestamp'), 135 | city : getUrlVar('city'), 136 | car_type : getUrlVar('car_type'), 137 | system_version: getUrlVar('system_version'), 138 | nickname : getUrlVar('nickname'), 139 | sign : getUrlVar('sign'), 140 | return_url : getUrlVar('return_url') 141 | } 142 | 143 | //获取参数 144 | if(params.uid && params.channel && params.sign){ 145 | //ajax访问后台 获取用户信息 146 | UserService.getUserInfoByThirdApp(params).$promise.then( 147 | function(data){ 148 | if(data && data.code==200){ 149 | //{ 150 | // account_type: 5 151 | // address: "" 152 | // alpha_id: "Jsj" 153 | // answer_number: 0 154 | // appoint_number: 0 155 | // car_number: "" 156 | // car_type_name: "" 157 | // channel_sign: "" 158 | // gender: 0 159 | // gender_str: "保密" 160 | // nickname: "13761783877" 161 | // realname: "" 162 | // telephone: "" 163 | // user_allow_login: true 164 | // user_avatar: "" 165 | // user_id: 35757 166 | // user_token: "k5oXXmClkQylC9ejpZxYsA==" 167 | //} 168 | $scope.userInfo = value.userInfo = data.data; 169 | 170 | //获取用户信息后 登陆IM 171 | socketService.connect().then( 172 | function(){ 173 | $rootScope.loginInfo = { 174 | 'uin': $scope.userInfo.user_id, 175 | 'nick':$scope.userInfo.nickname, 176 | 'pic': $scope.userInfo.user_avatar, 177 | 'location':params.city?decodeURI(params.city):'', 178 | 'city':params.city?decodeURI(params.city):'', 179 | 'area':params.city?decodeURI(params.city):'', 180 | 'address':$scope.userInfo.address, 181 | 'token':$scope.userInfo.user_token, 182 | 'client_type': 3, 183 | 'client_id':'', 184 | 'client_ver':'1.0.0', 185 | 'channel': $scope.userInfo.channel_sign,//渠道 186 | 'latitude':'' 187 | } 188 | socketService.loginIM($rootScope.loginInfo); 189 | value.user_info.avatar = $filter('format_avatar')(data.data.user_avatar,$scope.userInfo.channel_sign); 190 | value.user_info.name = $scope.userInfo.nickname; 191 | $rootScope.channel_sign = $scope.userInfo.channel_sign 192 | $rootScope.$apply('user_info'); 193 | 194 | 195 | //车与我 判断显示+号图标 196 | if($scope.userInfo.channel_sign == 'czl_cyw' 197 | && $rootScope.isAndroid && $rootScope.sys_version < 4.4){ 198 | $scope.showMoreBtn = false; 199 | $scope.showTopTitle = value.showTopTitle = true; 200 | }else if($scope.userInfo.channel_sign == 'czl_lechebang'){ 201 | $scope.showTopToolBar = value.showTopToolBar = true; 202 | }else if($scope.userInfo.channel_sign == 'czl_xxyh'){ 203 | $scope.showTopTitle = value.showTopTitle = true; 204 | } 205 | }, 206 | function(){ 207 | $rootScope.isLinkedToSocket = false; 208 | $rootScope.errorDialog('连接断开!'); 209 | console.log('连接断开'); 210 | } 211 | ) 212 | }else{ 213 | $rootScope.errorDialog('服务器错误!'); 214 | } 215 | 216 | } 217 | ); 218 | 219 | 220 | }else{ 221 | console.log('授权失败!'); 222 | $rootScope.errorDialog('服务器错误!'); 223 | //获取用户信息后 登陆IM 224 | //socketService.connect().then( 225 | // function(){ 226 | // $scope.userInfo = { 227 | // address: "", 228 | // alpha_id: "Gsj", 229 | // answer_number: 0, 230 | // appoint_number: 0, 231 | // car_number: "", 232 | // car_type_name: "", 233 | // gender: 1, 234 | // gender_str: "男", 235 | // nickname: "杨佳军", 236 | // realname: "", 237 | // telephone: "", 238 | // channel_sign:'czl_weixin', 239 | // user_allow_login: true, 240 | // user_avatar: "http://wx.qlogo.cn/mmopen/wJibWkqN1bUO2ozCTUD2e0k9AIsot7OdRLPt9UbRyaFa4I6cvaqXWyUrczoZn5gkOSngAJKWj8JAicRibZV6SVr9xjYPLqZ7qUZ/0", 241 | // user_id: 35754, 242 | // user_token: "9vEqDHX9wZo/Gz4Gpc2lmw==", 243 | // } 244 | // $rootScope.loginInfo = { 245 | // 'uin': $scope.userInfo.user_id, 246 | // 'nick':$scope.userInfo.nickname, 247 | // 'pic': $scope.userInfo.user_avatar, 248 | // 'location':'', 249 | // 'address':'', 250 | // 'token':$scope.userInfo.user_token, 251 | // 'client_type': 3, 252 | // 'client_id':'', 253 | // 'client_ver':'1.0.0', 254 | // 'channel': $scope.userInfo.channel_sign,//渠道 255 | // 'latitude':'' 256 | // }; 257 | // socketService.loginIM($rootScope.loginInfo); 258 | // $rootScope.$apply(function(){ 259 | // value.user_info.avatar = $scope.userInfo.user_avatar; 260 | // value.user_info.name = $scope.userInfo.nickname; 261 | // }); 262 | // }, 263 | // function(){ 264 | // $rootScope.isLinkedToSocket = false; 265 | // alert('连接断开'); 266 | // console.log('连接断开'); 267 | // } 268 | //) 269 | } 270 | } 271 | 272 | function focusMessageInput(){ 273 | toggleFace(false); 274 | $timeout(()=>{ 275 | $("#message_input").focus(); 276 | },100); 277 | } 278 | 279 | function toggleFace(status){ 280 | if(angular.isUndefined(status)){ 281 | $scope.open_face_status = !$scope.open_face_status; 282 | }else{ 283 | $scope.open_face_status = status; 284 | } 285 | var el = $("#message_box"); 286 | if($scope.open_face_status){ 287 | $(el[0]).css('height',$rootScope.winheight-$rootScope.header-$rootScope.topToolbar-$rootScope.bottom-200+'px'); 288 | }else{ 289 | $(el[0]).css('height',$rootScope.winheight-$rootScope.header-$rootScope.topToolbar-$rootScope.bottom+'px'); 290 | } 291 | } 292 | 293 | //绑定回车按键 294 | function keypressInChatInput($event){ 295 | if($scope.message.content.trim()!=''&&$event.keyCode==13 && $event.altKey == false && $event.ctrlKey==false && $event.shiftKey==false ){ 296 | $event.preventDefault(); 297 | $event.stopPropagation(); 298 | $scope.sendMessage($scope.message.content,1); 299 | return; 300 | } 301 | } 302 | /** 303 | * 根据md-component-id的值来显示或者隐藏侧栏 304 | */ 305 | function buildToggler(navID) { 306 | var debounceFn = $mdUtil.debounce(function(){ 307 | $mdSidenav(navID) 308 | .toggle() 309 | .then(function () { 310 | $log.debug("toggle " + navID + " is done"); 311 | }); 312 | },200); 313 | return debounceFn; 314 | } 315 | 316 | 317 | /** 318 | * 监听表情输入 319 | * @param event 320 | * @param msg 321 | */ 322 | function face_inputting(event,msg){ 323 | value.message.content += msg.face_name; 324 | } 325 | 326 | function audio_inputting(event,audio_url){ 327 | $scope.sendMessage(audio_url,2); 328 | $rootScope.$apply($scope.msg_list); 329 | } 330 | 331 | function handleImgUploadSuccess(event,data){ 332 | if(data && data.img_url){ 333 | $scope.sendMessage(data.img_url,3); 334 | } 335 | } 336 | /** 337 | * 滚到底部 338 | */ 339 | function gotoBottom(){ 340 | setTimeout(()=>{ 341 | document.getElementById("message_box").scrollTop = document.getElementById("message_box").scrollHeight; 342 | },100) 343 | } 344 | 345 | /** 346 | * 显示底部框 347 | * @param $event 348 | * @param type 349 | */ 350 | function showGridBottomSheet($event,type){ 351 | if(!$rootScope.isLoginIM){ 352 | pop('连接已断开,请重新进入页面!'); 353 | return; 354 | } 355 | if(angular.isDefined($scope.system_version)){ 356 | let version = $scope.system_version.split('_'); 357 | if(angular.isUndefined(version[1]) || version[0] == 'android' && parseFloat(version[1]) < 4.4){ 358 | pop('安卓版本过低,不能发送图片!'); 359 | return; 360 | } 361 | } 362 | if(angular.isDefined($scope.userInfo) && $scope.userInfo.channel_sign == 'czl_xxyh'){ 363 | if($rootScope.isiPhone){ 364 | pop('浏览器限制,不能发送图片!'); 365 | return; 366 | } 367 | } 368 | $mdBottomSheet.show({ 369 | template: SendOtherMessageHtml, 370 | controller: 'SendOtherMessageCtrl', 371 | targetEvent: $event 372 | }).then(function(clickedItem) { 373 | 374 | }); 375 | } 376 | 377 | /** 378 | * 发送文字消息 379 | */ 380 | function sendMessage(message,type){ 381 | if(!$rootScope.isLinkedToSocket){ 382 | pop('连接已断开,请重新进入页面!'); 383 | return; 384 | } 385 | 386 | let time = new Date(); 387 | let date = $filter('date')(time,'yyyy-MM-dd HH:mm:ss'); 388 | let msg = { 389 | "msg_id": time.getTime(), 390 | "from": 0, 391 | "type": type, 392 | "content": message, 393 | "created_at": date, 394 | "updated_at": date, 395 | "push_status" : false 396 | }; 397 | if(type == 1){ 398 | value.message.content = ''; 399 | } 400 | value.msg_list.push(msg); 401 | $scope.gotoBottom(); 402 | value.open_face_status = false; 403 | socketService.sendMsg(msg); 404 | } 405 | 406 | /** 407 | * 只是上拉加载聊天历史 408 | */ 409 | function loadHistoryMsg(){ 410 | var prams = { 411 | page : value.page, 412 | timestamp : value.timestamp, 413 | user_id : $scope.userInfo.user_id, 414 | alpha_id : $scope.userInfo.alpha_id 415 | }; 416 | $scope.is_loading_history = value.is_loading_history = true; 417 | return new Promise(function(){ 418 | UserService.getHistoryMsg(prams).$promise.then( 419 | function(data){ 420 | if(data.data.length==0){ 421 | $scope.page = value.page = 0; 422 | return; 423 | } 424 | if(value.msg_list.length == 0){ 425 | for(let i=data.data.length-1;i>=0;i--){ 426 | value.msg_list.push(data.data[i]); 427 | } 428 | }else{ 429 | for(let j=0;j