├── LICENSE ├── README.md ├── java-server-todo ├── .gitignore ├── README.md ├── lib │ ├── client-sdk.api-1.0.2.jar │ ├── client-sdk.common-1.0.0-SNAPSHOT.jar │ ├── client-sdk.core-1.0.0-SNAPSHOT.jar │ ├── client-sdk.example-1.0.0-SNAPSHOT.jar │ ├── client-sdk.spring-1.0.0-SNAPSHOT.jar │ ├── lippi-oapi-encrpt.jar │ └── taobao-sdk-java-auto_1479188381469-20170724.jar ├── pom.xml ├── run.sh └── src │ └── main │ ├── java │ └── com │ │ └── alibaba │ │ └── dingtalk │ │ └── openapi │ │ ├── demo │ │ ├── Demo.java │ │ ├── Env.java │ │ ├── OApiException.java │ │ ├── auth │ │ │ └── AuthHelper.java │ │ ├── department │ │ │ └── DepartmentHelper.java │ │ ├── eventchange │ │ │ └── eventChangeHelper.java │ │ ├── media │ │ │ └── MediaHelper.java │ │ ├── message │ │ │ ├── ConversationMessageDelivery.java │ │ │ ├── ImageMessage.java │ │ │ ├── LightAppMessageDelivery.java │ │ │ ├── LinkMessage.java │ │ │ ├── Message.java │ │ │ ├── MessageDelivery.java │ │ │ ├── MessageHelper.java │ │ │ ├── OAMessage.java │ │ │ └── TextMessage.java │ │ ├── user │ │ │ ├── User.java │ │ │ └── UserHelper.java │ │ └── utils │ │ │ ├── FileUtils.java │ │ │ ├── HttpHelper.java │ │ │ └── aes │ │ │ ├── DingTalkEncryptException.java │ │ │ ├── DingTalkEncryptor.java │ │ │ ├── DingTalkJsApiSingnature.java │ │ │ ├── PKCS7Padding.java │ │ │ └── Utils.java │ │ └── servlet │ │ ├── ContactsServlet.java │ │ ├── EventChangeReceiveServlet.java │ │ ├── JsAPIServlet.java │ │ ├── UserIdServlet.java │ │ └── UserInfoServlet.java │ └── webapp │ └── WEB-INF │ └── web.xml ├── jquery-fed-oapage ├── .gitignore ├── README.md ├── app.css ├── app.js ├── index.html ├── info.text └── package.json ├── nodejs-server-todo ├── .gitignore ├── README.md ├── app │ ├── api │ │ └── index.js │ ├── controller │ │ ├── OAuth │ │ │ └── index.js │ │ ├── get │ │ │ └── index.js │ │ ├── getUserInfo │ │ │ └── index.js │ │ └── microapps │ │ │ └── index.js │ ├── env.js │ ├── index.js │ ├── logger │ │ └── index.js │ ├── middleware │ │ └── helper.js │ └── request │ │ ├── getAccessToken.js │ │ └── getJsApiTicket.js ├── info.text ├── nodemon.json └── package.json ├── react-fed-oapage ├── .babelrc ├── .gitignore ├── README.md ├── build │ ├── build-server.js │ ├── build.js │ ├── webpack.base.js │ ├── webpack.dev.js │ └── webpack.prod.js ├── config │ ├── dev.env.js │ ├── index.js │ └── prod.env.js ├── index.html ├── info.text ├── package.json └── src │ ├── app.js │ ├── app.scss │ ├── common │ ├── ding-service.js │ ├── env.js │ ├── logger.js │ └── normalize.css │ ├── containers │ ├── Home │ │ ├── HomeView.jsx │ │ ├── HomeView.scss │ │ ├── components │ │ │ ├── Admin │ │ │ │ ├── Admin.jsx │ │ │ │ ├── Admin.scss │ │ │ │ └── index.js │ │ │ ├── AllAppList │ │ │ │ ├── ALLAPPLISTMOCKDATA.jsx │ │ │ │ ├── AllAppList.jsx │ │ │ │ ├── AllAppList.scss │ │ │ │ └── index.js │ │ │ ├── Banner │ │ │ │ ├── Banner.jsx │ │ │ │ ├── Banner.scss │ │ │ │ └── index.js │ │ │ ├── Manager │ │ │ │ ├── Manager.jsx │ │ │ │ ├── Manager.scss │ │ │ │ └── index.js │ │ │ └── UserList │ │ │ │ ├── UserList.jsx │ │ │ │ ├── UserList.scss │ │ │ │ └── index.js │ │ ├── flow │ │ │ ├── constants.js │ │ │ ├── homeActions.js │ │ │ └── homeReducers.js │ │ └── index.js │ └── index.js │ └── store │ ├── configureStore.js │ └── reducers.js ├── vue-fed-oapage ├── .gitignore ├── README.md ├── build │ ├── build.js │ ├── check-versions.js │ ├── dev-client.js │ ├── dev-server.js │ ├── utils.js │ ├── vue-loader.conf.js │ ├── webpack.base.conf.js │ ├── webpack.dev.conf.js │ └── webpack.prod.conf.js ├── config │ ├── dev.env.js │ ├── index.js │ └── prod.env.js ├── dist │ ├── index.html │ ├── static │ │ ├── css │ │ │ ├── app.319f5aa30159266fbe379922b7b8ecbd.css │ │ │ └── app.319f5aa30159266fbe379922b7b8ecbd.css.map │ │ └── js │ │ │ ├── app.5d6868dab4b33330a32e.js │ │ │ ├── manifest.eb7218291907da2ade18.js │ │ │ └── vendor.cf746c67ffe28a1ae0e3.js │ └── weex-home.js ├── index.html ├── info.text ├── package.json ├── src │ ├── App.vue │ ├── components │ │ ├── complexApp.vue │ │ ├── grid.vue │ │ └── singleApp.vue │ ├── lib │ │ ├── ding-web.js │ │ ├── env.js │ │ ├── logger.js │ │ ├── metaHandler.js │ │ ├── shared.js │ │ └── util.js │ ├── main.js │ ├── mock │ │ └── meta.js │ ├── pages │ │ └── home │ │ │ ├── components │ │ │ ├── index-admin.vue │ │ │ ├── index-appManager.vue │ │ │ ├── index-applist.vue │ │ │ ├── index-banner.vue │ │ │ ├── index-item.vue │ │ │ └── index-userlist.vue │ │ │ └── index.vue │ └── router │ │ └── index.js └── static │ └── .gitkeep ├── weex-rax-fed-todo ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── README.md ├── build │ └── index.js ├── ding.config.js ├── info.text ├── package.json ├── src │ ├── components │ │ └── label │ │ │ ├── index.jsx │ │ │ └── index.less │ ├── pages │ │ └── index │ │ │ ├── container.jsx │ │ │ ├── container │ │ │ ├── main.jsx │ │ │ └── main.less │ │ │ ├── index.jsx │ │ │ ├── mods │ │ │ ├── addItem.jsx │ │ │ ├── addItem.less │ │ │ ├── list.jsx │ │ │ ├── list.less │ │ │ ├── profile.jsx │ │ │ └── profile.less │ │ │ └── redux │ │ │ ├── actions │ │ │ └── todo.js │ │ │ ├── reducers │ │ │ ├── index.js │ │ │ └── todo.js │ │ │ └── store │ │ │ ├── index.js │ │ │ └── middlewares.js │ └── util │ │ ├── apimap.js │ │ ├── global.js │ │ ├── index.js │ │ ├── lib │ │ ├── env.js │ │ ├── request.js │ │ ├── storage.js │ │ └── util.js │ │ └── request │ │ └── fetch.js ├── template.html └── www │ ├── index.html │ └── index.js └── weex-vue-fed-todo ├── .babelrc ├── .gitignore ├── README.md ├── build ├── build-weex.js ├── build.js ├── check-versions.js ├── dev-client.js ├── dev-server.js ├── dev-weex-server.js ├── mock-server.js ├── utils.js ├── vue-loader.conf.js ├── webpack.base.conf.js ├── webpack.dev.conf.js ├── webpack.prod.conf.js └── webpack.weex.conf.js ├── config ├── dev.env.js ├── index.js └── prod.env.js ├── dist ├── index.html ├── static │ └── js │ │ ├── manifest.js │ │ ├── vendor.js │ │ └── vue-bundle.js ├── weex-bundle-watch.js ├── weex-bundle.js └── weex-dingtalk.js ├── index.html ├── info.text ├── mock └── router.js ├── package.json ├── src ├── components │ └── component.vue ├── container │ ├── App.vue │ └── router.js ├── lib │ ├── env.js │ ├── request.js │ ├── storage.js │ └── util.js ├── pages │ ├── add │ │ └── index.vue │ ├── dingtalk │ │ └── index.vue │ ├── home │ │ └── index.vue │ └── list │ │ ├── component │ │ ├── todo-cells.vue │ │ └── todo-user.vue │ │ └── index.vue └── platforms │ ├── web │ └── web.entry.js │ └── weex │ ├── weex.dingtalk.js │ └── weex.entry.js └── static └── .gitkeep /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 钉钉开放平台团队 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## which-language-demo 2 | 3 | look me, we can just do more demo. guess, u select which one ? 4 | 5 | ## 社区支持 6 | 7 | 钉钉开发社区有数以万计的企业服务开发者,你的公开演示程序,可以有很高机会曝光让其他的开发者学习,使用,甚至可以在这里认识更多志同道合的开发者。 8 | 9 | 使用[语言]-[客户端或者服务端]-[实现的业务场景]来创建一个演示项目程序,解释如下: 10 | 11 | - [语言] 可以是具体的编程语言,框架(react),或者可以有指代含义的单词 12 | - [客户端或者服务端] 可以是fed,server,或者纯粹的cli等,能描述它使用在哪一方面 13 | - [实现的业务场景] 也就是可以用一个有明显含义的单词,描述这个项目是做什么的 14 | 15 | 我们非常欢迎社区的同学为钉钉的开发生态添砖加瓦,当你创建一个公开的演示项目时,你的项目中必须要包含:README.md,.gitignore,info.text 三个文件。 16 | 17 | - README.md可以把你的项目描述清楚,让钉钉的开发者可以快速的使用起来,好的反馈相信对你而言也是一种很有成就感的事情。 18 | - .gitignore文件可以将一些不是必须的文件忽略,不提交到仓库。 19 | - info.text 文件可以给予一些必要的版本信息,注意事项,项目依赖等。 20 | 21 | 对于公开演示的程序,我们要求必须包含JSAPI授权,获取userId,获取userInfo三个接口,并且有如下的规则: 22 | 23 | - 可以定义不同的host,port以及protocol 24 | - 可以自己实现不同的逻辑 25 | - 对外暴露的path必须按照我们的要求定义 26 | - 前后端分离的架构中服务端的实现需要注意 **跨域头 setHeader("Access-Control-Allow-Origin", "*")的设置** [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS) 27 | 28 | | path | method | 参数 | 作用 | response | 29 | | ------------- |:-------------:| -----:| -----:| ----: | 30 | | /api/jsapi-oauth | GET | href | 提供JSAPI授权 | {errcode:0,...response} | 31 | | /api/get-user-info | GET | code | 获取userid | {errcode:0,...response} | 32 | | /api/get | GET | userid | 获取用户信息 | {errcode:0,...response} | 33 | 34 | 对于前端项目: 35 | 36 | - 访问页面时需要在URL地址上配置一个**corpId** 参数,如:`http://127.0.0.1:8089/?corpId=ding94925051369422aa35c2f4657eb6378f` 37 | - 请求的地址需要替换成你本机的服务端IP 38 | - 钉钉客户端会有缓存,如果你修改了HTML,需要在设置中清除缓存,才能看到修改的内容。 39 | 40 | 如果你准备就绪,请不要忘记 Fork项目,并发起一次 [Pull request](https://github.com/open-dingtalk/which-language-demo/pulls) 。 41 | 42 | ## 社区开发群 43 | 44 | 使用钉钉扫描二维码,加入社区开发群。 45 | 46 | ![](https://gw.alicdn.com/tfs/TB1xkJRbwMPMeJjy1XdXXasrXXa-330-440.png) 47 | 48 | ## LICENSE 49 | 50 | MIT License 51 | 52 | Copyright (c) 2017 钉钉开放平台团队 53 | 54 | Permission is hereby granted, free of charge, to any person obtaining a copy 55 | of this software and associated documentation files (the "Software"), to deal 56 | in the Software without restriction, including without limitation the rights 57 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 58 | copies of the Software, and to permit persons to whom the Software is 59 | furnished to do so, subject to the following conditions: 60 | 61 | The above copyright notice and this permission notice shall be included in all 62 | copies or substantial portions of the Software. 63 | 64 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 65 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 66 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 67 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 68 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 69 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 70 | SOFTWARE. 71 | 72 | 73 | -------------------------------------------------------------------------------- /java-server-todo/.gitignore: -------------------------------------------------------------------------------- 1 | api/*.iml 2 | provider/*.iml 3 | web/*.iml 4 | *.iml 5 | **/*.iml 6 | .idea/ 7 | .idea/* 8 | .project 9 | Permanent_Data/* 10 | *secrect* -------------------------------------------------------------------------------- /java-server-todo/README.md: -------------------------------------------------------------------------------- 1 | ### 软件依赖 2 | * java version "1.7" 3 | * maven3 4 | 5 | ## Getting Started 6 | 7 | 1. 将工程clone到本地:`git clone https://github.com/open-dingtalk/which-language-demo.git`, **cd java-server-todo** 8 | 2. 使用IDE导入工程,比如eclipse点击`File->import`(推荐使用maven导入), IDEA点击`File->New->Project from Existing Sources...`, 文件编码都是UTF-8 9 | 3. 打开工程的Env.java文件,填入企业的CORP_ID和SECRET(CORP_ID和SECRET可以在企业OA后台找到) 10 | ```java 11 | public static final String CORP_ID = "your CORP_ID"; 12 | public static final String CORP_SECRET = "your CORP_SECRET"; 13 | ``` 14 | 4. 部署工程,建议使用mvn -DskipTests=true jetty:run运行或者IDE中的maven插件运行 15 | 16 | 17 | ## java版服务端实现 18 | 19 | #### 1. /api/jsapi-oauth 20 | 21 | * 获取jsapi的签名数据 22 | * 实现类com.alibaba.dingtalk.openapi.servlet.JsAPIServlet 23 | 24 | #### 2. /api/get-user-info 25 | 26 | * 根据免登授权码获取登陆用户userid 27 | * 实现类 com.alibaba.dingtalk.openapi.servlet.UserInfoServlet 28 | 29 | #### 3. /api/get 30 | 31 | * 根据userid查询用户信息 32 | * 实现类com.alibaba.dingtalk.openapi.servlet.UserIdServlet -------------------------------------------------------------------------------- /java-server-todo/lib/client-sdk.api-1.0.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-dingtalk/which-language-demo/beec798dff6eab38dec5b2c9c93434a6ffabed03/java-server-todo/lib/client-sdk.api-1.0.2.jar -------------------------------------------------------------------------------- /java-server-todo/lib/client-sdk.common-1.0.0-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-dingtalk/which-language-demo/beec798dff6eab38dec5b2c9c93434a6ffabed03/java-server-todo/lib/client-sdk.common-1.0.0-SNAPSHOT.jar -------------------------------------------------------------------------------- /java-server-todo/lib/client-sdk.core-1.0.0-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-dingtalk/which-language-demo/beec798dff6eab38dec5b2c9c93434a6ffabed03/java-server-todo/lib/client-sdk.core-1.0.0-SNAPSHOT.jar -------------------------------------------------------------------------------- /java-server-todo/lib/client-sdk.example-1.0.0-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-dingtalk/which-language-demo/beec798dff6eab38dec5b2c9c93434a6ffabed03/java-server-todo/lib/client-sdk.example-1.0.0-SNAPSHOT.jar -------------------------------------------------------------------------------- /java-server-todo/lib/client-sdk.spring-1.0.0-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-dingtalk/which-language-demo/beec798dff6eab38dec5b2c9c93434a6ffabed03/java-server-todo/lib/client-sdk.spring-1.0.0-SNAPSHOT.jar -------------------------------------------------------------------------------- /java-server-todo/lib/lippi-oapi-encrpt.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-dingtalk/which-language-demo/beec798dff6eab38dec5b2c9c93434a6ffabed03/java-server-todo/lib/lippi-oapi-encrpt.jar -------------------------------------------------------------------------------- /java-server-todo/lib/taobao-sdk-java-auto_1479188381469-20170724.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-dingtalk/which-language-demo/beec798dff6eab38dec5b2c9c93434a6ffabed03/java-server-todo/lib/taobao-sdk-java-auto_1479188381469-20170724.jar -------------------------------------------------------------------------------- /java-server-todo/run.sh: -------------------------------------------------------------------------------- 1 | mvn -DskipTests=true jetty:run -------------------------------------------------------------------------------- /java-server-todo/src/main/java/com/alibaba/dingtalk/openapi/demo/Env.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dingtalk.openapi.demo; 2 | 3 | 4 | /** 5 | * 企业应用接入时的常量定义 6 | */ 7 | public class Env { 8 | 9 | /** 10 | * 企业应用接入秘钥相关 11 | */ 12 | public static final String CORP_ID = ""; 13 | public static final String CORP_SECRET = ""; 14 | public static final String SSO_Secret = ""; 15 | 16 | /** 17 | * DING API地址 18 | */ 19 | public static final String OAPI_HOST = "https://oapi.dingtalk.com"; 20 | /** 21 | * 企业应用后台地址,用户管理后台免登使用 22 | */ 23 | public static final String OA_BACKGROUND_URL = ""; 24 | 25 | 26 | /** 27 | * 企业通讯回调加密Token,注册事件回调接口时需要传递给钉钉服务器 28 | */ 29 | public static final String TOKEN = ""; 30 | public static final String ENCODING_AES_KEY = ""; 31 | 32 | } 33 | -------------------------------------------------------------------------------- /java-server-todo/src/main/java/com/alibaba/dingtalk/openapi/demo/OApiException.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dingtalk.openapi.demo; 2 | 3 | public class OApiException extends Exception { 4 | 5 | public static final int ERR_RESULT_RESOLUTION = -2; 6 | 7 | public OApiException(String field) { 8 | this(ERR_RESULT_RESOLUTION, "Cannot resolve field " + field + " from oapi resonpse"); 9 | } 10 | 11 | public OApiException(int errCode, String errMsg) { 12 | super("error code: " + errCode + ", error message: " + errMsg); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /java-server-todo/src/main/java/com/alibaba/dingtalk/openapi/demo/department/DepartmentHelper.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dingtalk.openapi.demo.department; 2 | 3 | import com.dingtalk.open.client.ServiceFactory; 4 | import com.dingtalk.open.client.api.model.corp.Department; 5 | import com.dingtalk.open.client.api.service.corp.CorpDepartmentService; 6 | import com.dingtalk.open.client.common.SdkInitException; 7 | import com.dingtalk.open.client.common.ServiceException; 8 | import com.dingtalk.open.client.common.ServiceNotExistException; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * 部门相关API 14 | * 15 | * https://open-doc.dingtalk.com/docs/doc.htm?treeId=371&articleId=106817&docType=1 16 | */ 17 | public class DepartmentHelper { 18 | 19 | /** 20 | * 创建部门 21 | */ 22 | public static String createDepartment(String accessToken, String name, 23 | String parentId, String order, boolean createDeptGroup) throws Exception { 24 | 25 | CorpDepartmentService corpDepartmentService = ServiceFactory.getInstance().getOpenService(CorpDepartmentService.class); 26 | return corpDepartmentService.deptCreate(accessToken, name, parentId, order, createDeptGroup); 27 | } 28 | 29 | /** 30 | * 获取部门列表 31 | */ 32 | public static List listDepartments(String accessToken, String parentDeptId) 33 | throws ServiceNotExistException, SdkInitException, ServiceException { 34 | CorpDepartmentService corpDepartmentService = ServiceFactory.getInstance().getOpenService(CorpDepartmentService.class); 35 | List deptList = corpDepartmentService.getDeptList(accessToken, parentDeptId); 36 | return deptList; 37 | } 38 | 39 | 40 | /** 41 | * 删除部门 42 | */ 43 | public static void deleteDepartment(String accessToken, Long id) throws Exception { 44 | CorpDepartmentService corpDepartmentService = ServiceFactory.getInstance().getOpenService(CorpDepartmentService.class); 45 | corpDepartmentService.deptDelete(accessToken, id); 46 | } 47 | 48 | /** 49 | * 更新部门 50 | */ 51 | public static void updateDepartment(String accessToken, long id, String name, 52 | String parentId, String order, Boolean createDeptGroup, 53 | boolean autoAddUser, String deptManagerUseridList, boolean deptHiding, String deptPerimits, 54 | String userPerimits, Boolean outerDept, String outerPermitDepts, 55 | String outerPermitUsers, String orgDeptOwner) throws Exception { 56 | CorpDepartmentService corpDepartmentService = ServiceFactory.getInstance().getOpenService(CorpDepartmentService.class); 57 | corpDepartmentService.deptUpdate(accessToken, id, name, parentId, order, createDeptGroup, 58 | autoAddUser, deptManagerUseridList, deptHiding, deptPerimits, userPerimits, 59 | outerDept, outerPermitDepts, outerPermitUsers, orgDeptOwner); 60 | 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /java-server-todo/src/main/java/com/alibaba/dingtalk/openapi/demo/eventchange/eventChangeHelper.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dingtalk.openapi.demo.eventchange; 2 | 3 | import com.alibaba.dingtalk.openapi.demo.Env; 4 | import com.alibaba.dingtalk.openapi.demo.OApiException; 5 | import com.alibaba.dingtalk.openapi.demo.utils.HttpHelper; 6 | import com.alibaba.fastjson.JSONObject; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * 通讯录回调相关事件 12 | *

