├── .env ├── .env.production ├── .gitignore ├── README.md ├── app.js ├── babel.config.js ├── gene.js ├── genec.js ├── package-lock.json ├── package.json ├── public ├── css │ ├── font-awesome.min.css │ └── pluto.css ├── favicon.ico ├── index.html └── js │ ├── flexible.js │ ├── mock-min.js │ └── pluto.js ├── screenshots ├── S91006-001.png ├── S91006-002.png ├── S91006-003.png ├── S91006-004.png └── S91006-005.png ├── server ├── config │ ├── config-default.js │ ├── config-test.js │ └── index.js ├── controller.js ├── controller │ ├── dd.js │ └── order.js ├── cservice │ └── process.js ├── db.js ├── dto │ └── resp.js ├── kits │ ├── cryptoKit.js │ └── jwtKit.js ├── middleware │ ├── error.js │ ├── tokenError.js │ └── ukey.js ├── model-base │ ├── abase.js │ ├── dd_config.js │ ├── t_order.js │ └── t_user.js ├── model.js ├── model │ ├── DdConfig.js │ ├── order.js │ └── user.js └── service.js ├── src ├── App.vue ├── api.js ├── assets │ ├── finishOrder.png │ ├── logo.png │ ├── photo.png │ ├── success.png │ └── unfinishOrder.png ├── components │ └── HelloWorld.vue ├── cube-ui.js ├── main.js ├── router.js ├── store.js ├── theme.styl └── views │ ├── About.vue │ ├── Empty.vue │ ├── Home.vue │ ├── OrderAdd.vue │ ├── OrderList.vue │ └── Result.vue ├── static └── dingding-sdk.sql └── vue.config.js /.env: -------------------------------------------------------------------------------- 1 | VUE_APP_REMOTE=0 2 | VUE_APP_IP=http://localhost:9021 3 | -------------------------------------------------------------------------------- /.env.production: -------------------------------------------------------------------------------- 1 | VUE_APP_REMOTE=1 2 | VUE_APP_IP=http://94.191.121.109:9021 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw? 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dingding-nodejs-sdk 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | ``` 13 | node app 14 | ``` 15 | ### Compiles and minifies for production 16 | ``` 17 | npm run build 18 | ``` 19 | ## 应用截图 20 | 21 | ## Screenshots 22 | ![image](https://github.com/pluto1114/dingding-nodejs-SDK/blob/master/screenshots/S91006-001.png) 23 | 24 | ![image](https://github.com/pluto1114/dingding-nodejs-SDK/blob/master/screenshots/S91006-002.png) 25 | 26 | ![image](https://github.com/pluto1114/dingding-nodejs-SDK/blob/master/screenshots/S91006-003.png) 27 | 28 | ![image](https://github.com/pluto1114/dingding-nodejs-SDK/blob/master/screenshots/S91006-004.png) 29 | 30 | ![image](https://github.com/pluto1114/dingding-nodejs-SDK/blob/master/screenshots/S91006-005.png) 31 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | const Koa = require('koa'); 2 | var http = require('http'); 3 | 4 | var fs = require('fs'); 5 | const path = require('path'); 6 | const koaBody = require('koa-body'); 7 | const cors = require('koa2-cors'); 8 | const static = require('koa-static'); 9 | 10 | const controller = require('./server/controller'); 11 | const ukey = require('./server/middleware/ukey'); 12 | const error = require('./server/middleware/error'); 13 | const app = new Koa(); 14 | const port = 9021 15 | const compress = require('koa-compress') 16 | 17 | 18 | app.use(compress({ threshold: 2048 })); 19 | app.use(koaBody({ 20 | multipart: true, 21 | formidable: { 22 | uploadDir:path.join(__dirname,'static/upload/'), // 设置文件上传目录 23 | keepExtensions: true, // 保持文件的后缀 24 | maxFieldsSize:2 * 1024 * 1024, // 文件上传大小 25 | onFileBegin:(name,file) => { // 文件上传前的设置 26 | // console.log(`name: ${name}`); 27 | // console.log(file); 28 | }, 29 | } 30 | })); 31 | app.use(cors({ 32 | origin: function (ctx) { 33 | return '*' 34 | }, 35 | exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'], 36 | maxAge: 1000, 37 | credentials: true, 38 | allowMethods: ['POST', 'PUT', 'PATCH', 'DELETE','OPTIONS'], 39 | allowHeaders: ['*','x-requested-with','x-key','Accept','Content-Type'], 40 | })) 41 | 42 | const staticPath = path.resolve(__dirname, 'static'); 43 | app.use(static(staticPath, { 44 | setHeaders: (res, path, stats) => { 45 | if (path.indexOf('jpg') > -1||path.indexOf('png') > -1) { 46 | res.setHeader('Cache-Control', ['private', 'max-age=60']); 47 | } 48 | } 49 | })); 50 | app.use(ukey()) 51 | app.use(async (ctx, next) => { 52 | let d=new Date() 53 | console.log(`Process ${d.toString()} ${ctx.request.method} ${ctx.request.url}`); 54 | await next(); 55 | }); 56 | app.use(controller()); 57 | app.use(error()) 58 | 59 | http.createServer(app.callback()).listen(port); 60 | 61 | console.log(`app started at port ${port}...`); 62 | 63 | process.on('uncaughtException', function(err) { 64 | console.log(err) 65 | }) 66 | 67 | String.prototype.ellipsis=function(len){ 68 | return this.length>len?(this.substring(0,len)+'...'):this 69 | } 70 | 71 | function dateFormat(date, fmt) { 72 | if (null == date || undefined == date) return ''; 73 | var o = { 74 | "M+": date.getMonth() + 1, //月份 75 | "d+": date.getDate(), //日 76 | "h+": date.getHours(), //小时 77 | "m+": date.getMinutes(), //分 78 | "s+": date.getSeconds(), //秒 79 | "S": date.getMilliseconds() //毫秒 80 | }; 81 | if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length)); 82 | for (var k in o) 83 | if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); 84 | return fmt; 85 | } 86 | 87 | Date.prototype.toJSON = function () { return dateFormat(this,'yyyy-MM-dd hh:mm:ss')} 88 | Date.prototype.toString = function () { return dateFormat(this,'yyyy-MM-dd hh:mm:ss')} 89 | Date.prototype.toMM = function () { return dateFormat(this,'yyyyMMddhhmmss')} -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /gene.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash'); 2 | const SeqAuto = require('sequelize-auto') 3 | const path = require('path') 4 | const fs = require('fs') 5 | const config = require('./server/config'); 6 | const tables = process.argv.slice(2) 7 | const dir = 'server' 8 | if (tables.length === 0) { 9 | throw new Error('No table specified\nUsage: node generate_model table1 table2 table3\n') 10 | } 11 | 12 | const auto = new SeqAuto(config.database, config.username, config.password, { 13 | host: config.host, 14 | port: config.port, 15 | dialect: config.dialect, 16 | directory: path.resolve(__dirname, `${dir}/model-base`), 17 | additional: { 18 | timestamps: false 19 | }, 20 | tables: tables 21 | }) 22 | const modelStrArr = [] 23 | for (let table of tables) { 24 | let name = table.includes("t_") ? table.substring(table.indexOf("t_")+1) : table 25 | 26 | console.log(name) 27 | modelStrArr.push({ 28 | name: name, 29 | tpl: ` 30 | const table='${table}' 31 | const obj=require('../model-base/abase')(table) 32 | 33 | 34 | exports.obj = obj` 35 | }) 36 | } 37 | 38 | auto.run(err => { 39 | if (err) { 40 | throw err 41 | } 42 | for (let modelObj of modelStrArr) { 43 | console.log(modelObj) 44 | let file = path.resolve(__dirname, `${dir}/model`) + '/' + _.camelCase(modelObj.name) + '.js' 45 | if (!fs.existsSync(file)) { 46 | fs.writeFileSync(file, modelObj.tpl) 47 | } 48 | } 49 | console.log('\n\nProcess completed successfully.') 50 | console.log('You may need to add these Foreign Keys mannually:\n', auto.foreignKeys) 51 | }) -------------------------------------------------------------------------------- /genec.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash'); 2 | 3 | const path = require('path') 4 | const fs = require('fs') 5 | 6 | const controllers = process.argv.slice(2) 7 | const dir = 'server' 8 | if (controllers.length === 0) { 9 | throw new Error('No controller specified\nUsage: node generate_model controller1 controller2 controller3\n') 10 | } 11 | 12 | 13 | const modelStrArr = [] 14 | for (let controller of controllers) { 15 | let admin=controller.indexOf("-admin")>0 16 | let prefix=admin?'/api':'/v1' 17 | let name = admin? controller.substring(0, controller.indexOf("-admin") + 1) : controller 18 | 19 | modelStrArr.push({ 20 | name: name, 21 | admin:admin, 22 | tpl: ` 23 | const model = require('../model'); 24 | const service = require('../service'); 25 | const r=require('../dto/resp'); 26 | const Op = require('sequelize').Op; 27 | class ${_.capitalize(name)}{ 28 | async index(ctx){ 29 | let items = []; 30 | ctx.body=r().setItems(items); 31 | } 32 | async show(ctx){ 33 | let {id}=ctx.params; 34 | ctx.body=r().setItemMap({id}) 35 | } 36 | } 37 | let ${name}=new ${_.capitalize(name)}() 38 | module.exports = { 39 | 'GET ${prefix}/${name}/index': ${name}.index, 40 | 'GET ${prefix}/${name}/:id': ${name}.show, 41 | };` 42 | }) 43 | } 44 | 45 | 46 | for (let modelObj of modelStrArr) { 47 | console.log(modelObj) 48 | let filePath = dir + '/' + (modelObj.admin ? 'controller-admin' : 'controller') 49 | let file = path.resolve(__dirname, filePath) + '/' + _.camelCase(modelObj.name) + '.js' 50 | if (!fs.existsSync(file)) { 51 | fs.writeFileSync(file, modelObj.tpl) 52 | } 53 | } 54 | console.log('\n\nProcess completed successfully.') 55 | 56 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dingding-nodejs-sdk", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "axios": "^0.19.0", 12 | "core-js": "^2.6.5", 13 | "cube-ui": "~1.12.15", 14 | "koa": "^2.8.2", 15 | "koa-body": "^4.1.1", 16 | "koa-compress": "^3.0.0", 17 | "koa-router": "^7.4.0", 18 | "koa-static": "^5.0.0", 19 | "koa2-cors": "^2.0.6", 20 | "mysql": "^2.17.1", 21 | "mysql2": "^1.7.0", 22 | "mz": "^2.7.0", 23 | "node-uuid": "^1.4.8", 24 | "sequelize": "^5.19.1", 25 | "sequelize-auto": "^0.4.29", 26 | "vue": "^2.6.10", 27 | "vue-router": "^3.0.3", 28 | "vuex": "^3.0.1" 29 | }, 30 | "devDependencies": { 31 | "@vue/cli-plugin-babel": "^3.11.0", 32 | "@vue/cli-plugin-eslint": "^3.11.0", 33 | "@vue/cli-service": "^3.11.0", 34 | "babel-eslint": "^10.0.1", 35 | "eslint": "^5.16.0", 36 | "eslint-plugin-vue": "^5.0.0", 37 | "less": "^3.0.4", 38 | "less-loader": "^5.0.0", 39 | "postcss-px2rem": "^0.3.0", 40 | "stylus": "^0.54.5", 41 | "stylus-loader": "^3.0.2", 42 | "vue-cli-plugin-cube-ui": "^0.2.5", 43 | "vue-template-compiler": "^2.6.10" 44 | }, 45 | "eslintConfig": { 46 | "root": true, 47 | "env": { 48 | "node": true 49 | }, 50 | "extends": [ 51 | "plugin:vue/essential", 52 | "eslint:recommended" 53 | ], 54 | "rules": { 55 | "no-console": "off", 56 | "no-unused-vars": "off", 57 | "no-undef": "off" 58 | }, 59 | "parserOptions": { 60 | "parser": "babel-eslint" 61 | } 62 | }, 63 | "postcss": { 64 | "plugins": { 65 | "autoprefixer": {}, 66 | "postcss-px2rem": { 67 | "remUnit": 37.5 68 | } 69 | } 70 | }, 71 | "browserslist": [ 72 | "> 1%", 73 | "last 2 versions", 74 | "not ie <= 11", 75 | "Android >= 4.0", 76 | "iOS >= 8" 77 | ], 78 | "transformModules": { 79 | "cube-ui": { 80 | "transform": "cube-ui/src/modules/${member}", 81 | "kebabCase": true 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /public/css/font-awesome.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.7.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-vcard:before,.fa-address-card:before{content:"\f2bb"}.fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto} 5 | -------------------------------------------------------------------------------- /public/css/pluto.css: -------------------------------------------------------------------------------- 1 | ::-webkit-scrollbar { 2 | /*隐藏滚轮*/ 3 | display: none; 4 | } 5 | 6 | .ub{ 7 | display: flex; 8 | } 9 | .ub-v{ 10 | display: flex; 11 | flex-direction:column; 12 | } 13 | .uc{ 14 | justify-content: center; 15 | align-items: center; 16 | } 17 | .uf-jc{ 18 | justify-content: center; 19 | } 20 | .uf-ac{ 21 | align-items: center; 22 | } 23 | .ufe{ 24 | justify-content: flex-end; 25 | } 26 | .uf-1{ 27 | flex:1; 28 | } 29 | .uf-2{ 30 | flex:2; 31 | } 32 | .uf-3{ 33 | flex:3; 34 | } 35 | 36 | .bar { 37 | height: 10px; 38 | background-color: #eee; 39 | } 40 | .pad{ 41 | padding: 10px; 42 | } 43 | .line-text-1{ 44 | overflow: hidden; 45 | text-overflow:ellipsis; 46 | white-space: nowrap; 47 | } 48 | .line-text-2{ 49 | display: -webkit-box; 50 | -webkit-box-orient: vertical; 51 | -webkit-line-clamp: 2; 52 | overflow: hidden; 53 | } 54 | .line-text-3{ 55 | display: -webkit-box; 56 | -webkit-box-orient: vertical; 57 | -webkit-line-clamp: 3; 58 | overflow: hidden; 59 | } 60 | 61 | 62 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluto1114/dingding-nodejs-SDK/2426dbeff156a20d0dbb9ea07bda3b278db99687/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | dingding-nodejs-sdk 9 | 10 | 11 | 12 | 15 | 16 | 17 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /public/js/flexible.js: -------------------------------------------------------------------------------- 1 | (function flexible (window, document) { 2 | var docEl = document.documentElement 3 | var dpr = window.devicePixelRatio || 1 4 | 5 | // adjust body font size 6 | function setBodyFontSize () { 7 | if (document.body) { 8 | document.body.style.fontSize = (12 * dpr) + 'px' 9 | } 10 | else { 11 | document.addEventListener('DOMContentLoaded', setBodyFontSize) 12 | } 13 | } 14 | setBodyFontSize(); 15 | 16 | // set 1rem = viewWidth / 10 17 | function setRemUnit () { 18 | var rem = docEl.clientWidth / 10 19 | docEl.style.fontSize = rem + 'px' 20 | } 21 | 22 | setRemUnit() 23 | 24 | // reset rem unit on page resize 25 | window.addEventListener('resize', setRemUnit) 26 | window.addEventListener('pageshow', function (e) { 27 | if (e.persisted) { 28 | setRemUnit() 29 | } 30 | }) 31 | 32 | // detect 0.5px supports 33 | if (dpr >= 2) { 34 | var fakeBody = document.createElement('body') 35 | var testElement = document.createElement('div') 36 | testElement.style.border = '.5px solid transparent' 37 | fakeBody.appendChild(testElement) 38 | docEl.appendChild(fakeBody) 39 | if (testElement.offsetHeight === 1) { 40 | docEl.classList.add('hairlines') 41 | } 42 | docEl.removeChild(fakeBody) 43 | } 44 | }(window, document)) -------------------------------------------------------------------------------- /public/js/mock-min.js: -------------------------------------------------------------------------------- 1 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Mock=e():t.Mock=e()}(this,function(){return function(t){function e(r){if(n[r])return n[r].exports;var a=n[r]={exports:{},id:r,loaded:!1};return t[r].call(a.exports,a,a.exports,e),a.loaded=!0,a.exports}var n={};return e.m=t,e.c=n,e.p="",e(0)}([function(t,e,n){var r,a=n(1),o=n(3),u=n(5),i=n(20),l=n(23),s=n(25);"undefined"!=typeof window&&(r=n(27));/*! 2 | Mock - 模拟请求 & 模拟数据 3 | https://github.com/nuysoft/Mock 4 | 墨智 mozhi.gyy@taobao.com nuysoft@gmail.com 5 | */ 6 | var c={Handler:a,Random:u,Util:o,XHR:r,RE:i,toJSONSchema:l,valid:s,heredoc:o.heredoc,setup:function(t){return r.setup(t)},_mocked:{}};c.version="1.0.1-beta3",r&&(r.Mock=c),c.mock=function(t,e,n){return 1===arguments.length?a.gen(t):(2===arguments.length&&(n=e,e=void 0),r&&(window.XMLHttpRequest=r),c._mocked[t+(e||"")]={rurl:t,rtype:e,template:n},c)},t.exports=c},function(module,exports,__webpack_require__){var Constant=__webpack_require__(2),Util=__webpack_require__(3),Parser=__webpack_require__(4),Random=__webpack_require__(5),RE=__webpack_require__(20),Handler={extend:Util.extend};Handler.gen=function(t,e,n){e=void 0==e?"":e+"",n=n||{},n={path:n.path||[Constant.GUID],templatePath:n.templatePath||[Constant.GUID++],currentContext:n.currentContext,templateCurrentContext:n.templateCurrentContext||t,root:n.root||n.currentContext,templateRoot:n.templateRoot||n.templateCurrentContext||t};var r,a=Parser.parse(e),o=Util.type(t);return Handler[o]?(r=Handler[o]({type:o,template:t,name:e,parsedName:e?e.replace(Constant.RE_KEY,"$1"):e,rule:a,context:n}),n.root||(n.root=r),r):t},Handler.extend({array:function(t){var e,n,r=[];if(0===t.template.length)return r;if(t.rule.parameters)if(1===t.rule.min&&void 0===t.rule.max)t.context.path.push(t.name),t.context.templatePath.push(t.name),r=Random.pick(Handler.gen(t.template,void 0,{path:t.context.path,templatePath:t.context.templatePath,currentContext:r,templateCurrentContext:t.template,root:t.context.root||r,templateRoot:t.context.templateRoot||t.template})),t.context.path.pop(),t.context.templatePath.pop();else if(t.rule.parameters[2])t.template.__order_index=t.template.__order_index||0,t.context.path.push(t.name),t.context.templatePath.push(t.name),r=Handler.gen(t.template,void 0,{path:t.context.path,templatePath:t.context.templatePath,currentContext:r,templateCurrentContext:t.template,root:t.context.root||r,templateRoot:t.context.templateRoot||t.template})[t.template.__order_index%t.template.length],t.template.__order_index+=+t.rule.parameters[2],t.context.path.pop(),t.context.templatePath.pop();else for(e=0;e1)return this.getValueByKeyPath(key,options);if(templateContext&&"object"==typeof templateContext&&key in templateContext&&placeholder!==templateContext[key])return templateContext[key]=Handler.gen(templateContext[key],key,{currentContext:obj,templateCurrentContext:templateContext}),templateContext[key];if(!(key in Random||lkey in Random||okey in Random))return placeholder;for(var i=0;i1&&(a=e.context.path.slice(0),a.pop(),a=this.normalizePath(a.concat(r))),t=r[r.length-1];for(var o=e.context.root,u=e.context.templateRoot,i=1;ii;i++)if(t=arguments[i])for(e in t)r=u[e],a=t[e],u!==a&&void 0!==a&&(n.isArray(a)||n.isObject(a)?(n.isArray(a)&&(o=r&&n.isArray(r)?r:[]),n.isObject(a)&&(o=r&&n.isObject(r)?r:{}),u[e]=n.extend(o,a)):u[e]=a);return u},n.each=function(t,e,n){var r,a;if("number"===this.type(t))for(r=0;t>r;r++)e(r,r);else if(t.length===+t.length)for(r=0;r1/(t+e)*t?!n:n):Math.random()>=.5},bool:function(t,e,n){return this["boolean"](t,e,n)},natural:function(t,e){return t="undefined"!=typeof t?parseInt(t,10):0,e="undefined"!=typeof e?parseInt(e,10):9007199254740992,Math.round(Math.random()*(e-t))+t},integer:function(t,e){return t="undefined"!=typeof t?parseInt(t,10):-9007199254740992,e="undefined"!=typeof e?parseInt(e,10):9007199254740992,Math.round(Math.random()*(e-t))+t},"int":function(t,e){return this.integer(t,e)},"float":function(t,e,n,r){n=void 0===n?0:n,n=Math.max(Math.min(n,17),0),r=void 0===r?17:r,r=Math.max(Math.min(r,17),0);for(var a=this.integer(t,e)+".",o=0,u=this.natural(n,r);u>o;o++)a+=u-1>o?this.character("number"):this.character("123456789");return parseFloat(a,10)},character:function(t){var e={lower:"abcdefghijklmnopqrstuvwxyz",upper:"ABCDEFGHIJKLMNOPQRSTUVWXYZ",number:"0123456789",symbol:"!@#$%^&*()[]"};return e.alpha=e.lower+e.upper,e.undefined=e.lower+e.upper+e.number+e.symbol,t=e[(""+t).toLowerCase()]||t,t.charAt(this.natural(0,t.length-1))},"char":function(t){return this.character(t)},string:function(t,e,n){var r;switch(arguments.length){case 0:r=this.natural(3,7);break;case 1:r=t,t=void 0;break;case 2:"string"==typeof arguments[0]?r=e:(r=this.natural(t,e),t=void 0);break;case 3:r=this.natural(e,n)}for(var a="",o=0;r>o;o++)a+=this.character(t);return a},str:function(){return this.string.apply(this,arguments)},range:function(t,e,n){arguments.length<=1&&(e=t||0,t=0),n=arguments[2]||1,t=+t,e=+e,n=+n;for(var r=Math.max(Math.ceil((e-t)/n),0),a=0,o=new Array(r);r>a;)o[a++]=t,t+=n;return o}}},function(t,e){var n={yyyy:"getFullYear",yy:function(t){return(""+t.getFullYear()).slice(2)},y:"yy",MM:function(t){var e=t.getMonth()+1;return 10>e?"0"+e:e},M:function(t){return t.getMonth()+1},dd:function(t){var e=t.getDate();return 10>e?"0"+e:e},d:"getDate",HH:function(t){var e=t.getHours();return 10>e?"0"+e:e},H:"getHours",hh:function(t){var e=t.getHours()%12;return 10>e?"0"+e:e},h:function(t){return t.getHours()%12},mm:function(t){var e=t.getMinutes();return 10>e?"0"+e:e},m:"getMinutes",ss:function(t){var e=t.getSeconds();return 10>e?"0"+e:e},s:"getSeconds",SS:function(t){var e=t.getMilliseconds();return 10>e&&"00"+e||100>e&&"0"+e||e},S:"getMilliseconds",A:function(t){return t.getHours()<12?"AM":"PM"},a:function(t){return t.getHours()<12?"am":"pm"},T:"getTime"};t.exports={_patternLetters:n,_rformat:new RegExp(function(){var t=[];for(var e in n)t.push(e);return"("+t.join("|")+")"}(),"g"),_formatDate:function(t,e){return e.replace(this._rformat,function r(e,a){return"function"==typeof n[a]?n[a](t):n[a]in n?r(e,n[a]):t[n[a]]()})},_randomDate:function(t,e){return t=void 0===t?new Date(0):t,e=void 0===e?new Date:e,new Date(Math.random()*(e.getTime()-t.getTime()))},date:function(t){return t=t||"yyyy-MM-dd",this._formatDate(this._randomDate(),t)},time:function(t){return t=t||"HH:mm:ss",this._formatDate(this._randomDate(),t)},datetime:function(t){return t=t||"yyyy-MM-dd HH:mm:ss",this._formatDate(this._randomDate(),t)},now:function(t,e){1===arguments.length&&(/year|month|day|hour|minute|second|week/.test(t)||(e=t,t="")),t=(t||"").toLowerCase(),e=e||"yyyy-MM-dd HH:mm:ss";var n=new Date;switch(t){case"year":n.setMonth(0);case"month":n.setDate(1);case"week":case"day":n.setHours(0);case"hour":n.setMinutes(0);case"minute":n.setSeconds(0);case"second":n.setMilliseconds(0)}switch(t){case"week":n.setDate(n.getDate()-n.getDay())}return this._formatDate(n,e)}}},function(t,e,n){(function(t){t.exports={_adSize:["300x250","250x250","240x400","336x280","180x150","720x300","468x60","234x60","88x31","120x90","120x60","120x240","125x125","728x90","160x600","120x600","300x600"],_screenSize:["320x200","320x240","640x480","800x480","800x480","1024x600","1024x768","1280x800","1440x900","1920x1200","2560x1600"],_videoSize:["720x480","768x576","1280x720","1920x1080"],image:function(t,e,n,r,a){return 4===arguments.length&&(a=r,r=void 0),3===arguments.length&&(a=n,n=void 0),t||(t=this.pick(this._adSize)),e&&~e.indexOf("#")&&(e=e.slice(1)),n&&~n.indexOf("#")&&(n=n.slice(1)),"http://dummyimage.com/"+t+(e?"/"+e:"")+(n?"/"+n:"")+(r?"."+r:"")+(a?"&text="+a:"")},img:function(){return this.image.apply(this,arguments)},_brandColors:{"4ormat":"#fb0a2a","500px":"#02adea","About.me (blue)":"#00405d","About.me (yellow)":"#ffcc33",Addvocate:"#ff6138",Adobe:"#ff0000",Aim:"#fcd20b",Amazon:"#e47911",Android:"#a4c639","Angie's List":"#7fbb00",AOL:"#0060a3",Atlassian:"#003366",Behance:"#053eff","Big Cartel":"#97b538",bitly:"#ee6123",Blogger:"#fc4f08",Boeing:"#0039a6","Booking.com":"#003580",Carbonmade:"#613854",Cheddar:"#ff7243","Code School":"#3d4944",Delicious:"#205cc0",Dell:"#3287c1",Designmoo:"#e54a4f",Deviantart:"#4e6252","Designer News":"#2d72da",Devour:"#fd0001",DEWALT:"#febd17","Disqus (blue)":"#59a3fc","Disqus (orange)":"#db7132",Dribbble:"#ea4c89",Dropbox:"#3d9ae8",Drupal:"#0c76ab",Dunked:"#2a323a",eBay:"#89c507",Ember:"#f05e1b",Engadget:"#00bdf6",Envato:"#528036",Etsy:"#eb6d20",Evernote:"#5ba525","Fab.com":"#dd0017",Facebook:"#3b5998",Firefox:"#e66000","Flickr (blue)":"#0063dc","Flickr (pink)":"#ff0084",Forrst:"#5b9a68",Foursquare:"#25a0ca",Garmin:"#007cc3",GetGlue:"#2d75a2",Gimmebar:"#f70078",GitHub:"#171515","Google Blue":"#0140ca","Google Green":"#16a61e","Google Red":"#dd1812","Google Yellow":"#fcca03","Google+":"#dd4b39",Grooveshark:"#f77f00",Groupon:"#82b548","Hacker News":"#ff6600",HelloWallet:"#0085ca","Heroku (light)":"#c7c5e6","Heroku (dark)":"#6567a5",HootSuite:"#003366",Houzz:"#73ba37",HTML5:"#ec6231",IKEA:"#ffcc33",IMDb:"#f3ce13",Instagram:"#3f729b",Intel:"#0071c5",Intuit:"#365ebf",Kickstarter:"#76cc1e",kippt:"#e03500",Kodery:"#00af81",LastFM:"#c3000d",LinkedIn:"#0e76a8",Livestream:"#cf0005",Lumo:"#576396",Mixpanel:"#a086d3",Meetup:"#e51937",Nokia:"#183693",NVIDIA:"#76b900",Opera:"#cc0f16",Path:"#e41f11","PayPal (dark)":"#1e477a","PayPal (light)":"#3b7bbf",Pinboard:"#0000e6",Pinterest:"#c8232c",PlayStation:"#665cbe",Pocket:"#ee4056",Prezi:"#318bff",Pusha:"#0f71b4",Quora:"#a82400","QUOTE.fm":"#66ceff",Rdio:"#008fd5",Readability:"#9c0000","Red Hat":"#cc0000",Resource:"#7eb400",Rockpack:"#0ba6ab",Roon:"#62b0d9",RSS:"#ee802f",Salesforce:"#1798c1",Samsung:"#0c4da2",Shopify:"#96bf48",Skype:"#00aff0",Snagajob:"#f47a20",Softonic:"#008ace",SoundCloud:"#ff7700","Space Box":"#f86960",Spotify:"#81b71a",Sprint:"#fee100",Squarespace:"#121212",StackOverflow:"#ef8236",Staples:"#cc0000","Status Chart":"#d7584f",Stripe:"#008cdd",StudyBlue:"#00afe1",StumbleUpon:"#f74425","T-Mobile":"#ea0a8e",Technorati:"#40a800","The Next Web":"#ef4423",Treehouse:"#5cb868",Trulia:"#5eab1f",Tumblr:"#34526f","Twitch.tv":"#6441a5",Twitter:"#00acee",TYPO3:"#ff8700",Ubuntu:"#dd4814",Ustream:"#3388ff",Verizon:"#ef1d1d",Vimeo:"#86c9ef",Vine:"#00a478",Virb:"#06afd8","Virgin Media":"#cc0000",Wooga:"#5b009c","WordPress (blue)":"#21759b","WordPress (orange)":"#d54e21","WordPress (grey)":"#464646",Wunderlist:"#2b88d9",XBOX:"#9bc848",XING:"#126567","Yahoo!":"#720e9e",Yandex:"#ffcc00",Yelp:"#c41200",YouTube:"#c4302b",Zalongo:"#5498dc",Zendesk:"#78a300",Zerply:"#9dcc7a",Zootool:"#5e8b1d"},_brandNames:function(){var t=[];for(var e in this._brandColors)t.push(e);return t},dataImage:function(e,n){var r;if("undefined"!=typeof document)r=document.createElement("canvas");else{var a=t.require("canvas");r=new a}var o=r&&r.getContext&&r.getContext("2d");if(!r||!o)return"";e||(e=this.pick(this._adSize)),n=void 0!==n?n:e,e=e.split("x");var u=parseInt(e[0],10),i=parseInt(e[1],10),l=this._brandColors[this.pick(this._brandNames())],s="#FFF",c=14,h="sans-serif";return r.width=u,r.height=i,o.textAlign="center",o.textBaseline="middle",o.fillStyle=l,o.fillRect(0,0,u,i),o.fillStyle=s,o.font="bold "+c+"px "+h,o.fillText(n,u/2,i/2,u),r.toDataURL("image/png")}}}).call(e,n(9)(t))},function(t,e){t.exports=function(t){return t.webpackPolyfill||(t.deprecate=function(){},t.paths=[],t.children=[],t.webpackPolyfill=1),t}},function(t,e,n){var r=n(11),a=n(12);t.exports={color:function(t){return t||a[t]?a[t].nicer:this.hex()},hex:function(){var t=this._goldenRatioColor(),e=r.hsv2rgb(t),n=r.rgb2hex(e[0],e[1],e[2]);return n},rgb:function(){var t=this._goldenRatioColor(),e=r.hsv2rgb(t);return"rgb("+parseInt(e[0],10)+", "+parseInt(e[1],10)+", "+parseInt(e[2],10)+")"},rgba:function(){var t=this._goldenRatioColor(),e=r.hsv2rgb(t);return"rgba("+parseInt(e[0],10)+", "+parseInt(e[1],10)+", "+parseInt(e[2],10)+", "+Math.random().toFixed(2)+")"},hsl:function(){var t=this._goldenRatioColor(),e=r.hsv2hsl(t);return"hsl("+parseInt(e[0],10)+", "+parseInt(e[1],10)+", "+parseInt(e[2],10)+")"},_goldenRatioColor:function(t,e){return this._goldenRatio=.618033988749895,this._hue=this._hue||Math.random(),this._hue+=this._goldenRatio,this._hue%=1,"number"!=typeof t&&(t=.5),"number"!=typeof e&&(e=.95),[360*this._hue,100*t,100*e]}}},function(t,e){t.exports={rgb2hsl:function(t){var e,n,r,a=t[0]/255,o=t[1]/255,u=t[2]/255,i=Math.min(a,o,u),l=Math.max(a,o,u),s=l-i;return l==i?e=0:a==l?e=(o-u)/s:o==l?e=2+(u-a)/s:u==l&&(e=4+(a-o)/s),e=Math.min(60*e,360),0>e&&(e+=360),r=(i+l)/2,n=l==i?0:.5>=r?s/(l+i):s/(2-l-i),[e,100*n,100*r]},rgb2hsv:function(t){var e,n,r,a=t[0],o=t[1],u=t[2],i=Math.min(a,o,u),l=Math.max(a,o,u),s=l-i;return n=0===l?0:s/l*1e3/10,l==i?e=0:a==l?e=(o-u)/s:o==l?e=2+(u-a)/s:u==l&&(e=4+(a-o)/s),e=Math.min(60*e,360),0>e&&(e+=360),r=l/255*1e3/10,[e,n,r]},hsl2rgb:function(t){var e,n,r,a,o,u=t[0]/360,i=t[1]/100,l=t[2]/100;if(0===i)return o=255*l,[o,o,o];n=.5>l?l*(1+i):l+i-l*i,e=2*l-n,a=[0,0,0];for(var s=0;3>s;s++)r=u+1/3*-(s-1),0>r&&r++,r>1&&r--,o=1>6*r?e+6*(n-e)*r:1>2*r?n:2>3*r?e+(n-e)*(2/3-r)*6:e,a[s]=255*o;return a},hsl2hsv:function(t){var e,n,r=t[0],a=t[1]/100,o=t[2]/100;return o*=2,a*=1>=o?o:2-o,n=(o+a)/2,e=2*a/(o+a),[r,100*e,100*n]},hsv2rgb:function(t){var e=t[0]/60,n=t[1]/100,r=t[2]/100,a=Math.floor(e)%6,o=e-Math.floor(e),u=255*r*(1-n),i=255*r*(1-n*o),l=255*r*(1-n*(1-o));switch(r=255*r,a){case 0:return[r,l,u];case 1:return[i,r,u];case 2:return[u,r,l];case 3:return[u,i,r];case 4:return[l,u,r];case 5:return[r,u,i]}},hsv2hsl:function(t){var e,n,r=t[0],a=t[1]/100,o=t[2]/100;return n=(2-a)*o,e=a*o,e/=1>=n?n:2-n,n/=2,[r,100*e,100*n]},rgb2hex:function(t,e,n){return"#"+((256+t<<8|e)<<8|n).toString(16).slice(1)},hex2rgb:function(t){return t="0x"+t.slice(1).replace(t.length>4?t:/./g,"$&$&")|0,[t>>16,t>>8&255,255&t]}}},function(t,e){t.exports={navy:{value:"#000080",nicer:"#001F3F"},blue:{value:"#0000ff",nicer:"#0074D9"},aqua:{value:"#00ffff",nicer:"#7FDBFF"},teal:{value:"#008080",nicer:"#39CCCC"},olive:{value:"#008000",nicer:"#3D9970"},green:{value:"#008000",nicer:"#2ECC40"},lime:{value:"#00ff00",nicer:"#01FF70"},yellow:{value:"#ffff00",nicer:"#FFDC00"},orange:{value:"#ffa500",nicer:"#FF851B"},red:{value:"#ff0000",nicer:"#FF4136"},maroon:{value:"#800000",nicer:"#85144B"},fuchsia:{value:"#ff00ff",nicer:"#F012BE"},purple:{value:"#800080",nicer:"#B10DC9"},silver:{value:"#c0c0c0",nicer:"#DDDDDD"},gray:{value:"#808080",nicer:"#AAAAAA"},black:{value:"#000000",nicer:"#111111"},white:{value:"#FFFFFF",nicer:"#FFFFFF"}}},function(t,e,n){function r(t,e,n,r){return void 0===n?a.natural(t,e):void 0===r?n:a.natural(parseInt(n,10),parseInt(r,10))}var a=n(6),o=n(14);t.exports={paragraph:function(t,e){for(var n=r(3,7,t,e),a=[],o=0;n>o;o++)a.push(this.sentence());return a.join(" ")},cparagraph:function(t,e){for(var n=r(3,7,t,e),a=[],o=0;n>o;o++)a.push(this.csentence());return a.join("")},sentence:function(t,e){for(var n=r(12,18,t,e),a=[],u=0;n>u;u++)a.push(this.word());return o.capitalize(a.join(" "))+"."},csentence:function(t,e){for(var n=r(12,18,t,e),a=[],o=0;n>o;o++)a.push(this.cword());return a.join("")+"。"},word:function(t,e){for(var n=r(3,10,t,e),o="",u=0;n>u;u++)o+=a.character("lower");return o},cword:function(t,e,n){var r,a="的一是在不了有和人这中大为上个国我以要他时来用们生到作地于出就分对成会可主发年动同工也能下过子说产种面而方后多定行学法所民得经十三之进着等部度家电力里如水化高自二理起小物现实加量都两体制机当使点从业本去把性好应开它合还因由其些然前外天政四日那社义事平形相全表间样与关各重新线内数正心反你明看原又么利比或但质气第向道命此变条只没结解问意建月公无系军很情者最立代想已通并提直题党程展五果料象员革位入常文总次品式活设及管特件长求老头基资边流路级少图山统接知较将组见计别她手角期根论运农指几九区强放决西被干做必战先回则任取据处队南给色光门即保治北造百规热领七海口东导器压志世金增争济阶油思术极交受联什认六共权收证改清己美再采转更单风切打白教速花带安场身车例真务具万每目至达走积示议声报斗完类八离华名确才科张信马节话米整空元况今集温传土许步群广石记需段研界拉林律叫且究观越织装影算低持音众书布复容儿须际商非验连断深难近矿千周委素技备半办青省列习响约支般史感劳便团往酸历市克何除消构府称太准精值号率族维划选标写存候毛亲快效斯院查江型眼王按格养易置派层片始却专状育厂京识适属圆包火住调满县局照参红细引听该铁价严龙飞";switch(arguments.length){case 0:t=a,r=1;break;case 1:"string"==typeof arguments[0]?r=1:(r=t,t=a);break;case 2:"string"==typeof arguments[0]?r=e:(r=this.natural(t,e),t=a);break;case 3:r=this.natural(e,n)}for(var o="",u=0;r>u;u++)o+=t.charAt(this.natural(0,t.length-1));return o},title:function(t,e){for(var n=r(3,7,t,e),a=[],o=0;n>o;o++)a.push(this.capitalize(this.word()));return a.join(" ")},ctitle:function(t,e){for(var n=r(3,7,t,e),a=[],o=0;n>o;o++)a.push(this.cword());return a.join("")}}},function(t,e,n){var r=n(3);t.exports={capitalize:function(t){return(t+"").charAt(0).toUpperCase()+(t+"").substr(1)},upper:function(t){return(t+"").toUpperCase()},lower:function(t){return(t+"").toLowerCase()},pick:function(t,e,n){return r.isArray(t)?(void 0===e&&(e=1),void 0===n&&(n=e)):(t=[].slice.call(arguments),e=1,n=1),1===e&&1===n?t[this.natural(0,t.length-1)]:this.shuffle(t,e,n)},shuffle:function(t,e,n){t=t||[];for(var r=t.slice(0),a=[],o=0,u=r.length,i=0;u>i;i++)o=this.natural(0,r.length-1),a.push(r[o]),r.splice(o,1);switch(arguments.length){case 0:case 1:return a;case 2:n=e;case 3:return e=parseInt(e,10),n=parseInt(n,10),a.slice(0,this.natural(e,n))}},order:function a(t){a.cache=a.cache||{},arguments.length>1&&(t=[].slice.call(arguments,0));var e=a.options,n=e.context.templatePath.join("."),r=a.cache[n]=a.cache[n]||{index:0,array:t};return r.array[r.index++%r.array.length]}}},function(t,e){t.exports={first:function(){var t=["James","John","Robert","Michael","William","David","Richard","Charles","Joseph","Thomas","Christopher","Daniel","Paul","Mark","Donald","George","Kenneth","Steven","Edward","Brian","Ronald","Anthony","Kevin","Jason","Matthew","Gary","Timothy","Jose","Larry","Jeffrey","Frank","Scott","Eric"].concat(["Mary","Patricia","Linda","Barbara","Elizabeth","Jennifer","Maria","Susan","Margaret","Dorothy","Lisa","Nancy","Karen","Betty","Helen","Sandra","Donna","Carol","Ruth","Sharon","Michelle","Laura","Sarah","Kimberly","Deborah","Jessica","Shirley","Cynthia","Angela","Melissa","Brenda","Amy","Anna"]);return this.pick(t)},last:function(){var t=["Smith","Johnson","Williams","Brown","Jones","Miller","Davis","Garcia","Rodriguez","Wilson","Martinez","Anderson","Taylor","Thomas","Hernandez","Moore","Martin","Jackson","Thompson","White","Lopez","Lee","Gonzalez","Harris","Clark","Lewis","Robinson","Walker","Perez","Hall","Young","Allen"];return this.pick(t)},name:function(t){return this.first()+" "+(t?this.first()+" ":"")+this.last()},cfirst:function(){var t="王 李 张 刘 陈 杨 赵 黄 周 吴 徐 孙 胡 朱 高 林 何 郭 马 罗 梁 宋 郑 谢 韩 唐 冯 于 董 萧 程 曹 袁 邓 许 傅 沈 曾 彭 吕 苏 卢 蒋 蔡 贾 丁 魏 薛 叶 阎 余 潘 杜 戴 夏 锺 汪 田 任 姜 范 方 石 姚 谭 廖 邹 熊 金 陆 郝 孔 白 崔 康 毛 邱 秦 江 史 顾 侯 邵 孟 龙 万 段 雷 钱 汤 尹 黎 易 常 武 乔 贺 赖 龚 文".split(" ");return this.pick(t)},clast:function(){var t="伟 芳 娜 秀英 敏 静 丽 强 磊 军 洋 勇 艳 杰 娟 涛 明 超 秀兰 霞 平 刚 桂英".split(" ");return this.pick(t)},cname:function(){return this.cfirst()+this.clast()}}},function(t,e){t.exports={url:function(t,e){return(t||this.protocol())+"://"+(e||this.domain())+"/"+this.word()},protocol:function(){return this.pick("http ftp gopher mailto mid cid news nntp prospero telnet rlogin tn3270 wais".split(" "))},domain:function(t){return this.word()+"."+(t||this.tld())},tld:function(){return this.pick("com net org edu gov int mil cn com.cn net.cn gov.cn org.cn 中国 中国互联.公司 中国互联.网络 tel biz cc tv info name hk mobi asia cd travel pro museum coop aero ad ae af ag ai al am an ao aq ar as at au aw az ba bb bd be bf bg bh bi bj bm bn bo br bs bt bv bw by bz ca cc cf cg ch ci ck cl cm cn co cq cr cu cv cx cy cz de dj dk dm do dz ec ee eg eh es et ev fi fj fk fm fo fr ga gb gd ge gf gh gi gl gm gn gp gr gt gu gw gy hk hm hn hr ht hu id ie il in io iq ir is it jm jo jp ke kg kh ki km kn kp kr kw ky kz la lb lc li lk lr ls lt lu lv ly ma mc md mg mh ml mm mn mo mp mq mr ms mt mv mw mx my mz na nc ne nf ng ni nl no np nr nt nu nz om qa pa pe pf pg ph pk pl pm pn pr pt pw py re ro ru rw sa sb sc sd se sg sh si sj sk sl sm sn so sr st su sy sz tc td tf tg th tj tk tm tn to tp tr tt tv tw tz ua ug uk us uy va vc ve vg vn vu wf ws ye yu za zm zr zw".split(" "))},email:function(t){return this.character("lower")+"."+this.word()+"@"+(t||this.word()+"."+this.tld())},ip:function(){return this.natural(0,255)+"."+this.natural(0,255)+"."+this.natural(0,255)+"."+this.natural(0,255)}}},function(t,e,n){var r=n(18),a=["东北","华北","华东","华中","华南","西南","西北"];t.exports={region:function(){return this.pick(a)},province:function(){return this.pick(r).name},city:function(t){var e=this.pick(r),n=this.pick(e.children);return t?[e.name,n.name].join(" "):n.name},county:function(t){var e=this.pick(r),n=this.pick(e.children),a=this.pick(n.children)||{name:"-"};return t?[e.name,n.name,a.name].join(" "):a.name},zip:function(t){for(var e="",n=0;(t||6)>n;n++)e+=this.natural(0,9);return e}}},function(t,e){function n(t){for(var e,n={},r=0;ra;a++)o=t.charAt(a),"\n"===o?(e.seenCR||e.line++,e.column=1,e.seenCR=!1):"\r"===o||"\u2028"===o||"\u2029"===o?(e.line++,e.column=1,e.seenCR=!0):(e.column++,e.seenCR=!1)}return tr!==e&&(tr>e&&(tr=0,er={line:1,column:1,seenCR:!1}),n(er,tr,e),tr=e),er}function b(t){nr>Zn||(Zn>nr&&(nr=Zn,rr=[]),rr.push(t))}function w(t){var e=0;for(t.sort();eZn?(r=t.charAt(Zn),Zn++):(r=null,0===ar&&b(Hn)),null!==r?(Qn=e,n=Sn(r),null===n?(Zn=e,e=n):e=n):(Zn=e,e=kt)):(Zn=e,e=kt),e}function ft(){var e,n,r;return e=Zn,92===t.charCodeAt(Zn)?(n=Dn,Zn++):(n=null,0===ar&&b(qn)),null!==n?(Fn.test(t.charAt(Zn))?(r=t.charAt(Zn),Zn++):(r=null,0===ar&&b(Ln)),null!==r?(Qn=e,n=On(r),null===n?(Zn=e,e=n):e=n):(Zn=e,e=kt)):(Zn=e,e=kt),e}function dt(){var e,n,r,a;if(e=Zn,t.substr(Zn,2)===In?(n=In,Zn+=2):(n=null,0===ar&&b(jn)),null!==n){if(r=[],Nn.test(t.charAt(Zn))?(a=t.charAt(Zn),Zn++):(a=null,0===ar&&b(zn)),null!==a)for(;null!==a;)r.push(a),Nn.test(t.charAt(Zn))?(a=t.charAt(Zn),Zn++):(a=null,0===ar&&b(zn));else r=kt;null!==r?(Qn=e,n=Un(r),null===n?(Zn=e,e=n):e=n):(Zn=e,e=kt)}else Zn=e,e=kt;return e}function mt(){var e,n,r,a;if(e=Zn,t.substr(Zn,2)===Bn?(n=Bn,Zn+=2):(n=null,0===ar&&b(Gn)),null!==n){if(r=[],Xn.test(t.charAt(Zn))?(a=t.charAt(Zn),Zn++):(a=null,0===ar&&b(Kn)),null!==a)for(;null!==a;)r.push(a),Xn.test(t.charAt(Zn))?(a=t.charAt(Zn),Zn++):(a=null,0===ar&&b(Kn));else r=kt;null!==r?(Qn=e,n=Wn(r),null===n?(Zn=e,e=n):e=n):(Zn=e,e=kt)}else Zn=e,e=kt;return e}function gt(){var e,n,r,a;if(e=Zn,t.substr(Zn,2)===Yn?(n=Yn,Zn+=2):(n=null,0===ar&&b($n)),null!==n){if(r=[],Xn.test(t.charAt(Zn))?(a=t.charAt(Zn),Zn++):(a=null,0===ar&&b(Kn)),null!==a)for(;null!==a;)r.push(a),Xn.test(t.charAt(Zn))?(a=t.charAt(Zn),Zn++):(a=null,0===ar&&b(Kn));else r=kt;null!==r?(Qn=e,n=Jn(r),null===n?(Zn=e,e=n):e=n):(Zn=e,e=kt)}else Zn=e,e=kt;return e}function vt(){var e,n;return e=Zn,t.substr(Zn,2)===In?(n=In,Zn+=2):(n=null,0===ar&&b(jn)),null!==n&&(Qn=e,n=Vn()),null===n?(Zn=e,e=n):e=n,e}function xt(){var e,n,r;return e=Zn,92===t.charCodeAt(Zn)?(n=Dn,Zn++):(n=null,0===ar&&b(qn)),null!==n?(t.length>Zn?(r=t.charAt(Zn),Zn++):(r=null,0===ar&&b(Hn)),null!==r?(Qn=e,n=Fe(r),null===n?(Zn=e,e=n):e=n):(Zn=e,e=kt)):(Zn=e,e=kt),e}var yt,bt=arguments.length>1?arguments[1]:{},wt={regexp:C},Ct=C,kt=null,Et="",Rt="|",At='"|"',_t=function(t,e){return e?new r(t,e[1]):t},Mt=function(t,e,n){return new a([t].concat(e).concat([n]))},Pt="^",Tt='"^"',Ht=function(){return new n("start")},St="$",Dt='"$"',qt=function(){return new n("end")},Ft=function(t,e){return new i(t,e)},Lt="Quantifier",Ot=function(t,e){return e&&(t.greedy=!1),t},It="{",jt='"{"',Nt=",",zt='","',Ut="}",Bt='"}"',Gt=function(t,e){return new l(t,e)},Xt=",}",Kt='",}"',Wt=function(t){return new l(t,1/0)},Yt=function(t){return new l(t,t)},$t="+",Jt='"+"',Vt=function(){return new l(1,1/0)},Zt="*",Qt='"*"',te=function(){return new l(0,1/0)},ee="?",ne='"?"',re=function(){return new l(0,1)},ae=/^[0-9]/,oe="[0-9]",ue=function(t){return+t.join("")},ie="(",le='"("',se=")",ce='")"',he=function(t){return t},pe=function(t){return new u(t)},fe="?:",de='"?:"',me=function(t){return new o("non-capture-group",t)},ge="?=",ve='"?="',xe=function(t){return new o("positive-lookahead",t)},ye="?!",be='"?!"',we=function(t){return new o("negative-lookahead",t)},Ce="CharacterSet",ke="[",Ee='"["',Re="]",Ae='"]"',_e=function(t,e){return new s(!!t,e)},Me="CharacterRange",Pe="-",Te='"-"',He=function(t,e){return new c(t,e)},Se="Character",De=/^[^\\\]]/,qe="[^\\\\\\]]",Fe=function(t){return new h(t)},Le=".",Oe='"."',Ie=function(){return new n("any-character")},je="Literal",Ne=/^[^|\\\/.[()?+*$\^]/,ze="[^|\\\\\\/.[()?+*$\\^]",Ue="\\b",Be='"\\\\b"',Ge=function(){return new n("backspace")},Xe=function(){return new n("word-boundary")},Ke="\\B",We='"\\\\B"',Ye=function(){return new n("non-word-boundary")},$e="\\d",Je='"\\\\d"',Ve=function(){return new n("digit")},Ze="\\D",Qe='"\\\\D"',tn=function(){return new n("non-digit")},en="\\f",nn='"\\\\f"',rn=function(){return new n("form-feed")},an="\\n",on='"\\\\n"',un=function(){return new n("line-feed")},ln="\\r",sn='"\\\\r"',cn=function(){return new n("carriage-return")},hn="\\s",pn='"\\\\s"',fn=function(){return new n("white-space")},dn="\\S",mn='"\\\\S"',gn=function(){return new n("non-white-space")},vn="\\t",xn='"\\\\t"',yn=function(){return new n("tab")},bn="\\v",wn='"\\\\v"',Cn=function(){return new n("vertical-tab")},kn="\\w",En='"\\\\w"',Rn=function(){ 9 | return new n("word")},An="\\W",_n='"\\\\W"',Mn=function(){return new n("non-word")},Pn="\\c",Tn='"\\\\c"',Hn="any character",Sn=function(t){return new g(t)},Dn="\\",qn='"\\\\"',Fn=/^[1-9]/,Ln="[1-9]",On=function(t){return new m(t)},In="\\0",jn='"\\\\0"',Nn=/^[0-7]/,zn="[0-7]",Un=function(t){return new d(t.join(""))},Bn="\\x",Gn='"\\\\x"',Xn=/^[0-9a-fA-F]/,Kn="[0-9a-fA-F]",Wn=function(t){return new f(t.join(""))},Yn="\\u",$n='"\\\\u"',Jn=function(t){return new p(t.join(""))},Vn=function(){return new n("null-character")},Zn=0,Qn=0,tr=0,er={line:1,column:1,seenCR:!1},nr=0,rr=[],ar=0;if("startRule"in bt){if(!(bt.startRule in wt))throw new Error("Can't start parsing from rule \""+bt.startRule+'".');Ct=wt[bt.startRule]}if(n.offset=x,n.text=v,yt=Ct(),null!==yt&&Zn===t.length)return yt;throw w(rr),Qn=Math.max(Zn,nr),new e(rr,Qn=r;r++)n+=String.fromCharCode(r);return n}var a=n(3),o=n(5),u={extend:a.extend},i=r(97,122),l=r(65,90),s=r(48,57),c=r(32,47)+r(58,64)+r(91,96)+r(123,126),h=r(32,126),p=" \f\n\r \x0B \u2028\u2029",f={"\\w":i+l+s+"_","\\W":c.replace("_",""),"\\s":p,"\\S":function(){for(var t=h,e=0;ea;a++)e+=this.gen(t.body,e,n);return e},quantifier:function(t,e,n){var r=Math.max(t.min,0),a=isFinite(t.max)?t.max:r+o.integer(3,7);return o.integer(r,a)},charset:function(t,e,n){if(t.invert)return this["invert-charset"](t,e,n);var r=o.pick(t.body);return this.gen(r,e,n)},"invert-charset":function(t,e,n){for(var r,a=h,u=0;u=s;s++)a=a.replace(String.fromCharCode(s),"");default:var c=f[r.text];if(c)for(var p=0;p<=c.length;p++)a=a.replace(c[p],"")}return o.pick(a.split(""))},range:function(t,e,n){var r=this.gen(t.start,e,n).charCodeAt(),a=this.gen(t.end,e,n).charCodeAt();return String.fromCharCode(o.integer(r,a))},literal:function(t,e,n){return t.escaped?t.body:t.text},unicode:function(t,e,n){return String.fromCharCode(parseInt(t.code,16))},hex:function(t,e,n){return String.fromCharCode(parseInt(t.code,16))},octal:function(t,e,n){return String.fromCharCode(parseInt(t.code,8))},"back-reference":function(t,e,n){return n[t.code]||""},CONTROL_CHARACTER_MAP:function(){for(var t="@ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \\ ] ^ _".split(" "),e="\x00        \b \n \x0B \f \r                  ".split(" "),n={},r=0;rr)return!0;var u={path:e,type:t,actual:n,expected:r,action:"is greater than",message:o};return u.message=l.message(u),a.push(u),!1},lessThan:function(t,e,n,r,a,o){if(r>n)return!0;var u={path:e,type:t,actual:n,expected:r,action:"is less to",message:o};return u.message=l.message(u),a.push(u),!1},greaterThanOrEqualTo:function(t,e,n,r,a,o){if(n>=r)return!0;var u={path:e,type:t,actual:n,expected:r,action:"is greater than or equal to",message:o};return u.message=l.message(u),a.push(u),!1},lessThanOrEqualTo:function(t,e,n,r,a,o){if(r>=n)return!0;var u={path:e,type:t,actual:n,expected:r,action:"is less than or equal to",message:o};return u.message=l.message(u),a.push(u),!1}};r.Diff=i,r.Assert=l,t.exports=r},function(t,e,n){t.exports=n(28)},function(t,e,n){function r(){this.custom={events:{},requestHeaders:{},responseHeaders:{}}}function a(){function t(){try{return new window._XMLHttpRequest}catch(t){}}function e(){try{return new window._ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}var n=function(){var t=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,e=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,n=location.href,r=e.exec(n.toLowerCase())||[];return t.test(r[1])}();return window.ActiveXObject?!n&&t()||e():t()}function o(t){function e(t,e){return"string"===i.type(t)?t===e:"regexp"===i.type(t)?t.test(e):void 0}for(var n in r.Mock._mocked){var a=r.Mock._mocked[n];if((!a.rurl||e(a.rurl,t.url))&&(!a.rtype||e(a.rtype,t.type.toLowerCase())))return a}}function u(t,e){return i.isFunction(t.template)?t.template(e):r.Mock.mock(t.template)}var i=n(3);window._XMLHttpRequest=window.XMLHttpRequest,window._ActiveXObject=window.ActiveXObject;try{new window.Event("custom")}catch(l){window.Event=function(t,e,n,r){var a=document.createEvent("CustomEvent");return a.initCustomEvent(t,e,n,r),a}}var s={UNSENT:0,OPENED:1,HEADERS_RECEIVED:2,LOADING:3,DONE:4},c="readystatechange loadstart progress abort error load timeout loadend".split(" "),h="timeout withCredentials".split(" "),p="readyState responseURL status statusText responseType response responseText responseXML".split(" "),f={100:"Continue",101:"Switching Protocols",200:"OK",201:"Created",202:"Accepted",203:"Non-Authoritative Information",204:"No Content",205:"Reset Content",206:"Partial Content",300:"Multiple Choice",301:"Moved Permanently",302:"Found",303:"See Other",304:"Not Modified",305:"Use Proxy",307:"Temporary Redirect",400:"Bad Request",401:"Unauthorized",402:"Payment Required",403:"Forbidden",404:"Not Found",405:"Method Not Allowed",406:"Not Acceptable",407:"Proxy Authentication Required",408:"Request Timeout",409:"Conflict",410:"Gone",411:"Length Required",412:"Precondition Failed",413:"Request Entity Too Large",414:"Request-URI Too Long",415:"Unsupported Media Type",416:"Requested Range Not Satisfiable",417:"Expectation Failed",422:"Unprocessable Entity",500:"Internal Server Error",501:"Not Implemented",502:"Bad Gateway",503:"Service Unavailable",504:"Gateway Timeout",505:"HTTP Version Not Supported"};r._settings={timeout:"10-100"},r.setup=function(t){return i.extend(r._settings,t),r._settings},i.extend(r,s),i.extend(r.prototype,s),r.prototype.mock=!0,r.prototype.match=!1,i.extend(r.prototype,{open:function(t,e,n,u,l){function s(t){for(var e=0;e -1) { 48 | value = value.split('#')[0] 49 | } 50 | res[name] = value; 51 | } 52 | return res; 53 | } 54 | function getDDUser() { 55 | if (window.localStorage.dduser) 56 | return JSON.parse(window.localStorage.dduser); 57 | else 58 | return null; 59 | } 60 | function setNavTitle(title) { 61 | dd.ready(function () { 62 | dd.biz.navigation.setTitle({ 63 | title: title 64 | }); 65 | }) 66 | 67 | } 68 | 69 | function setMenu(param, callback) { 70 | dd.ready(function () { 71 | dd.biz.navigation.setMenu({ 72 | // backgroundColor : "#ADD8E6", 73 | // textColor : "#6495ed", 74 | items: [ 75 | { 76 | "id": "3", 77 | "iconId": "setting", 78 | "text": "disange", 79 | }, 80 | { 81 | "id": "4", 82 | "iconId": "time", 83 | "text": "disige" 84 | } 85 | ], 86 | onSuccess: function (data) { 87 | }, 88 | onFail: function (err) { } 89 | }); 90 | }) 91 | } 92 | function setNavRight(param, callback) { 93 | console.log("setNavRight", param.text) 94 | dd.ready(function () { 95 | dd.biz.navigation.setRight({ 96 | control: true,//是否控制点击事件,true 控制,false 不控制, 默认false 97 | text: param.text,//控制显示文本,空字符串表示显示默认文本 98 | onSuccess: function (result) { 99 | callback(result); 100 | }, 101 | onFail: function (err) { } 102 | }); 103 | }) 104 | } 105 | function setNavLeft(param, callback) { 106 | dd.ready(function () { 107 | dd.biz.navigation.setLeft({ 108 | control: true,//是否控制点击事件,true 控制,false 不控制, 默认false 109 | text: param.text,//控制显示文本,空字符串表示显示默认文本 110 | onSuccess: function (result) { 111 | // callback(result); 112 | dd.biz.navigation.close() 113 | }, 114 | onFail: function (err) { } 115 | }); 116 | }) 117 | } 118 | function hideNavRight() { 119 | dd.ready(function () { 120 | dd.biz.navigation.setRight({ 121 | // control: true, 122 | text: "" 123 | }); 124 | }) 125 | } 126 | function ddscan(param, callback) { 127 | dd.ready(function () { 128 | dd.biz.util.scan({ 129 | type: "qrcode", // type 为 all、qrCode、barCode,默认是all。 130 | tips: param.tips, //进入扫码页面显示的自定义文案 131 | onSuccess: function (data) { 132 | callback(data); 133 | }, 134 | onFail: function (err) { 135 | } 136 | }) 137 | }) 138 | } 139 | 140 | 141 | 142 | //dingcce3c449b62ce9ea35c2f4657eb6378f 143 | function requestAuthCode(corpid, callback) { 144 | try { 145 | dd.ready(function () { 146 | console.log('corpid', corpid) 147 | dd.runtime.permission.requestAuthCode({ 148 | corpId: corpid, 149 | onSuccess: function (result) { 150 | callback(result) 151 | }, 152 | onFail: function (err) { 153 | console.error(err) 154 | } 155 | 156 | }); 157 | }); 158 | } catch (e) { 159 | console.error(e.message) 160 | } 161 | } 162 | //调取小鱼第三方应用 163 | function ddLaunchApp(jsconfig, app, callback) { 164 | 165 | console.log('ddconfig') 166 | dd.config({ 167 | agentId: jsconfig.agentid, 168 | corpId: jsconfig.corpId, 169 | timeStamp: jsconfig.timeStamp, 170 | nonceStr: jsconfig.nonceStr, 171 | signature: jsconfig.signature, 172 | jsApiList: ['device.launcher.launchApp'] 173 | }); 174 | dd.ready(function () { 175 | console.log('app', app) 176 | dd.device.launcher.launchApp({ 177 | app: app,//iOS:应用scheme;Android:应用包名 178 | onSuccess: function (data) { 179 | console.log('success') 180 | callback(data) 181 | }, 182 | onFail: function (err) { 183 | console.log('fail', err) 184 | } 185 | }); 186 | }); 187 | 188 | dd.error(function (err) { 189 | alert('dd error: ' + JSON.stringify(err)); 190 | }); 191 | } 192 | function ddConfirm(message, callback) { 193 | try { 194 | dd.ready(function () { 195 | dd.device.notification.confirm({ 196 | message: message, 197 | title: "提示", 198 | buttonLabels: ['确定', '取消'], 199 | // buttonLabels: buttonLabels, 200 | onSuccess: function (result) { 201 | callback(result) 202 | }, 203 | onFail: function (err) { } 204 | }); 205 | }) 206 | } catch (e) { 207 | console.error(e.message) 208 | } 209 | } 210 | function ddAlert(message, callback) { 211 | dd.device.notification.alert({ 212 | message: message, 213 | title: "提示",//可传空 214 | buttonName: "确定", 215 | onSuccess: function () { 216 | //onSuccess将在点击button之后回调 217 | /*回调*/ 218 | }, 219 | onFail: function (err) { } 220 | }); 221 | } 222 | function complexPicker(jsconfig, callback) { 223 | console.log('ddconfig') 224 | 225 | dd.ready(function () { 226 | dd.biz.contact.complexPicker({ 227 | title: "选择处理人", //标题 228 | corpId: jsconfig.corpId, //企业的corpId 229 | multiple: false, //是否多选 230 | limitTips: "超出了", //超过限定人数返回提示 231 | appId: jsconfig.agentid, //微应用的Id 232 | permissionType: "GLOBAL", //选人权限,目前只有GLOBAL这个参数 233 | responseUserOnly: true, //返回人,或者返回人和部门 234 | startWithDepartmentId: 0, // 0表示从企业最上层开始 235 | onSuccess: function (result) { 236 | /** 237 | { 238 | selectedCount:1, //选择人数 239 | users:[{"name":"","avatar":"","emplId":""}],//返回选人的列表,列表中的对象包含name(用户名),avatar(用户头像),emplId(用户工号)三个字段 240 | departments:[{"id":,"name":"","number":}]//返回已选部门列表,列表中每个对象包含id(部门id)、name(部门名称)、number(部门人数) 241 | } 242 | */ 243 | console.info('complexPicker', result) 244 | callback(result); 245 | }, 246 | onFail: function (err) { } 247 | }); 248 | }) 249 | 250 | dd.error(function (err) { 251 | alert('dd error: ' + JSON.stringify(err)); 252 | }); 253 | 254 | } 255 | 256 | function pickConversation(jsconfig, callback) { 257 | console.log('ddconfig') 258 | dd.ready(function () { 259 | dd.biz.chat.pickConversation({ 260 | corpId: jsconfig.corpId, //企业id 261 | // isConfirm:'false', //是否弹出确认窗口,默认为true 262 | onSuccess: function (result) { 263 | //onSuccess将在选择结束之后调用 264 | // 该cid和服务端开发文档-普通会话消息接口配合使用,而且只能使用一次,之后将失效 265 | /*{ 266 | cid: 'xxxx', 267 | title:'xxx' 268 | }*/ 269 | console.info('pickConversation', result) 270 | callback(result); 271 | }, 272 | onFail: function () { } 273 | }) 274 | }) 275 | 276 | dd.error(function (err) { 277 | alert('dd error: ' + JSON.stringify(err)); 278 | }); 279 | } 280 | function chooseConversationByCorpId(jsconfig, callback) { 281 | console.log('ddconfig') 282 | dd.ready(function () { 283 | dd.biz.chat.chooseConversationByCorpId({ 284 | corpId: jsconfig.corpId, //企业id 285 | isAllowCreateGroup:false, 286 | filterNotOwnerGroup:false, 287 | onSuccess: function (result) { 288 | //onSuccess将在选择结束之后调用 289 | /*{ 290 | chatId: 'xxxx', 291 | title:'xxx' 292 | }*/ 293 | console.info('chooseConversationByCorpId', result) 294 | callback(result); 295 | }, 296 | onFail: function () { } 297 | }) 298 | }) 299 | 300 | dd.error(function (err) { 301 | alert('dd error: ' + JSON.stringify(err)); 302 | }); 303 | } 304 | 305 | function ddAuthconfig(jsconfig, jsApiList) { 306 | console.info('jsApiList',jsApiList) 307 | dd.config({ 308 | agentId: jsconfig.agentId, 309 | corpId: jsconfig.corpId, 310 | timeStamp: jsconfig.timeStamp, 311 | nonceStr: jsconfig.nonceStr, 312 | signature: jsconfig.signature, 313 | jsApiList: jsApiList 314 | }); 315 | dd.error(function (err) { 316 | alert('dd error: ' + JSON.stringify(err)); 317 | }); 318 | } 319 | function openSingleChat(jsconfig, userid) { 320 | console.log('ddconfig', jsconfig, userid) 321 | 322 | dd.ready(function () { 323 | dd.biz.chat.openSingleChat({ 324 | corpId: jsconfig.corpId, // 企业id,必须是用户所属的企业的corpid 325 | userId: userid, // 用户的工号 326 | onSuccess: function () {}, 327 | onFail: function (e) { 328 | alert(JSON.stringify(e)) 329 | } 330 | }) 331 | }) 332 | 333 | 334 | 335 | } 336 | function showCallMenu(jsconfig, mobile) { 337 | console.log('ddconfig', jsconfig,mobile) 338 | 339 | dd.ready(function () { 340 | dd.biz.telephone.showCallMenu({ 341 | phoneNumber: mobile, // 期望拨打的电话号码 342 | code: '+86', // 国家代号,中国是+86 343 | showDingCall: false, // 是否显示钉钉电话 344 | onSuccess: function () { }, 345 | onFail: function (e) { 346 | alert(JSON.stringify(e)) 347 | } 348 | }) 349 | }) 350 | 351 | } 352 | function alipay(jsconfig, info, callback) { 353 | console.log('jsconfig') 354 | dd.config({ 355 | agentId: jsconfig.agentid, 356 | corpId: jsconfig.corpId, 357 | timeStamp: jsconfig.timeStamp, 358 | nonceStr: jsconfig.nonceStr, 359 | signature: jsconfig.signature, 360 | jsApiList: ['biz.alipay.pay'] 361 | }); 362 | 363 | dd.ready(function () { 364 | console.log('alipay') 365 | dd.biz.alipay.pay({ 366 | info: info, 367 | onSuccess: function (result) { 368 | console.log("alipay success") 369 | callback(result) 370 | }, 371 | onFail: function (err) { 372 | console.log("alipay err") 373 | console.error(err) 374 | } 375 | }) 376 | }) 377 | 378 | dd.error(function (err) { 379 | alert('dd error: ' + JSON.stringify(err)); 380 | }); 381 | 382 | } 383 | 384 | -------------------------------------------------------------------------------- /screenshots/S91006-001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluto1114/dingding-nodejs-SDK/2426dbeff156a20d0dbb9ea07bda3b278db99687/screenshots/S91006-001.png -------------------------------------------------------------------------------- /screenshots/S91006-002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluto1114/dingding-nodejs-SDK/2426dbeff156a20d0dbb9ea07bda3b278db99687/screenshots/S91006-002.png -------------------------------------------------------------------------------- /screenshots/S91006-003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluto1114/dingding-nodejs-SDK/2426dbeff156a20d0dbb9ea07bda3b278db99687/screenshots/S91006-003.png -------------------------------------------------------------------------------- /screenshots/S91006-004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluto1114/dingding-nodejs-SDK/2426dbeff156a20d0dbb9ea07bda3b278db99687/screenshots/S91006-004.png -------------------------------------------------------------------------------- /screenshots/S91006-005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluto1114/dingding-nodejs-SDK/2426dbeff156a20d0dbb9ea07bda3b278db99687/screenshots/S91006-005.png -------------------------------------------------------------------------------- /server/config/config-default.js: -------------------------------------------------------------------------------- 1 | var config = { 2 | database: 'dingding-sdk', 3 | dialect:'mysql', 4 | username: 'root', 5 | password: 'pluto1114', 6 | host: '94.191.121.109', 7 | port: 3306, 8 | secret:'pluto1114', 9 | }; 10 | 11 | module.exports = config; -------------------------------------------------------------------------------- /server/config/config-test.js: -------------------------------------------------------------------------------- 1 | var config = { 2 | database: 'selnum', 3 | username: 'root', 4 | password: 'root', 5 | host: 'localhost', 6 | port: 3306 7 | }; 8 | 9 | module.exports = config; -------------------------------------------------------------------------------- /server/config/index.js: -------------------------------------------------------------------------------- 1 | const defaultConfig = './config-default.js'; 2 | // 可设定为绝对路径,如 /opt/product/config-override.js 3 | const overrideConfig = 'e:/config-override.js'; 4 | const testConfig = './config-test.js'; 5 | 6 | const fs = require('fs'); 7 | 8 | var config = null; 9 | 10 | if (process.env.NODE_ENV === 'test') { 11 | console.log(`Load ${testConfig}...`); 12 | config = require(testConfig); 13 | } else { 14 | console.log(`Load ${defaultConfig}...`); 15 | config = require(defaultConfig); 16 | try { 17 | // if (fs.statSync(overrideConfig).isFile()) { 18 | // console.log(`Load ${overrideConfig}...`); 19 | // config = Object.assign(config, require(overrideConfig)); 20 | // } 21 | } catch (err) { 22 | console.log(err) 23 | console.log(`Cannot load ${overrideConfig}.`); 24 | } 25 | } 26 | 27 | module.exports = config; -------------------------------------------------------------------------------- /server/controller.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | function addMapping(router, mapping) { 4 | for (var url in mapping) { 5 | var 6 | delimiter = url.indexOf(' '); 7 | method = url.slice(0, delimiter); 8 | path = url.slice(delimiter + 1); 9 | router[method.toLowerCase()](path, mapping[url]); 10 | console.log(`register URL mapping: ${method} ${path}`); 11 | } 12 | } 13 | 14 | function addControllers(router, dir) { 15 | var files = fs.readdirSync(__dirname + '/' + dir); 16 | var js_files = files.filter((f) => { 17 | return f.endsWith('.js'); 18 | }); 19 | 20 | 21 | for (var f of js_files) { 22 | console.log(`process controller: ${f}...`); 23 | let mapping = require(__dirname + `/${dir}/` + f); 24 | let name = f.replace('.js', ''); 25 | let keys = Object.keys(mapping); 26 | 27 | if (keys.every(k => k.includes(`/v1/${name}/`)||k.includes(`/v2/${name}/`))) { 28 | addMapping(router, mapping); 29 | } else { 30 | throw new Error(`${f} 路径命名不合法`); 31 | } 32 | 33 | } 34 | } 35 | function _to(s) { 36 | let d = "s", e = "es"; 37 | let len = s.length; 38 | if ((s[len - 1] == 'o' || s[len - 1] == 's' || s[len - 1] == 'x') || ((s[len - 2] == 'c' || s[len - 2] == 's') && (s[len - 1] == 'h'))) { 39 | s = s.concat(e); 40 | } 41 | else if (s[len - 1] == 'y') { 42 | s[len - 1] = 'i'; 43 | s = s.concat(e); 44 | } 45 | else { 46 | s = s.concat(d); 47 | } 48 | return s; 49 | } 50 | module.exports = function (dir) { 51 | let 52 | controller_dir = dir || 'controller', // 如果不传参数,扫描目录默认为'controllers' 53 | router = require('koa-router')(); 54 | addControllers(router, controller_dir); 55 | return router.routes(); 56 | } -------------------------------------------------------------------------------- /server/controller/dd.js: -------------------------------------------------------------------------------- 1 | const model = require('../model') 2 | const r = require('../dto/resp') 3 | 4 | class Dd{ 5 | async getCorpid(ctx){ 6 | let ddConfig = await model.DdConfig.getBy({ ukey: ctx.ukey }) 7 | ctx.body = r().setItemMap({ corpid: ddConfig.corpid }) 8 | }; 9 | async getUserinfo(ctx){ 10 | let ukey = ctx.ukey 11 | let code = ctx.query.code 12 | console.log('code', code) 13 | let options = { 14 | url: 'https://oapi.dingtalk.com/user/getuserinfo', 15 | params: { code }, 16 | } 17 | let info = await model.DdConfig.callApi(ctx.ukey, options) 18 | console.log('info', info) 19 | 20 | let user = await model.user.getBy({ userid: info.userid }) 21 | 22 | if (user) { 23 | let lasttime = user.accesstime 24 | user.hot = user.hot + 1 25 | user.accesstime = new Date 26 | await user.save() 27 | user.accesstime = lasttime 28 | } else { 29 | user= await model.user.createUser(info.userid,ukey) 30 | } 31 | 32 | ctx.body = r().setItemMap({ user }) 33 | }; 34 | async getJsconfig(ctx){ 35 | let jsconfig = await model.DdConfig.getJsconfig(ctx.ukey) 36 | console.log('info', jsconfig) 37 | 38 | ctx.body = r().setItemMap({ jsconfig }) 39 | }; 40 | 41 | } 42 | 43 | let dd=new Dd(); 44 | module.exports = { 45 | 'GET /v1/dd/corpid': dd.getCorpid, 46 | 'GET /v1/dd/userinfo': dd.getUserinfo, 47 | 'GET /v1/dd/jsconfig': dd.getJsconfig, 48 | 49 | }; -------------------------------------------------------------------------------- /server/controller/order.js: -------------------------------------------------------------------------------- 1 | 2 | const model = require('../model'); 3 | const service = require('../service'); 4 | const r = require('../dto/resp'); 5 | const Op = require('sequelize').Op; 6 | class Order { 7 | async index(ctx) { 8 | let { userid, orderStatus } = ctx.query; 9 | const orders = await model.order.findBy({ userid, orderStatus}) 10 | ctx.body = r().setItems(orders); 11 | } 12 | async show(ctx) { 13 | let { id } = ctx.params; 14 | const order = await model.order.getBy({ orderId: id }) 15 | ctx.body = r().setItemMap({ order }) 16 | } 17 | async count(ctx) { 18 | let { userid } = ctx.query; 19 | let unfinCount = await model.order.countBy({ orderStatus: {[Op.ne]:'orderFinish'}, userid }) 20 | let finCount = await model.order.countBy({ orderStatus: 'orderFinish', userid }) 21 | ctx.body = r().setItemMap({ unfinCount, finCount }); 22 | } 23 | async save(ctx) { 24 | let body = ctx.request.body; 25 | let order = await model.order.create({ 26 | orderId: new Date().getTime(), 27 | orderStatus: 'orderStart', 28 | createtime: new Date(), 29 | ...body 30 | }) 31 | service.process.createTask({ukey:ctx.ukey,orderId:order.orderId}) 32 | ctx.body = r().setItemMap({ order }) 33 | } 34 | async finish(ctx) { 35 | let body = ctx.request.body; 36 | const order=await model.order.getBy({orderId:body.orderId}) 37 | order.orderStatus='orderFinish' 38 | await order.save() 39 | service.process.cancelTask({ukey:ctx.ukey,orderId:order.orderId}) 40 | ctx.body = r() 41 | } 42 | } 43 | let order = new Order() 44 | module.exports = { 45 | 'GET /v1/order/index': order.index, 46 | 'GET /v1/order/count': order.count, 47 | 'GET /v1/order/:id': order.show, 48 | 'POST /v1/order/save': order.save, 49 | 'PUT /v1/order/finish': order.finish, 50 | 51 | }; -------------------------------------------------------------------------------- /server/cservice/process.js: -------------------------------------------------------------------------------- 1 | const model = require('../model'); 2 | const Op = require('sequelize').Op; 3 | 4 | class Process { 5 | async createTask({ ukey, orderId }) { 6 | let order = await model.order.getBy({ orderId }); 7 | let ddConfig = await model.DdConfig.getBy({ ukey }); 8 | let url = `${ddConfig.url}`; 9 | let createInstanceOptions = { 10 | url: 'https://oapi.dingtalk.com/topapi/process/workrecord/create', 11 | data: { 12 | "request": { 13 | "title": `demo未处理工单(${order.orderName})`, 14 | "process_code": `${ddConfig.process_code}`, 15 | "originator_user_id": order.userid, 16 | "form_component_values": { 17 | "name": "待办工单", 18 | "value": `${order.orderId}` 19 | }, 20 | "url": `${url}` 21 | } 22 | }, 23 | method: 'post' 24 | }; 25 | let process_instance_id = order.processInstanceId; 26 | if (process_instance_id == null) { 27 | let instanceData = await model.DdConfig.callApi(ukey, createInstanceOptions); 28 | process_instance_id = instanceData.result.process_instance_id 29 | } 30 | 31 | let createTaskOptions = { 32 | url: 'https://oapi.dingtalk.com/topapi/process/workrecord/task/create', 33 | data: { 34 | "request": { 35 | "process_instance_id": process_instance_id, 36 | "activity_id": "solve", 37 | "tasks": { 38 | "userid": order.userid, 39 | "url": `${url}` 40 | } 41 | } 42 | }, 43 | method: 'post' 44 | }; 45 | let taskData = await model.DdConfig.callApi(ukey, createTaskOptions); 46 | if (taskData.errcode === 0) { 47 | await order.update({ processInstanceId: process_instance_id }); 48 | return process_instance_id; 49 | } else { 50 | return null; 51 | } 52 | 53 | } 54 | async cancelTask({ ukey, orderId }) { 55 | let order = await model.order.getBy({ orderId }); 56 | let cancelTaskOptions = { 57 | url: 'https://oapi.dingtalk.com/topapi/process/workrecord/taskgroup/cancel', 58 | data: { 59 | "request": { 60 | "process_instance_id": `${order.processInstanceId}`, 61 | "activity_id": "solve" 62 | } 63 | }, 64 | method: 'post' 65 | }; 66 | if (order.processInstanceId) { 67 | await model.DdConfig.callApi(ukey, cancelTaskOptions); 68 | } 69 | } 70 | async updateInstance({ ukey, orderId }) { 71 | let order = await model.Order.getBy({ orderId }); 72 | let updateInstanceOptions = { 73 | url: 'https://oapi.dingtalk.com/topapi/process/workrecord/update', 74 | data: { 75 | "request": { 76 | "process_instance_id": `${order.processInstanceId}`, 77 | "status": "COMPLETED", 78 | "result": order.revisitCode == "yes" ? "agree" : "refuse" 79 | } 80 | }, 81 | method: 'post' 82 | }; 83 | if (order.processInstanceId) { 84 | await model.DdConfig.callApi(ukey, updateInstanceOptions); 85 | } 86 | } 87 | } 88 | 89 | const obj=new Process() 90 | exports.obj = obj 91 | 92 | -------------------------------------------------------------------------------- /server/db.js: -------------------------------------------------------------------------------- 1 | const Sequelize = require('sequelize'); 2 | 3 | const uuid = require('node-uuid'); 4 | 5 | const config = require('./config'); 6 | 7 | console.log('init sequelize...'); 8 | 9 | function generateId() { 10 | return uuid.v4(); 11 | } 12 | 13 | var sequelize = new Sequelize(config.database, config.username, config.password, { 14 | host: config.host, 15 | port: config.port, 16 | dialect: config.dialect, 17 | timezone:"+08:00", 18 | pool: { 19 | max: 6, 20 | min: 0, 21 | idle: 30000 22 | } 23 | }); 24 | 25 | var exp = { 26 | sequelize:sequelize, 27 | dataTypes:Sequelize, 28 | sync: () => { 29 | // only allow create ddl in non-production environment: 30 | if (process.env.NODE_ENV !== 'production') { 31 | return sequelize.sync({ force: true }); 32 | } else { 33 | throw new Error('Cannot sync() when NODE_ENV is set to \'production\'.'); 34 | } 35 | } 36 | }; 37 | exp.SELECT=sequelize.QueryTypes.SELECT 38 | exp.generateId = generateId; 39 | exp.pageSize=15 40 | module.exports = exp; -------------------------------------------------------------------------------- /server/dto/resp.js: -------------------------------------------------------------------------------- 1 | var r = () => { 2 | return { 3 | errcode: '0', 4 | message: 'success', 5 | items: [], 6 | itemMap: {}, 7 | 8 | setErrcode(val) { 9 | this.errcode = val 10 | return this 11 | }, 12 | 13 | setMessage(val) { 14 | this.message = val 15 | return this 16 | }, 17 | 18 | setItems(val) { 19 | this.items = val 20 | return this 21 | }, 22 | 23 | setItemMap(val) { 24 | this.itemMap = val 25 | return this 26 | }, 27 | fail(message='fail'){ 28 | this.errcode='-1' 29 | this.message=message 30 | return this 31 | } 32 | } 33 | } 34 | module.exports = r -------------------------------------------------------------------------------- /server/kits/cryptoKit.js: -------------------------------------------------------------------------------- 1 | var crypto = require('crypto'); 2 | 3 | var toSha1 = str=>{ 4 | return crypto.createHash('sha1').update(str).digest('hex') 5 | } 6 | 7 | module.exports = { 8 | toSha1 9 | }; -------------------------------------------------------------------------------- /server/kits/jwtKit.js: -------------------------------------------------------------------------------- 1 | const jwt = require('jsonwebtoken') 2 | const config=require('../config') 3 | const secret = config.secret 4 | 5 | const expiresIn='6h' 6 | let sign=(userToken)=>{ 7 | return jwt.sign(userToken, secret, { expiresIn}) 8 | } 9 | 10 | module.exports = { 11 | 'sign':sign 12 | }; -------------------------------------------------------------------------------- /server/middleware/error.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | module.exports = function () { 5 | return async function (ctx, next) { 6 | try { 7 | await next(); 8 | } catch (err) { 9 | console.error(err) 10 | ctx.body = 'server error'; 11 | ctx.status = err.status || 500; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /server/middleware/tokenError.js: -------------------------------------------------------------------------------- 1 | const jwt = require('jsonwebtoken'); 2 | const config = require('../config'); 3 | const util = require('util'); 4 | const verify = util.promisify(jwt.verify); 5 | 6 | /** 7 | * 判断token是否可用 8 | */ 9 | module.exports = function () { 10 | return async function (ctx, next) { 11 | try { 12 | // console.log('authorization',ctx.header.authorization) 13 | const token = ctx.header.authorization; 14 | if (token) { 15 | try { 16 | let payload = await verify(token.split(' ')[1], config.secret); 17 | // console.log(payload) 18 | ctx.user = { 19 | code:payload.code, 20 | name: payload.name, 21 | mobile:payload.mobile, 22 | role_code:payload.role_code 23 | }; 24 | } catch (err) { 25 | console.log('token verify fail: ', err) 26 | } 27 | } 28 | await next(); 29 | } catch (err) { 30 | console.error(err) 31 | if (err.status === 401) { 32 | ctx.status = 401; 33 | ctx.body = { 34 | errcode: -1, 35 | message: '认证失败' 36 | }; 37 | } else { 38 | err.status = 404; 39 | ctx.body = { 40 | errcode: -4, 41 | message: '404' 42 | }; 43 | } 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /server/middleware/ukey.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | module.exports = function () { 5 | return async function (ctx, next) { 6 | try { 7 | const keyArr=['nmlt','pluto1114','rcpbe-cs'] 8 | const ukey = ctx.header['x-key']; 9 | console.log('ukey',ukey) 10 | if (ukey&&keyArr.findIndex(k=>k==ukey)>-1) { 11 | ctx.ukey=ukey 12 | await next(); 13 | }else if(ctx.is('multipart')){ 14 | await next(); 15 | }else{ 16 | await next(); 17 | } 18 | } catch (err) { 19 | console.error(err) 20 | 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /server/model-base/abase.js: -------------------------------------------------------------------------------- 1 | const db = require('../db'); 2 | const pageSize=db.pageSize 3 | 4 | function base(table) { 5 | const contruct = require(`./${table}`) 6 | const obj = contruct(db.sequelize, db.dataTypes) 7 | obj.sql=db.sequelize 8 | obj.SELECT=db.sequelize.QueryTypes.SELECT 9 | obj.getBy = (param) => { 10 | return obj.findOne({ where: param }); 11 | } 12 | obj.findBy = (whereParam,otherParams) => { 13 | return obj.findAll({ where: whereParam,...otherParams }) 14 | } 15 | obj.findByOrder = (param,order) => { 16 | return obj.findAll({ where: param ,order}) 17 | } 18 | obj.pageByOrder = async (param,order,pageNum) => { 19 | // return obj.findAll({ where: param ,order:order,offset:(pageNum-1)*pageSize,limit:pageSize}) 20 | let items=await obj.findAll({ where: param ,order:order,offset:(pageNum-1)*pageSize,limit:pageSize}) 21 | let total=await obj.count({ where: param}) 22 | return {items,total} 23 | } 24 | obj.findBySql=(sql,param)=>{ 25 | return obj.sql.query(sql,{replacements:param,type : obj.SELECT}) 26 | } 27 | obj.pageBySql=(sql,param,pageNum)=>{ 28 | sql=sql+' limit '+(pageNum-1)*pageSize+','+pageSize 29 | return obj.sql.query(sql,{replacements:param,type : obj.SELECT}) 30 | } 31 | obj.updateBySql=(sql,param)=>{ 32 | return obj.sql.query(sql,{replacements:param,type : obj.UPDATE}) 33 | } 34 | obj.updateBy = (model,param) => { 35 | return obj.update(model,{ where: param }) 36 | } 37 | obj.deleteBy = (param) => { 38 | return obj.destroy({ where: param }) 39 | } 40 | obj.countBy = (param) => { 41 | return obj.count({ where: param }) 42 | } 43 | 44 | return obj 45 | 46 | } 47 | module.exports = base 48 | 49 | -------------------------------------------------------------------------------- /server/model-base/dd_config.js: -------------------------------------------------------------------------------- 1 | /* jshint indent: 1 */ 2 | 3 | module.exports = function(sequelize, DataTypes) { 4 | return sequelize.define('dd_config', { 5 | id: { 6 | type: DataTypes.INTEGER(11), 7 | allowNull: false 8 | }, 9 | ukey: { 10 | type: DataTypes.STRING(64), 11 | allowNull: false, 12 | primaryKey: true 13 | }, 14 | uname: { 15 | type: DataTypes.STRING(128), 16 | allowNull: true 17 | }, 18 | sname: { 19 | type: DataTypes.STRING(64), 20 | allowNull: true 21 | }, 22 | corpid: { 23 | type: DataTypes.STRING(128), 24 | allowNull: false 25 | }, 26 | corpsecret: { 27 | type: DataTypes.STRING(128), 28 | allowNull: true 29 | }, 30 | appkey: { 31 | type: DataTypes.STRING(128), 32 | allowNull: true 33 | }, 34 | appsecret: { 35 | type: DataTypes.STRING(128), 36 | allowNull: true 37 | }, 38 | agentid: { 39 | type: DataTypes.STRING(128), 40 | allowNull: true 41 | }, 42 | chatid: { 43 | type: DataTypes.STRING(128), 44 | allowNull: true 45 | }, 46 | access_token: { 47 | type: DataTypes.STRING(128), 48 | allowNull: true 49 | }, 50 | token_begin_time: { 51 | type: DataTypes.DATE, 52 | allowNull: true 53 | }, 54 | ticket: { 55 | type: DataTypes.STRING(128), 56 | allowNull: true 57 | }, 58 | ticket_begin_time: { 59 | type: DataTypes.DATE, 60 | allowNull: true 61 | }, 62 | url: { 63 | type: DataTypes.STRING(256), 64 | allowNull: true 65 | }, 66 | process_code: { 67 | type: DataTypes.STRING(64), 68 | allowNull: true 69 | } 70 | }, { 71 | tableName: 'dd_config', 72 | timestamps: false 73 | }); 74 | }; 75 | -------------------------------------------------------------------------------- /server/model-base/t_order.js: -------------------------------------------------------------------------------- 1 | /* jshint indent: 1 */ 2 | 3 | module.exports = function(sequelize, DataTypes) { 4 | return sequelize.define('t_order', { 5 | orderId: { 6 | type: DataTypes.BIGINT, 7 | allowNull: false, 8 | primaryKey: true, 9 | autoIncrement: true 10 | }, 11 | orderName: { 12 | type: DataTypes.STRING(255), 13 | allowNull: true 14 | }, 15 | userid: { 16 | type: DataTypes.STRING(64), 17 | allowNull: true 18 | }, 19 | totalPrice: { 20 | type: DataTypes.DECIMAL, 21 | allowNull: true 22 | }, 23 | orderStatus: { 24 | type: DataTypes.STRING(64), 25 | allowNull: true 26 | }, 27 | processInstanceId: { 28 | type: DataTypes.STRING(64), 29 | allowNull: true 30 | }, 31 | createtime: { 32 | type: DataTypes.DATE, 33 | allowNull: true 34 | } 35 | }, { 36 | tableName: 't_order', 37 | timestamps: false 38 | }); 39 | }; 40 | -------------------------------------------------------------------------------- /server/model-base/t_user.js: -------------------------------------------------------------------------------- 1 | /* jshint indent: 1 */ 2 | 3 | module.exports = function(sequelize, DataTypes) { 4 | return sequelize.define('t_user', { 5 | id: { 6 | type: DataTypes.INTEGER(11), 7 | allowNull: false, 8 | autoIncrement: true, 9 | unique: true 10 | }, 11 | userid: { 12 | type: DataTypes.STRING(64), 13 | allowNull: false, 14 | primaryKey: true 15 | }, 16 | name: { 17 | type: DataTypes.STRING(64), 18 | allowNull: true 19 | }, 20 | department: { 21 | type: DataTypes.STRING(64), 22 | allowNull: true 23 | }, 24 | departmentName: { 25 | type: DataTypes.STRING(255), 26 | allowNull: true 27 | }, 28 | mobile: { 29 | type: DataTypes.STRING(64), 30 | allowNull: true 31 | }, 32 | email: { 33 | type: DataTypes.STRING(64), 34 | allowNull: true 35 | }, 36 | avatar: { 37 | type: DataTypes.STRING(256), 38 | allowNull: true 39 | }, 40 | openid: { 41 | type: DataTypes.STRING(64), 42 | allowNull: true 43 | }, 44 | unionid: { 45 | type: DataTypes.STRING(64), 46 | allowNull: true 47 | }, 48 | createtime: { 49 | type: DataTypes.DATE, 50 | allowNull: false 51 | }, 52 | accesstime: { 53 | type: DataTypes.DATE, 54 | allowNull: true 55 | }, 56 | hot: { 57 | type: DataTypes.INTEGER(11), 58 | allowNull: true, 59 | defaultValue: '0' 60 | }, 61 | upDepart: { 62 | type: DataTypes.BIGINT, 63 | allowNull: true 64 | }, 65 | ukey: { 66 | type: DataTypes.STRING(64), 67 | allowNull: true 68 | }, 69 | point: { 70 | type: DataTypes.INTEGER(11), 71 | allowNull: true, 72 | defaultValue: '0' 73 | }, 74 | god: { 75 | type: DataTypes.INTEGER(1), 76 | allowNull: false, 77 | defaultValue: '0' 78 | }, 79 | role: { 80 | type: DataTypes.STRING(16), 81 | allowNull: false, 82 | defaultValue: 'P' 83 | } 84 | }, { 85 | tableName: 't_user', 86 | timestamps: false 87 | }); 88 | }; 89 | -------------------------------------------------------------------------------- /server/model.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const db = require('./db'); 3 | 4 | let files = fs.readdirSync(__dirname + '/model'); 5 | 6 | let js_files = files.filter((f) => { 7 | return f.endsWith('.js'); 8 | }, files); 9 | 10 | module.exports = {}; 11 | 12 | for (let f of js_files) { 13 | if (f === 'AAA.js') continue 14 | console.log(`import model from file ${f}...`); 15 | let name = f.substring(0, f.length - 3); 16 | module.exports[name] = require(__dirname + '/model/' + f).obj; 17 | } 18 | module.exports.now = () => { 19 | let date = new Date(); 20 | return date 21 | } 22 | module.exports.date = (s) => { 23 | let date = new Date(s); 24 | // date.setHours(date.getHours() + 8); 25 | return date 26 | } 27 | module.exports.sync = () => { 28 | db.sync(); 29 | }; 30 | 31 | module.exports.pageSize=db.pageSize -------------------------------------------------------------------------------- /server/model/DdConfig.js: -------------------------------------------------------------------------------- 1 | 2 | const table='dd_config' 3 | const obj=require('../model-base/abase')(table) 4 | const axios = require('axios') 5 | const config = require('../config') 6 | const cryptoKit=require('../kits/cryptoKit') 7 | 8 | var _merge = require('lodash/merge') 9 | obj.gettoken = async (ukey) => { 10 | let ddconfig = await obj.getBy({ ukey}) 11 | let date=new Date() 12 | date.setHours(date.getHours()-1) 13 | if(ddconfig.ticket_begin_time.getTime()>date.getTime()){ 14 | console.log('token used') 15 | return ddconfig.access_token 16 | } 17 | var options = { 18 | url: 'https://oapi.dingtalk.com/gettoken', 19 | params: { 20 | appkey: ddconfig.corpid, 21 | appsecret: ddconfig.corpsecret, 22 | } 23 | }; 24 | if(ddconfig.corpsecret){ 25 | // console.warn("corpid") 26 | options.params={ 27 | appkey: ddconfig.corpid, 28 | appsecret: ddconfig.corpsecret, 29 | } 30 | }else{ 31 | // console.warn("appkey") 32 | options.params={ 33 | appkey: ddconfig.appkey, 34 | appsecret: ddconfig.appsecret, 35 | } 36 | } 37 | 38 | let { data } = await axios(options) 39 | await ddconfig.update({ access_token: data.access_token, token_begin_time: new Date() }) 40 | return data.access_token 41 | } 42 | obj._getticket = async (ukey,access_token) => { 43 | let ddconfig = await obj.getBy({ ukey}) 44 | let date=new Date() 45 | date.setHours(date.getHours()-1) 46 | if(ddconfig.ticket_begin_time.getTime()>date.getTime()){ 47 | console.log('ticket used') 48 | return ddconfig.ticket 49 | } 50 | var options = { 51 | url: 'https://oapi.dingtalk.com/get_jsapi_ticket', 52 | params: {access_token} 53 | }; 54 | 55 | let {data} = await axios(options) 56 | console.log(data) 57 | await ddconfig.update({ticket: data.ticket,ticket_begin_time:new Date()}) 58 | return data.ticket 59 | } 60 | function sign(ticket,nonceStr,timeStamp,url){ 61 | let plain = "jsapi_ticket=" + ticket + "&noncestr=" + nonceStr + "×tamp=" + timeStamp 62 | + "&url=" + url; 63 | console.log('plain',plain) 64 | return cryptoKit.toSha1(plain) 65 | } 66 | 67 | obj.getJsconfig=async (ukey)=>{ 68 | let access_token= await obj.gettoken(ukey) 69 | let ticket=await obj._getticket(ukey,access_token) 70 | let ddconfig = await obj.getBy({ ukey}) 71 | let timeStamp=new Date().getTime() 72 | let nonceStr=config.secret 73 | 74 | return { 75 | agentId:ddconfig.agentid, 76 | corpId:ddconfig.corpid, 77 | signature:sign(ticket,nonceStr,timeStamp,ddconfig.url), 78 | timeStamp, 79 | nonceStr 80 | } 81 | } 82 | 83 | obj.callApi=async (ukey,options)=>{ 84 | let access_token= await obj.gettoken(ukey) 85 | let DEFAULTS = { 86 | url: 'https://oapi.dingtalk.com/', 87 | params: {access_token} 88 | }; 89 | options=_merge(DEFAULTS,options) 90 | console.log('options',options) 91 | let {data} = await axios(options) 92 | return data 93 | } 94 | 95 | exports.obj = obj -------------------------------------------------------------------------------- /server/model/order.js: -------------------------------------------------------------------------------- 1 | 2 | const table='t_order' 3 | const obj=require('../model-base/abase')(table) 4 | 5 | 6 | exports.obj = obj 7 | -------------------------------------------------------------------------------- /server/model/user.js: -------------------------------------------------------------------------------- 1 | 2 | const table = 't_user' 3 | const obj = require('../model-base/abase')(table) 4 | const model = require('../model') 5 | 6 | obj.createUser = async (userid, ukey) => { 7 | let options = { 8 | url: 'https://oapi.dingtalk.com/user/get', 9 | params: { userid }, 10 | } 11 | let u = await model.DdConfig.callApi(ukey, options) 12 | 13 | let user = await model.user.create({ 14 | userid: u.userid, openid: u.openId, name: u.name, mobile: u.mobile, email: u.email, avatar: u.avatar, department: u.department[0], jobnumber: u.jobnumber, ukey: ukey, createtime: new Date, accesstime: new Date, god: 1 15 | }) 16 | return user 17 | } 18 | exports.obj = obj 19 | -------------------------------------------------------------------------------- /server/service.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | let files = fs.readdirSync(__dirname + '/cservice'); 3 | 4 | let js_files = files.filter((f) => { 5 | return f.endsWith('.js'); 6 | }, files); 7 | 8 | module.exports = {}; 9 | 10 | for (let f of js_files) { 11 | console.log(`import service from file ${f}...`); 12 | let name = f.substring(0, f.length - 3); 13 | module.exports[name] = require(__dirname + '/cservice/' + f).obj; 14 | } 15 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 49 | 50 | 67 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /src/api.js: -------------------------------------------------------------------------------- 1 | 2 | import Vue from 'vue' 3 | import axios from 'axios' 4 | 5 | var debug = true; 6 | var showStr = false; 7 | 8 | export function api(url, options) { 9 | var p = {}; 10 | if (!url) url = '/api' 11 | var defaultOptions = { 12 | 'method': 'get' 13 | }; 14 | // window.location.href="http://www.baidu.com" 15 | var opt = Object.assign(defaultOptions, options); 16 | console.log("localStorage.ddKey",localStorage.ddKey) 17 | 18 | if(localStorage.ddKey){ 19 | axios.defaults.headers.common['x-key'] = localStorage.ddKey; 20 | } 21 | 22 | p = axios(url, opt) 23 | p.then(resp => { 24 | // console.log(resp) 25 | if (debug) { 26 | console.log(`resp.data from ${url}`, opt.data); 27 | console.log(`%c${url} result`, 'color:green', resp.data) 28 | } 29 | if (showStr) { 30 | console.log(JSON.stringify(resp)); 31 | } 32 | if (resp.headers.refresh_token) { 33 | window.localStorage.token = resp.headers.refresh_token; 34 | } 35 | 36 | }).catch(err => { 37 | console.error(err) 38 | // window.location.href = "/#/login" 39 | }) 40 | return p.then(res=>res.data) 41 | } 42 | 43 | -------------------------------------------------------------------------------- /src/assets/finishOrder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluto1114/dingding-nodejs-SDK/2426dbeff156a20d0dbb9ea07bda3b278db99687/src/assets/finishOrder.png -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluto1114/dingding-nodejs-SDK/2426dbeff156a20d0dbb9ea07bda3b278db99687/src/assets/logo.png -------------------------------------------------------------------------------- /src/assets/photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluto1114/dingding-nodejs-SDK/2426dbeff156a20d0dbb9ea07bda3b278db99687/src/assets/photo.png -------------------------------------------------------------------------------- /src/assets/success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluto1114/dingding-nodejs-SDK/2426dbeff156a20d0dbb9ea07bda3b278db99687/src/assets/success.png -------------------------------------------------------------------------------- /src/assets/unfinishOrder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluto1114/dingding-nodejs-SDK/2426dbeff156a20d0dbb9ea07bda3b278db99687/src/assets/unfinishOrder.png -------------------------------------------------------------------------------- /src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 41 | 42 | 43 | 59 | -------------------------------------------------------------------------------- /src/cube-ui.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | // By default we import all the components. 4 | // Only reserve the components on demand and remove the rest. 5 | // Style is always required. 6 | import { 7 | /* eslint-disable no-unused-vars */ 8 | Style, 9 | // basic 10 | Button, 11 | Loading, 12 | Tip, 13 | Toolbar, 14 | TabBar, 15 | TabPanels, 16 | // form 17 | Checkbox, 18 | CheckboxGroup, 19 | Checker, 20 | Radio, 21 | RadioGroup, 22 | Input, 23 | Textarea, 24 | Select, 25 | Switch, 26 | Rate, 27 | Validator, 28 | Upload, 29 | Form, 30 | // popup 31 | Popup, 32 | Toast, 33 | Picker, 34 | CascadePicker, 35 | DatePicker, 36 | TimePicker, 37 | SegmentPicker, 38 | Dialog, 39 | ActionSheet, 40 | Drawer, 41 | ImagePreview, 42 | // scroll 43 | Scroll, 44 | Slide, 45 | IndexList, 46 | Swipe, 47 | Sticky, 48 | ScrollNav, 49 | ScrollNavBar 50 | } from 'cube-ui' 51 | 52 | Vue.use(Button) 53 | Vue.use(Loading) 54 | Vue.use(Tip) 55 | Vue.use(Toolbar) 56 | Vue.use(TabBar) 57 | Vue.use(TabPanels) 58 | Vue.use(Checkbox) 59 | Vue.use(CheckboxGroup) 60 | Vue.use(Checker) 61 | Vue.use(Radio) 62 | Vue.use(RadioGroup) 63 | Vue.use(Input) 64 | Vue.use(Textarea) 65 | Vue.use(Select) 66 | Vue.use(Switch) 67 | Vue.use(Rate) 68 | Vue.use(Validator) 69 | Vue.use(Upload) 70 | Vue.use(Form) 71 | Vue.use(Popup) 72 | Vue.use(Toast) 73 | Vue.use(Picker) 74 | Vue.use(CascadePicker) 75 | Vue.use(DatePicker) 76 | Vue.use(TimePicker) 77 | Vue.use(SegmentPicker) 78 | Vue.use(Dialog) 79 | Vue.use(ActionSheet) 80 | Vue.use(Drawer) 81 | Vue.use(ImagePreview) 82 | Vue.use(Scroll) 83 | Vue.use(Slide) 84 | Vue.use(IndexList) 85 | Vue.use(Swipe) 86 | Vue.use(Sticky) 87 | Vue.use(ScrollNav) 88 | Vue.use(ScrollNavBar) 89 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import './cube-ui' 3 | import App from './App.vue' 4 | import router from './router' 5 | import store from './store' 6 | 7 | Vue.config.productionTip = false 8 | /* eslint-disable */ 9 | let query = parseQueryString(); 10 | if (query.key) { 11 | localStorage.ddKey = query.key 12 | } 13 | new Vue({ 14 | router, 15 | store, 16 | render: h => h(App) 17 | }).$mount('#app'); 18 | 19 | Date.prototype.format = function (fmt) { //author: meizz 20 | var o = { 21 | "M+": this.getMonth() + 1, //月份 22 | "d+": this.getDate(), //日 23 | "h+": this.getHours(), //小时 24 | "m+": this.getMinutes(), //分 25 | "s+": this.getSeconds(), //秒 26 | "q+": Math.floor((this.getMonth() + 3) / 3), //季度 27 | "S": this.getMilliseconds() //毫秒 28 | }; 29 | if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); 30 | for (var k in o) 31 | if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); 32 | return fmt; 33 | }; 34 | -------------------------------------------------------------------------------- /src/router.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import Home from './views/Home.vue' 4 | 5 | Vue.use(Router) 6 | 7 | export default new Router({ 8 | routes: [ 9 | { 10 | path: '/', 11 | name: 'home', 12 | component: Home 13 | }, 14 | { 15 | path: '/about', 16 | name: 'about', 17 | component: () => import('./views/About.vue') 18 | }, 19 | { 20 | path: '/order-add', 21 | name: 'OrderAdd', 22 | component: () => import('./views/OrderAdd.vue') 23 | }, 24 | { 25 | path: '/order-list', 26 | name: 'OrderList', 27 | component: () => import('./views/OrderList.vue') 28 | }, 29 | { 30 | path: '/result', 31 | name: 'Result', 32 | component: () => import('./views/Result.vue') 33 | }, 34 | ] 35 | }) 36 | -------------------------------------------------------------------------------- /src/store.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import { api } from './api' 4 | 5 | const remote = process.env.VUE_APP_REMOTE == '1' 6 | 7 | const HOST = process.env.VUE_APP_IP 8 | 9 | Vue.use(Vuex) 10 | if (!remote) { 11 | localStorage.ddKey = 'pluto1114' 12 | } 13 | export default new Vuex.Store({ 14 | state: { 15 | host: HOST, 16 | remote:remote, 17 | dduser: remote ? null : { userid: 'manager8036', upDepart:319411090, name: '高健', mobile: '18698401720', avatar: 'https://static.dingtalk.com/media/lADPBbCc1a_esH_NAkDNAkA_576_576.jpg', points: '16', leader: true, point:0, god:1, ukey:'nmlt', }, 18 | // dduser: null, 19 | }, 20 | mutations: { 21 | updateDduser(state, payload) { 22 | state.dduser = payload 23 | }, 24 | updateJsconfig(state, payload) { 25 | state.jsconfig = payload 26 | }, 27 | }, 28 | actions: { 29 | /* dingding相关 */ 30 | fetchCorpid(context, payload) { 31 | console.log('corpid', `${HOST}/v1/dd/corpid`) 32 | return api(`${HOST}/v1/dd/corpid`) 33 | }, 34 | fetchUserinfo(context, payload) { 35 | return api(`${HOST}/v1/dd/userinfo?code=${payload.code}`) 36 | }, 37 | fetchJsconfig({ state }, payload) { 38 | return api(`${HOST}/v1/dd/jsconfig`, { params: payload }) 39 | }, 40 | 41 | fetchMyOrderCount(context, payload) { 42 | return api(`${HOST}/v1/order/count`, { params: payload }) 43 | }, 44 | fetchOrderList(context, payload) { 45 | return api(`${HOST}/v1/order/index`, { params: payload }) 46 | }, 47 | saveOrder(context, payload) { 48 | return api(`${HOST}/v1/order/save`, { method:'post', data: payload }) 49 | }, 50 | finishOrder(context, payload) { 51 | return api(`${HOST}/v1/order/finish`, { method:'put', data: payload }) 52 | }, 53 | } 54 | }) 55 | -------------------------------------------------------------------------------- /src/theme.styl: -------------------------------------------------------------------------------- 1 | @require "~cube-ui/src/common/stylus/var/color.styl" 2 | 3 | 4 | // action-sheet 5 | $action-sheet-color := $color-grey 6 | $action-sheet-active-color := $color-orange 7 | $action-sheet-bgc := $color-white 8 | $action-sheet-active-bgc := $color-light-grey-opacity 9 | $action-sheet-title-color := $color-dark-grey 10 | $action-sheet-space-bgc := $color-mask-bg 11 | /// picker style 12 | $action-sheet-picker-cancel-color := $color-light-grey 13 | $action-sheet-picker-cancel-active-color := $color-light-grey-s 14 | 15 | // bubble 16 | 17 | // button 18 | $btn-color := $color-white 19 | $btn-bgc := $color-regular-blue 20 | $btn-bdc := $color-regular-blue 21 | $btn-active-bgc := $color-blue 22 | $btn-active-bdc := $color-blue 23 | $btn-disabled-color := $color-white 24 | $btn-disabled-bgc := $color-light-grey-s 25 | $btn-disabled-bdc := $color-light-grey-s 26 | /// primary 27 | $btn-primary-color := $color-white 28 | $btn-primary-bgc := $color-orange 29 | $btn-primary-bdc := $color-orange 30 | $btn-primary-active-bgc := $color-dark-orange 31 | $btn-primary-active-bdc := $color-dark-orange 32 | /// light 33 | $btn-light-color := $color-grey 34 | $btn-light-bgc := $color-light-grey-sss 35 | $btn-light-bdc := $color-light-grey-sss 36 | $btn-light-active-bgc := $color-active-grey 37 | $btn-light-active-bdc := $color-active-grey 38 | /// outline 39 | $btn-outline-color := $color-grey 40 | $btn-outline-bgc := transparent 41 | $btn-outline-bdc := $color-grey 42 | $btn-outline-active-bgc := $color-grey-opacity 43 | $btn-outline-active-bdc := $color-grey 44 | /// outline-primary 45 | $btn-outline-primary-color := $color-orange 46 | $btn-outline-primary-bgc := transparent 47 | $btn-outline-primary-bdc := $color-orange 48 | $btn-outline-primary-active-bgc := $color-orange-opacity 49 | $btn-outline-primary-active-bdc := $color-dark-orange 50 | 51 | // toolbar 52 | $toolbar-bgc := $color-light-grey-sss 53 | $toolbar-active-bgc := $color-active-grey 54 | 55 | // checkbox 56 | $checkbox-color := $color-grey 57 | $checkbox-icon-color := $color-light-grey-s 58 | /// checked 59 | $checkbox-checked-icon-color := $color-orange 60 | $checkbox-checked-icon-bgc := $color-white 61 | /// disabled 62 | $checkbox-disabled-icon-color := $color-light-grey-ss 63 | $checkbox-disabled-icon-bgc := $color-light-grey-ss 64 | // checkbox hollow 65 | $checkbox-hollow-checked-icon-color := $color-orange 66 | $checkbox-hollow-disabled-icon-color := $color-light-grey-ss 67 | // checkbox-group 68 | $checkbox-group-bgc := $color-white 69 | $checkbox-group-horizontal-bdc := $color-light-grey-s 70 | 71 | // radio 72 | $radio-group-bgc := $color-white 73 | $radio-group-horizontal-bdc := $color-light-grey-s 74 | $radio-color := $color-grey 75 | $radio-icon-color := $color-light-grey-s 76 | /// selected 77 | $radio-selected-icon-color := $color-white 78 | $radio-selected-icon-bgc := $color-orange 79 | /// disabled 80 | $radio-disabled-icon-bgc := $color-light-grey-ss 81 | // radio hollow 82 | $radio-hollow-selected-icon-color := $color-orange 83 | $radio-hollow-disabled-icon-color := $color-light-grey-ss 84 | 85 | // dialog 86 | $dialog-color := $color-grey 87 | $dialog-bgc := $color-white 88 | $dialog-icon-color := $color-regular-blue 89 | $dialog-icon-bgc := $color-background 90 | $dialog-title-color := $color-dark-grey 91 | $dialog-close-color := $color-light-grey 92 | $dialog-btn-color := $color-light-grey 93 | $dialog-btn-bgc := $color-white 94 | $dialog-btn-active-bgc := $color-light-grey-opacity 95 | $dialog-btn-highlight-color := $color-orange 96 | $dialog-btn-highlight-active-bgc := $color-light-orange-opacity 97 | $dialog-btn-disabled-color := $color-light-grey 98 | $dialog-btn-disabled-active-bgc := transparent 99 | $dialog-btns-split-color := $color-row-line 100 | 101 | // index-list 102 | $index-list-bgc := $color-white 103 | $index-list-title-color := $color-dark-grey 104 | $index-list-anchor-color := $color-light-grey 105 | $index-list-anchor-bgc := #f7f7f7 106 | $index-list-item-color := $color-dark-grey 107 | $index-list-item-active-bgc := $color-light-grey-opacity 108 | $index-list-nav-color := $color-grey 109 | $index-list-nav-active-color := $color-orange 110 | 111 | // loading 112 | 113 | // picker 114 | $picker-bgc := $color-white 115 | $picker-title-color := $color-dark-grey 116 | $picker-subtitle-color := $color-light-grey 117 | $picker-confirm-btn-color := $color-orange 118 | $picker-confirm-btn-active-color := $color-light-orange 119 | $picker-cancel-btn-color := $color-light-grey 120 | $picker-cancel-btn-active-color := $color-light-grey-s 121 | $picker-item-color := $color-dark-grey 122 | 123 | // popup 124 | $popup-mask-bgc := rgb(37, 38, 45) 125 | $popup-mask-opacity := .4 126 | 127 | //scroll 128 | 129 | // slide 130 | $slide-dot-bgc := $color-light-grey-s 131 | $slide-dot-active-bgc := $color-orange 132 | 133 | // time-picker 134 | 135 | // tip 136 | $tip-color := $color-white 137 | $tip-bgc := $color-dark-grey-opacity 138 | 139 | // toast 140 | $toast-color := $color-light-grey-s 141 | $toast-bgc := rgba(37, 38, 45, 0.9) 142 | 143 | // upload 144 | $upload-btn-color := $color-grey 145 | $upload-btn-bgc := $color-white 146 | $upload-btn-active-bgc := $color-light-grey-opacity 147 | $upload-btn-box-shadow := 0 0 6px 2px $color-grey-opacity 148 | $upload-btn-border-color := #e5e5e5 149 | $upload-file-bgc := $color-white 150 | $upload-file-remove-color := rgba(0, 0, 0, .8) 151 | $upload-file-remove-bgc := $color-white 152 | $upload-file-state-bgc := $color-mask-bg 153 | $upload-file-success-color := $color-orange 154 | $upload-file-error-color := #f43530 155 | $upload-file-status-bgc := $color-white 156 | $upload-file-progress-color := $color-white 157 | 158 | // switch 159 | $switch-on-bgc := $color-orange 160 | $switch-off-bgc := $color-white 161 | $switch-off-border-color := #e4e4e4 162 | 163 | // input 164 | $input-color := $color-grey 165 | $input-bgc := $color-white 166 | $input-border-color := $color-row-line 167 | $input-focus-border-color := $color-orange 168 | $input-placeholder-color := $color-light-grey-s 169 | $input-clear-icon-color := $color-light-grey 170 | 171 | //textarea 172 | $textarea-color := $color-grey 173 | $textarea-bgc := $color-white 174 | $textarea-border-color := $color-row-line 175 | $textarea-focus-border-color := $color-orange 176 | $textarea-outline-color := $color-orange 177 | $textarea-placeholder-color := $color-light-grey-s 178 | $textarea-indicator-color := $color-light-grey-s 179 | 180 | // validator 181 | $validator-msg-def-color := #e64340 182 | 183 | // select 184 | $select-color := $color-grey 185 | $select-bgc := $color-white 186 | $select-disabled-color := #b8b8b8 187 | $select-disabled-bgc := $color-light-grey-opacity 188 | $select-border-color := $color-light-grey-s 189 | $select-border-active-color := $color-orange 190 | $select-icon-color := $color-light-grey 191 | $select-placeholder-color := $color-light-grey-s 192 | 193 | // swipe 194 | $swipe-btn-color := $color-white 195 | 196 | // form 197 | $form-color := $color-grey 198 | $form-bgc := $color-white 199 | $form-invalid-color := #e64340 200 | $form-group-legend-color := $color-light-grey 201 | $form-group-legend-bgc := $color-background 202 | $form-label-required-color := #e64340 203 | 204 | // drawer 205 | $drawer-color := $color-dark-grey 206 | $drawer-title-bdc := $color-light-grey-ss 207 | $drawer-title-bgc := $color-white 208 | $drawer-panel-bgc := $color-white 209 | $drawer-item-active-bgc := $color-light-grey-opacity 210 | 211 | // scroll-nav 212 | $scroll-nav-bgc := $color-white 213 | $scroll-nav-color := $color-grey 214 | $scroll-nav-active-color := $color-orange 215 | 216 | // image-preview 217 | $image-preview-counter-color := $color-white 218 | 219 | // tab-bar & tab-panel 220 | $tab-color := $color-grey 221 | $tab-active-color := $color-dark-orange 222 | $tab-slider-bgc := $color-dark-orange 223 | -------------------------------------------------------------------------------- /src/views/About.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/views/Empty.vue: -------------------------------------------------------------------------------- 1 | 3 | 6 | 24 | -------------------------------------------------------------------------------- /src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 69 | 121 | 171 | -------------------------------------------------------------------------------- /src/views/OrderAdd.vue: -------------------------------------------------------------------------------- 1 | 16 | 33 | 76 | -------------------------------------------------------------------------------- /src/views/OrderList.vue: -------------------------------------------------------------------------------- 1 | 13 | 28 | 63 | -------------------------------------------------------------------------------- /src/views/Result.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 24 | -------------------------------------------------------------------------------- /static/dingding-sdk.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat MySQL Data Transfer 3 | 4 | Source Server : mytencent 5 | Source Server Version : 50726 6 | Source Host : 94.191.121.109:3306 7 | Source Database : dingding-sdk 8 | 9 | Target Server Type : MYSQL 10 | Target Server Version : 50726 11 | File Encoding : 65001 12 | 13 | Date: 2019-10-06 15:19:34 14 | */ 15 | 16 | SET FOREIGN_KEY_CHECKS=0; 17 | 18 | -- ---------------------------- 19 | -- Table structure for dd_config 20 | -- ---------------------------- 21 | DROP TABLE IF EXISTS `dd_config`; 22 | CREATE TABLE `dd_config` ( 23 | `id` int(11) NOT NULL AUTO_INCREMENT, 24 | `ukey` varchar(64) NOT NULL, 25 | `uname` varchar(128) DEFAULT NULL, 26 | `sname` varchar(64) DEFAULT NULL, 27 | `corpid` varchar(128) NOT NULL, 28 | `corpsecret` varchar(128) DEFAULT NULL, 29 | `appkey` varchar(128) DEFAULT NULL, 30 | `appsecret` varchar(128) DEFAULT NULL, 31 | `agentid` varchar(128) DEFAULT NULL, 32 | `chatid` varchar(128) DEFAULT NULL, 33 | `access_token` varchar(128) DEFAULT NULL, 34 | `token_begin_time` timestamp NULL DEFAULT NULL, 35 | `ticket` varchar(128) DEFAULT NULL, 36 | `ticket_begin_time` timestamp NULL DEFAULT NULL, 37 | `url` varchar(256) DEFAULT NULL, 38 | `process_code` varchar(64) DEFAULT NULL, 39 | PRIMARY KEY (`ukey`), 40 | KEY `id` (`id`) 41 | ) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8mb4; 42 | 43 | -- ---------------------------- 44 | -- Records of dd_config 45 | -- ---------------------------- 46 | INSERT INTO `dd_config` VALUES ('2', 'pluto1114', '功夫熊猫', '熊猫', 'ding275ce32e2776968e35c2f4657eb6378f', null, 'ding5xtlfq9fetzeu9lh', 'UxFQjUYies19AdPd7zAkf7Y2ApXre1JryYVOVhM8A8vrCW8QH4KCToVmLinmpgiG', '273096225', 'chat9c5f8af5a1ad3768a648a0a0d3c96dea', '3440a736fff837a3a3e06a74b6caf237', '2019-10-06 14:07:56', 'LyoXbMWD9VGNikFRHmOxP0WUuCz7JjoXrGP3VIdbm1K9B2M4oGUc55qYgkVYFW73R3lITksAcdHCz9skJnpG2t', '2019-10-01 09:05:38', 'http://94.191.121.109/dingding-sdk', 'PROC-8143FE43-735A-400A-8B75-1B64C137F1FB'); 47 | 48 | -- ---------------------------- 49 | -- Table structure for t_order 50 | -- ---------------------------- 51 | DROP TABLE IF EXISTS `t_order`; 52 | CREATE TABLE `t_order` ( 53 | `orderId` bigint(20) NOT NULL AUTO_INCREMENT, 54 | `orderName` varchar(255) DEFAULT NULL, 55 | `userid` varchar(64) DEFAULT NULL, 56 | `totalPrice` decimal(10,2) DEFAULT NULL, 57 | `orderStatus` varchar(64) DEFAULT NULL, 58 | `processInstanceId` varchar(64) DEFAULT NULL, 59 | `createtime` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, 60 | PRIMARY KEY (`orderId`) 61 | ) ENGINE=InnoDB AUTO_INCREMENT=1570343722608 DEFAULT CHARSET=utf8mb4; 62 | 63 | -- ---------------------------- 64 | -- Records of t_order 65 | -- ---------------------------- 66 | INSERT INTO `t_order` VALUES ('1570341114736', 'test2', 'manager8036', '666.00', 'orderFinish', '76bf06c0-6fd4-4bfa-921b-4be5917422c9', '2019-10-06 14:29:51'); 67 | INSERT INTO `t_order` VALUES ('1570342076477', 'kk', 'manager8036', '456.00', 'orderFinish', '1a7cb361-5e96-4dd9-b09d-7ea0af70d9c6', '2019-10-06 14:29:48'); 68 | INSERT INTO `t_order` VALUES ('1570342365605', 'gg', 'manager8036', '899.00', 'orderFinish', '772d6a44-cc30-4286-ab7d-08b33f74d4b6', '2019-10-06 14:15:26'); 69 | INSERT INTO `t_order` VALUES ('1570343722607', '音乐', 'manager8036', '487.00', 'orderFinish', 'c6ce5bcf-51d9-4ad8-9ff4-d13634194c9b', '2019-10-06 14:35:54'); 70 | 71 | -- ---------------------------- 72 | -- Table structure for t_user 73 | -- ---------------------------- 74 | DROP TABLE IF EXISTS `t_user`; 75 | CREATE TABLE `t_user` ( 76 | `id` int(11) NOT NULL AUTO_INCREMENT, 77 | `userid` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL, 78 | `name` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL, 79 | `department` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL, 80 | `departmentName` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, 81 | `mobile` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL, 82 | `email` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL, 83 | `avatar` varchar(256) COLLATE utf8mb4_unicode_ci DEFAULT NULL, 84 | `openid` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL, 85 | `unionid` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL, 86 | `createtime` datetime NOT NULL, 87 | `accesstime` datetime DEFAULT NULL, 88 | `hot` int(11) DEFAULT '0', 89 | `upDepart` bigint(20) DEFAULT NULL, 90 | `ukey` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL, 91 | `point` int(11) DEFAULT '0', 92 | `god` tinyint(1) NOT NULL DEFAULT '0', 93 | `role` varchar(16) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'P', 94 | PRIMARY KEY (`userid`), 95 | UNIQUE KEY `id` (`id`) USING BTREE 96 | ) ENGINE=InnoDB AUTO_INCREMENT=2325 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; 97 | 98 | -- ---------------------------- 99 | -- Records of t_user 100 | -- ---------------------------- 101 | INSERT INTO `t_user` VALUES ('2324', 'manager8036', '高健', '1', null, '18698401720', '', 'https://static-legacy.dingtalk.com/media/lADPDgQ9q-ph7vDNAoDNAeA_480_640.jpg', '2dNE0hnueBGiSc4pIzii1HSgiEiE', null, '2019-10-06 12:51:51', '2019-10-06 14:35:35', '13', null, 'pluto1114', '0', '1', 'P'); 102 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | publicPath: process.env.NODE_ENV === 'production' 3 | ? '/dingding-sdk' 4 | : '/', 5 | productionSourceMap: false, 6 | css: { 7 | loaderOptions: { 8 | stylus: { 9 | 'resolve url': true, 10 | 'import': [ 11 | './src/theme' 12 | ] 13 | } 14 | } 15 | }, 16 | pluginOptions: { 17 | 'cube-ui': { 18 | postCompile: true, 19 | theme: true 20 | } 21 | } 22 | } 23 | --------------------------------------------------------------------------------