13 | * https://open-doc.dingtalk.com/docs/doc.htm?treeId=371&articleId=104975&docType=1 14 | */ 15 | public class eventChangeHelper { 16 | 17 | /** 18 | * 注册事件回调接口 19 | */ 20 | public static String registerEventChange(String accessToken, List callBackTag, String token, String aesKey, String url) throws OApiException { 21 | String signUpUrl = Env.OAPI_HOST + "/call_back/register_call_back?" + 22 | "access_token=" + accessToken; 23 | JSONObject args = new JSONObject(); 24 | args.put("call_back_tag", callBackTag); 25 | args.put("token", token); 26 | args.put("aes_key", aesKey); 27 | args.put("url", url); 28 | 29 | JSONObject response = HttpHelper.httpPost(signUpUrl, args); 30 | if (response.containsKey("errcode")) { 31 | return response.getString("errcode"); 32 | } else { 33 | return null; 34 | } 35 | } 36 | 37 | //查询事件回调接口 38 | public static String getEventChange(String accessToken) throws OApiException { 39 | String url = Env.OAPI_HOST + "/call_back/get_call_back?" + 40 | "access_token=" + accessToken; 41 | JSONObject response = HttpHelper.httpGet(url); 42 | return response.toString(); 43 | } 44 | 45 | //更新事件回调接口 46 | public static String updateEventChange(String accessToken, List callBackTag, String token, String aesKey, String url) throws OApiException { 47 | String signUpUrl = Env.OAPI_HOST + "/call_back/update_call_back?" + 48 | "access_token=" + accessToken; 49 | JSONObject args = new JSONObject(); 50 | args.put("call_back_tag", callBackTag); 51 | args.put("token", token); 52 | args.put("aes_key", aesKey); 53 | args.put("url", url); 54 | 55 | JSONObject response = HttpHelper.httpPost(signUpUrl, args); 56 | if (response.containsKey("errcode")) { 57 | return response.getString("errcode"); 58 | } else { 59 | return null; 60 | } 61 | } 62 | 63 | //删除事件回调接口 64 | public static String deleteEventChange(String accessToken) throws OApiException { 65 | String url = Env.OAPI_HOST + "/call_back/delete_call_back?" + 66 | "access_token=" + accessToken; 67 | JSONObject response = HttpHelper.httpGet(url); 68 | return response.toString(); 69 | } 70 | 71 | 72 | public static String getFailedResult(String accessToken) throws OApiException { 73 | String url = Env.OAPI_HOST + "/call_back/get_call_back_failed_result?" + 74 | "access_token=" + accessToken; 75 | JSONObject response = HttpHelper.httpGet(url); 76 | return response.toString(); 77 | } 78 | 79 | 80 | } 81 | -------------------------------------------------------------------------------- /java-server-todo/src/main/java/com/alibaba/dingtalk/openapi/demo/media/MediaHelper.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dingtalk.openapi.demo.media; 2 | 3 | import com.alibaba.dingtalk.openapi.demo.Env; 4 | import com.alibaba.dingtalk.openapi.demo.utils.HttpHelper; 5 | import com.alibaba.fastjson.JSONObject; 6 | import com.dingtalk.open.client.ServiceFactory; 7 | import com.dingtalk.open.client.api.model.corp.UploadResult; 8 | import com.dingtalk.open.client.api.service.corp.MediaService; 9 | 10 | import java.io.File; 11 | 12 | /** 13 | * 管理多媒体文件 14 | * https://open-doc.dingtalk.com/docs/doc.htm?source=search&treeId=373&articleId=104971&docType=1 15 | */ 16 | public class MediaHelper { 17 | 18 | /** 19 | * 资源文件类型 20 | */ 21 | public static final String TYPE_IMAGE = "image"; 22 | public static final String TYPE_VOICE = "voice"; 23 | public static final String TYPE_VIDEO = "video"; 24 | public static final String TYPE_FILE = "file"; 25 | 26 | 27 | public static class MediaUploadResult { 28 | public String type; 29 | public String media_id; 30 | public String created_at; 31 | } 32 | 33 | /** 34 | * 上传多媒体文件 35 | *

36 | */ 37 | public static UploadResult upload(String accessToken, String type, File file) throws Exception { 38 | 39 | MediaService mediaService = ServiceFactory.getInstance().getOpenService(MediaService.class); 40 | UploadResult uploadResult = mediaService.uploadMediaFile(accessToken, type, file); 41 | return uploadResult; 42 | } 43 | 44 | /** 45 | * 下载多媒体文件,目前sdk没有封装此接口,需要通过HTTP访问 46 | */ 47 | public static void download(String accessToken, String mediaId, String fileDir) throws Exception { 48 | String url = Env.OAPI_HOST + "/media/downloadFile?" + 49 | "access_token=" + accessToken + "&media_id=" + mediaId; 50 | JSONObject response = HttpHelper.downloadMedia(url, fileDir); 51 | System.out.println(response); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /java-server-todo/src/main/java/com/alibaba/dingtalk/openapi/demo/message/ConversationMessageDelivery.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dingtalk.openapi.demo.message; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | 5 | public class ConversationMessageDelivery extends MessageDelivery { 6 | 7 | public String sender; 8 | public String cid; 9 | public String agentid; 10 | 11 | public ConversationMessageDelivery(String sender, String cid, 12 | String agentId) { 13 | this.sender = sender; 14 | this.cid = cid; 15 | this.agentid = agentId; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /java-server-todo/src/main/java/com/alibaba/dingtalk/openapi/demo/message/ImageMessage.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dingtalk.openapi.demo.message; 2 | 3 | 4 | public class ImageMessage extends Message { 5 | 6 | public String media_id; 7 | 8 | public ImageMessage(String mediaId) { 9 | super(); 10 | media_id = mediaId; 11 | } 12 | 13 | @Override 14 | public String type() { 15 | return "image"; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /java-server-todo/src/main/java/com/alibaba/dingtalk/openapi/demo/message/LightAppMessageDelivery.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dingtalk.openapi.demo.message; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | 5 | public class LightAppMessageDelivery extends MessageDelivery { 6 | 7 | public String touser; 8 | public String toparty; 9 | public String agentid; 10 | 11 | public LightAppMessageDelivery(String toUsers, String toParties, String agentId) { 12 | this.touser = toUsers; 13 | this.toparty = toParties; 14 | this.agentid = agentId; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /java-server-todo/src/main/java/com/alibaba/dingtalk/openapi/demo/message/LinkMessage.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dingtalk.openapi.demo.message; 2 | 3 | public class LinkMessage extends Message { 4 | 5 | public String messageUrl; 6 | public String picUrl; 7 | public String title; 8 | public String text; 9 | 10 | public LinkMessage(String messageUrl, String picUrl, String title, String text) { 11 | super(); 12 | this.messageUrl = messageUrl; 13 | this.picUrl = picUrl; 14 | this.title = title; 15 | this.text = text; 16 | } 17 | 18 | @Override 19 | public String type() { 20 | return "link"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /java-server-todo/src/main/java/com/alibaba/dingtalk/openapi/demo/message/Message.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dingtalk.openapi.demo.message; 2 | 3 | 4 | public abstract class Message { 5 | public abstract String type(); 6 | } 7 | -------------------------------------------------------------------------------- /java-server-todo/src/main/java/com/alibaba/dingtalk/openapi/demo/message/MessageDelivery.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dingtalk.openapi.demo.message; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONObject; 5 | import com.dingtalk.open.client.api.model.corp.MessageBody; 6 | 7 | public class MessageDelivery { 8 | 9 | public String msgType; 10 | public MessageBody message; 11 | 12 | public MessageDelivery withMessage(String msgType, MessageBody msg) { 13 | this.msgType = msgType; 14 | this.message = msg; 15 | return this; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /java-server-todo/src/main/java/com/alibaba/dingtalk/openapi/demo/message/MessageHelper.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dingtalk.openapi.demo.message; 2 | 3 | import com.dingtalk.open.client.ServiceFactory; 4 | import com.dingtalk.open.client.api.model.corp.MessageSendResult; 5 | import com.dingtalk.open.client.api.service.corp.MessageService; 6 | 7 | /** 8 | * 发送消息 9 | */ 10 | public class MessageHelper { 11 | 12 | public static class Receipt { 13 | String invaliduser; 14 | String invalidparty; 15 | } 16 | 17 | /** 18 | * 发送普通消息 19 | * 20 | * @param accessToken 21 | * @param delivery 22 | * @return 23 | * @throws Exception 24 | */ 25 | public static Receipt send(String accessToken, LightAppMessageDelivery delivery) 26 | throws Exception { 27 | MessageService messageService = ServiceFactory.getInstance().getOpenService(MessageService.class); 28 | MessageSendResult reulst = messageService.sendToCorpConversation(accessToken, delivery.touser, 29 | delivery.toparty, delivery.agentid, delivery.msgType, delivery.message); 30 | Receipt receipt = new Receipt(); 31 | receipt.invaliduser = reulst.getInvaliduser(); 32 | receipt.invalidparty = reulst.getInvalidparty(); 33 | return receipt; 34 | } 35 | 36 | 37 | public static String send(String accessToken, ConversationMessageDelivery delivery) 38 | throws Exception { 39 | MessageService messageService = ServiceFactory.getInstance().getOpenService(MessageService.class); 40 | return messageService.sendToNormalConversation(accessToken, delivery.sender, 41 | delivery.cid, delivery.msgType, delivery.message); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /java-server-todo/src/main/java/com/alibaba/dingtalk/openapi/demo/message/OAMessage.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dingtalk.openapi.demo.message; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | { 7 | "message_url": "http://dingtalk.com", 8 | "head": { 9 | "bgcolor": "FFCC0000" 10 | }, 11 | "body": { 12 | "title": "标题", 13 | "form": [ 14 | { 15 | "key": "姓名", 16 | "value": "张三" 17 | }, 18 | { 19 | "key": "年龄", 20 | "value": "30" 21 | } 22 | ], 23 | "rich": { 24 | "num": "15.6", 25 | "unit": "元" 26 | }, 27 | "content": "大段文本", 28 | "image": "@lADOAAGXIszazQKA", 29 | "file_count": "3", 30 | "author": "李四" 31 | } 32 | */ 33 | public class OAMessage extends Message { 34 | 35 | public String message_url; 36 | public Head head; 37 | public Body body; 38 | 39 | 40 | @Override 41 | public String type() { 42 | return "oa"; 43 | } 44 | 45 | //content 46 | public static class Head { 47 | public String bgcolor; 48 | } 49 | 50 | public static class Body { 51 | public String title; 52 | public List

form; 53 | public Rich rich; 54 | public String content; 55 | public String image; 56 | public String file_found; 57 | public String author; 58 | 59 | public static class Form { 60 | public String key; 61 | public String value; 62 | } 63 | 64 | public static class Rich { 65 | public String num; 66 | public String unit; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /java-server-todo/src/main/java/com/alibaba/dingtalk/openapi/demo/message/TextMessage.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dingtalk.openapi.demo.message; 2 | 3 | 4 | public class TextMessage extends Message { 5 | 6 | public String content; 7 | 8 | public TextMessage(String content) { 9 | super(); 10 | this.content = content; 11 | } 12 | 13 | @Override 14 | public String type() { 15 | return "text"; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /java-server-todo/src/main/java/com/alibaba/dingtalk/openapi/demo/user/User.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dingtalk.openapi.demo.user; 2 | 3 | import java.util.List; 4 | 5 | import com.alibaba.fastjson.JSONObject; 6 | 7 | public class User { 8 | public String userid; 9 | public String name; 10 | public boolean active; 11 | public String avatar; 12 | public List department; 13 | public String position; 14 | public String mobile; 15 | public String tel; 16 | public String workPlace; 17 | public String remark; 18 | public String email; 19 | public String jobnumber; 20 | public JSONObject extattr; 21 | public boolean isAdmin; 22 | public boolean isBoss; 23 | public String dingId; 24 | 25 | 26 | 27 | public User() { 28 | } 29 | 30 | public User(String userid, String name) { 31 | this.userid = userid; 32 | this.name = name; 33 | } 34 | 35 | @Override 36 | public String toString() { 37 | List users; 38 | return "User[userid:" + userid + ", name:" + name + ", active:" + active + ", " 39 | + "avatar:" + avatar + ", department:" + department + 40 | ", position:" + position + ", mobile:" + mobile + ", email:" + email + 41 | ", extattr:" + extattr; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /java-server-todo/src/main/java/com/alibaba/dingtalk/openapi/demo/utils/aes/DingTalkEncryptException.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dingtalk.openapi.demo.utils.aes; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * 钉钉开放平台加解密异常类 8 | */ 9 | public class DingTalkEncryptException extends Exception { 10 | /**成功**/ 11 | public static final int SUCCESS = 0; 12 | /**加密明文文本非法**/ 13 | public final static int ENCRYPTION_PLAINTEXT_ILLEGAL = 900001; 14 | /**加密时间戳参数非法**/ 15 | public final static int ENCRYPTION_TIMESTAMP_ILLEGAL = 900002; 16 | /**加密随机字符串参数非法**/ 17 | public final static int ENCRYPTION_NONCE_ILLEGAL = 900003; 18 | /**不合法的aeskey**/ 19 | public final static int AES_KEY_ILLEGAL = 900004; 20 | /**签名不匹配**/ 21 | public final static int SIGNATURE_NOT_MATCH = 900005; 22 | /**计算签名错误**/ 23 | public final static int COMPUTE_SIGNATURE_ERROR = 900006; 24 | /**计算加密文字错误**/ 25 | public final static int COMPUTE_ENCRYPT_TEXT_ERROR = 900007; 26 | /**计算解密文字错误**/ 27 | public final static int COMPUTE_DECRYPT_TEXT_ERROR = 900008; 28 | /**计算解密文字长度不匹配**/ 29 | public final static int COMPUTE_DECRYPT_TEXT_LENGTH_ERROR = 900009; 30 | /**计算解密文字corpid不匹配**/ 31 | public final static int COMPUTE_DECRYPT_TEXT_CORPID_ERROR = 900010; 32 | 33 | private static Map msgMap = new HashMap(); 34 | static{ 35 | msgMap.put(SUCCESS,"成功"); 36 | msgMap.put(ENCRYPTION_PLAINTEXT_ILLEGAL,"加密明文文本非法"); 37 | msgMap.put(ENCRYPTION_TIMESTAMP_ILLEGAL,"加密时间戳参数非法"); 38 | msgMap.put(ENCRYPTION_NONCE_ILLEGAL,"加密随机字符串参数非法"); 39 | msgMap.put(SIGNATURE_NOT_MATCH,"签名不匹配"); 40 | msgMap.put(COMPUTE_SIGNATURE_ERROR,"签名计算失败"); 41 | msgMap.put(AES_KEY_ILLEGAL,"不合法的aes key"); 42 | msgMap.put(COMPUTE_ENCRYPT_TEXT_ERROR,"计算加密文字错误"); 43 | msgMap.put(COMPUTE_DECRYPT_TEXT_ERROR,"计算解密文字错误"); 44 | msgMap.put(COMPUTE_DECRYPT_TEXT_LENGTH_ERROR,"计算解密文字长度不匹配"); 45 | msgMap.put(COMPUTE_DECRYPT_TEXT_CORPID_ERROR,"计算解密文字corpid或者suiteKey不匹配"); 46 | } 47 | 48 | public Integer code; 49 | public DingTalkEncryptException(Integer exceptionCode){ 50 | super(msgMap.get(exceptionCode)); 51 | this.code = exceptionCode; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /java-server-todo/src/main/java/com/alibaba/dingtalk/openapi/demo/utils/aes/DingTalkJsApiSingnature.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dingtalk.openapi.demo.utils.aes; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.security.MessageDigest; 5 | import java.security.NoSuchAlgorithmException; 6 | import java.util.Formatter; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | /** 11 | * 钉钉jsapi签名工具类 12 | */ 13 | public class DingTalkJsApiSingnature { 14 | /** 15 | * 获取jsapi签名 16 | * @param url 17 | * @param nonce 18 | * @param timeStamp 19 | * @param jsTicket 20 | * @return 21 | * @throws DingTalkEncryptException 22 | */ 23 | public static String getJsApiSingnature(String url,String nonce,Long timeStamp,String jsTicket) throws DingTalkEncryptException{ 24 | String plainTex = "jsapi_ticket=" + jsTicket +"&noncestr=" + nonce +"×tamp=" + timeStamp + "&url=" + url; 25 | System.out.println(plainTex); 26 | String signature = ""; 27 | try{ 28 | MessageDigest crypt = MessageDigest.getInstance("SHA-1"); 29 | crypt.reset(); 30 | crypt.update(plainTex.getBytes("UTF-8")); 31 | signature = byteToHex(crypt.digest()); 32 | return signature; 33 | }catch (Exception e){ 34 | throw new DingTalkEncryptException(DingTalkEncryptException.COMPUTE_SIGNATURE_ERROR); 35 | } 36 | } 37 | 38 | private static String byteToHex(final byte[] hash) { 39 | Formatter formatter = new Formatter(); 40 | for (byte b : hash){ 41 | formatter.format("%02x", b); 42 | } 43 | String result = formatter.toString(); 44 | formatter.close(); 45 | return result; 46 | } 47 | 48 | 49 | public static void main(String args[]) throws Exception{ 50 | String url="http://10.62.53.138:3000/jsapi"; 51 | String nonce="abcdefgh"; 52 | Long timeStamp = 1437027269927L; 53 | String tikcet="zHoQdGJuH0ZDebwo7sLqLzHGUueLmkWCC4RycYgkuvDu3eoROgN5qhwnQLgfzwEXtuR9SDzh6BdhyVngzAjrxV"; 54 | System.err.println(getJsApiSingnature(url,nonce,timeStamp,tikcet)); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /java-server-todo/src/main/java/com/alibaba/dingtalk/openapi/demo/utils/aes/PKCS7Padding.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dingtalk.openapi.demo.utils.aes; 2 | 3 | import java.nio.charset.Charset; 4 | import java.util.Arrays; 5 | 6 | /* 7 | * PKCS7算法的加密填充 8 | */ 9 | 10 | public class PKCS7Padding { 11 | private final static Charset CHARSET = Charset.forName("utf-8"); 12 | private final static int BLOCK_SIZE = 32; 13 | 14 | /** 15 | * 填充mode字节 16 | * @param count 17 | * @return 18 | */ 19 | public static byte[] getPaddingBytes(int count) { 20 | int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE); 21 | if (amountToPad == 0) { 22 | amountToPad = BLOCK_SIZE; 23 | } 24 | char padChr = chr(amountToPad); 25 | String tmp = new String(); 26 | for (int index = 0; index < amountToPad; index++) { 27 | tmp += padChr; 28 | } 29 | return tmp.getBytes(CHARSET); 30 | } 31 | 32 | /** 33 | * 移除mode填充字节 34 | * @param decrypted 35 | * @return 36 | */ 37 | public static byte[] removePaddingBytes(byte[] decrypted) { 38 | int pad = (int) decrypted[decrypted.length - 1]; 39 | if (pad < 1 || pad > BLOCK_SIZE) { 40 | pad = 0; 41 | } 42 | return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad); 43 | } 44 | 45 | private static char chr(int a) { 46 | byte target = (byte) (a & 0xFF); 47 | return (char) target; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /java-server-todo/src/main/java/com/alibaba/dingtalk/openapi/demo/utils/aes/Utils.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dingtalk.openapi.demo.utils.aes; 2 | 3 | import java.util.Random; 4 | 5 | /** 6 | * 加解密工具类 7 | */ 8 | public class Utils { 9 | 10 | /** 11 | * 获取随机字符串 12 | * 13 | * @return 14 | */ 15 | public static String getRandomStr(int count) { 16 | String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 17 | Random random = new Random(); 18 | StringBuffer sb = new StringBuffer(); 19 | for (int i = 0; i < count; i++) { 20 | int number = random.nextInt(base.length()); 21 | sb.append(base.charAt(number)); 22 | } 23 | return sb.toString(); 24 | } 25 | 26 | 27 | /* 28 | * int转byte数组,高位在前 29 | */ 30 | public static byte[] int2Bytes(int count) { 31 | byte[] byteArr = new byte[4]; 32 | byteArr[3] = (byte) (count & 0xFF); 33 | byteArr[2] = (byte) (count >> 8 & 0xFF); 34 | byteArr[1] = (byte) (count >> 16 & 0xFF); 35 | byteArr[0] = (byte) (count >> 24 & 0xFF); 36 | return byteArr; 37 | } 38 | 39 | /** 40 | * 高位在前bytes数组转int 41 | * 42 | * @param byteArr 43 | * @return 44 | */ 45 | public static int bytes2int(byte[] byteArr) { 46 | int count = 0; 47 | for (int i = 0; i < 4; i++) { 48 | count <<= 8; 49 | count |= byteArr[i] & 0xff; 50 | } 51 | return count; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /java-server-todo/src/main/java/com/alibaba/dingtalk/openapi/servlet/JsAPIServlet.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dingtalk.openapi.servlet; 2 | 3 | import com.alibaba.dingtalk.openapi.demo.auth.AuthHelper; 4 | import com.alibaba.fastjson.JSON; 5 | 6 | import javax.servlet.ServletException; 7 | import javax.servlet.http.HttpServlet; 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | import java.io.IOException; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | /** 15 | * 获取企业应用的jsapi的签名数据 16 | */ 17 | public class JsAPIServlet extends HttpServlet { 18 | 19 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { 20 | 21 | response.setContentType("text/html; charset=utf-8"); 22 | response.setHeader("Access-Control-Allow-Origin", "*"); 23 | 24 | Map config = AuthHelper.getConfig(request); 25 | Map rs = new HashMap<>(); 26 | rs.put("errcode", 0); 27 | rs.putAll(config); 28 | String signConfig = JSON.toJSONString(rs); 29 | System.out.println("JsAPI:" + signConfig); 30 | 31 | response.getWriter().append(signConfig); 32 | } 33 | 34 | 35 | protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 36 | doGet(request, response); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /java-server-todo/src/main/java/com/alibaba/dingtalk/openapi/servlet/UserIdServlet.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dingtalk.openapi.servlet; 2 | 3 | import com.alibaba.dingtalk.openapi.demo.auth.AuthHelper; 4 | import com.alibaba.dingtalk.openapi.demo.user.UserHelper; 5 | import com.alibaba.fastjson.JSON; 6 | import com.dingtalk.open.client.api.model.corp.CorpUserDetail; 7 | import org.apache.commons.lang3.StringUtils; 8 | 9 | import javax.servlet.http.HttpServlet; 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | import java.io.IOException; 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | 16 | /** 17 | * 根据用户id查询用户信息 18 | */ 19 | public class UserIdServlet extends HttpServlet { 20 | 21 | /** 22 | * 根据userId查询用户信息 23 | * 24 | * @param request 25 | * @param response 26 | * @throws IOException 27 | */ 28 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { 29 | Map rs = new HashMap<>(); 30 | String userid = request.getParameter("userid"); 31 | System.out.println("userid:" + userid); 32 | try { 33 | response.setContentType("application/json; charset=utf-8"); 34 | response.setHeader("Access-Control-Allow-Origin", "*"); 35 | 36 | if (StringUtils.isBlank(userid)) { 37 | rs.put("errcode", -1); 38 | String userJson = JSON.toJSONString(rs); 39 | response.getWriter().append(userJson); 40 | return; 41 | } 42 | 43 | String accessToken = AuthHelper.getAccessToken(); 44 | System.out.println("access token:" + accessToken); 45 | CorpUserDetail user = UserHelper.getUser(accessToken, userid); 46 | 47 | if (user != null) { 48 | rs.put("errcode", 0); 49 | // user信息字段写在根字段上 50 | rs.putAll(JSON.parseObject(JSON.toJSONString(user))); 51 | String userJson = JSON.toJSONString(rs); 52 | response.getWriter().append(userJson); 53 | System.out.println("userjson:" + userJson); 54 | return; 55 | } 56 | } catch (Exception e) { 57 | e.printStackTrace(); 58 | } 59 | 60 | rs.put("errcode", -1); 61 | String userJson = JSON.toJSONString(rs); 62 | response.getWriter().append(userJson); 63 | } 64 | 65 | protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { 66 | doGet(request, response); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /java-server-todo/src/main/java/com/alibaba/dingtalk/openapi/servlet/UserInfoServlet.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.dingtalk.openapi.servlet; 2 | 3 | import com.alibaba.dingtalk.openapi.demo.auth.AuthHelper; 4 | import com.alibaba.dingtalk.openapi.demo.user.UserHelper; 5 | import com.alibaba.fastjson.JSON; 6 | import com.dingtalk.open.client.api.model.corp.CorpUserDetail; 7 | import org.apache.commons.lang3.StringUtils; 8 | 9 | import javax.servlet.http.HttpServlet; 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | import java.io.IOException; 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | 16 | /** 17 | * 根据免登授权码查询免登用户信息 18 | */ 19 | public class UserInfoServlet extends HttpServlet { 20 | 21 | 22 | /** 23 | * 根据免登授权码获取免登用户userId 24 | * 25 | * @param request 26 | * @param response 27 | * @throws IOException 28 | */ 29 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { 30 | 31 | Map rs = new HashMap<>(); 32 | // 获取免登授权码 33 | String code = request.getParameter("code"); 34 | System.out.println("authCode:" + code); 35 | try { 36 | response.setContentType("application/json; charset=utf-8"); 37 | response.setHeader("Access-Control-Allow-Origin", "*"); 38 | 39 | // 免登授权码不能为空 40 | if (StringUtils.isBlank(code)) { 41 | rs.put("errcode", -1); 42 | String userJson = JSON.toJSONString(rs); 43 | response.getWriter().append(userJson); 44 | return; 45 | } 46 | 47 | String accessToken = AuthHelper.getAccessToken(); 48 | System.out.println("access token:" + accessToken); 49 | CorpUserDetail user = UserHelper.getUser(accessToken, UserHelper.getUserInfo(accessToken, code).getUserid()); 50 | 51 | rs.put("errcode", 0); 52 | rs.put("userid", user.getUserid()); 53 | String userJson = JSON.toJSONString(rs); 54 | response.getWriter().append(userJson); 55 | System.out.println("userjson:" + userJson); 56 | } catch (Exception e) { 57 | e.printStackTrace(); 58 | rs.put("errcode", -1); 59 | String userJson = JSON.toJSONString(rs); 60 | response.getWriter().append(userJson); 61 | } 62 | } 63 | 64 | protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { 65 | doGet(request, response); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /java-server-todo/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | UserInfoServlet 7 | com.alibaba.dingtalk.openapi.servlet.UserInfoServlet 8 | 9 | 10 | JsAPIServlet 11 | com.alibaba.dingtalk.openapi.servlet.JsAPIServlet 12 | 13 | 14 | UserIdServlet 15 | com.alibaba.dingtalk.openapi.servlet.UserIdServlet 16 | 17 | 18 | ContactsServlet 19 | com.alibaba.dingtalk.openapi.servlet.ContactsServlet 20 | 21 | 22 | EventChangeReceiveServlet 23 | com.alibaba.dingtalk.openapi.servlet.EventChangeReceiveServlet 24 | 25 | 26 | UserInfoServlet 27 | /api/get-user-info 28 | 29 | 30 | JsAPIServlet 31 | /api/jsapi-oauth 32 | 33 | 34 | UserIdServlet 35 | /api/get 36 | 37 | 38 | ContactsServlet 39 | /contactsinfo 40 | 41 | 42 | EventChangeReceiveServlet 43 | /eventreceive 44 | 45 | -------------------------------------------------------------------------------- /jquery-fed-oapage/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | -------------------------------------------------------------------------------- /jquery-fed-oapage/README.md: -------------------------------------------------------------------------------- 1 | # 企业定制首页 2 | 3 | > A jQuery project 4 | 5 | [自定义企业首页文档](https://yq.aliyun.com/articles/71162?spm=5176.8091938.0.0.LLs5na) 6 | 7 | ![](https://gw.alicdn.com/tps/TB1T.XwPVXXXXX7XpXXXXXXXXXX-720-1280.jpg) 8 | 9 | ``` bash 10 | python -m SimpleHTTPServer 8089 11 | ``` 12 | 13 | 在你的终端运行这个启动一个临时服务器,访问这个地址,来查看。或者你也可以将jquery目录下的文件放置到你自己的服务器中。 14 | -------------------------------------------------------------------------------- /jquery-fed-oapage/info.text: -------------------------------------------------------------------------------- 1 | dependencies nodejs-server-todo -------------------------------------------------------------------------------- /jquery-fed-oapage/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-fed-oapage", 3 | "version": "1.0.0", 4 | "description": "A jQuery project", 5 | "author": "icepy ", 6 | "private": true 7 | } 8 | -------------------------------------------------------------------------------- /nodejs-server-todo/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | .idea 40 | -------------------------------------------------------------------------------- /nodejs-server-todo/app/api/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by xiangwenwen on 2017/2/16. 3 | */ 4 | 5 | const router = require('koa-router')(); 6 | const jsapiOAuth = require('../controller/OAuth'); 7 | const getUserInfo = require('../controller/getUserInfo'); 8 | const get = require('../controller/get'); 9 | const microApps = require('../controller/microapps'); 10 | 11 | router.prefix('/api'); 12 | router.get('/jsapi-oauth',jsapiOAuth); 13 | router.get('/get-user-info',getUserInfo); 14 | router.get('/get',get); 15 | router.get('/get-microapp-list',microApps); 16 | 17 | module.exports = router; 18 | -------------------------------------------------------------------------------- /nodejs-server-todo/app/controller/OAuth/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by xiangwenwen on 2017/2/16. 3 | */ 4 | 5 | const crypto = require('crypto'); 6 | const querystring = require('querystring'); 7 | const url = require('url'); 8 | const logger = require('../../logger'); 9 | const env = require('../../env'); 10 | const getAccessToken = require('../../request/getAccessToken'); 11 | const getJsApiTicket = require('../../request/getJsApiTicket'); 12 | const CorpID = env.CorpID; 13 | 14 | /* 15 | * 16 | * 根据jsapiTicket生成签名,返回给前端 17 | * */ 18 | function signature(params) { 19 | const origUrl = params.signedUrl; 20 | let origUrlObj = url.parse(origUrl); 21 | delete origUrlObj['hash']; 22 | const newUrl = url.format(origUrlObj); 23 | logger.info('newUrl:' + newUrl); 24 | const plain = 'jsapi_ticket=' + params.ticket + 25 | '&noncestr=' + params.nonceStr + 26 | '×tamp=' + params.timeStamp + 27 | '&url=' + newUrl; 28 | logger.info('signa plain:',plain); 29 | const sha1 = crypto.createHash('sha1'); 30 | sha1.update(plain, 'utf8'); 31 | const signature = sha1.digest('hex'); 32 | logger.info('signature:' + signature); 33 | return signature; 34 | } 35 | 36 | /* 37 | * 38 | * js-api权限校验入口 39 | * */ 40 | function *jsApiOAuth(next) { 41 | const nonceStr = 'icepy'; 42 | const timeStamp = new Date().getTime(); 43 | const href = querystring.parse(this.querystring).href; 44 | const signedUrl = decodeURIComponent(href); 45 | this.set('Access-Control-Allow-Origin','*'); 46 | // 获取token 47 | const accessTokenResponse = yield getAccessToken(); 48 | if (accessTokenResponse.errcode !== 0){ 49 | this.body = { 50 | errcode: 101, 51 | errmsg: accessTokenResponse.errmsg 52 | }; 53 | return; 54 | } 55 | //获取ticket 56 | const jsapiTicketResponse = yield getJsApiTicket(accessTokenResponse.access_token); 57 | if (jsapiTicketResponse.errcode !== 0){ 58 | this.body = { 59 | errcode: 102, 60 | errmsg: jsapiTicketResponse.errmsg 61 | }; 62 | return; 63 | } 64 | logger.info('ticket:' + jsapiTicketResponse.ticket); 65 | //签名 66 | const sign = signature({ 67 | nonceStr: nonceStr, 68 | timeStamp: timeStamp, 69 | signedUrl: signedUrl, 70 | ticket: jsapiTicketResponse.ticket 71 | }); 72 | this.body = { 73 | // agentId: '76853717', 74 | signature: sign, 75 | nonceStr: nonceStr, 76 | timeStamp: timeStamp, 77 | corpId: CorpID, 78 | errcode: 0 79 | }; 80 | } 81 | 82 | module.exports = jsApiOAuth; -------------------------------------------------------------------------------- /nodejs-server-todo/app/controller/get/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by xiangwenwen on 2017/2/17. 3 | */ 4 | 5 | const querystring = require('querystring'); 6 | const url = require('url'); 7 | const axios = require('axios'); 8 | const logger = require('../../logger'); 9 | const env = require('../../env'); 10 | const getAccessToken = require('../../request/getAccessToken'); 11 | const OAPI_HOST = env.OAPI_HOST[env.scheme]; 12 | 13 | 14 | function *get(){ 15 | this.set('Access-Control-Allow-Origin','*'); 16 | const accessTokenResponse = yield getAccessToken(); 17 | if (accessTokenResponse.errcode !== 0){ 18 | this.body = { 19 | errcode: 101, 20 | errmsg: accessTokenResponse.errmsg 21 | }; 22 | return; 23 | } 24 | const userid = querystring.parse(url.parse(this.url).query).userid; 25 | logger.log('warn','userid:',userid); 26 | if (!userid){ 27 | this.body = { 28 | errcode: 102, 29 | errmsg: 'userid is empty' 30 | }; 31 | return; 32 | } 33 | const getRequest = { 34 | url: OAPI_HOST + '/user/get', 35 | params: { 36 | access_token: accessTokenResponse.access_token, 37 | userid: userid 38 | } 39 | }; 40 | const getResponse = yield axios(getRequest).then(function(response){ 41 | return response.data; 42 | }).catch(function(err){ 43 | logger.log('error','get request bad'); 44 | return { 45 | errcode: 500, 46 | errmsg: 'get request bad', 47 | error: err 48 | } 49 | }); 50 | if (getResponse.errcode !== 0){ 51 | this.body = { 52 | errcode: 103, 53 | errmsg: getResponse.errmsg 54 | }; 55 | } else { 56 | this.body = getResponse; 57 | } 58 | } 59 | 60 | module.exports = get; 61 | -------------------------------------------------------------------------------- /nodejs-server-todo/app/controller/getUserInfo/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by xiangwenwen on 2017/2/17. 3 | */ 4 | 5 | const querystring = require('querystring'); 6 | const url = require('url'); 7 | const axios = require('axios'); 8 | const logger = require('../../logger'); 9 | const env = require('../../env'); 10 | const getAccessToken = require('../../request/getAccessToken'); 11 | const OAPI_HOST = env.OAPI_HOST[env.scheme]; 12 | 13 | function *getuserinfo(){ 14 | this.set('Access-Control-Allow-Origin','*'); 15 | const accessTokenResponse = yield getAccessToken(); 16 | if (accessTokenResponse.errcode !== 0){ 17 | this.body = { 18 | errcode: 101, 19 | errmsg: accessTokenResponse.errmsg 20 | }; 21 | return; 22 | } 23 | const code = querystring.parse(url.parse(this.url).query).code; 24 | logger.log('warn','code:',code); 25 | if(!code){ 26 | this.body = { 27 | errcode: 102, 28 | errmsg: 'code is empty' 29 | }; 30 | return; 31 | } 32 | const getUserInfoRequest = { 33 | url: OAPI_HOST + '/user/getuserinfo', 34 | params: { 35 | access_token: accessTokenResponse.access_token, 36 | code: code 37 | } 38 | }; 39 | const getUserInfoResponse = yield axios(getUserInfoRequest).then(function(response){ 40 | return response.data; 41 | }).catch(function(err){ 42 | logger.log('error','get micro apps request bad'); 43 | return { 44 | errcode: 500, 45 | errmsg: 'getuserinfo request bad', 46 | error: err 47 | } 48 | }); 49 | 50 | if (getUserInfoResponse.errcode !== 0){ 51 | this.body = { 52 | errcode: 103, 53 | errmsg: getUserInfoResponse.errmsg 54 | }; 55 | } else { 56 | this.body = getUserInfoResponse; 57 | } 58 | } 59 | 60 | module.exports = getuserinfo; 61 | -------------------------------------------------------------------------------- /nodejs-server-todo/app/controller/microapps/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by xiangwenwen on 2017/10/2. 3 | */ 4 | 5 | const axios = require('axios'); 6 | const getAccessToken = require('../../request/getAccessToken'); 7 | const env = require('../../env'); 8 | const logger = require('../../logger'); 9 | const OAPI_HOST = env.OAPI_HOST[env.scheme]; 10 | 11 | function *getMicroApps() { 12 | if (!TokenCache){ 13 | const accessTokenResponse = yield getAccessToken(); 14 | if (accessTokenResponse.errcode !== 0){ 15 | this.body = { 16 | errcode: 101, 17 | errmsg: accessTokenResponse.errmsg 18 | }; 19 | return; 20 | } 21 | } 22 | 23 | const microAppsRequest = { 24 | url: OAPI_HOST + '/microapp/get_microapp_list', 25 | params: { 26 | access_token: TokenCache 27 | } 28 | }; 29 | 30 | const microAppsResponse = yield axios(microAppsRequest).then(function (response) { 31 | return response.data; 32 | }).catch(function(err){ 33 | logger.log('error','get micro apps request bad'); 34 | return { 35 | errcode: 500, 36 | errmsg: 'micro apps request bad', 37 | error: err 38 | } 39 | }); 40 | this.set('Access-Control-Allow-Origin','*'); 41 | if (microAppsResponse.errcode !== 0){ 42 | this.body = { 43 | errcode: 102, 44 | errmsg: microAppsResponse.errmsg 45 | }; 46 | } else { 47 | this.body = microAppsResponse; 48 | } 49 | } 50 | 51 | module.exports = getMicroApps; -------------------------------------------------------------------------------- /nodejs-server-todo/app/env.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by xiangwenwen on 2017/2/16. 3 | */ 4 | 5 | const config = { 6 | scheme: 'release', 7 | connect: { 8 | beta: 'mongodb://127.0.0.1:27017/tokentable', 9 | release: 'mongodb://127.0.0.1:27017/tokentable' 10 | }, 11 | CorpID: '', 12 | CorpSecret: '', 13 | OAPI_HOST: { 14 | release: 'https://oapi.dingtalk.com' 15 | } 16 | }; 17 | 18 | if (process.env.NODE_ENV !== 'product') { 19 | config.scheme = 'release'; 20 | } 21 | 22 | module.exports = config; 23 | -------------------------------------------------------------------------------- /nodejs-server-todo/app/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by xiangwenwen on 2017/2/15. 3 | */ 4 | 5 | const koa = require('koa'); 6 | const koaLogger = require('koa-logger'); 7 | const onerror = require('koa-onerror'); 8 | const bodyParser = require('koa-body-parser'); 9 | const apis = require('./api'); 10 | const helper = require('./middleware/helper'); 11 | const app = koa(); 12 | 13 | global.PORT = 3000; 14 | global.TicketCacheMap = []; 15 | global.TokenCache = {}; 16 | app.env = process.env.NODE_ENV || 'development'; 17 | if (app.env === 'development') { 18 | app.use(koaLogger()); 19 | app.use(helper()); 20 | } 21 | onerror(app); 22 | app.use(bodyParser()); 23 | app.use(apis.routes()); 24 | app.use(apis.allowedMethods()); 25 | app.listen(PORT); 26 | -------------------------------------------------------------------------------- /nodejs-server-todo/app/middleware/helper.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by xiangwenwen on 2017/2/16. 3 | */ 4 | 5 | const os = require('os'); 6 | const querystring = require('querystring'); 7 | const url = require('url'); 8 | const logger = require('../logger'); 9 | 10 | function helper(){ 11 | let IPv4; 12 | let i = 0; 13 | try { 14 | for(;i (200*100)){ 50 | logger.log('info','cache access_token' + JSON.stringify(TokenCache)) 51 | return { 52 | 'access_token':TokenCache.access_token, 53 | errcode: 0 54 | } 55 | } else { 56 | return sendTokenRequest(); 57 | } 58 | } 59 | return sendTokenRequest(); 60 | } 61 | 62 | module.exports = getAccessToken; 63 | -------------------------------------------------------------------------------- /nodejs-server-todo/app/request/getJsApiTicket.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by xiangwenwen on 2017/2/17. 3 | */ 4 | 5 | const axios = require('axios'); 6 | const logger = require('../logger'); 7 | const env = require('../env'); 8 | const OAPI_HOST = env.OAPI_HOST[env.scheme]; 9 | 10 | function *getJsApiTicket(access_token) { 11 | const cacheTime = 7000 * 1000; //缓存时间 12 | const currentTime = new Date().getTime(); //获取当前时间 13 | const futureTime = currentTime + cacheTime; //未来过期时间 14 | const ticket = TicketCacheMap[0]; 15 | const sendTicketRequest = function(){ 16 | const jsApiTicketRequest = { 17 | url: OAPI_HOST + '/get_jsapi_ticket', 18 | method: 'get', 19 | params: { 20 | access_token: access_token 21 | } 22 | }; 23 | return axios(jsApiTicketRequest).then(function (response) { 24 | const data = response.data; 25 | if (data.errcode !== 0){ 26 | return data; 27 | } else { 28 | TicketCacheMap.length = 0; 29 | TicketCacheMap.push({ 30 | timestamp: futureTime, 31 | ticket: data.ticket, 32 | errcode: 0 33 | }); 34 | return data; 35 | } 36 | }).catch(function (err) { 37 | logger.log('error','get js api ticket request error'); 38 | return { 39 | errcode: 500, 40 | errmsg: 'ticket request bad', 41 | error: err 42 | } 43 | }); 44 | }; 45 | if (ticket){ 46 | /* 47 | * 缓存的时间 - 当前的时间,如果还大于 (200*100) 表示有效期还存在,返回缓存 48 | * 49 | * */ 50 | if((ticket.timestamp - currentTime) > (200*100)){ 51 | return { 52 | ticket: ticket, 53 | errcode: 0 54 | } 55 | } else { 56 | logger.log('warn', 'ticket cache overdue'); 57 | return sendTicketRequest(); 58 | } 59 | } 60 | logger.log('warn', 'ticket cache empty'); 61 | return sendTicketRequest(); 62 | } 63 | 64 | module.exports = getJsApiTicket; 65 | -------------------------------------------------------------------------------- /nodejs-server-todo/info.text: -------------------------------------------------------------------------------- 1 | dependencies none -------------------------------------------------------------------------------- /nodejs-server-todo/nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "restartable": "rs", 3 | "ignore": [ 4 | ".git", 5 | "node_modules/**/node_modules", 6 | "app/test" 7 | ], 8 | "verbose": true, 9 | "execMap": { 10 | "js": "node --harmony" 11 | }, 12 | "env": { 13 | "NODE_ENV": "development" 14 | }, 15 | "events": { 16 | "restart": "osascript -e 'display notification \"App restarted due to:\n'$FILENAME'\" with title \"nodemon\"'" 17 | }, 18 | "watch": [ 19 | "app/" 20 | ], 21 | "ext": "js json", 22 | "colous": true 23 | } 24 | -------------------------------------------------------------------------------- /nodejs-server-todo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodejs-server-todo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "./app/index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "serve": "nodemon" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "" 13 | }, 14 | "author": "icepy", 15 | "license": "MIT", 16 | "devDependencies": { 17 | "stack-trace": "^0.0.9", 18 | "winston": "^2.3.1", 19 | "winston-daily-rotate-file": "^1.4.4" 20 | }, 21 | "dependencies": { 22 | "axios": "^0.15.3", 23 | "koa": "^1.2.5", 24 | "koa-body-parser": "^1.1.2", 25 | "koa-logger": "^1.3.1", 26 | "koa-onerror": "^3.0.2", 27 | "koa-router": "^5.4.0", 28 | "moment": "^2.17.1" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /react-fed-oapage/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets":["react","stage-0"] 3 | } -------------------------------------------------------------------------------- /react-fed-oapage/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | -------------------------------------------------------------------------------- /react-fed-oapage/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-dingtalk/which-language-demo/beec798dff6eab38dec5b2c9c93434a6ffabed03/react-fed-oapage/README.md -------------------------------------------------------------------------------- /react-fed-oapage/build/build-server.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const chalk = require('chalk'); 3 | const WebpackDevServer = require('webpack-dev-server'); 4 | const webpackConfig = require('./webpack.dev'); 5 | 6 | const compiler = webpack(webpackConfig); 7 | 8 | const server = new WebpackDevServer(compiler, { 9 | stats: { 10 | colors: true 11 | }, 12 | hot: true 13 | }); 14 | 15 | server.listen(8080, "127.0.0.1", function() { 16 | console.log("Starting server on http://127.0.0.1:8080"); 17 | }); -------------------------------------------------------------------------------- /react-fed-oapage/build/build.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-dingtalk/which-language-demo/beec798dff6eab38dec5b2c9c93434a6ffabed03/react-fed-oapage/build/build.js -------------------------------------------------------------------------------- /react-fed-oapage/build/webpack.base.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const autoprefixer = require('autoprefixer'); 3 | 4 | function resolve(dir){ 5 | return path.join(__dirname,'..',dir) 6 | } 7 | 8 | let config = { 9 | entry: { 10 | app: './src/app.js', 11 | vendor: ['react','react-dom','react-router-dom','redux','history','react-redux','react-router-redux','redux-thunk'] 12 | }, 13 | output: { 14 | filename: '[name].js', 15 | path: resolve('dist') 16 | }, 17 | devtool: "source-map", 18 | module: { 19 | rules: [ 20 | { 21 | test: /\.js$/, 22 | exclude: /node_modules/, 23 | use: ['babel-loader'], 24 | include: path.join(__dirname, '../src') 25 | }, 26 | { 27 | test: /\.jsx$/, 28 | exclude: /node_modules/, 29 | use: ['babel-loader'], 30 | include: path.join(__dirname, '../src') 31 | }, 32 | { 33 | test: /\.scss$/, 34 | use: [ 35 | { 36 | loader: 'style-loader' 37 | }, 38 | { 39 | loader: 'css-loader', 40 | options: { 41 | modules: true, 42 | importLoaders: 1, 43 | localIdentName: '[name]__[local]___[hash:base64:5]', 44 | } 45 | }, 46 | { 47 | loader: 'postcss-loader', 48 | options: { 49 | plugins: [autoprefixer({ 50 | remove: false, 51 | browsers: ['last 2 versions', 'ie > 8', 'safari > 7'], 52 | })], 53 | sourceMap: 'inline' 54 | } 55 | }, 56 | { 57 | loader: 'sass-loader', 58 | options: { 59 | sourceMap: true, 60 | } 61 | } 62 | ] 63 | }, 64 | { 65 | test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, 66 | loader: 'file-loader', 67 | }, 68 | { 69 | test: /\.woff2?(\?v=\d+\.\d+\.\d+)?$/, 70 | loader: 'url-loader?limit=10000&minetype=application/font-woff', 71 | }, 72 | { 73 | test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, 74 | loader: 'url-loader?limit=10000&minetype=application/octet-stream', 75 | }, 76 | { 77 | test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, 78 | loader: 'url-loader?limit=10000&minetype=image/svg+xml', 79 | }, 80 | { 81 | test: /\.(jpe?g|png|gif|svg)$/i, 82 | loaders: ['url-loader?limit=8192'], 83 | exclude: /node_modules/, 84 | } 85 | ] 86 | }, 87 | resolve: { 88 | modules: [ 89 | 'node_modules', 90 | path.resolve(__dirname, '../node_modules'), 91 | path.resolve(__dirname, '../src'), 92 | ], 93 | extensions: ['.js','.json','.jsx','.css'] 94 | } 95 | }; 96 | 97 | module.exports = config; -------------------------------------------------------------------------------- /react-fed-oapage/build/webpack.dev.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | const base = require('./webpack.base'); 4 | const config = require('../config'); 5 | 6 | process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV); 7 | 8 | const env = process.env.NODE_ENV; 9 | 10 | let devConfig 11 | 12 | if (env === 'development'){ 13 | devConfig = Object.assign(base,{ 14 | plugins: [ 15 | new webpack.optimize.CommonsChunkPlugin({ 16 | names: ['vendor','manifest'] 17 | }), 18 | new webpack.HotModuleReplacementPlugin() 19 | ] 20 | }); 21 | devConfig.module.rules.push( 22 | { 23 | test: /\.css$/, 24 | use: ['style-loader','css-loader'] 25 | } 26 | ); 27 | devConfig.output.publicPath = 'http://127.0.0.1:8080/'; 28 | devConfig.entry = Object.assign({ 29 | index: [ 30 | 'webpack-dev-server/client?http://127.0.0.1:8080/', 31 | 'webpack/hot/dev-server' 32 | ] 33 | },devConfig.entry); 34 | } 35 | 36 | module.exports = devConfig; -------------------------------------------------------------------------------- /react-fed-oapage/build/webpack.prod.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-dingtalk/which-language-demo/beec798dff6eab38dec5b2c9c93434a6ffabed03/react-fed-oapage/build/webpack.prod.js -------------------------------------------------------------------------------- /react-fed-oapage/config/dev.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: '"development"' 3 | } -------------------------------------------------------------------------------- /react-fed-oapage/config/index.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | module.exports = { 4 | build: { 5 | env: require('./prod.env'), 6 | index: path.resolve(__dirname, '../dist/index.html'), 7 | assetsRoot: path.resolve(__dirname, '../dist'), 8 | assetsSubDirectory: 'static', 9 | assetsPublicPath: '/', 10 | productionSourceMap: true, 11 | productionGzip: false, 12 | productionGzipExtensions: ['js', 'css'], 13 | bundleAnalyzerReport: process.env.npm_config_report 14 | }, 15 | dev: { 16 | env: require('./dev.env'), 17 | port: 8080, 18 | autoOpenBrowser: true, 19 | assetsSubDirectory: 'static', 20 | assetsPublicPath: '/', 21 | proxyTable: {}, 22 | cssSourceMap: false 23 | } 24 | } -------------------------------------------------------------------------------- /react-fed-oapage/config/prod.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: '"production"' 3 | } -------------------------------------------------------------------------------- /react-fed-oapage/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /react-fed-oapage/info.text: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-dingtalk/which-language-demo/beec798dff6eab38dec5b2c9c93434a6ffabed03/react-fed-oapage/info.text -------------------------------------------------------------------------------- /react-fed-oapage/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-fed-oapage", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node ./build/build-server.js", 9 | "build": "node ./build/build.js" 10 | }, 11 | "keywords": [], 12 | "author": "icepy", 13 | "license": "MIT", 14 | "devDependencies": { 15 | "autoprefixer": "^7.1.4", 16 | "babel-core": "^6.26.0", 17 | "babel-loader": "^7.1.2", 18 | "babel-preset-env": "^1.6.0", 19 | "babel-preset-react": "^6.24.1", 20 | "babel-preset-stage-0": "^6.24.1", 21 | "chalk": "^2.1.0", 22 | "css-loader": "^0.28.7", 23 | "file-loader": "^1.1.5", 24 | "node-sass": "^4.5.3", 25 | "postcss-loader": "^2.0.6", 26 | "sass-loader": "^6.0.6", 27 | "style-loader": "^0.19.0", 28 | "url-loader": "^0.6.2", 29 | "webpack": "^3.6.0", 30 | "webpack-dev-server": "^2.9.1" 31 | }, 32 | "dependencies": { 33 | "axios": "^0.16.2", 34 | "classnames": "^2.2.5", 35 | "dingtalk-javascript-sdk": "^0.1.5", 36 | "dingtalk-javascript-utility": "^0.1.5", 37 | "history": "^4.7.2", 38 | "prop-types": "^15.6.0", 39 | "react": "^16.0.0", 40 | "react-dom": "^16.0.0", 41 | "react-redux": "^5.0.6", 42 | "react-router-dom": "^4.2.2", 43 | "react-router-redux": "^5.0.0-alpha.6", 44 | "redux": "^3.7.2", 45 | "redux-thunk": "^2.2.0" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /react-fed-oapage/src/app.js: -------------------------------------------------------------------------------- 1 | import './common/normalize.css'; 2 | import styles from './app.scss'; 3 | import React from 'react'; 4 | import ReactDOM from 'react-dom'; 5 | import { Route } from 'react-router-dom'; 6 | import createHistory from 'history/createBrowserHistory'; 7 | import { Provider } from 'react-redux'; 8 | import { ConnectedRouter } from 'react-router-redux'; 9 | import configureStore from './store/configureStore'; 10 | import routes from './containers/index'; 11 | import classnames from 'classnames/bind'; 12 | 13 | const cx = classnames.bind(styles); 14 | 15 | const history = createHistory(); 16 | const store = configureStore({},history); 17 | const { loadHomeView } = routes; 18 | 19 | ReactDOM.render( 20 | 21 | 22 |
23 | 24 |
25 |
26 |
, 27 | document.getElementById('root') 28 | ) -------------------------------------------------------------------------------- /react-fed-oapage/src/app.scss: -------------------------------------------------------------------------------- 1 | body { 2 | font-size: 14px; 3 | color: #333; 4 | background-color: #eee; 5 | } 6 | 7 | h1{ 8 | margin: 0px; 9 | padding: 0px; 10 | } 11 | 12 | .app-container{ 13 | width: 100%; 14 | height: 100%; 15 | overflow: hidden; 16 | overflow-y: scroll; 17 | } -------------------------------------------------------------------------------- /react-fed-oapage/src/common/env.js: -------------------------------------------------------------------------------- 1 | export const OPENAPIHOST = ''; 2 | export const HASCONSOLE = typeof console !== undefined; 3 | export const ISBROWSER = typeof window !== 'undefined' && typeof window === 'object'; 4 | export const UA = ISBROWSER && window.navigator.userAgent.toLowerCase(); -------------------------------------------------------------------------------- /react-fed-oapage/src/common/logger.js: -------------------------------------------------------------------------------- 1 | import { HASCONSOLE } from './env'; 2 | 3 | const logger = { 4 | warn: function (msg, e){ 5 | if (HASCONSOLE) { 6 | console.warn('[DING WEB SDK Warning]:', msg); 7 | if (e) { 8 | throw e; 9 | } else { 10 | const warning = new Error('WARNING STACK TRACE'); 11 | console.warn(warning.stack); 12 | } 13 | } 14 | }, 15 | info: function (msg){ 16 | if (HASCONSOLE) { 17 | console.info('[DING WEB SDK INFO]:', msg); 18 | } 19 | }, 20 | error: function (msg){ 21 | if (HASCONSOLE){ 22 | console.error('[DING WEB SDK ERROR]:', msg); 23 | } 24 | } 25 | }; 26 | 27 | if (process.env.NODE_ENV !== 'production') { 28 | 29 | } 30 | 31 | export default logger; -------------------------------------------------------------------------------- /react-fed-oapage/src/containers/Home/HomeView.jsx: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { connect } from 'react-redux'; 4 | import * as actions from './flow/homeActions.js'; 5 | import styles from './HomeView.scss'; 6 | import classnames from 'classnames/bind'; 7 | import Banner from './components/Banner'; 8 | import Admin from './components/Admin'; 9 | import Manager from './components/Manager'; 10 | import AllAppList from './components/AllAppList'; 11 | import UserList from './components/UserList'; 12 | 13 | const cx = classnames.bind(styles); 14 | 15 | const defaultProps = { 16 | home: { 17 | name: '', 18 | asyncName: '', 19 | userInfo: {} 20 | } 21 | }; 22 | 23 | const propTypes = { 24 | home: PropTypes.object 25 | }; 26 | 27 | class HomeView extends PureComponent{ 28 | 29 | constructor(props){ 30 | super(props); 31 | console.log(this) 32 | } 33 | 34 | componentWillReceiveProps(nextProps){ 35 | 36 | } 37 | 38 | componentDidMount(){ 39 | this.props.getDefault({'name':'wower'}); 40 | this.props.getAsyncDefault({'name':'icepy'}); 41 | this.props.fetchJSAPIOAuth(); 42 | this.props.fetchUserInfo(); 43 | } 44 | 45 | render(){ 46 | const { name,asyncName,userInfo } = this.props.home; 47 | return ( 48 |
49 | 50 | 51 | 52 | 53 | 54 |
55 | ) 56 | } 57 | } 58 | 59 | HomeView.propTypes = propTypes; 60 | HomeView.defaultProps = defaultProps; 61 | 62 | const mapState = ({ home }) => { 63 | return { 64 | home 65 | } 66 | } 67 | 68 | export default connect(mapState,actions)(HomeView); -------------------------------------------------------------------------------- /react-fed-oapage/src/containers/Home/HomeView.scss: -------------------------------------------------------------------------------- 1 | .icepy{ 2 | width: 100%; 3 | } -------------------------------------------------------------------------------- /react-fed-oapage/src/containers/Home/components/Admin/Admin.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './Admin.scss'; 3 | import classnames from 'classnames/bind'; 4 | 5 | const cx = classnames.bind(styles); 6 | 7 | class Admin extends React.Component{ 8 | constructor(props){ 9 | super(props) 10 | } 11 | 12 | updateName(){ 13 | const dateTime = new Date().getHours(); 14 | const { name, isAdmin } = this.props.userInfo; 15 | if(name){ 16 | if (dateTime >= 5 && dateTime <= 12) { 17 | return { 18 | wh: isAdmin ? '早上好,管理员,' + name : '早上好,' + name, 19 | whImage: 'https://gw.alicdn.com/tps/TB1ubtjOFXXXXbzXpXXXXXXXXXX-36-36.jpg' 20 | } 21 | } else if (dateTime > 12 && dateTime <= 18) { 22 | return { 23 | wh: isAdmin ? '下午好,管理员,' + name : '下午好,' + name, 24 | whImage: 'https://gw.alicdn.com/tps/TB1ubtjOFXXXXbzXpXXXXXXXXXX-36-36.jpg' 25 | } 26 | } else { 27 | return { 28 | wh: isAdmin ? '晚上好,管理员,' + name : '晚上好,' + name, 29 | whImage: 'https://gw.alicdn.com/tps/TB15FNwOFXXXXbqXXXXXXXXXXXX-36-36.jpg' 30 | } 31 | } 32 | } else { 33 | return {}; 34 | } 35 | } 36 | 37 | render(){ 38 | const infos = this.updateName(); 39 | const { wh, whImage } = infos; 40 | return( 41 |
42 |
43 |
44 | 45 |
46 | { wh } 47 |
48 |
49 |
编辑分组
50 |
51 |
52 | ) 53 | } 54 | } 55 | 56 | export default Admin; -------------------------------------------------------------------------------- /react-fed-oapage/src/containers/Home/components/Admin/Admin.scss: -------------------------------------------------------------------------------- 1 | .index-admin{ 2 | width: 100%; 3 | height: 44px; 4 | background-color: #fff; 5 | border-top-color: #e4e4e4; 6 | border-top-style: solid; 7 | border-top-width: 1px; 8 | border-bottom-color: #e4e4e4; 9 | border-bottom-style: solid; 10 | border-bottom-width: 1px; 11 | } 12 | .admin{ 13 | position: relative; 14 | padding-left: 12.5px; 15 | padding-right: 12.5px; 16 | height: 44px; 17 | } 18 | .admin-image{ 19 | width: 16.5px; 20 | height: 16.5px; 21 | position: absolute; 22 | top:12.5px; 23 | } 24 | .admin-hello{ 25 | font-size: 17px; 26 | color: #999; 27 | float: left; 28 | padding-left: 26px; 29 | padding-top: 10.5px; 30 | } 31 | .admin-edit{ 32 | font-size: 17px; 33 | color: #38ADFF; 34 | position: absolute; 35 | right: 12px; 36 | top: 10.5px; 37 | } -------------------------------------------------------------------------------- /react-fed-oapage/src/containers/Home/components/Admin/index.js: -------------------------------------------------------------------------------- 1 | import Admin from './Admin.jsx'; 2 | 3 | export default Admin; -------------------------------------------------------------------------------- /react-fed-oapage/src/containers/Home/components/AllAppList/ALLAPPLISTMOCKDATA.jsx: -------------------------------------------------------------------------------- 1 | 2 | export const data = [ 3 | { 4 | id: 1, 5 | name: '签到', 6 | icon: 'http://static.dingtalk.com/media/lALOcrvqOszIzMg_200_200.png' 7 | }, 8 | { 9 | id:2, 10 | name: '考勤打卡', 11 | icon: 'http://static.dingtalk.com/media/lALOcsYpu8zIzMg_200_200.png' 12 | }, 13 | { 14 | id:3, 15 | name: '日志', 16 | icon: 'http://static.dingtalk.com/media/lALOcsZGkszIzMg_200_200.png' 17 | }, 18 | { 19 | id:4, 20 | name: '公告', 21 | icon: 'http://static.dingtalk.com/media/lALOcsZHFszIzMg_200_200.png' 22 | }, 23 | { 24 | id:5, 25 | name: '审批', 26 | icon: 'http://static.dingtalk.com/media/lALOcsZGQszIzMg_200_200.png' 27 | }, 28 | { 29 | id:6, 30 | name: '钉邮', 31 | icon: 'http://static.dingtalk.com/media/lALOcsah9MzIzMg_200_200.png' 32 | }, 33 | { 34 | id:7, 35 | name: '钉盘', 36 | icon: 'http://static.dingtalk.com/media/lALOcsahiMzIzMg_200_200.png' 37 | }, 38 | { 39 | id:8, 40 | name: '智能报表', 41 | icon: 'http://static.dingtalk.com/media/lALOcsxZiszIzMg_200_200.png' 42 | }, 43 | { 44 | id:9, 45 | name: '电话会议', 46 | icon: 'http://static.dingtalk.com/media/lALOcsajBszIzMg_200_200.png' 47 | }, 48 | { 49 | id:10, 50 | name: '视频会议', 51 | icon: 'http://static.dingtalk.com/media/lALOcsaifMzIzMg_200_200.png' 52 | }, 53 | { 54 | id:11, 55 | name: '客户管理', 56 | icon: 'http://static.dingtalk.com/media/lALOjlM0h8zIzMg_200_200.png' 57 | }, 58 | { 59 | id:12, 60 | name: '办公电话', 61 | icon: 'http://static.dingtalk.com/media/lALOcevpQczIzMg_200_200.png' 62 | }, 63 | { 64 | id:13, 65 | name: '阿里商旅', 66 | icon: 'http://static.dingtalk.com/media/lALOa28YQMzIzMg_200_200.png' 67 | } 68 | ]; 69 | 70 | export default data; -------------------------------------------------------------------------------- /react-fed-oapage/src/containers/Home/components/AllAppList/AllAppList.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './AllAppList.scss'; 3 | import classnames from 'classnames/bind'; 4 | import ALLAPPLISTMOCKDATA from './ALLAPPLISTMOCKDATA' 5 | 6 | const cx = classnames.bind(styles); 7 | 8 | class AllAppList extends React.Component{ 9 | constructor(props){ 10 | super(props) 11 | } 12 | 13 | render(){ 14 | return ( 15 |
16 |
17 |

全部应用

18 |
19 |
20 | { 21 | ALLAPPLISTMOCKDATA.map((v) => { 22 | return ( 23 |
24 |
25 |
26 | 27 |
28 |
{v.name}
29 |
30 |
31 | ) 32 | }) 33 | } 34 |
35 |
36 | ) 37 | } 38 | } 39 | 40 | export default AllAppList; -------------------------------------------------------------------------------- /react-fed-oapage/src/containers/Home/components/AllAppList/AllAppList.scss: -------------------------------------------------------------------------------- 1 | .index-all-applist{ 2 | margin-top: 16px; 3 | background-color: #fff; 4 | border-top-color: #e4e4e4; 5 | border-top-width: 1px; 6 | border-top-style: solid; 7 | } 8 | 9 | .applist-title{ 10 | width: 100%; 11 | height: 49px; 12 | position: relative; 13 | } 14 | 15 | .applist-text{ 16 | color: #999; 17 | font-size: 17px; 18 | position: absolute; 19 | top: 16px; 20 | left: 12px; 21 | } 22 | 23 | 24 | 25 | .grid{ 26 | display: flex; 27 | flex-direction: row; 28 | flex-wrap: wrap; 29 | } 30 | .cell{ 31 | width: 25%; 32 | position: relative; 33 | margin-bottom: 20px; 34 | } 35 | .cell-image-container{ 36 | width: 50px; 37 | height: 49px; 38 | position: relative; 39 | border-radius: 10px; 40 | background-color: #f8f8f8; 41 | overflow: hidden; 42 | margin: 0 auto; 43 | } 44 | .cell-text{ 45 | text-align: center; 46 | color: #323334; 47 | font-size: 13px; 48 | margin-top: 12px; 49 | } 50 | .cell-mount{ 51 | color: #323334; 52 | font-size: 20px; 53 | text-align: center; 54 | } 55 | .cell-unit{ 56 | color: #999; 57 | font-size: 10px; 58 | } 59 | .cell-tag{ 60 | text-align: center; 61 | color: #999; 62 | font-size: 10px; 63 | margin-top: 4.5px; 64 | } 65 | .cell-app-type-container{ 66 | width: 100%; 67 | position: absolute; 68 | bottom: 0; 69 | background-color: rgba(0, 0, 0, .2); 70 | margin: 0; 71 | padding: 0; 72 | height: 13px; 73 | } 74 | .cell-app-type{ 75 | font-size:8px; 76 | color: #fff; 77 | text-align: center; 78 | line-height: 13px; 79 | } 80 | .cell-image{ 81 | width: 50px; 82 | height: 49px; 83 | border-radius: 10px; 84 | } 85 | .cell-image-container{ 86 | width: 50px; 87 | height: 49px; 88 | position: relative; 89 | border-radius: 10px; 90 | background-color: #f8f8f8; 91 | overflow: hidden; 92 | margin: 0 auto; 93 | } 94 | .cell-image{ 95 | width: 50px; 96 | height: 49px; 97 | border-radius: 10px; 98 | } 99 | .cell-text{ 100 | text-align: center; 101 | color: #323334; 102 | font-size: 13px; 103 | margin-top: 12px; 104 | } 105 | -------------------------------------------------------------------------------- /react-fed-oapage/src/containers/Home/components/AllAppList/index.js: -------------------------------------------------------------------------------- 1 | import AllAppList from './AllAppList.jsx'; 2 | 3 | export default AllAppList; -------------------------------------------------------------------------------- /react-fed-oapage/src/containers/Home/components/Banner/Banner.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './Banner.scss'; 3 | import classnames from 'classnames/bind'; 4 | 5 | const cx = classnames.bind(styles); 6 | 7 | class Banner extends React.Component{ 8 | constructor(props){ 9 | super(props) 10 | } 11 | render(){ 12 | return( 13 |
14 |
15 | 16 |
17 |
18 | ) 19 | } 20 | } 21 | 22 | export default Banner; 23 | -------------------------------------------------------------------------------- /react-fed-oapage/src/containers/Home/components/Banner/Banner.scss: -------------------------------------------------------------------------------- 1 | .banner-slider{ 2 | width: 100%; 3 | height: 150px; 4 | flex-direction: row; 5 | background-color: white; 6 | border-width: 1px; 7 | border-color: #dadada; 8 | margin-bottom: 17px; 9 | } 10 | 11 | .banner{ 12 | width: 100%; 13 | height: 150px; 14 | } 15 | 16 | .banner-image{ 17 | width: 100%; 18 | height: 150px; 19 | } -------------------------------------------------------------------------------- /react-fed-oapage/src/containers/Home/components/Banner/index.js: -------------------------------------------------------------------------------- 1 | import Banner from './Banner.jsx'; 2 | 3 | export default Banner; -------------------------------------------------------------------------------- /react-fed-oapage/src/containers/Home/components/Manager/Manager.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './Manager.scss'; 3 | import classnames from 'classnames/bind'; 4 | 5 | const cx = classnames.bind(styles); 6 | 7 | class Manager extends React.Component{ 8 | constructor(props){ 9 | super(props); 10 | } 11 | render(){ 12 | return( 13 |
14 |
15 | 16 |
添加/管理
17 | 18 |
19 |
20 | ) 21 | } 22 | } 23 | 24 | export default Manager; -------------------------------------------------------------------------------- /react-fed-oapage/src/containers/Home/components/Manager/Manager.scss: -------------------------------------------------------------------------------- 1 | .add-manager{ 2 | width: 100%; 3 | height: 44px; 4 | background-color: #fff; 5 | border-bottom-color: rgba(228, 228, 228, 1); 6 | border-bottom-style: solid; 7 | border-bottom-width: 1px; 8 | border-top-color: rgba(228, 228, 228, 1); 9 | border-top-style: solid; 10 | border-top-width: 1px; 11 | margin-bottom: 10px 12 | } 13 | .add-manager-container{ 14 | position: relative; 15 | width: 100%; 16 | height: 44px; 17 | } 18 | 19 | .add-manager-text{ 20 | color: #323334; 21 | padding-left: 42px; 22 | padding-top: 12px; 23 | font-size: 17px; 24 | } 25 | .add-manager-add-icon{ 26 | width: 14px; 27 | height: 14px; 28 | position: absolute; 29 | top:15px; 30 | left: 12px; 31 | } 32 | .add-manager-more-icon{ 33 | width: 14px; 34 | height: 14px; 35 | position: absolute; 36 | top: 15px; 37 | right: 12px; 38 | } -------------------------------------------------------------------------------- /react-fed-oapage/src/containers/Home/components/Manager/index.js: -------------------------------------------------------------------------------- 1 | import Manager from './Manager.jsx'; 2 | 3 | export default Manager; -------------------------------------------------------------------------------- /react-fed-oapage/src/containers/Home/components/UserList/UserList.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './UserList.scss'; 3 | import classnames from 'classnames/bind'; 4 | 5 | const cx = classnames.bind(styles); 6 | 7 | class UserList extends React.Component{ 8 | constructor(props){ 9 | super(props) 10 | } 11 | render(){ 12 | return ( 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 | export default UserList; -------------------------------------------------------------------------------- /react-fed-oapage/src/containers/Home/components/UserList/UserList.scss: -------------------------------------------------------------------------------- 1 | .index-userlist{ 2 | background-color: #fff; 3 | } 4 | .index-userlist-item{ 5 | position: relative; 6 | } 7 | .index-title{ 8 | position: relative; 9 | height: 49px; 10 | } 11 | .index-text{ 12 | position: absolute; 13 | font-size: 15px; 14 | color: #323334; 15 | left: 12px; 16 | top: 16.5px; 17 | } 18 | .index-userlist-line{ 19 | background-color: rgba(228, 228, 228, 1); 20 | height: 1px; 21 | width: calc(100% - 11.5px); 22 | position: absolute; 23 | left: 11.5px; 24 | bottom: 0px; 25 | } 26 | 27 | .grid{ 28 | display: flex; 29 | flex-direction: row; 30 | flex-wrap: wrap; 31 | } 32 | .cell{ 33 | width: 25%; 34 | position: relative; 35 | margin-bottom: 20px; 36 | } 37 | .cell-image-container{ 38 | width: 50px; 39 | height: 49px; 40 | position: relative; 41 | border-radius: 10px; 42 | background-color: #f8f8f8; 43 | overflow: hidden; 44 | margin: 0 auto; 45 | } 46 | .cell-text{ 47 | text-align: center; 48 | color: #323334; 49 | font-size: 13px; 50 | margin-top: 12px; 51 | } 52 | .cell-mount{ 53 | color: #323334; 54 | font-size: 20px; 55 | text-align: center; 56 | } 57 | .cell-unit{ 58 | color: #999; 59 | font-size: 10px; 60 | } 61 | .cell-tag{ 62 | text-align: center; 63 | color: #999; 64 | font-size: 10px; 65 | margin-top: 4.5px; 66 | } 67 | .cell-app-type-container{ 68 | width: 100%; 69 | position: absolute; 70 | bottom: 0; 71 | background-color: rgba(0, 0, 0, .2); 72 | margin: 0; 73 | padding: 0; 74 | height: 13px; 75 | } 76 | .cell-app-type{ 77 | font-size:8px; 78 | color: #fff; 79 | text-align: center; 80 | line-height: 13px; 81 | } 82 | .cell-image{ 83 | width: 50px; 84 | height: 49px; 85 | border-radius: 10px; 86 | } 87 | .cell-image-container{ 88 | width: 50px; 89 | height: 49px; 90 | position: relative; 91 | border-radius: 10px; 92 | background-color: #f8f8f8; 93 | overflow: hidden; 94 | margin: 0 auto; 95 | } 96 | .cell-image{ 97 | width: 50px; 98 | height: 49px; 99 | border-radius: 10px; 100 | } 101 | .cell-text{ 102 | text-align: center; 103 | color: #323334; 104 | font-size: 13px; 105 | margin-top: 12px; 106 | } 107 | -------------------------------------------------------------------------------- /react-fed-oapage/src/containers/Home/components/UserList/index.js: -------------------------------------------------------------------------------- 1 | import UserList from './UserList.jsx'; 2 | 3 | export default UserList; -------------------------------------------------------------------------------- /react-fed-oapage/src/containers/Home/flow/constants.js: -------------------------------------------------------------------------------- 1 | export const HOME_SYNC_DEFAULT = 'HOME_SYNC_DEFAULT'; 2 | export const HOME_ASYNC_DEFAULT = 'HOME_ASYNC_DEFAULT'; 3 | export const HOME_FETCH_USERINFO = 'HOME_FETCH_USERINFO'; -------------------------------------------------------------------------------- /react-fed-oapage/src/containers/Home/flow/homeActions.js: -------------------------------------------------------------------------------- 1 | import { HOME_SYNC_DEFAULT,HOME_ASYNC_DEFAULT,HOME_FETCH_USERINFO } from './constants'; 2 | import { jsApiOAuth, getUserId, getUserInfo} from '../../../common/ding-service'; 3 | import { OPENAPIHOST } from '../../../common/env'; 4 | 5 | export const getDefault = (params) => { 6 | return { 7 | type: HOME_SYNC_DEFAULT, 8 | payload: { 9 | data: 'wower' 10 | } 11 | } 12 | } 13 | 14 | const setUserInfo = data => ({ 15 | type: HOME_FETCH_USERINFO, 16 | payload: { 17 | data: data 18 | } 19 | }) 20 | 21 | export const getAsyncDefault = (params) => (dispatch) => { 22 | setTimeout(() => { 23 | dispatch((() => { 24 | return { 25 | type: HOME_ASYNC_DEFAULT, 26 | payload: { 27 | data: 'icepy' 28 | } 29 | } 30 | })()) 31 | },2000) 32 | } 33 | 34 | function fetchUserId(){ 35 | return function(cb){ 36 | const getUserIdRequest = { 37 | url: OPENAPIHOST + '/api/get-user-info' 38 | } 39 | getUserId(getUserIdRequest).then( (response) => { 40 | const data = response.data; 41 | cb(null,data.userid); 42 | }).catch((error) => { 43 | alert('获取userid error :' + JSON.stringify(error)); 44 | cb(error); 45 | }) 46 | } 47 | } 48 | 49 | function fetchUserInfos(userid){ 50 | return function(cb){ 51 | const getUserInfoRequest = { 52 | url: OPENAPIHOST + '/api/get', 53 | params: { 54 | userid: userid 55 | } 56 | }; 57 | getUserInfo(getUserInfoRequest).then( (response) => { 58 | cb(null,response.data); 59 | }).catch((error) => { 60 | alert('获取用户信息 error:' + JSON.stringify(error)); 61 | cb(error); 62 | }); 63 | } 64 | } 65 | 66 | function run(task){ 67 | let _task = task(); 68 | let res = _task.next(); 69 | while(!res.done){ 70 | if (typeof res.value === 'function'){ 71 | res.value((err,data) => { 72 | if (err){ 73 | res = _task.next(err); 74 | } else { 75 | res = _task.next(null,data); 76 | } 77 | }); 78 | } else { 79 | res = _task.next(res.value); 80 | } 81 | } 82 | } 83 | 84 | export const fetchUserInfo = () => (dispatch) => { 85 | run(function *(){ 86 | let userid = yield fetchUserId(); 87 | let userInfo = yield fetchUserInfos(userid); 88 | dispatch(setUserInfo(userInfo)); 89 | }); 90 | } 91 | 92 | export const fetchJSAPIOAuth = () => (dispatch) => { 93 | const signRequest = { 94 | url: OPENAPIHOST + '/api/jsapi-oauth', 95 | params: { 96 | href: location.href 97 | } 98 | }; 99 | jsApiOAuth(signRequest).then( () => { 100 | alert('JS API 权限校验成功'); 101 | }).catch((error) => { 102 | alert('JS API 权限校验失败 error : ' + JSON.stringify(error)); 103 | }) 104 | } -------------------------------------------------------------------------------- /react-fed-oapage/src/containers/Home/flow/homeReducers.js: -------------------------------------------------------------------------------- 1 | import { HOME_SYNC_DEFAULT,HOME_ASYNC_DEFAULT,HOME_FETCH_USERINFO } from './constants'; 2 | 3 | const initState = { 4 | name: '', 5 | asyncName: '...', 6 | userInfo: {} 7 | }; 8 | 9 | export default function homeReducers(state = initState, action){ 10 | const { type, payload } = action; 11 | switch (type){ 12 | case HOME_SYNC_DEFAULT: 13 | return { ...state, name: payload.data } 14 | case HOME_ASYNC_DEFAULT: 15 | return { ...state, asyncName: payload.data} 16 | case HOME_FETCH_USERINFO: 17 | return { ...state, userInfo: payload.data} 18 | default: 19 | return { ...state} 20 | } 21 | } -------------------------------------------------------------------------------- /react-fed-oapage/src/containers/Home/index.js: -------------------------------------------------------------------------------- 1 | import HomeView from './HomeView.jsx'; 2 | import homeReducers from './flow/homeReducers'; 3 | import { injectReducers } from 'store/reducers'; 4 | 5 | export default function loadHomeView(store){ 6 | injectReducers(store,{ 7 | home:homeReducers 8 | }); 9 | return HomeView; 10 | }; -------------------------------------------------------------------------------- /react-fed-oapage/src/containers/index.js: -------------------------------------------------------------------------------- 1 | import loadHomeView from './Home'; 2 | 3 | export default { 4 | loadHomeView 5 | }; -------------------------------------------------------------------------------- /react-fed-oapage/src/store/configureStore.js: -------------------------------------------------------------------------------- 1 | import { applyMiddleware, createStore } from 'redux'; 2 | import { routerMiddleware } from 'react-router-redux'; 3 | import thunk from 'redux-thunk'; 4 | import makeRootReducer from './reducers'; 5 | 6 | export default function configureStore(initialState = {},history) { 7 | const store = createStore( 8 | makeRootReducer(), 9 | initialState, 10 | applyMiddleware(thunk, routerMiddleware(history)) 11 | ); 12 | store.asyncReducers = {}; 13 | 14 | if (module.hot) { 15 | module.hot.accept('./reducers', () => { 16 | const reducers = require('./reducers').default; 17 | store.replaceReducer(reducers(store.asyncReducers)); 18 | }); 19 | } 20 | 21 | return store; 22 | } 23 | -------------------------------------------------------------------------------- /react-fed-oapage/src/store/reducers.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import { routerReducer } from 'react-router-redux'; 3 | 4 | export const makeRootReducer = (asyncReducers) => ( 5 | combineReducers({ 6 | routing: routerReducer, 7 | ...asyncReducers 8 | }) 9 | ); 10 | 11 | export const injectReducers = (store, reducers) => { 12 | store.asyncReducers = { 13 | ...store.asyncReducers, 14 | ...reducers 15 | }; 16 | store.replaceReducer(makeRootReducer(store.asyncReducers)); 17 | }; 18 | 19 | export default makeRootReducer; 20 | -------------------------------------------------------------------------------- /vue-fed-oapage/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | -------------------------------------------------------------------------------- /vue-fed-oapage/README.md: -------------------------------------------------------------------------------- 1 | # index-oa-template 2 | 3 | > A Vue.js project 4 | 5 | [自定义企业首页文档](https://yq.aliyun.com/articles/71162?spm=5176.8091938.0.0.LLs5na) 6 | 7 | ![](https://gw.alicdn.com/tps/TB1T.XwPVXXXXX7XpXXXXXXXXXX-720-1280.jpg) 8 | 9 | ## Build Setup 10 | 11 | ``` bash 12 | # install dependencies 13 | npm install 14 | 15 | # serve with hot reload at localhost:8080 16 | npm run dev 17 | 18 | # build for production with minification 19 | npm run build 20 | 21 | # build for production and view the bundle analyzer report 22 | npm run build --report 23 | ``` 24 | 25 | For detailed explanation on how things work, checkout the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). 26 | -------------------------------------------------------------------------------- /vue-fed-oapage/build/build.js: -------------------------------------------------------------------------------- 1 | // https://github.com/shelljs/shelljs 2 | require('./check-versions')() 3 | 4 | process.env.NODE_ENV = 'production' 5 | 6 | var ora = require('ora') 7 | var path = require('path') 8 | var chalk = require('chalk') 9 | var shell = require('shelljs') 10 | var webpack = require('webpack') 11 | var config = require('../config') 12 | var webpackConfig = require('./webpack.prod.conf') 13 | 14 | var spinner = ora('building for production...') 15 | spinner.start() 16 | 17 | var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory) 18 | shell.rm('-rf', assetsPath) 19 | shell.mkdir('-p', assetsPath) 20 | shell.config.silent = true 21 | shell.cp('-R', 'static/*', assetsPath) 22 | shell.config.silent = false 23 | 24 | webpack(webpackConfig, function (err, stats) { 25 | spinner.stop() 26 | if (err) throw err 27 | process.stdout.write(stats.toString({ 28 | colors: true, 29 | modules: false, 30 | children: false, 31 | chunks: false, 32 | chunkModules: false 33 | }) + '\n\n') 34 | 35 | console.log(chalk.cyan(' Build complete.\n')) 36 | console.log(chalk.yellow( 37 | ' Tip: built files are meant to be served over an HTTP server.\n' + 38 | ' Opening index.html over file:// won\'t work.\n' 39 | )) 40 | }) 41 | -------------------------------------------------------------------------------- /vue-fed-oapage/build/check-versions.js: -------------------------------------------------------------------------------- 1 | var chalk = require('chalk') 2 | var semver = require('semver') 3 | var packageConfig = require('../package.json') 4 | 5 | function exec (cmd) { 6 | return require('child_process').execSync(cmd).toString().trim() 7 | } 8 | 9 | var versionRequirements = [ 10 | { 11 | name: 'node', 12 | currentVersion: semver.clean(process.version), 13 | versionRequirement: packageConfig.engines.node 14 | }, 15 | { 16 | name: 'npm', 17 | currentVersion: exec('npm --version'), 18 | versionRequirement: packageConfig.engines.npm 19 | } 20 | ] 21 | 22 | module.exports = function () { 23 | var warnings = [] 24 | for (var i = 0; i < versionRequirements.length; i++) { 25 | var mod = versionRequirements[i] 26 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 27 | warnings.push(mod.name + ': ' + 28 | chalk.red(mod.currentVersion) + ' should be ' + 29 | chalk.green(mod.versionRequirement) 30 | ) 31 | } 32 | } 33 | 34 | if (warnings.length) { 35 | console.log('') 36 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 37 | console.log() 38 | for (var i = 0; i < warnings.length; i++) { 39 | var warning = warnings[i] 40 | console.log(' ' + warning) 41 | } 42 | console.log() 43 | process.exit(1) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /vue-fed-oapage/build/dev-client.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | require('eventsource-polyfill') 3 | var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') 4 | 5 | hotClient.subscribe(function (event) { 6 | if (event.action === 'reload') { 7 | window.location.reload() 8 | } 9 | }) 10 | -------------------------------------------------------------------------------- /vue-fed-oapage/build/dev-server.js: -------------------------------------------------------------------------------- 1 | require('./check-versions')() 2 | 3 | var config = require('../config') 4 | if (!process.env.NODE_ENV) { 5 | process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV) 6 | } 7 | 8 | var opn = require('opn') 9 | var path = require('path') 10 | var express = require('express') 11 | var webpack = require('webpack') 12 | var proxyMiddleware = require('http-proxy-middleware') 13 | var webpackConfig = require('./webpack.dev.conf') 14 | 15 | // default port where dev server listens for incoming traffic 16 | var port = process.env.PORT || config.dev.port 17 | // automatically open browser, if not set will be false 18 | var autoOpenBrowser = !!config.dev.autoOpenBrowser 19 | // Define HTTP proxies to your custom API backend 20 | // https://github.com/chimurai/http-proxy-middleware 21 | var proxyTable = config.dev.proxyTable 22 | 23 | var app = express() 24 | var compiler = webpack(webpackConfig) 25 | 26 | var devMiddleware = require('webpack-dev-middleware')(compiler, { 27 | publicPath: webpackConfig.output.publicPath, 28 | quiet: true 29 | }) 30 | 31 | var hotMiddleware = require('webpack-hot-middleware')(compiler, { 32 | log: () => {} 33 | }) 34 | // force page reload when html-webpack-plugin template changes 35 | compiler.plugin('compilation', function (compilation) { 36 | compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { 37 | hotMiddleware.publish({ action: 'reload' }) 38 | cb() 39 | }) 40 | }) 41 | 42 | // proxy api requests 43 | Object.keys(proxyTable).forEach(function (context) { 44 | var options = proxyTable[context] 45 | if (typeof options === 'string') { 46 | options = { target: options } 47 | } 48 | app.use(proxyMiddleware(options.filter || context, options)) 49 | }) 50 | 51 | // handle fallback for HTML5 history API 52 | app.use(require('connect-history-api-fallback')()) 53 | 54 | // serve webpack bundle output 55 | app.use(devMiddleware) 56 | 57 | // enable hot-reload and state-preserving 58 | // compilation error display 59 | app.use(hotMiddleware) 60 | 61 | // serve pure static assets 62 | var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) 63 | app.use(staticPath, express.static('./static')) 64 | 65 | var uri = 'http://localhost:' + port 66 | 67 | devMiddleware.waitUntilValid(function () { 68 | console.log('> Listening at ' + uri + '\n') 69 | }) 70 | 71 | module.exports = app.listen(port, function (err) { 72 | if (err) { 73 | console.log(err) 74 | return 75 | } 76 | 77 | // when env is testing, don't need open it 78 | if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') { 79 | opn(uri) 80 | } 81 | }) 82 | -------------------------------------------------------------------------------- /vue-fed-oapage/build/utils.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 4 | 5 | exports.assetsPath = function (_path) { 6 | var assetsSubDirectory = process.env.NODE_ENV === 'production' 7 | ? config.build.assetsSubDirectory 8 | : config.dev.assetsSubDirectory 9 | return path.posix.join(assetsSubDirectory, _path) 10 | } 11 | 12 | exports.cssLoaders = function (options) { 13 | options = options || {} 14 | // generate loader string to be used with extract text plugin 15 | function generateLoaders (loaders) { 16 | var sourceLoader = loaders.map(function (loader) { 17 | var extraParamChar 18 | if (/\?/.test(loader)) { 19 | loader = loader.replace(/\?/, '-loader?') 20 | extraParamChar = '&' 21 | } else { 22 | loader = loader + '-loader' 23 | extraParamChar = '?' 24 | } 25 | return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '') 26 | }).join('!') 27 | 28 | // Extract CSS when that option is specified 29 | // (which is the case during production build) 30 | if (options.extract) { 31 | return ExtractTextPlugin.extract({ 32 | use: sourceLoader, 33 | fallback: 'vue-style-loader' 34 | }) 35 | } else { 36 | return ['vue-style-loader', sourceLoader].join('!') 37 | } 38 | } 39 | 40 | // http://vuejs.github.io/vue-loader/en/configurations/extract-css.html 41 | return { 42 | css: generateLoaders(['css']), 43 | postcss: generateLoaders(['css']), 44 | less: generateLoaders(['css', 'less']), 45 | sass: generateLoaders(['css', 'sass?indentedSyntax']), 46 | scss: generateLoaders(['css', 'sass']), 47 | stylus: generateLoaders(['css', 'stylus']), 48 | styl: generateLoaders(['css', 'stylus']) 49 | } 50 | } 51 | 52 | // Generate loaders for standalone style files (outside of .vue) 53 | exports.styleLoaders = function (options) { 54 | var output = [] 55 | var loaders = exports.cssLoaders(options) 56 | for (var extension in loaders) { 57 | var loader = loaders[extension] 58 | output.push({ 59 | test: new RegExp('\\.' + extension + '$'), 60 | loader: loader 61 | }) 62 | } 63 | return output 64 | } 65 | -------------------------------------------------------------------------------- /vue-fed-oapage/build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | var utils = require('./utils') 2 | var config = require('../config') 3 | var isProduction = process.env.NODE_ENV === 'production' 4 | 5 | module.exports = { 6 | loaders: utils.cssLoaders({ 7 | sourceMap: isProduction 8 | ? config.build.productionSourceMap 9 | : config.dev.cssSourceMap, 10 | extract: isProduction 11 | }), 12 | postcss: [ 13 | require('autoprefixer')({ 14 | browsers: ['last 2 versions'] 15 | }) 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /vue-fed-oapage/build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var utils = require('./utils') 3 | var config = require('../config') 4 | var vueLoaderConfig = require('./vue-loader.conf') 5 | 6 | function resolve (dir) { 7 | return path.join(__dirname, '..', dir) 8 | } 9 | 10 | module.exports = { 11 | entry: { 12 | app: './src/main.js' 13 | }, 14 | output: { 15 | path: config.build.assetsRoot, 16 | filename: '[name].js', 17 | publicPath: process.env.NODE_ENV === 'production' 18 | ? config.build.assetsPublicPath 19 | : config.dev.assetsPublicPath 20 | }, 21 | resolve: { 22 | extensions: ['.js', '.vue', '.json'], 23 | modules: [ 24 | resolve('src'), 25 | resolve('node_modules') 26 | ], 27 | alias: { 28 | 'vue$': 'vue/dist/vue.common.js', 29 | 'src': resolve('src'), 30 | 'assets': resolve('src/assets'), 31 | 'components': resolve('src/components') 32 | } 33 | }, 34 | module: { 35 | rules: [ 36 | { 37 | test: /\.vue$/, 38 | loader: 'vue-loader', 39 | options: vueLoaderConfig 40 | }, 41 | { 42 | test: /\.js$/, 43 | loader: 'babel-loader', 44 | include: [resolve('src'), resolve('test')] 45 | }, 46 | { 47 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 48 | loader: 'url-loader', 49 | query: { 50 | limit: 10000, 51 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 52 | } 53 | }, 54 | { 55 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 56 | loader: 'url-loader', 57 | query: { 58 | limit: 10000, 59 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 60 | } 61 | } 62 | ] 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /vue-fed-oapage/build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | var utils = require('./utils') 2 | var webpack = require('webpack') 3 | var config = require('../config') 4 | var merge = require('webpack-merge') 5 | var baseWebpackConfig = require('./webpack.base.conf') 6 | var HtmlWebpackPlugin = require('html-webpack-plugin') 7 | var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 8 | 9 | // add hot-reload related code to entry chunks 10 | Object.keys(baseWebpackConfig.entry).forEach(function (name) { 11 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) 12 | }) 13 | 14 | module.exports = merge(baseWebpackConfig, { 15 | module: { 16 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) 17 | }, 18 | // cheap-module-eval-source-map is faster for development 19 | devtool: '#source-map', 20 | plugins: [ 21 | new webpack.DefinePlugin({ 22 | 'process.env': config.dev.env 23 | }), 24 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage 25 | new webpack.HotModuleReplacementPlugin(), 26 | new webpack.NoEmitOnErrorsPlugin(), 27 | // https://github.com/ampedandwired/html-webpack-plugin 28 | new HtmlWebpackPlugin({ 29 | filename: 'index.html', 30 | template: 'index.html', 31 | inject: true 32 | }), 33 | new FriendlyErrorsPlugin() 34 | ] 35 | }) 36 | -------------------------------------------------------------------------------- /vue-fed-oapage/config/dev.env.js: -------------------------------------------------------------------------------- 1 | var merge = require('webpack-merge') 2 | var prodEnv = require('./prod.env') 3 | 4 | module.exports = merge(prodEnv, { 5 | NODE_ENV: '"development"' 6 | }) 7 | -------------------------------------------------------------------------------- /vue-fed-oapage/config/index.js: -------------------------------------------------------------------------------- 1 | // see http://vuejs-templates.github.io/webpack for documentation. 2 | var path = require('path') 3 | 4 | module.exports = { 5 | build: { 6 | env: require('./prod.env'), 7 | index: path.resolve(__dirname, '../dist/index.html'), 8 | assetsRoot: path.resolve(__dirname, '../dist'), 9 | assetsSubDirectory: 'static', 10 | assetsPublicPath: '/', 11 | productionSourceMap: true, 12 | // Gzip off by default as many popular static hosts such as 13 | // Surge or Netlify already gzip all static assets for you. 14 | // Before setting to `true`, make sure to: 15 | // npm install --save-dev compression-webpack-plugin 16 | productionGzip: false, 17 | productionGzipExtensions: ['js', 'css'], 18 | // Run the build command with an extra argument to 19 | // View the bundle analyzer report after build finishes: 20 | // `npm run build --report` 21 | // Set to `true` or `false` to always turn it on or off 22 | bundleAnalyzerReport: process.env.npm_config_report 23 | }, 24 | dev: { 25 | env: require('./dev.env'), 26 | port: 8080, 27 | autoOpenBrowser: true, 28 | assetsSubDirectory: 'static', 29 | assetsPublicPath: '/', 30 | proxyTable: {}, 31 | // CSS Sourcemaps off by default because relative paths are "buggy" 32 | // with this option, according to the CSS-Loader README 33 | // (https://github.com/webpack/css-loader#sourcemaps) 34 | // In our experience, they generally work as expected, 35 | // just be aware of this issue when enabling this option. 36 | cssSourceMap: false 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /vue-fed-oapage/config/prod.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: '"production"' 3 | } 4 | -------------------------------------------------------------------------------- /vue-fed-oapage/dist/index.html: -------------------------------------------------------------------------------- 1 | oa-template
-------------------------------------------------------------------------------- /vue-fed-oapage/dist/static/js/manifest.eb7218291907da2ade18.js: -------------------------------------------------------------------------------- 1 | !function(e){function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}var n=window.webpackJsonp;window.webpackJsonp=function(t,c,a){for(var i,u,f,s=0,l=[];s 2 | 3 | 4 | 5 | 6 | oa-template 7 | 8 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /vue-fed-oapage/info.text: -------------------------------------------------------------------------------- 1 | dependencies nodejs-server-todo -------------------------------------------------------------------------------- /vue-fed-oapage/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "index-oa-template", 3 | "version": "1.0.0", 4 | "description": "A Vue.js project", 5 | "author": "icepy ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "node build/dev-server.js", 9 | "build": "node build/build.js" 10 | }, 11 | "dependencies": { 12 | "axios": "^0.16.1", 13 | "lodash": "^4.17.4", 14 | "vue": "^2.1.10", 15 | "vue-router": "^2.2.0", 16 | "vuex": "^2.1.2" 17 | }, 18 | "devDependencies": { 19 | "autoprefixer": "^6.7.2", 20 | "babel-core": "^6.22.1", 21 | "babel-loader": "^6.2.10", 22 | "babel-plugin-transform-runtime": "^6.22.0", 23 | "babel-preset-es2015": "^6.22.0", 24 | "babel-preset-stage-2": "^6.22.0", 25 | "babel-register": "^6.22.0", 26 | "chalk": "^1.1.3", 27 | "connect-history-api-fallback": "^1.3.0", 28 | "css-loader": "^0.26.1", 29 | "eventsource-polyfill": "^0.9.6", 30 | "express": "^4.14.1", 31 | "extract-text-webpack-plugin": "^2.0.0-rc.2", 32 | "file-loader": "^0.10.0", 33 | "friendly-errors-webpack-plugin": "^1.1.3", 34 | "function-bind": "^1.1.0", 35 | "html-webpack-plugin": "^2.28.0", 36 | "http-proxy-middleware": "^0.17.3", 37 | "opn": "^4.0.2", 38 | "ora": "^1.1.0", 39 | "semver": "^5.3.0", 40 | "shelljs": "^0.7.6", 41 | "url-loader": "^0.5.7", 42 | "vue-loader": "^10.3.0", 43 | "vue-style-loader": "^2.0.0", 44 | "vue-template-compiler": "^2.1.10", 45 | "webpack": "^2.2.1", 46 | "webpack-bundle-analyzer": "^2.2.1", 47 | "webpack-dev-middleware": "^1.10.0", 48 | "webpack-hot-middleware": "^2.16.1", 49 | "webpack-merge": "^2.6.1" 50 | }, 51 | "engines": { 52 | "node": ">= 4.0.0", 53 | "npm": ">= 3.0.0" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /vue-fed-oapage/src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | 15 | 18 | -------------------------------------------------------------------------------- /vue-fed-oapage/src/components/grid.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 31 | 32 | 44 | -------------------------------------------------------------------------------- /vue-fed-oapage/src/components/singleApp.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 47 | 48 | 70 | -------------------------------------------------------------------------------- /vue-fed-oapage/src/lib/env.js: -------------------------------------------------------------------------------- 1 | 2 | export const OPENAPIHOST = ''; 3 | export const HASCONSOLE = typeof console !== undefined; 4 | export const ISBROWSER = typeof window !== 'undefined' && typeof window === 'object'; 5 | export const UA = ISBROWSER && window.navigator.userAgent.toLowerCase(); -------------------------------------------------------------------------------- /vue-fed-oapage/src/lib/logger.js: -------------------------------------------------------------------------------- 1 | import { HASCONSOLE } from './env'; 2 | 3 | const logger = { 4 | warn: function (msg, e){ 5 | if (HASCONSOLE) { 6 | console.warn('[DING WEB SDK Warning]:', msg); 7 | if (e) { 8 | throw e; 9 | } else { 10 | const warning = new Error('WARNING STACK TRACE'); 11 | console.warn(warning.stack); 12 | } 13 | } 14 | }, 15 | info: function (msg){ 16 | if (HASCONSOLE) { 17 | console.info('[DING WEB SDK INFO]:', msg); 18 | } 19 | }, 20 | error: function (msg){ 21 | if (HASCONSOLE){ 22 | console.error('[DING WEB SDK ERROR]:', msg); 23 | } 24 | } 25 | }; 26 | 27 | if (process.env.NODE_ENV !== 'production') { 28 | 29 | } 30 | 31 | export default logger; -------------------------------------------------------------------------------- /vue-fed-oapage/src/lib/shared.js: -------------------------------------------------------------------------------- 1 | import logger from './logger'; 2 | 3 | export function authCode(corpId){ 4 | return new Promise(function(resolve, reject){ 5 | dd.ready(function(){ 6 | dd.runtime.permission.requestAuthCode({ 7 | corpId: corpId, 8 | onSuccess: function(result) { 9 | resolve(result); 10 | }, 11 | onFail : function(err) { 12 | reject(err); 13 | } 14 | }); 15 | }); 16 | }); 17 | } 18 | 19 | export function isObject(obj){ 20 | return obj !== null && typeof obj === 'object' 21 | } 22 | 23 | export function msgLog(opt){ 24 | wpo.log('DING WEB INTERFACE SDK API' + opt.url,1); 25 | } -------------------------------------------------------------------------------- /vue-fed-oapage/src/lib/util.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by xiangwenwen on 2017/2/9. 3 | */ 4 | 5 | import metaHandler from './metaHandler'; 6 | 7 | var isDingtalk = /DingTalk/.test(navigator.userAgent); 8 | 9 | export function parseCorpId(url, param) { 10 | var searchIndex = url.indexOf('?'); 11 | var searchParams = url.slice(searchIndex + 1).split('&'); 12 | for (var i = 0; i < searchParams.length; i++) { 13 | var items = searchParams[i].split('='); 14 | if (items[0].trim() == param) { 15 | return items[1].trim(); 16 | } 17 | } 18 | } 19 | 20 | export function parseMetaData(response, corpId) { 21 | var meta = {}; 22 | meta.admin = response.admin; 23 | meta.bannerMetas = metaHandler.homeBannerModelsHandler(response.homeBannerModels, corpId); 24 | meta.itemMetas = metaHandler.homeHeaderModelHandler(response.homeHeaderModel, corpId); 25 | meta.userlistMetas = metaHandler.homeGroupsHandler(response.homeGroups, corpId); 26 | meta.allapplistMetas = metaHandler.microAppsHandler(response.microApps, corpId); 27 | meta.h5Config = response.h5Config; 28 | meta.userInfo = response.userInfo; 29 | return meta; 30 | } 31 | 32 | export function parseMicroApps(microApps, corpId){ 33 | return metaHandler.microAppsHandler(microApps, corpId); 34 | } 35 | 36 | export function openLink(url, corpId){ 37 | if(corpId && typeof corpId === 'string'){ 38 | if (url && url.indexOf('$CORPID$') !== -1) { 39 | url = url.replace(/\$CORPID\$/, corpId); 40 | } 41 | } 42 | if (isDingtalk) { 43 | dd.biz.util.openLink({ 44 | url: url, 45 | onSuccess: function(){ 46 | if(typeof corpId === 'function'){ 47 | corpId(); 48 | } 49 | }, 50 | onFail: function(){ 51 | if(typeof corpId === 'function'){ 52 | corpId(); 53 | } 54 | } 55 | }); 56 | } else { 57 | window.open(url); 58 | } 59 | } 60 | 61 | export default { 62 | parseCorpId: parseCorpId, 63 | parseMetaData: parseMetaData, 64 | parseMicroApps: parseMicroApps 65 | } 66 | -------------------------------------------------------------------------------- /vue-fed-oapage/src/main.js: -------------------------------------------------------------------------------- 1 | // The Vue build version to load with the `import` command 2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 3 | 4 | import Vue from 'vue'; 5 | import App from './App'; 6 | import router from './router'; 7 | 8 | new Vue({ 9 | el: '#app', 10 | router, 11 | template: '', 12 | components: { App } 13 | }); 14 | -------------------------------------------------------------------------------- /vue-fed-oapage/src/pages/home/components/index-admin.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 61 | 62 | 102 | -------------------------------------------------------------------------------- /vue-fed-oapage/src/pages/home/components/index-appManager.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 39 | 40 | 81 | -------------------------------------------------------------------------------- /vue-fed-oapage/src/pages/home/components/index-applist.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 32 | 33 | -------------------------------------------------------------------------------- /vue-fed-oapage/src/pages/home/components/index-banner.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 35 | 36 | 63 | -------------------------------------------------------------------------------- /vue-fed-oapage/src/pages/home/components/index-userlist.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 36 | 37 | 64 | -------------------------------------------------------------------------------- /vue-fed-oapage/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import Home from 'pages/home/index.vue' 4 | 5 | Vue.use(Router); 6 | 7 | const routes = [ 8 | { 9 | path: '/', 10 | name: 'home', 11 | component: Home 12 | } 13 | ]; 14 | 15 | export default new Router({ 16 | routes: routes 17 | }); 18 | -------------------------------------------------------------------------------- /vue-fed-oapage/static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-dingtalk/which-language-demo/beec798dff6eab38dec5b2c9c93434a6ffabed03/vue-fed-oapage/static/.gitkeep -------------------------------------------------------------------------------- /weex-rax-fed-todo/.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [makefile] 16 | indent_style = tab 17 | indent_size = 4 18 | -------------------------------------------------------------------------------- /weex-rax-fed-todo/.eslintignore: -------------------------------------------------------------------------------- 1 | # 忽略目录 2 | build/ 3 | test/ 4 | 5 | # node 覆盖率文件 6 | coverage/ 7 | 8 | node_modules/ 9 | 10 | # 忽略文件 11 | **/*.min.js 12 | **/*-min.js 13 | -------------------------------------------------------------------------------- /weex-rax-fed-todo/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint-config-ali/react", 3 | "globals": { 4 | "it": true, 5 | "describe": true, 6 | "require": true, 7 | "process": true, 8 | "before": true, 9 | "after": true, 10 | "beforeEach": true, 11 | "afterEach": true 12 | }, 13 | "env": { 14 | "browser": true, 15 | "node": true 16 | }, 17 | "parserOptions": { 18 | "ecmaVersion": 6, 19 | "sourceType": "module", 20 | "ecmaFeatures": { 21 | "jsx": true, 22 | "experimentalObjectRestSpread": true 23 | } 24 | }, 25 | "rules": { 26 | "strict": "off", 27 | "react/react-in-jsx-scope": "off", 28 | "new-cap": "off", 29 | "no-console": "off", 30 | "no-unused-vars": [ 31 | "error", 32 | { 33 | "vars": "all", 34 | "args": "after-used", 35 | "ignoreRestSiblings": false, 36 | "varsIgnorePattern": "createElement" 37 | } 38 | ], 39 | "class-methods-use-this": "off" 40 | }, 41 | "parser": "babel-eslint" 42 | } -------------------------------------------------------------------------------- /weex-rax-fed-todo/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | .idea 4 | .jssdk.json -------------------------------------------------------------------------------- /weex-rax-fed-todo/README.md: -------------------------------------------------------------------------------- 1 | 2 | > 项目A线上链接 [example.com](https://example.com/) 3 | 4 | ## 项目介绍 5 | 6 | 项目简介及业务范围介绍 7 | 8 | 9 | ## 人员 10 | 11 | 人员列表 12 | 13 | ## 相关资料 14 | 15 | - [PRD地址]() 16 | - [视觉稿地址]() 17 | - [数据接口约定]() 18 | - [其他资料]() 19 | 20 | ## 开发环境依赖 21 | 22 | - `nodejs`: ~4.4.0 23 | - `fie`: ~2.0.0 24 | 25 | ## 本地开发 26 | 27 | ### hosts 绑定 28 | 29 | ``` 30 | 127.0.0.1 example.taobao.com 31 | 127.0.0.1 api.example.taobao.com 32 | ``` 33 | 34 | ### 开发调试 35 | 36 | 37 | ``` 38 | 39 | ding start 40 | 41 | ``` 42 | 43 | ### 打包 44 | 45 | ``` 46 | 47 | ding build 48 | 49 | ``` 50 | 51 | ## weex调试 52 | 53 | ``` 54 | 55 | http://nuke.taobao.org/nukedocs/guide/develop-tools.html 56 | 57 | ``` 58 | 59 | ## 项目架构及目录结构介绍 60 | 61 | 介绍一下项目使用了哪些技术,及目录结构和技术架构说明 62 | 63 | ## 升级日志 64 | 65 | 66 | ### 0.0.1 67 | 68 | @张全蛋 69 | 70 | - 实现了XX功能 71 | - 支持`websocket`通信 72 | - ... 73 | 74 | 75 | ## 其他 76 | 77 | ### 注意点 78 | 79 | - 什么地方需要注意 80 | 81 | ### TODO 82 | 83 | - 后面可以做的优化的地方 -------------------------------------------------------------------------------- /weex-rax-fed-todo/ding.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | toolkit: 'fie-toolkit-nuke', 3 | toolkitConfig: { 4 | webpack: { 5 | sourcemap: 'cheap-module-inline-source-map', // 调试sourcemap类型,默认为inline-cheap-module-source-map。 6 | uglify: true, // 是否对生产环境的代码进行压缩混淆,默认为true。 7 | hotreload: true, // 是否进行热更新,默认为true 8 | 'optimize-size': { 9 | nuke: true, // 是否开启对nuke的按需引用,默认为fasle 10 | webpack: true, // 是否按照使用webpack3进行tree shaking,代码需满足export import的es6规范 11 | }, 12 | externals: { 13 | nuke: false, // 是否使用内置到客户端的nuke组件,仅千牛可用,true 14 | rax: false, // 是否使用内置到客户端的rax组件,true 15 | 'QAP-SDK': false, // 是否使用内置到客户端的QAP-SDK组件,仅千牛可用,true 16 | }, 17 | alias: { 18 | $components: './src/components', 19 | $pages: './src/pages', 20 | $util: './src/util', 21 | $root: './src/', 22 | $data: './data/', 23 | }, 24 | report: true, //是否开启构建信息上报,默认为true 25 | }, 26 | open: true, //启动调试后自动打开调试辅助页面 27 | devType: 'dingtalk' 28 | }, 29 | }; 30 | -------------------------------------------------------------------------------- /weex-rax-fed-todo/info.text: -------------------------------------------------------------------------------- 1 | dependencies nodejs-server-todo -------------------------------------------------------------------------------- /weex-rax-fed-todo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "weex-rax-fed-todo", 3 | "description": "rax demo", 4 | "version": "0.1.0", 5 | "keyword": [ 6 | "weex-nuke", 7 | "nuke", 8 | "dingtalk" 9 | ], 10 | "author": "icepy", 11 | "readmeFilename": "README.md", 12 | "dependencies": { 13 | "dingtalk-javascript-sdk": "^0.1.5", 14 | "dingtalk-javascript-utility": "^0.1.5", 15 | "qs": "^6.4.0", 16 | "rax": "^0.4.x", 17 | "rax-redux": "^0.4.x", 18 | "redux": "^3.6.0", 19 | "redux-thunk": "^2.1.0", 20 | "universal-toast": "0.4.x", 21 | "weex-nuke": "^0.0.3" 22 | }, 23 | "devDependencies": { 24 | "eslint": "3.19.0", 25 | "babel-eslint": "^7.2.3", 26 | "eslint-config-ali": "2.0.0", 27 | "eslint-plugin-import": "2.6.0", 28 | "eslint-plugin-jsx-a11y": "6.0.2", 29 | "eslint-plugin-react": "7.1.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /weex-rax-fed-todo/src/components/label/index.jsx: -------------------------------------------------------------------------------- 1 | // 多个页面都会使用到的label组件 -------------------------------------------------------------------------------- /weex-rax-fed-todo/src/components/label/index.less: -------------------------------------------------------------------------------- 1 | // label组件的样式部分 -------------------------------------------------------------------------------- /weex-rax-fed-todo/src/pages/index/container.jsx: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { createElement, Component } from 'rax'; 4 | import { Provider } from 'rax-redux'; 5 | import dingtalk from 'dingtalk-javascript-sdk'; 6 | import reducers from './redux/reducers/index.js'; 7 | import createStore from './redux/store/index.js'; 8 | import Todo from './container/main.jsx'; 9 | 10 | const store = createStore(reducers); 11 | class ReduxPage extends Component { 12 | componentWillMount() { 13 | dingtalk.ready(() => { 14 | const dd = dingtalk.apis; 15 | dd.biz.navigation.setTitle({ 16 | title: '待办列表', 17 | }); 18 | }); 19 | } 20 | 21 | render() { 22 | return ( 23 | 24 | 25 | 26 | ); 27 | } 28 | } 29 | export default ReduxPage; 30 | -------------------------------------------------------------------------------- /weex-rax-fed-todo/src/pages/index/container/main.jsx: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { createElement, Component } from 'rax'; 4 | import { View } from 'weex-nuke'; 5 | import { connect } from 'rax-redux'; 6 | import AddItem from '../mods/addItem.jsx'; 7 | import List from '../mods/list.jsx'; 8 | import Profile from '../mods/profile.jsx'; 9 | import { modifyItem, addItem,fetchUserInfo } from '../redux/actions/todo.js'; 10 | import styles from './main.less'; 11 | 12 | class Todo extends Component { 13 | constructor(props) { 14 | super(props); 15 | this.state = {}; 16 | } 17 | componentDidMount(){ 18 | this.props.dispatch(fetchUserInfo()); 19 | } 20 | modifyItem = (index) => { 21 | this.props.dispatch(modifyItem(index)); 22 | } 23 | addItem = (obj) => { 24 | this.props.dispatch(addItem(obj)); 25 | } 26 | render() { 27 | 28 | return ( 29 | 30 | 31 | 32 | 33 | 34 | ); 35 | } 36 | } 37 | 38 | function mapStateToProps(state) { 39 | return { 40 | todoMVC: state.todoReducer, 41 | }; 42 | } 43 | 44 | export default connect(mapStateToProps)(Todo); 45 | -------------------------------------------------------------------------------- /weex-rax-fed-todo/src/pages/index/container/main.less: -------------------------------------------------------------------------------- 1 | .container { 2 | flex:1; 3 | width:750; 4 | padding-top:20; 5 | align-items: center; 6 | background-color: #EADEAD; 7 | } 8 | .list{ 9 | margin-top:20; 10 | flex:1; 11 | justify-content: flex-start; 12 | } -------------------------------------------------------------------------------- /weex-rax-fed-todo/src/pages/index/index.jsx: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { createElement, render } from 'rax'; 4 | import Container from './container.jsx'; 5 | 6 | render(); 7 | -------------------------------------------------------------------------------- /weex-rax-fed-todo/src/pages/index/mods/addItem.jsx: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import { createElement, Component } from 'rax'; 3 | import { View, Text, Modal, Button, Env, Input } from 'weex-nuke'; 4 | import styles from './addItem.less'; 5 | const { isWeb } = Env; 6 | 7 | class AddItem extends Component { 8 | constructor(props) { 9 | super(props); 10 | 11 | this.state = { 12 | text: '' 13 | }; 14 | } 15 | changeInput = (e) => { 16 | this.setState({ 17 | text: e.value || e.target.value, 18 | }) 19 | 20 | } 21 | /** 22 | * hack onReturn event for web 23 | * @param {[type]} e [description] 24 | * @return {[type]} [description] 25 | */ 26 | keyUp = (e) => { 27 | 28 | if (isWeb && e.keyCode === 13) { 29 | this.addItem(); 30 | } 31 | } 32 | clearInput() { 33 | // this.setState({ 34 | // input:'' 35 | // }) 36 | } 37 | addItem() { 38 | 39 | this.setState({ 40 | input: this.state.text, 41 | 42 | }) 43 | if (this.state.text.length == 0) { 44 | Modal.toast('哎~空的看不到吗'); 45 | } else { 46 | 47 | this.props.addItem({ 48 | content: this.state.text, 49 | }); 50 | this.setState({ 51 | text: '', 52 | input: '' 53 | }) 54 | } 55 | } 56 | render() { 57 | return ( 58 | 59 | 60 | 61 | ); 62 | } 63 | } 64 | 65 | 66 | export default AddItem; 67 | -------------------------------------------------------------------------------- /weex-rax-fed-todo/src/pages/index/mods/addItem.less: -------------------------------------------------------------------------------- 1 | .container { 2 | height:90; 3 | width:750; 4 | justify-content:'center'; 5 | flex-direction:'row' 6 | }; 7 | .input { 8 | width:710; 9 | height:80; 10 | font-size:28; 11 | background-color: rgba(0,0,0,0.4); 12 | border-color:transparent; 13 | color:#ffffff; 14 | border-radius:10 15 | }; 16 | .button { 17 | width:100; 18 | height:80; 19 | margin-left:10; 20 | } 21 | -------------------------------------------------------------------------------- /weex-rax-fed-todo/src/pages/index/mods/list.jsx: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { createElement, Component, findDOMNode } from 'rax'; 4 | import { View, Text, ListView, Checkbox, Transition, Cell, Touchable } from 'weex-nuke'; 5 | import styles from './list.less'; 6 | 7 | class List extends Component { 8 | constructor(props) { 9 | super(props); 10 | const doneCount = 0; 11 | this.state = { 12 | doneCount, 13 | showDone: false, 14 | }; 15 | this.showDone = this.showDone.bind(this); 16 | } 17 | 18 | changeItemStatus(item) { 19 | const animationStyle = { opacity: '0.5' }; 20 | const box = findDOMNode('cell_' + item.id); 21 | Transition(box, animationStyle, { 22 | timingFunction: 'ease-in', 23 | delay: 0, 24 | duration: 200, 25 | }, () => { 26 | console.log(this); 27 | this.props.modifyItem(item); 28 | }); 29 | } 30 | showDone() { 31 | this.setState({ 32 | showDone: !this.state.showDone, 33 | }); 34 | } 35 | render() { 36 | const { style, dataSource } = this.props; 37 | return ( 38 | 39 | { 40 | dataSource.toDoList.map((item) => { 41 | return ( 42 | 43 | 44 | 45 | {item.content} 46 | 47 | 48 | ); 49 | }) 50 | } 51 | { 52 | dataSource.doneList.length ? 53 | 54 | 55 | 56 | 查看 {dataSource.doneList.length} 个已完成任务 57 | 58 | 59 | 60 | : null 61 | } 62 | { 63 | this.state.showDone && dataSource.doneList.map((item) => { 64 | return ( 65 | 66 | 67 | 68 | {item.content} 69 | 70 | 71 | ); 72 | }) 73 | } 74 | 75 | ); 76 | } 77 | } 78 | 79 | 80 | export default List; 81 | -------------------------------------------------------------------------------- /weex-rax-fed-todo/src/pages/index/mods/list.less: -------------------------------------------------------------------------------- 1 | 2 | .listContainer { 3 | flex: 1; 4 | width: 710; 5 | align-items: 'center'; 6 | }; 7 | .cellItem { 8 | border-color: transparent; 9 | width: 710; 10 | min-height: 70; 11 | background-color: #ffffff; 12 | justify-content: 'center'; 13 | align-items: 'center'; 14 | flex-direction: 'row'; 15 | border-radius: 12; 16 | margin-bottom: 4; 17 | }; 18 | .content { 19 | flex: 1; 20 | font-size: 28; 21 | lines: 1; 22 | text-overflow: 'ellipsis'; 23 | -webkit-line-clamp: '1'; 24 | white-space: 'nowrap'; 25 | overflow: 'hidden' 26 | }; 27 | 28 | .checkbox { 29 | border-radius: 6; 30 | background-color: #f8f8f8; 31 | 32 | }; 33 | .checkbox_checked { 34 | color: #666666; 35 | }; 36 | .done { 37 | background-color: rgba(255,255,255,0.4); 38 | }; 39 | .doneText { 40 | text-decoration: 'line-through'; 41 | color: #666666; 42 | }; 43 | .statusText { 44 | color: #8A8A8A; 45 | font-size: 24; 46 | }; 47 | .shortCell { 48 | flex-direction: 'row'; 49 | justify-content: 'center'; 50 | }; 51 | .viewDone { 52 | justify-content: 'center'; 53 | align-items: 'center'; 54 | width: 710; 55 | margin: 10; 56 | }; 57 | .viewDoneBtn { 58 | width: 300; 59 | height: 60; 60 | justify-content: 'center'; 61 | align-items: 'center'; 62 | border-radius: 12; 63 | background-color: rgba(0,0,0,0.4); 64 | }; 65 | .viewDoneText { 66 | color: #eeeeee; 67 | font-size: 24; 68 | } -------------------------------------------------------------------------------- /weex-rax-fed-todo/src/pages/index/mods/profile.jsx: -------------------------------------------------------------------------------- 1 | import { createElement, Component } from 'rax'; 2 | import { View, Text,Image } from 'weex-nuke'; 3 | import styles from './profile.less'; 4 | 5 | class Profile extends Component{ 6 | 7 | render(){ 8 | const { name, avatar} = this.props.userInfo; 9 | return( 10 | 11 | 12 | 13 | 14 | 15 | 16 | { name } 17 | 18 | 19 | 20 | ); 21 | } 22 | } 23 | 24 | export default Profile; -------------------------------------------------------------------------------- /weex-rax-fed-todo/src/pages/index/mods/profile.less: -------------------------------------------------------------------------------- 1 | .app_users{ 2 | width:710; 3 | height: 136; 4 | background-color: #fff; 5 | justify-content:'center'; 6 | flex-direction:'row'; 7 | border-radius:10; 8 | margin-bottom: 30; 9 | } 10 | .app_users_con{ 11 | width: 710; 12 | height: 136; 13 | flex-direction: row; 14 | } 15 | .app_users_image_box{ 16 | width: 148; 17 | height: 136; 18 | justify-content: center; 19 | align-items: center; 20 | margin-right: 10; 21 | } 22 | .app_users_image{ 23 | width: 100; 24 | height: 100; 25 | background-color: #f8f8f8; 26 | } 27 | .app_users_name_box{ 28 | justify-content: center; 29 | align-items: center; 30 | } 31 | .app_users_name{ 32 | font-size: 34; 33 | color: #323334 34 | } -------------------------------------------------------------------------------- /weex-rax-fed-todo/src/pages/index/redux/actions/todo.js: -------------------------------------------------------------------------------- 1 | import {getUserInfo,getUserId} from '../../../../util/lib/request'; 2 | import { toast } from '../../../../util/lib/util'; 3 | 4 | export const INIT_LIST = 'INIT_LIST'; 5 | export const DELETE_ITEM = 'DELETE_ITEM'; 6 | export const ADD_ITEM = 'ADD_ITEM'; 7 | export const MODIFY_ITEM = 'MODIFY_ITEM'; 8 | export const GET_USER_INFO = 'GET_USER_INFO'; 9 | 10 | export function initList() { 11 | return { type: INIT_LIST }; 12 | } 13 | export function deleteItem(id) { 14 | return { type: DELETE_ITEM, id }; 15 | } 16 | export function addItem(obj) { 17 | return { type: ADD_ITEM, obj }; 18 | } 19 | export function modifyItem(obj) { 20 | return { type: MODIFY_ITEM, obj }; 21 | } 22 | 23 | function userInfoData(data){ 24 | return { 25 | type: GET_USER_INFO, 26 | payload: { 27 | data:data 28 | } 29 | }; 30 | } 31 | 32 | export function fetchUserInfo(){ 33 | return function(dispatch){ 34 | /* 35 | 模拟数据 36 | { 37 | name: 'icepy', 38 | avatar: 'https://avatars3.githubusercontent.com/u/3321837?v=4&u=474bf7c009911c87a36679fe18ab6e5aba26d9b7&s=400' 39 | } 40 | */ 41 | getUserId().then((res) =>{ 42 | getUserInfo(res.userid).then((res) => { 43 | const { avatar, name, mobile } = res; 44 | dispatch(userInfoData({ 45 | avatar, 46 | name, 47 | mobile 48 | })); 49 | }).catch((err) => { 50 | toast('fetch user info error : ' + JSON.stringify(err)); 51 | }); 52 | }).catch((err) => { 53 | toast('fetch user id error : ' + JSON.stringify(err)); 54 | }); 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /weex-rax-fed-todo/src/pages/index/redux/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import todoReducer from './todo.js'; 3 | 4 | //combine所有reducer为一个根reducer 5 | const rootReducer = combineReducers({ 6 | todoReducer 7 | }); 8 | 9 | export default rootReducer; 10 | -------------------------------------------------------------------------------- /weex-rax-fed-todo/src/pages/index/redux/reducers/todo.js: -------------------------------------------------------------------------------- 1 | import { INIT_LIST, DELETE_ITEM, ADD_ITEM, MODIFY_ITEM,GET_USER_INFO } from '../actions/todo.js' 2 | 3 | function guid() { 4 | function s4() { 5 | return Math.floor((1 + Math.random()) * 0x10000) 6 | .toString(16) 7 | .substring(1); 8 | } 9 | return s4() + s4() + '-' + s4() + '-' + s4() + '-' + 10 | s4() + '-' + s4() + s4() + s4(); 11 | } 12 | const initState = { 13 | toDoList: [ 14 | { 15 | content: '拜访好友', 16 | id: '1111', 17 | }, { 18 | content: '圣诞夜准备', 19 | id: '2222', 20 | }, { 21 | content: '读一本书', 22 | id: '333', 23 | }, { 24 | content: '逛超市', 25 | id: '45454534', 26 | }, { 27 | content: 'Image组件,我设置了 resizeMode=\'center\', 在 ios里面是ok的,但是在安卓上没有生效', 28 | id: '32423f', 29 | }, { 30 | content: '写一封邮件', 31 | id: '123123', 32 | }, 33 | ], 34 | doneList: [], 35 | userInfo:{} 36 | }; 37 | export default function todoMVC(state = initState, action) { 38 | switch (action.type) { 39 | case INIT_LIST: 40 | return state; 41 | case DELETE_ITEM: 42 | return { 43 | ...state, 44 | toDoList: [ 45 | ...state.toDoList.slice(0, action.id), 46 | ...state.toDoList.slice(action.id + 1), 47 | ], 48 | }; 49 | case ADD_ITEM: 50 | state.toDoList.splice(0, 0, { 51 | content: action.obj.content, 52 | id: guid(), 53 | }); 54 | return { 55 | ...state, 56 | toDoList: state.toDoList, 57 | }; 58 | case MODIFY_ITEM: { 59 | let deleteIndex; 60 | for (let i = 0; i < state.toDoList.length; i++) { 61 | if (state.toDoList[i].id === action.obj.id) { 62 | deleteIndex = i; 63 | break; 64 | } 65 | } 66 | const item = state.toDoList[deleteIndex]; 67 | state.doneList.push(item); 68 | state.toDoList.splice(deleteIndex, 1); 69 | return { 70 | ...state, 71 | toDoList: state.toDoList, 72 | doneList: state.doneList, 73 | }; 74 | } 75 | case GET_USER_INFO: 76 | return {...state, userInfo: action.payload.data} 77 | default: 78 | return state; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /weex-rax-fed-todo/src/pages/index/redux/store/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import { createStore, applyMiddleware, compose } from 'redux'; 3 | import thunkMiddleware from 'redux-thunk'; 4 | import { logger } from './middlewares' 5 | 6 | const createStoreWithMiddleware = compose( 7 | applyMiddleware( 8 | thunkMiddleware, 9 | logger 10 | ) 11 | )(createStore); 12 | export default createStoreWithMiddleware; 13 | -------------------------------------------------------------------------------- /weex-rax-fed-todo/src/util/apimap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const local = { 4 | 'theme.list.get.info': { 5 | type: 'jsonp', 6 | value: 'hahahaha', 7 | }, 8 | }; 9 | const product = { 10 | 'nuke.demo.interface.get': { //fetch请求 11 | type: 'jsonp', 12 | value: 'http://easy-mock.com/mock/5954c9509adc231f356da90e/example/mock' 13 | }, 14 | }; 15 | export { 16 | local, 17 | product, 18 | }; 19 | -------------------------------------------------------------------------------- /weex-rax-fed-todo/src/util/global.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 全局设置 local 日常 production 线上和预发 3 | */ 4 | export default { 5 | env: 'production' 6 | } 7 | -------------------------------------------------------------------------------- /weex-rax-fed-todo/src/util/index.js: -------------------------------------------------------------------------------- 1 | import fetch from './request/fetch'; 2 | 3 | export const Http = { 4 | fetch: fetch 5 | } 6 | export function NameSpace(name) { 7 | return function (v) { 8 | return name + '-' + v; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /weex-rax-fed-todo/src/util/lib/env.js: -------------------------------------------------------------------------------- 1 | export const APPHOST = 'http://www.w3crange.com'; 2 | -------------------------------------------------------------------------------- /weex-rax-fed-todo/src/util/lib/request.js: -------------------------------------------------------------------------------- 1 | import dingtalk from 'dingtalk-javascript-sdk'; 2 | import { request, authCode, fetchBundleUrl } from './util.js'; 3 | import { APPHOST } from './env.js'; 4 | 5 | export function jsApiOAuth (){ 6 | let Config = { 7 | method: 'GET', 8 | uri: APPHOST + '/api/jsapi-oauth', 9 | body: { 10 | href: fetchBundleUrl() 11 | } 12 | }; 13 | let jsApiList = []; 14 | return new Promise(function(resolve, reject){ 15 | request(Config,function(error,res){ 16 | if (!error){ 17 | const data = res.data; 18 | if (data.errcode === 0){ 19 | const oauth = { 20 | agentId: data.agentId || '', 21 | corpId: data.corpId || '', 22 | timeStamp: data.timeStamp || '', 23 | nonceStr: data.nonceStr || '', 24 | signature: data.signature || '', 25 | jsApiList: jsApiList || [] 26 | }; 27 | dingtalk.config(oauth); 28 | resolve(); 29 | } 30 | } else { 31 | reject(res); 32 | } 33 | }); 34 | }); 35 | } 36 | 37 | export function getUserId (){ 38 | let Config = { 39 | method: 'GET', 40 | uri: APPHOST + '/api/get-user-info' 41 | }; 42 | return new Promise(function(resolve, reject){ 43 | authCode().then(function(result){ 44 | const code = result.code; 45 | Config.body = {}; 46 | Config.body.code = code; 47 | request(Config,function(error,res){ 48 | if (!error && res.ok){ 49 | const data = res.data; 50 | if (data.errcode === 0){ 51 | resolve(data); 52 | } else { 53 | reject(data); 54 | } 55 | } 56 | }); 57 | }).catch(function(err){ 58 | reject(err); 59 | }); 60 | }); 61 | } 62 | 63 | export function getUserInfo(userId){ 64 | let Config = { 65 | method: 'GET', 66 | uri: APPHOST + '/api/get', 67 | body: { 68 | userid: userId 69 | } 70 | }; 71 | return new Promise(function(resolve, reject){ 72 | request(Config, function(error, res){ 73 | if (!error && res.ok){ 74 | const data = res.data; 75 | if (data.errcode === 0){ 76 | // 再处理 77 | resolve(data); 78 | } else { 79 | reject(data); 80 | } 81 | } 82 | }); 83 | }); 84 | } 85 | -------------------------------------------------------------------------------- /weex-rax-fed-todo/src/util/lib/storage.js: -------------------------------------------------------------------------------- 1 | import dingtalk from 'dingtalk-javascript-sdk'; 2 | import { toast } from './util.js'; 3 | 4 | export function getItem (name,cb){ 5 | const date = new Date(); 6 | dingtalk.ready(function(){ 7 | dingtalk.apis.util.domainStorage.getItem({ 8 | name: name, 9 | onSuccess (res){ 10 | const value = res.value; 11 | if (!value){ 12 | if (typeof cb === 'function'){ 13 | cb(1,value); 14 | } 15 | return; 16 | } 17 | if (typeof cb === 'function'){ 18 | try { 19 | let item = JSON.parse(value); 20 | cb(null, item); 21 | }catch(e){ 22 | cb(e,res); 23 | } 24 | } 25 | } 26 | }); 27 | }); 28 | } 29 | 30 | export function clearItems (){ 31 | dingtalk.ready(function(){ 32 | dingtalk.apis.util.domainStorage.clearItems({}); 33 | }); 34 | } 35 | 36 | export function removeItem (name){ 37 | dingtalk.ready(function(){ 38 | dingtalk.apis.util.domainStorage.removeItem({ 39 | name: name 40 | }); 41 | }); 42 | } 43 | 44 | export function setItem (name,val){ 45 | dingtalk.ready(function(){ 46 | dingtalk.apis.util.domainStorage.setItem({ 47 | name: name, 48 | value: JSON.stringify(val) 49 | }); 50 | }); 51 | } 52 | -------------------------------------------------------------------------------- /weex-rax-fed-todo/src/util/request/fetch.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import qs from 'qs'; 4 | import G from '../global.js'; 5 | import * as APIMAP from '../apimap.js'; 6 | 7 | export default function (param) { 8 | /** 9 | * 全局定义NODE_ENV 不把mock的数据逻辑带到线上 10 | */ 11 | if (process.env.NODE_ENV === 'development' && G.env && G.env === 'local') { 12 | try { 13 | const url = APIMAP.local[param.name].value; 14 | return fetch(url).then((response) => { 15 | return response.json(); 16 | }).catch((err) => { 17 | console.log(err); 18 | }); 19 | } catch (error) { 20 | throw new Error(error, 'local url is undefined in apimap.js'); 21 | } 22 | } else { 23 | try { 24 | const url = APIMAP.product[param.name].value; 25 | const queryString = qs.stringify(param.data); 26 | param.url = `${url}?${queryString}`; 27 | 28 | return fetch(param.url, param).then((response) => { 29 | return response.json(); 30 | }).catch((err) => { 31 | console.log('fetch error >>>>>', err); 32 | }); 33 | } catch (error) { 34 | throw new Error(error, 'product url is undefined in apimap.js'); 35 | } 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /weex-rax-fed-todo/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | weex-nuke降级H5 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /weex-rax-fed-todo/www/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | weex-nuke降级H5 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [[ 3 | "es2015", { "modules": false }]], 4 | "plugins": ["transform-flow-strip-types"] 5 | } 6 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/README.md: -------------------------------------------------------------------------------- 1 | ## How Run 2 | 3 | ```bash 4 | # install dependencies 5 | npm install 6 | 7 | # 启动 mock 服务器 8 | npm run mock 9 | 10 | # 启动 vue web dev 环境,自启服务器 at localhost:8080 11 | npm run dev:web 12 | 13 | # build vue web release 环境 14 | npm run build:web 15 | 16 | # 启动 weex dev 环境,自启服务器 at localhost:8089 17 | npm run dev:weex 18 | 19 | # 启动 weex release 环境 20 | npm run build:weex 21 | 22 | # 编译weex和Web环境下所需要的资源,这是可以正式部署的静态资源 23 | npm run build 24 | ``` -------------------------------------------------------------------------------- /weex-vue-fed-todo/build/build-weex.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by xiangwenwen on 2017/2/8. 3 | */ 4 | 5 | var webpack = require('webpack'); 6 | var chalk = require('chalk'); 7 | var webpackConfig = require('./webpack.weex.conf'); 8 | 9 | webpack(webpackConfig,function (err, stats) { 10 | if (err) { 11 | throw err 12 | } 13 | process.stdout.write(stats.toString({ 14 | colors: true, 15 | modules: false, 16 | children: false, 17 | chunks: false, 18 | chunkModules: false 19 | }) + '\n\n') 20 | 21 | console.log(chalk.cyan(' Build complete.\n')) 22 | console.log(chalk.yellow( 23 | ' Tip: weex bundle.js \n' 24 | )) 25 | }); 26 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/build/build.js: -------------------------------------------------------------------------------- 1 | // https://github.com/shelljs/shelljs 2 | require('./check-versions')() 3 | 4 | process.env.NODE_ENV = 'production' 5 | 6 | var ora = require('ora') 7 | var path = require('path') 8 | var chalk = require('chalk') 9 | var shell = require('shelljs') 10 | var webpack = require('webpack') 11 | var config = require('../config') 12 | var webpackConfig = require('./webpack.prod.conf') 13 | 14 | var spinner = ora('building for production...') 15 | spinner.start() 16 | 17 | var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory) 18 | shell.rm('-rf', assetsPath) 19 | shell.mkdir('-p', assetsPath) 20 | shell.config.silent = true 21 | shell.cp('-R', 'static/*', assetsPath) 22 | shell.config.silent = false 23 | 24 | webpack(webpackConfig, function (err, stats) { 25 | spinner.stop() 26 | if (err) throw err 27 | process.stdout.write(stats.toString({ 28 | colors: true, 29 | modules: false, 30 | children: false, 31 | chunks: false, 32 | chunkModules: false 33 | }) + '\n\n') 34 | 35 | console.log(chalk.cyan(' Build complete.\n')) 36 | console.log(chalk.yellow( 37 | ' Tip: built files are meant to be served over an HTTP server.\n' + 38 | ' Opening index.html over file:// won\'t work.\n' 39 | )) 40 | }) 41 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/build/check-versions.js: -------------------------------------------------------------------------------- 1 | var chalk = require('chalk') 2 | var semver = require('semver') 3 | var packageConfig = require('../package.json') 4 | 5 | function exec (cmd) { 6 | return require('child_process').execSync(cmd).toString().trim() 7 | } 8 | 9 | var versionRequirements = [ 10 | { 11 | name: 'node', 12 | currentVersion: semver.clean(process.version), 13 | versionRequirement: packageConfig.engines.node 14 | }, 15 | { 16 | name: 'npm', 17 | currentVersion: exec('npm --version'), 18 | versionRequirement: packageConfig.engines.npm 19 | } 20 | ] 21 | 22 | module.exports = function () { 23 | var warnings = [] 24 | for (var i = 0; i < versionRequirements.length; i++) { 25 | var mod = versionRequirements[i] 26 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 27 | warnings.push(mod.name + ': ' + 28 | chalk.red(mod.currentVersion) + ' should be ' + 29 | chalk.green(mod.versionRequirement) 30 | ) 31 | } 32 | } 33 | 34 | if (warnings.length) { 35 | console.log('') 36 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 37 | console.log() 38 | for (var i = 0; i < warnings.length; i++) { 39 | var warning = warnings[i] 40 | console.log(' ' + warning) 41 | } 42 | console.log() 43 | process.exit(1) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/build/dev-client.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | require('eventsource-polyfill') 3 | var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') 4 | 5 | hotClient.subscribe(function (event) { 6 | if (event.action === 'reload') { 7 | window.location.reload() 8 | } 9 | }) 10 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/build/dev-server.js: -------------------------------------------------------------------------------- 1 | require('./check-versions')() 2 | 3 | var config = require('../config') 4 | if (!process.env.NODE_ENV) { 5 | process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV) 6 | } 7 | 8 | var opn = require('opn') 9 | var path = require('path') 10 | var express = require('express') 11 | var webpack = require('webpack') 12 | var proxyMiddleware = require('http-proxy-middleware') 13 | var webpackConfig = require('./webpack.dev.conf') 14 | 15 | // default port where dev server listens for incoming traffic 16 | var port = process.env.PORT || config.dev.port 17 | // automatically open browser, if not set will be false 18 | var autoOpenBrowser = !!config.dev.autoOpenBrowser 19 | // Define HTTP proxies to your custom API backend 20 | // https://github.com/chimurai/http-proxy-middleware 21 | var proxyTable = config.dev.proxyTable 22 | 23 | var app = express() 24 | var compiler = webpack(webpackConfig) 25 | 26 | var devMiddleware = require('webpack-dev-middleware')(compiler, { 27 | publicPath: webpackConfig.output.publicPath, 28 | quiet: true 29 | }) 30 | 31 | var hotMiddleware = require('webpack-hot-middleware')(compiler, { 32 | log: () => {} 33 | }) 34 | // force page reload when html-webpack-plugin template changes 35 | compiler.plugin('compilation', function (compilation) { 36 | compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { 37 | hotMiddleware.publish({ action: 'reload' }) 38 | cb() 39 | }) 40 | }) 41 | 42 | // proxy api requests 43 | Object.keys(proxyTable).forEach(function (context) { 44 | var options = proxyTable[context] 45 | if (typeof options === 'string') { 46 | options = { target: options } 47 | } 48 | app.use(proxyMiddleware(options.filter || context, options)) 49 | }) 50 | 51 | // handle fallback for HTML5 history API 52 | app.use(require('connect-history-api-fallback')()) 53 | 54 | // serve webpack bundle output 55 | app.use(devMiddleware) 56 | 57 | // enable hot-reload and state-preserving 58 | // compilation error display 59 | app.use(hotMiddleware) 60 | 61 | // serve pure static assets 62 | var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) 63 | app.use(staticPath, express.static('./static')) 64 | 65 | var uri = 'http://localhost:' + port 66 | 67 | devMiddleware.waitUntilValid(function () { 68 | console.log('> Listening at ' + uri + '\n') 69 | }) 70 | 71 | module.exports = app.listen(port, function (err) { 72 | if (err) { 73 | console.log(err) 74 | return 75 | } 76 | 77 | // when env is testing, don't need open it 78 | if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') { 79 | opn(uri) 80 | } 81 | }) 82 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/build/dev-weex-server.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by xiangwenwen on 2017/2/8. 3 | */ 4 | 5 | var config = require('../config') 6 | if (!process.env.NODE_ENV) { 7 | process.env.NODE_ENV = JSON.parse(config.weex.env.NODE_ENV) 8 | } 9 | var path = require('path'); 10 | var express = require('express'); 11 | var webpack = require('webpack'); 12 | var webpackConfig = require('./webpack.weex.conf.js'); 13 | var port = process.env.PORT || config.weex.port; 14 | var app = express(); 15 | var compiler = webpack(webpackConfig); 16 | var devMiddleware = require('webpack-dev-middleware')(compiler, { 17 | publicPath: webpackConfig.output.publicPath, 18 | quiet: true 19 | }) 20 | var uri = 'http://localhost:' + port; 21 | console.log(uri); 22 | app.use(devMiddleware); 23 | var staticPath = path.posix.join(config.weex.assetsPublicPath, config.weex.assetsSubDirectory) 24 | app.use(staticPath, express.static('./dist')) 25 | module.exports = app.listen(port, function (err) { 26 | if (err) { 27 | console.log(err) 28 | return; 29 | } 30 | }) 31 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/build/mock-server.js: -------------------------------------------------------------------------------- 1 | var serve = require('koa-static'); 2 | var router = require('../mock/router.js'); 3 | var path = require('path'); 4 | var koa = require('koa'); 5 | var app = koa(); 6 | 7 | function getIPAdress() { 8 | var interfaces = require('os').networkInterfaces(); 9 | for (var devName in interfaces) { 10 | var iface = interfaces[devName]; 11 | for (var i = 0; i < iface.length; i++) { 12 | var alias = iface[i]; 13 | if (alias.family === 'IPv4') { 14 | return alias.address; 15 | } 16 | } 17 | } 18 | } 19 | 20 | app.use(serve('.')); 21 | app.use(router.routes()); 22 | app.use(router.allowedMethods()); 23 | var server = require('http').createServer(app.callback()); 24 | server.listen(8999, function () { 25 | console.log('Http server running on http://%s:%s', getIPAdress(), server.address().port); 26 | }); 27 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/build/utils.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 4 | 5 | exports.assetsPath = function (_path) { 6 | var assetsSubDirectory = process.env.NODE_ENV === 'production' 7 | ? config.build.assetsSubDirectory 8 | : config.dev.assetsSubDirectory 9 | return path.posix.join(assetsSubDirectory, _path) 10 | } 11 | 12 | exports.cssLoaders = function (options) { 13 | options = options || {} 14 | // generate loader string to be used with extract text plugin 15 | function generateLoaders (loaders) { 16 | var sourceLoader = loaders.map(function (loader) { 17 | var extraParamChar 18 | if (/\?/.test(loader)) { 19 | loader = loader.replace(/\?/, '-loader?') 20 | extraParamChar = '&' 21 | } else { 22 | loader = loader + '-loader' 23 | extraParamChar = '?' 24 | } 25 | return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '') 26 | }).join('!') 27 | 28 | // Extract CSS when that option is specified 29 | // (which is the case during production build) 30 | if (options.extract) { 31 | return ExtractTextPlugin.extract({ 32 | use: sourceLoader, 33 | fallback: 'vue-style-loader' 34 | }) 35 | } else { 36 | return ['vue-style-loader', sourceLoader].join('!') 37 | } 38 | } 39 | 40 | // http://vuejs.github.io/vue-loader/en/configurations/extract-css.html 41 | return { 42 | css: generateLoaders(['css']), 43 | postcss: generateLoaders(['css']), 44 | less: generateLoaders(['css', 'less']), 45 | sass: generateLoaders(['css', 'sass?indentedSyntax']), 46 | scss: generateLoaders(['css', 'sass']), 47 | stylus: generateLoaders(['css', 'stylus']), 48 | styl: generateLoaders(['css', 'stylus']) 49 | } 50 | } 51 | 52 | // Generate loaders for standalone style files (outside of .vue) 53 | exports.styleLoaders = function (options) { 54 | var output = [] 55 | var loaders = exports.cssLoaders(options) 56 | for (var extension in loaders) { 57 | var loader = loaders[extension] 58 | output.push({ 59 | test: new RegExp('\\.' + extension + '$'), 60 | loader: loader 61 | }) 62 | } 63 | return output 64 | } 65 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | var utils = require('./utils') 2 | var config = require('../config') 3 | var isProduction = process.env.NODE_ENV === 'production' 4 | 5 | module.exports = { 6 | /** 7 | * important! should use postTransformNode to add $processStyle for 8 | * inline style normalization. 9 | */ 10 | compilerModules: [ 11 | { 12 | postTransformNode: el => { 13 | el.staticStyle = `$processStyle(${el.staticStyle})` 14 | el.styleBinding = `$processStyle(${el.styleBinding})` 15 | } 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var utils = require('./utils') 3 | var config = require('../config') 4 | var vueLoaderConfig = require('./vue-loader.conf') 5 | 6 | function resolve (dir) { 7 | return path.join(__dirname, '..', dir) 8 | } 9 | module.exports = { 10 | entry: { 11 | 'vue-bundle': './src/platforms/web/web.entry.js' 12 | }, 13 | output: { 14 | path: config.build.assetsRoot, 15 | filename: '[name].web.js', 16 | publicPath: process.env.NODE_ENV === 'production' 17 | ? config.build.assetsPublicPath 18 | : config.dev.assetsPublicPath 19 | }, 20 | resolve: { 21 | extensions: ['.js', '.vue', '.json'], 22 | modules: [ 23 | resolve('src'), 24 | resolve('node_modules') 25 | ], 26 | alias: { 27 | 'vue$': 'vue/dist/vue.common.js', 28 | 'src': resolve('src'), 29 | 'assets': resolve('src/assets'), 30 | 'components': resolve('src/components') 31 | } 32 | }, 33 | module: { 34 | rules: [ 35 | { 36 | test: /\.vue$/, 37 | loader: 'vue-loader', 38 | options: vueLoaderConfig 39 | }, 40 | { 41 | test: /\.js$/, 42 | loader: 'babel-loader', 43 | include: [resolve('src'), resolve('test')] 44 | }, 45 | { 46 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 47 | loader: 'url-loader', 48 | query: { 49 | limit: 10000, 50 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 51 | } 52 | }, 53 | { 54 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 55 | loader: 'url-loader', 56 | query: { 57 | limit: 10000, 58 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 59 | } 60 | } 61 | ] 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | var utils = require('./utils') 2 | var webpack = require('webpack') 3 | var config = require('../config') 4 | var merge = require('webpack-merge') 5 | var baseWebpackConfig = require('./webpack.base.conf') 6 | var HtmlWebpackPlugin = require('html-webpack-plugin') 7 | var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 8 | 9 | // add hot-reload related code to entry chunks 10 | Object.keys(baseWebpackConfig.entry).forEach(function (name) { 11 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) 12 | }) 13 | 14 | module.exports = merge(baseWebpackConfig, { 15 | module: { 16 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) 17 | }, 18 | // cheap-module-eval-source-map is faster for development 19 | devtool: '#cheap-module-eval-source-map', 20 | plugins: [ 21 | new webpack.DefinePlugin({ 22 | 'process.env': config.dev.env 23 | }), 24 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage 25 | new webpack.HotModuleReplacementPlugin(), 26 | new webpack.NoEmitOnErrorsPlugin(), 27 | // https://github.com/ampedandwired/html-webpack-plugin 28 | new HtmlWebpackPlugin({ 29 | filename: 'index.html', 30 | template: 'index.html', 31 | inject: true 32 | }), 33 | new FriendlyErrorsPlugin() 34 | ] 35 | }) 36 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/build/webpack.weex.conf.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by xiangwenwen on 2017/2/8. 3 | */ 4 | 5 | // { "framework": "Vue" } 6 | 7 | var webpack = require('webpack'); 8 | var path = require('path'); 9 | var webacpkConfig = require('../config'); 10 | var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 11 | if (!process.env.NODE_ENV) { 12 | process.env.NODE_ENV = JSON.parse(config.weex.env.NODE_ENV) 13 | } 14 | var env = process.env.NODE_ENV; 15 | function resolve (dir) { 16 | return path.join(__dirname, '..', dir) 17 | } 18 | var watch = false; 19 | var plugins = []; 20 | var filename = '[name].js'; 21 | if (env === 'production'){ 22 | plugins = [ 23 | new webpack.DefinePlugin({ 24 | 'process.env': JSON.stringify(env) 25 | }), 26 | new webpack.optimize.UglifyJsPlugin({ 27 | compress: { 28 | warnings: false 29 | } 30 | }) 31 | ]; 32 | } else { 33 | if (env === 'watch'){ 34 | watch = true; 35 | filename = '[name]-watch.js'; 36 | } else { 37 | filename = '[name]-dev.js'; 38 | plugins = [ 39 | new FriendlyErrorsPlugin() 40 | ]; 41 | } 42 | } 43 | 44 | plugins.push( 45 | new webpack.BannerPlugin({ 46 | raw: true , 47 | banner: '// { "framework": "Vue" }\n' 48 | }) 49 | ); 50 | 51 | var config = { 52 | entry: { 53 | 'weex-bundle': './src/platforms/weex/weex.entry.js?entry=true' 54 | }, 55 | output: { 56 | path: path.resolve(__dirname, '../dist'), 57 | filename: filename 58 | }, 59 | module: { 60 | rules: [ 61 | { 62 | test: /\.vue(\?[^?]+)?$/, 63 | loaders: ['weex-loader'], 64 | exclude: /node_modules/ 65 | }, 66 | { 67 | test: /\.js$/, 68 | loaders: ['babel-loader'], 69 | exclude: /node_modules/ 70 | } 71 | ] 72 | }, 73 | plugins: plugins, 74 | resolve: { 75 | alias: {} 76 | }, 77 | watch: watch 78 | }; 79 | 80 | if (env !== 'production'){ 81 | config.output.publicPath = webacpkConfig.weex.assetsPublicPath; 82 | } 83 | 84 | module.exports = config; 85 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/config/dev.env.js: -------------------------------------------------------------------------------- 1 | var merge = require('webpack-merge') 2 | var prodEnv = require('./prod.env') 3 | 4 | module.exports = merge(prodEnv, { 5 | NODE_ENV: '"development"' 6 | }) 7 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/config/index.js: -------------------------------------------------------------------------------- 1 | // see http://vuejs-templates.github.io/webpack for documentation. 2 | var path = require('path') 3 | 4 | module.exports = { 5 | build: { 6 | env: require('./prod.env'), 7 | index: path.resolve(__dirname, '../dist/index.html'), 8 | assetsRoot: path.resolve(__dirname, '../dist'), 9 | assetsSubDirectory: 'static', 10 | assetsPublicPath: '/', 11 | productionSourceMap: true, 12 | // Gzip off by default as many popular static hosts such as 13 | // Surge or Netlify already gzip all static assets for you. 14 | // Before setting to `true`, make sure to: 15 | // npm install --save-dev compression-webpack-plugin 16 | productionGzip: false, 17 | productionGzipExtensions: ['js', 'css'], 18 | // Run the build command with an extra argument to 19 | // View the bundle analyzer report after build finishes: 20 | // `npm run build --report` 21 | // Set to `true` or `false` to always turn it on or off 22 | bundleAnalyzerReport: process.env.npm_config_report 23 | }, 24 | dev: { 25 | env: require('./dev.env'), 26 | port: 8080, 27 | autoOpenBrowser: true, 28 | assetsSubDirectory: 'static', 29 | assetsPublicPath: '/', 30 | proxyTable: {}, 31 | // CSS Sourcemaps off by default because relative paths are "buggy" 32 | // with this option, according to the CSS-Loader README 33 | // (https://github.com/webpack/css-loader#sourcemaps) 34 | // In our experience, they generally work as expected, 35 | // just be aware of this issue when enabling this option. 36 | cssSourceMap: false 37 | }, 38 | weex: { 39 | env: require('./dev.env'), 40 | port: 8089, 41 | assetsSubDirectory: 'dist', 42 | assetsPublicPath: '/' 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/config/prod.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: '"production"' 3 | } 4 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/dist/index.html: -------------------------------------------------------------------------------- 1 | Todo
-------------------------------------------------------------------------------- /weex-vue-fed-todo/dist/static/js/manifest.js: -------------------------------------------------------------------------------- 1 | !function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,c,i){for(var u,a,f,s=0,l=[];s 2 | 3 | 4 | 5 | 6 | Todo 7 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/info.text: -------------------------------------------------------------------------------- 1 | dependencies nodejs-server-todo -------------------------------------------------------------------------------- /weex-vue-fed-todo/mock/router.js: -------------------------------------------------------------------------------- 1 | var router = require('koa-router')(); 2 | 3 | /* 4 | * 这是一个例子,分别展示了post请求下的mock和get请求下的mock 5 | */ 6 | 7 | router.post('/weex/post', function *(next) { 8 | this.body = { 9 | success: true 10 | }; 11 | }); 12 | 13 | router.get('/weex/get', function *(next) { 14 | this.body = { 15 | success: 1 16 | }; 17 | }); 18 | 19 | module.exports = router; 20 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "weex-vue-fed-todo", 3 | "version": "1.0.0", 4 | "description": "A Weex and Vue.js project", 5 | "author": "icepy", 6 | "private": true, 7 | "scripts": { 8 | "dev:web": "node build/dev-server.js", 9 | "build:web": "npm run release:web", 10 | "release:web": "node build/build.js", 11 | "dev:weex": "node build/dev-weex-server.js", 12 | "build:weex": "npm run release:weex", 13 | "release:weex": "NODE_ENV=production node build/build-weex.js", 14 | "build": "npm run release:weex && npm run release:web", 15 | "dev:watch": "NODE_ENV=watch node build/build-weex.js", 16 | "mock": "nodemon build/mock-server.js" 17 | }, 18 | "dependencies": { 19 | "lodash": "^4.17.4", 20 | "vue": "^2.1.10", 21 | "vue-router": "^2.5.3", 22 | "weex-dingtalk": "^0.1.4", 23 | "weex-dingtalk-journey": "^0.1.0", 24 | "weex-html5": "^0.4.1", 25 | "weex-vue-render": "^0.11.42" 26 | }, 27 | "devDependencies": { 28 | "babel-core": "^6.22.1", 29 | "babel-loader": "^6.2.10", 30 | "babel-plugin-transform-flow-strip-types": "^6.22.0", 31 | "babel-plugin-transform-runtime": "^6.22.0", 32 | "babel-preset-es2015": "^6.22.0", 33 | "babel-preset-stage-2": "^6.22.0", 34 | "babel-register": "^6.22.0", 35 | "chalk": "^1.1.3", 36 | "connect-history-api-fallback": "^1.3.0", 37 | "css-loader": "^0.26.1", 38 | "eventsource-polyfill": "^0.9.6", 39 | "express": "^4.14.1", 40 | "extract-text-webpack-plugin": "^2.0.0-rc.2", 41 | "file-loader": "^0.10.0", 42 | "flow-bin": "^0.42.0", 43 | "friendly-errors-webpack-plugin": "^1.1.3", 44 | "function-bind": "^1.1.0", 45 | "html-webpack-plugin": "^2.28.0", 46 | "http-proxy-middleware": "^0.17.3", 47 | "opn": "^4.0.2", 48 | "ora": "^1.1.0", 49 | "semver": "^5.3.0", 50 | "shelljs": "^0.7.6", 51 | "url-loader": "^0.5.7", 52 | "vue-loader": "^11.3.3", 53 | "vue-style-loader": "^2.0.0", 54 | "vue-template-compiler": "^2.1.10", 55 | "webpack": "^2.2.1", 56 | "webpack-bundle-analyzer": "^2.2.1", 57 | "webpack-dev-middleware": "^1.10.0", 58 | "webpack-hot-middleware": "^2.16.1", 59 | "webpack-merge": "^2.6.1", 60 | "weex-loader": "^0.4.4", 61 | "koa": "~1.1.2", 62 | "koa-router": "~5.3.0", 63 | "koa-static": "~1.5.2", 64 | "nodemon": "^1.11.0" 65 | }, 66 | "engines": { 67 | "node": ">= 4.0.0", 68 | "npm": ">= 3.0.0" 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/src/components/component.vue: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-dingtalk/which-language-demo/beec798dff6eab38dec5b2c9c93434a6ffabed03/weex-vue-fed-todo/src/components/component.vue -------------------------------------------------------------------------------- /weex-vue-fed-todo/src/container/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 11 | 12 | 17 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/src/container/router.js: -------------------------------------------------------------------------------- 1 | import VueRouter from 'vue-router'; 2 | import dingtalk from 'weex-dingtalk'; 3 | import journey from 'weex-dingtalk-journey'; 4 | import { toast,setLeft } from '../lib/util.js'; 5 | import { jsApiOAuth } from '../lib/request.js'; 6 | import HomePage from '../pages/home/index.vue'; 7 | import TodoAppListPage from '../pages/list/index.vue'; 8 | import AddCellPage from '../pages/add/index.vue'; 9 | 10 | const routes = [ 11 | { 12 | path:'/', 13 | name: 'home', 14 | component: HomePage 15 | }, 16 | { 17 | path: '/list', 18 | name: 'list', 19 | component: TodoAppListPage 20 | }, 21 | { 22 | path: '/add', 23 | name: 'add', 24 | component: AddCellPage 25 | } 26 | ]; 27 | 28 | dingtalk.error(function(err){ 29 | console.log(JSON.stringify(err)) 30 | toast('Error : ' + JSON.stringify(err)); 31 | }); 32 | 33 | const { env } = journey; 34 | 35 | export default function Router(Vue){ 36 | Vue.use(VueRouter); 37 | const router = new VueRouter({ 38 | routes: routes 39 | }); 40 | const left = { 41 | show: true, 42 | control: true, 43 | text: '返回' 44 | } 45 | const backHandler = function(e){ 46 | if (env.isWeb){ 47 | e.preventDefault(); 48 | } 49 | 50 | router.go(-1); 51 | } 52 | setLeft(left, backHandler); 53 | // jsApiOAuth().then(function(){ 54 | // console.log('签名完成'); 55 | // }).catch(function(err){ 56 | // console.log(JSON.stringify(err)) 57 | // }); 58 | return { 59 | router 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/src/lib/env.js: -------------------------------------------------------------------------------- 1 | export const APPHOST = 'http://www.w3crange.com'; 2 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/src/lib/request.js: -------------------------------------------------------------------------------- 1 | import dingtalk from 'weex-dingtalk'; 2 | import { request, authCode, fetchBundleUrl } from './util.js'; 3 | import { APPHOST } from './env.js'; 4 | 5 | export function jsApiOAuth (){ 6 | let Config = { 7 | method: 'GET', 8 | uri: APPHOST + '/api/jsapi-oauth', 9 | body: { 10 | href: fetchBundleUrl() 11 | } 12 | }; 13 | let jsApiList = []; 14 | return new Promise(function(resolve, reject){ 15 | request(Config,function(error,res){ 16 | if (!error){ 17 | const data = res.data; 18 | if (data.errcode === 0){ 19 | const oauth = { 20 | agentId: data.agentId || '', 21 | corpId: data.corpId || '', 22 | timeStamp: data.timeStamp || '', 23 | nonceStr: data.nonceStr || '', 24 | signature: data.signature || '', 25 | jsApiList: jsApiList || [] 26 | }; 27 | dingtalk.config(oauth); 28 | resolve(); 29 | } 30 | } else { 31 | reject(res); 32 | } 33 | }); 34 | }); 35 | } 36 | 37 | export function getUserId (){ 38 | let Config = { 39 | method: 'GET', 40 | uri: APPHOST + '/api/get-user-info' 41 | }; 42 | return new Promise(function(resolve, reject){ 43 | authCode().then(function(result){ 44 | const code = result.code; 45 | Config.body = {}; 46 | Config.body.code = code; 47 | request(Config,function(error,res){ 48 | if (!error && res.ok){ 49 | const data = res.data; 50 | if (data.errcode === 0){ 51 | resolve(data); 52 | } else { 53 | reject(data); 54 | } 55 | } 56 | }); 57 | }).catch(function(err){ 58 | reject(err); 59 | }); 60 | }); 61 | } 62 | 63 | export function getUserInfo(userId){ 64 | let Config = { 65 | method: 'GET', 66 | uri: APPHOST + '/api/get', 67 | body: { 68 | userid: userId 69 | } 70 | }; 71 | return new Promise(function(resolve, reject){ 72 | request(Config, function(error, res){ 73 | if (!error && res.ok){ 74 | const data = res.data; 75 | if (data.errcode === 0){ 76 | // 再处理 77 | resolve(data); 78 | } else { 79 | reject(data); 80 | } 81 | } 82 | }); 83 | }); 84 | } 85 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/src/lib/storage.js: -------------------------------------------------------------------------------- 1 | import dingtalk from 'weex-dingtalk'; 2 | import { toast } from './util.js'; 3 | 4 | export function getItem (name,cb){ 5 | const date = new Date(); 6 | dingtalk.ready(function(){ 7 | dingtalk.apis.util.domainStorage.getItem({ 8 | name: name, 9 | onSuccess (res){ 10 | const value = res.value; 11 | if (!value){ 12 | if (typeof cb === 'function'){ 13 | cb(1,value); 14 | } 15 | return; 16 | } 17 | if (typeof cb === 'function'){ 18 | try { 19 | let item = JSON.parse(value); 20 | cb(null, item); 21 | }catch(e){ 22 | cb(e,res); 23 | } 24 | } 25 | } 26 | }); 27 | }); 28 | } 29 | 30 | export function clearItems (){ 31 | dingtalk.ready(function(){ 32 | dingtalk.apis.util.domainStorage.clearItems({}); 33 | }); 34 | } 35 | 36 | export function removeItem (name){ 37 | dingtalk.ready(function(){ 38 | dingtalk.apis.util.domainStorage.removeItem({ 39 | name: name 40 | }); 41 | }); 42 | } 43 | 44 | export function setItem (name,val){ 45 | dingtalk.ready(function(){ 46 | dingtalk.apis.util.domainStorage.setItem({ 47 | name: name, 48 | value: JSON.stringify(val) 49 | }); 50 | }); 51 | } 52 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/src/pages/dingtalk/index.vue: -------------------------------------------------------------------------------- 1 | 17 | 32 | 80 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/src/pages/home/index.vue: -------------------------------------------------------------------------------- 1 | 7 | 36 | 58 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/src/pages/list/component/todo-cells.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 62 | 63 | 128 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/src/pages/list/component/todo-user.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 32 | 33 | 61 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/src/pages/list/index.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 85 | 86 | 93 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/src/platforms/web/web.entry.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import weex from 'weex-vue-render'; 3 | weex.init(Vue); 4 | import App from '../../container/App.vue'; 5 | import Router from '../../container/router.js'; 6 | const { router } = Router(Vue); 7 | 8 | new Vue(Vue.util.extend({ 9 | el:'#root', 10 | router, 11 | },App)); 12 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/src/platforms/weex/weex.dingtalk.js: -------------------------------------------------------------------------------- 1 | import Dingtalk from '../../pages/dingtalk/index.vue'; 2 | Dingtalk.el = '#root'; 3 | new Vue(Dingtalk); 4 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/src/platforms/weex/weex.entry.js: -------------------------------------------------------------------------------- 1 | import App from '../../container/App.vue'; 2 | import Router from '../../container/router.js'; 3 | 4 | const { router } = Router(Vue); 5 | 6 | new Vue(Vue.util.extend({ 7 | el:'#root', 8 | router 9 | },App)); 10 | 11 | router.push('/') 12 | -------------------------------------------------------------------------------- /weex-vue-fed-todo/static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-dingtalk/which-language-demo/beec798dff6eab38dec5b2c9c93434a6ffabed03/weex-vue-fed-todo/static/.gitkeep --------------------------------------------------------------------------------