├── .gitignore ├── images └── 1.jpeg ├── README.md ├── package.json ├── utils ├── qmsg.js ├── wxpusher.js └── xyb.js ├── .github └── workflows │ └── main.yml ├── config.js ├── LICENSE └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | ._* 3 | -------------------------------------------------------------------------------- /images/1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CncCbz/xybSign/HEAD/images/1.jpeg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | `本代码仅供参考和学习,请勿用于任何商业用途,所造成的一切法律后果自负,与本代码无关!` 2 | 3 | [异地打卡](https://xyb.1zpass.cloud/) ✅ 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "xyb", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "webpack" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "axios": "^1.4.0", 14 | "blueimp-md5": "^2.19.0", 15 | "form-data": "^4.0.0" 16 | }, 17 | "devDependencies": { 18 | "webpack": "^5.88.1", 19 | "webpack-cli": "^5.1.4" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /utils/qmsg.js: -------------------------------------------------------------------------------- 1 | const axios = require("axios"); 2 | // const { config } = require("../config.js"); 3 | 4 | const sendMsg = async (msg, config) => { 5 | let data = { msg }; 6 | if (config.qmsgTo) { 7 | data.qq = config.qmsgTo; 8 | } 9 | axios 10 | .post("https://qmsg.zendee.cn/send/" + config.qmsgKey, data, { 11 | headers: { 12 | "Content-Type": "application/x-www-form-urlencoded", 13 | }, 14 | }) 15 | .then((res) => { 16 | console.log("qmsg消息发送成功"); 17 | }) 18 | .catch((err) => { 19 | // console.log(err); 20 | console.log("qmsg消息发送失败"); 21 | }); 22 | }; 23 | 24 | module.exports = { sendMsg }; 25 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: 签到 # yml文件名 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | # https://crontab.guru/ 7 | # UTC 时间,中国时区应减 8 8 | # ┌────────── minute (0 - 59) 9 | # │ ┌──────── hour (0 - 23) 10 | # │ │ ┌────── day of the month (1 - 31) 11 | # │ │ │ ┌──── month (1 - 12 or JAN-DEC) 12 | # │ │ │ │ ┌── day of the week (0 - 6 or SUN-SAT) 13 | # │ │ │ │ │ 14 | - cron: '0 1 * * *' 15 | 16 | jobs: 17 | run-check-in: # 任务名 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Checkout repository 21 | uses: actions/checkout@v3 22 | 23 | - uses: actions/setup-node@v3 24 | with: 25 | node-version: '20.x' 26 | 27 | - name: 安装依赖 28 | run: | 29 | npm install 30 | 31 | - name: 运行签到 32 | run: | 33 | node ./index.js '${{ secrets.XYB }}' 34 | -------------------------------------------------------------------------------- /utils/wxpusher.js: -------------------------------------------------------------------------------- 1 | const axios = require("axios"); 2 | 3 | const sendWxMsg = (msg, config) => { 4 | const getAllUsers = (page = 1, allUsers = []) => { 5 | // 获取当前页的用户数据 6 | axios.get("https://wxpusher.zjiecode.com/api/fun/wxuser/v2", { 7 | params: { 8 | appToken: config.wxPusherAppToken, 9 | page, 10 | pageSize: 100, // 默认每页最多获取100条用户数据 11 | } 12 | }) 13 | .then((userListResponse) => { 14 | if (!userListResponse.data.success) { 15 | console.error('获取用户数据失败:', userListResponse.data.msg); 16 | return; 17 | } 18 | 19 | // 提取当前页用户的uid并添加到allUsers 20 | const users = userListResponse.data.data.records; 21 | allUsers = allUsers.concat(users.map(user => user.uid)); 22 | 23 | // 判断是否还有更多页面 24 | const total = userListResponse.data.data.total; 25 | const pageSize = userListResponse.data.data.pageSize; // 从响应中提取 pageSize 26 | if (allUsers.length < total) { 27 | // 如果没有获取完所有用户,继续请求下一页 28 | getAllUsers(page + 1, allUsers); 29 | } else { 30 | // 获取到所有用户后,发送消息 31 | sendMessageToUsers(allUsers, msg, config); 32 | } 33 | }) 34 | .catch((_error) => { 35 | console.error('获取用户数据失败'); 36 | }); 37 | }; 38 | 39 | const sendMessageToUsers = (userUids, msg, config) => { 40 | if (userUids.length === 0) { 41 | console.info('没有用户需要发送消息'); 42 | return; 43 | } 44 | 45 | // 构建消息内容 46 | const payload = { 47 | content: msg, 48 | summary: "校友邦每日签到", 49 | contentType: 1, // 1 代表纯文本, 2 代表 HTML, 3 代表 Markdown 50 | appToken: config.wxPusherAppToken, 51 | uids: userUids, // 将提取到的所有用户的uid加入 52 | }; 53 | 54 | // 发送消息 55 | axios.post("https://wxpusher.zjiecode.com/api/send/message", payload, { 56 | headers: { 57 | "Content-Type": "application/json" 58 | } 59 | }) 60 | .then((response) => { 61 | // console.debug(response.data); 62 | console.info('WxPusher 消息发送成功'); 63 | }) 64 | .catch((_error) => { 65 | console.error('WxPusher 消息发送失败'); 66 | }); 67 | }; 68 | 69 | // 开始获取用户列表 70 | getAllUsers(); 71 | }; 72 | 73 | module.exports = { sendWxMsg }; 74 | 75 | -------------------------------------------------------------------------------- /utils/xyb.js: -------------------------------------------------------------------------------- 1 | const md5 = require("blueimp-md5"); 2 | const Q = new RegExp( 3 | "[`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?]" 4 | ), 5 | W = (e) => { 6 | let t = [ 7 | "`", 8 | "~", 9 | "!", 10 | "@", 11 | "#", 12 | "$", 13 | "%", 14 | "^", 15 | "&", 16 | "*", 17 | "(", 18 | ")", 19 | "+", 20 | "=", 21 | "|", 22 | "{", 23 | "}", 24 | "'", 25 | ":", 26 | ";", 27 | "'", 28 | ",", 29 | "[", 30 | "]", 31 | ".", 32 | "<", 33 | ">", 34 | "/", 35 | "?", 36 | "~", 37 | "!", 38 | "@", 39 | "#", 40 | "¥", 41 | "%", 42 | "…", 43 | "…", 44 | "&", 45 | "*", 46 | "(", 47 | ")", 48 | "—", 49 | "—", 50 | "+", 51 | "|", 52 | "{", 53 | "}", 54 | "【", 55 | "】", 56 | "‘", 57 | ";", 58 | ":", 59 | "”", 60 | "“", 61 | "’", 62 | "。", 63 | ",", 64 | "、", 65 | "?", 66 | '"', 67 | ], 68 | n = [ 69 | "content", 70 | "deviceName", 71 | "keyWord", 72 | "blogBody", 73 | "blogTitle", 74 | "getType", 75 | "responsibilities", 76 | "street", 77 | "text", 78 | "reason", 79 | "searchvalue", 80 | "key", 81 | "answers", 82 | "leaveReason", 83 | "personRemark", 84 | "selfAppraisal", 85 | "imgUrl", 86 | "wxname", 87 | "deviceId", 88 | "avatarTempPath", 89 | "file", 90 | "file", 91 | "model", 92 | "brand", 93 | "system", 94 | "deviceId", 95 | "platform", 96 | "code", 97 | "openId", 98 | "unionid", 99 | "clockDeviceToken", 100 | "clockDevice", 101 | ]; 102 | for (var a in e) { 103 | //!(过滤的字段 || 特殊字符)不添加到字符串中 104 | let o = e[a] + ""; 105 | o && 106 | o.split("").some((e, o) => { 107 | if (t.indexOf(e) > -1) return -1 == n.indexOf(a) && n.push(a), !0; 108 | }); 109 | } 110 | return n; 111 | }, 112 | V = () => { 113 | let e = [ 114 | "front/enterprise/loadEnterprise.action", 115 | "front/post/EnterprisePostLoad.action", 116 | "helpcenter/video/VideoPlayAuth.action", 117 | "login/teacher/sendMobileOrEmailCode.action", 118 | "login/student/sendMobileCode.action", 119 | ]; 120 | return e; 121 | }, 122 | z = (e) => { 123 | //分割字符串 124 | if (void 0 == e) return {}; 125 | for (var t = Object.keys(e).sort(), n = {}, a = 0; a < t.length; a++) 126 | n[t[a]] = e[t[a]]; 127 | return n; 128 | }, 129 | F = (e, t) => { 130 | //生成(e.length - t)个随机排序的数字 131 | var n, 132 | a, 133 | o = e.slice(0), 134 | i = e.length, 135 | r = i - t; 136 | while (i-- > r) 137 | (a = Math.floor((i + 1) * Math.random())), 138 | (n = o[a]), 139 | (o[a] = o[i]), 140 | (o[i] = n); 141 | return o.slice(r); 142 | }, 143 | H = (e, t) => { 144 | let n = [ 145 | "5", 146 | "b", 147 | "f", 148 | "A", 149 | "J", 150 | "Q", 151 | "g", 152 | "a", 153 | "l", 154 | "p", 155 | "s", 156 | "q", 157 | "H", 158 | "4", 159 | "L", 160 | "Q", 161 | "g", 162 | "1", 163 | "6", 164 | "Q", 165 | "Z", 166 | "v", 167 | "w", 168 | "b", 169 | "c", 170 | "e", 171 | "2", 172 | "2", 173 | "m", 174 | "l", 175 | "E", 176 | "g", 177 | "G", 178 | "H", 179 | "I", 180 | "r", 181 | "o", 182 | "s", 183 | "d", 184 | "5", 185 | "7", 186 | "x", 187 | "t", 188 | "J", 189 | "S", 190 | "T", 191 | "F", 192 | "v", 193 | "w", 194 | "4", 195 | "8", 196 | "9", 197 | "0", 198 | "K", 199 | "E", 200 | "3", 201 | "4", 202 | "0", 203 | "m", 204 | "r", 205 | "i", 206 | "n", 207 | ], 208 | a = []; 209 | for (let u = 0; u < 62; u++) a.push(u + ""); 210 | let o = Math.round(new Date().getTime() / 1e3), 211 | i = F(a, 20), 212 | r = ""; 213 | i.forEach((e, t) => { 214 | r += n[e]; 215 | }); 216 | let s = z(e); 217 | var c = ""; 218 | //!(过滤的字段 || 特殊字符)不添加到字符串中 过滤   219 | // 过滤出参与加密的字段 220 | for (var l in s) { 221 | -1 != W(e).indexOf(l) || 222 | Q.test(s[l]) || 223 | (null != s[l] && "" !== s[l] && '""' !== s[l] && (c += s[l])); 224 | } 225 | return ( 226 | (c += o), 227 | (c += r), 228 | (c = c.replace(/\s+/g, "")), 229 | (c = c.replace(/\n+/g, "")), 230 | (c = c.replace(/\r+/g, "")), 231 | (c = c.replace(//g, "")), 233 | (c = c.replace(/&/g, "")), 234 | (c = c.replace(/-/g, "")), 235 | (c = c.replace(/\uD83C[\uDF00-\uDFFF]|\uD83D[\uDC00-\uDE4F]/g, "")), 236 | (c = encodeURIComponent(c)), 237 | (c = md5(c)), 238 | { 239 | md5: c, 240 | tstr: o, 241 | iArrStr: i && i.length > 0 ? i.join("_") : "", 242 | } 243 | ); 244 | }, 245 | Y = (e, t) => { 246 | if (!e) return; 247 | let n = [ 248 | "5", 249 | "b", 250 | "f", 251 | "A", 252 | "J", 253 | "Q", 254 | "g", 255 | "a", 256 | "l", 257 | "p", 258 | "s", 259 | "q", 260 | "H", 261 | "4", 262 | "L", 263 | "Q", 264 | "g", 265 | "1", 266 | "6", 267 | "Q", 268 | "Z", 269 | "v", 270 | "w", 271 | "b", 272 | "c", 273 | "e", 274 | "2", 275 | "2", 276 | "m", 277 | "l", 278 | "E", 279 | "g", 280 | "G", 281 | "H", 282 | "I", 283 | "r", 284 | "o", 285 | "s", 286 | "d", 287 | "5", 288 | "7", 289 | "x", 290 | "t", 291 | "J", 292 | "S", 293 | "T", 294 | "F", 295 | "v", 296 | "w", 297 | "4", 298 | "8", 299 | "9", 300 | "0", 301 | "K", 302 | "E", 303 | "3", 304 | "4", 305 | "0", 306 | "m", 307 | "r", 308 | "i", 309 | "n", 310 | ], 311 | a = e.t, 312 | o = e.s.split("_"), 313 | i = ""; 314 | o.forEach((e, t) => { 315 | i += n[e]; 316 | }); 317 | var r = ""; 318 | return ( 319 | (r += a), 320 | (r += i), 321 | (r = r.replace(/\s+/g, "")), 322 | (r = r.replace(/\n+/g, "")), 323 | (r = r.replace(/\r+/g, "")), 324 | (r = r.replace(//g, "")), 326 | (r = r.replace(/&/g, "")), 327 | (r = r.replace(/-/g, "")), 328 | (r = r.replace(/\uD83C[\uDF00-\uDFFF]|\uD83D[\uDC00-\uDE4F]/g, "")), 329 | (r = encodeURIComponent(r)), 330 | (r = md5(r)), 331 | r == e.m 332 | ); 333 | }; 334 | const t = { 335 | Z: { 336 | set(e, t, n) { 337 | const a = new Date(); 338 | a.setDate(a.getDate() + n), 339 | (document.cookie = e + "=" + t + ";expires=" + a); 340 | }, 341 | get(e) { 342 | let t = document.cookie.replace(/\s/g, "").split(";"); 343 | for (let n = 0; n < t.length; n++) { 344 | let a = t[n].split("="); 345 | if (a[0] === e) return decodeURIComponent(a[1]); 346 | } 347 | return ""; 348 | }, 349 | remove(e) { 350 | this.set(e, "1", -1); 351 | }, 352 | getAll() { 353 | let e = document.cookie.split(";"), 354 | t = {}; 355 | for (let n = 0; n < e.length; n++) { 356 | let a = e[n].split(""); 357 | t[a[0]] = unescape(a[1]); 358 | } 359 | return t; 360 | }, 361 | clear() { 362 | let e = document.cookie.match(/[^ =;]+(?=\=)/g); 363 | if (e) 364 | for (let t = e.length; t--; ) 365 | document.cookie = e[t] + "=0;expires=" + new Date(0).toUTCString(); 366 | }, 367 | }, 368 | }; 369 | const Z = { 370 | getTokenData: H, 371 | checkToken: Y, 372 | nocheckArrs: W, 373 | checkUrl: V, 374 | }; 375 | 376 | const getHeaders = function (url, data) { 377 | let headers = { 378 | Host: "xcx.xybsyw.com", 379 | Connection: "keep-alive", 380 | "User-agent": 381 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36 MicroMessenger/7.0.9.501 NetType/WIFI MiniProgramEnv/Windows WindowsWechat", 382 | // referer: "https://servicewechat.com/wx9f1c2e0bbc10673c/317/page-frame.html", 383 | "Accept-Encoding": "gzip, deflate, br", 384 | "Accept-Language": "zh-cn", 385 | "content-type": "application/x-www-form-urlencoded", 386 | v: "1.6.36", 387 | // xweb_xhr: 1, 388 | }; 389 | let n = Z.nocheckArrs(data).join(","), 390 | a = Z.getTokenData(data, url); 391 | Z.checkUrl(); 392 | (headers.n = n), 393 | (headers.m = a.md5), 394 | (headers.t = a.tstr), 395 | (headers.s = a.iArrStr); 396 | return headers; 397 | }; 398 | 399 | module.exports = { getHeaders }; 400 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | mode: "in", // 签到:in,签退:out 3 | accounts: [ 4 | { 5 | username: "", //用户名 6 | password: "", //密码 7 | openId: "", //微信小程序抓包openid(可选) 8 | unionId: "", //微信小程序抓包unionId(可选) 9 | sign: true, //是否自动签到 10 | reSign: false, //是否重新签到 11 | location: "", //经纬度 (可选),例如 "120.210792,30.246026"、"经度,纬度",不填写则自动获取(推荐) 12 | // signImagePath: "./images/1.jpeg", //签到图片 13 | // needReport: false, //是否自动填写周报 14 | }, 15 | // 添加多个账户 16 | // { 17 | // username: "", 18 | // password: "", 19 | // openId: "", 20 | // unionId: "", 21 | // sign: true, //是否自动签到 22 | // reSign: true, //是否重新签到 23 | // signImagePath: "./images/1.jpeg", //签到图片 24 | // needReport: false, //是否自动填写周报 25 | // }, 26 | ], 27 | qmsgKey: "", //qmsg酱key 28 | qmsgTo: "", //推送的qq号,用,分隔(可选) 29 | wxPusherAppToken: "", // wxPusher 的 appToken 30 | // TODO: feat: (wxpusher/topic) support wxpusher/topic push 31 | }; 32 | 33 | const modeCN = { 34 | in: "签到", 35 | out: "签退", 36 | }; 37 | config.modeCN = modeCN[config.mode]; 38 | 39 | const apis = { 40 | login: "login/login.action", 41 | accountInfo: "account/LoadAccountInfo.action", 42 | projects: "student/progress/ProjectList.action", 43 | tasks: "student/progress/ProjectProgressInfo.action", 44 | //周报 45 | weekBlogStatus: "student/blog/Plan!getDefault.action", 46 | weekReportsDate: "student/blog/LoadBlogDate!weekYear.action", 47 | weekReports: "student/blog/LoadBlogDate!week.action", 48 | weelBlogSave: "student/blog/Blog!save.action", 49 | weelBlogSubmit: "student/blog/Blog!getSubmitData.action", 50 | //签到 51 | clockDefault: "student/clock/GetPlan!getDefault.action", //planId => traineeId 52 | clockDetail: "student/clock/GetPlan!detail.action", //traineeId => postInfo 53 | clock: "student/clock/Post!autoClock.action", //首次签到 54 | clockNew: "student/clock/PostNew.action", //重新签到或签退 55 | // clockUpdate: "student/clock/PostNew!updateClock.action", //更新最近的签到/签退记录,已有签退记录时无法更新之前的签到记录 56 | clockUpdate: "student/clock/Post!updateClock.action", // reClock 57 | // clockNew: "student/clock/Post!autoClock.action", //临时接口 58 | // clockUpdate: "student/clock/postTemporary!updateClock.action", // reClock 临时接口 59 | //上传 60 | uploadInfo: "uploadfile/commonPostPolicy.action", //oss info 61 | uploadFile: "https://xyb001.oss-cn-hangzhou.aliyuncs.com/", 62 | duration: "behavior/Duration.action", 63 | ip: "behavior/Duration!getIp.action", 64 | // 地图api 65 | map: "https://restapi.amap.com/v3/geocode/regeo", 66 | }; 67 | 68 | const reports = [ 69 | [ 70 | `本周,是我实习的第一周。刚进入公司的时候,很茫然,不知道要做些什么,对自己的岗位充满期待,对公司充满好奇。领导叫做什么,我们就做什么,最开始的时候是培训。也怕自己没有能够做好相关的工作,带来不好的影响以及麻烦。好在公司给我安排了一位和我年纪相仿的小姐姐带我熟悉工作环境,工作内容。由于我初来乍到,对这个岗位的工作流程还不太熟悉,幸好我的实习负责人耐心的给我讲解了一些(什么工作)需要注意的地方,然后慢慢让我尝试自己做一下,自己去理解,我自己做的过程中,产生了很多疑问,我经常带着我不懂的问题去问负责人,负责人都耐心的教我。这一周的学习内容虽然不是很多,但是最主要的还是尽快适应工作的节奏,以及熟悉工作,我也对我的工作环境以及工作内容有了初步的了解。经过这一周的相处,公司的人也都很好,很好相处,在接下来的时间里,我会更加努力认真的学习,多问多听多学多看,努力的工作。`, 71 | "本周充满了新奇和挑战。在这一周中,我学到了许多新知识和技能,也体验了职场的工作氛围。首先,我参与了团队的日常工作,包括与同事合作完成项目、参加会议并记录会议纪要等。通过与团队成员的互动,我深刻体会到了团队协作的重要性。大家相互合作,共同解决问题,以达到项目的目标。我学会了如何与他人进行有效的沟通和合作,这对于未来的职业发展将是非常宝贵的。其次,我还接触了一些新的工作工具和流程。在实习的过程中,我学会了如何利用公司提供的软件来进行数据分析和报告的制作。这项技能不仅提高了我的工作效率,还使我更加熟悉了行业内的常用工具和流程。我也深刻认识到,在不断发展的数字化时代,掌握和适应新技术是非常重要的。此外,我还参与了一些培训和学习活动。公司组织了一次关于市场营销策略的讲座,我从中学到了许多关于市场调研和市场推广的知识。这次讲座为我未来的职业发展提供了很大的帮助,并且让我对市场营销这个领域产生了浓厚的兴趣。在这一周中,我还面临了一些挑战。由于我对公司的业务和流程还不够熟悉,有时候需要花费更多的时间来理解和完成工作。但是,我通过请教同事和自己不断的学习,逐渐克服了这些困难,并且在实践中不断提升自己。总的来说,这一周的实习经历让我受益匪浅。我不仅学到了专业知识和技能,还提高了自己的工作能力和团队合作能力。我期待在接下来的实习中,继续学习和成长,为公司做出更大的贡献。", 72 | `临近毕业的最后一年,是我们真正实习生活的开始,是汇报我们这三年来在学校学习成果的开始,是步入社会大展宏图的开始。从学校到社会的大环境的转变,身边接触的人也完全换了角色,老师变成老板,同学变成同事,相处之道完全不同。突然面对这么大的转变,我知道我必须得适应。好在同事们都很乐意帮助我,这也给我了很大的动力去学习每件事情。 73 | 74 | 才来的那天最糗的事情就是去复印一点资料。平时在学校复印东西都是打印店的人复印的,从来没有自己亲手复印过。以为也没什么难的吧,谁知道我弄了半天都没复印出来,想想这么简单的事情又不好意思问同事,可急死我了。好在一个同事姐姐看见了,主动教我怎么用,还跟我说以后再有什么不懂的就问她,不用觉得不好意思。后来我就经常请教同事问题了,不会再觉得有什么好尴尬的了。 75 | 76 | 由于现在还住校,所以我每天7点不到就得起床去挤公交车,就算再寒冷再差的天气,只要不是周末,都得去上班,有时候公司业务繁忙,晚上或周末得加班,那留给个人支配的时间更少。我必须克制自己,不能随心所欲地不想上班就不来,这也锻炼了我的自制能力。 77 | 78 | 常言道:工作一两年胜过十多年的读书。实习时间虽然才几天,但是我从中学到了很多知识,关于做人,做事,做学问。每日重复单调繁琐的工作,时间久了容易厌倦。“在大学里学的不是知识,而是一种叫做自学的能力”。参加工作后才能深刻体会这句话的含义。我发现除了英语和计算机操作外,课本上学的理论知识用到的很少很少。我担任的是文员一职,每天都是整理文档,负责人员考勤,薪资福利,接听电话等工作,虽然工作简单但也不能马虎,一个小小的错误可能会给公司带来巨大的麻烦或损失,还是得认真完成。 79 | 80 | 1个星期的实习时间看似不长,但是因为刚进公司,也许是最艰难的几天,需要适应的东西太多,我想我能够克服的,在克服的同时也尽量把工作做到最好。`, 81 | ], 82 | [ 83 | `不觉中,来这里实习已十来天了,虽然时间已接近两星期,但是很多工作都还不是那么得心应手。不过同事们都很热心,很好相处,我一有什么不懂的都会请教他们,在他们的帮助下我也能够独自完成很多事情啦。虽然在他们的眼里我看起来很小很年轻,都把我当作小妹妹似的,但是我自己却不那么想,我觉得既然在一起工作就要以同样的态度对待每件事,不能因为自己小就把事情推给别人。 84 | 85 | 为了能够真正的学到知识,我很严格的要求自己去做好每一件事情,即使再简单的事情我都会认真考虑几遍,因此,虽然做得不算快,但能够保证让同事们满意。同事通常也不催促,都把任务安排好,然后便交给我自己去处理,同时还不时提供一些帮助。等慢慢熟悉起来,相信做起事情也会越来越顺手的。一方面要发扬自主思考问题的能力,在碰到问题的事情,自觉努力去独立解决,这样对问题便能够有一个更深刻的了解,当解决的时候也会获益良多。另一方面,要发扬团队精神。公司是一个整体,公司产品是团队的结晶,每个人都需要跟其他人更好的沟通和交流,互相帮助,合力完成共同的目标,团结众人的智慧才能够发挥最大的效能。 86 | 87 | 我觉得自己进入工作的状态越来越好了,与同事们也越来越融洽,期待所有的事都越来越好!`, 88 | ], 89 | [ 90 | `本周我在这一周中继续积极地投入工作,提高自己的能力。在本周的实习中,我更加熟悉了公司的业务和流程。我参与了更多的项目,并且在团队中承担了更多的责任。通过这些实践,我逐渐掌握了项目的执行步骤和方法,并学会了如何高效地与团队合作,以确保项目的顺利进行。在与团队成员的合作中,我学到了许多重要的团队协作技巧。我们相互支持,共同解决问题,充分发挥了每个人的优势。我意识到团队的力量是巨大的,只有通过相互合作和协调,我们才能取得更好的成果。此外,在本周的实习中,我还参与了一次专业培训。这次培训涵盖了我们所从事行业的最新发展趋势和技术应用。通过学习和讨论,我对行业的前沿动态有了更深入的了解,并且掌握了一些实用的工具和方法。这对于我的个人成长和职业发展非常有益。在实习的过程中,我也遇到了一些挑战。有时候,工作任务的紧迫性和复杂性让我感到压力很大。但是,我学会了调整心态,分解任务,合理安排时间,并与同事进行密切合作,最终顺利完成了任务。这些经历让我更加坚定了自己的意志和决心,无论面对什么样的困难,我都能够勇往直前。总的来说,这一周的实习经历让我不断成长。我通过实践锻炼了自己的专业能力和团队合作能力,也学到了许多宝贵的经验。我期待在接下来的实习中,继续挑战自己,不断提升自己的能力。`, 91 | ], 92 | [ 93 | `经过一周的实习,对公司的运作流程也有了一些了解,虽然还没有具体的操作过,但是在接触到新的事务不再不知所措,学会了如何去处理一些突发事件。懂得从中学到一定的处理事情的发那个发,而且从工作地过程中明白了主动出击的重要性,在你可以选择的时候,就要把主动权握在自己手中。相信大家刚开始实习的时候,都做过类似复印打字、整理文档等的“杂活”,因为刚开始对于公司的工作内容、流程还不了解,所以做“杂活”成了实习工作必做的工作。虽然工作比较繁杂但是从中也学到不少的东西。所以说事情是不分大小,只要积极学习积极办事,做好份内事,勤学、勤问、勤做,就会有意想不到的收获。`, 94 | ], 95 | [ 96 | `在经历了一周的打杂工作,让我对公司的运作流程以及业务有了一个整体的了解,因此这一周我们的工作内容也有了一个小变化,除了进行简单的技术资料整理, 还有就是如何去做好这个产品方面的设计,我本来以为就要将具体的尺寸用工具测量出来,然后通过autocad画出来就可以了,但是结果并不是想象中那么简单。老板总是叫我一遍又一遍的检查画的图是否还有其他的错误,经过几天的检查,我开始感觉到一整天坐在电脑面前开始有些疲倦,整天面对着电脑,看着那枯燥无谓的图形,我有点开始厌倦了,但是我还是坚持着做着,细心的检查着。就这样我熬过了枯燥的一个星期。`, 97 | ], 98 | [ 99 | `俗话说的好一年之季在于春,一天之季在于晨,又是一个星期的开始,早上起来呼吸着窗外的新鲜空气,来到厂里开始新的工作,将上个星期的零件图把他装 100 | 101 | 配起来,我以为本来是很简单的事,不过事实并不是想象中的那样的简单,在装配过程中出现了许多问题,这下可把我个弄荤了,都不知道该从何下手,比如说在装配的过程中出现尺寸的不一样,出现很大的间隙等等其他的许多问题。一时间看出许多的毛病和错误,只好在次慢慢的修改,寻找还有没有其他的错误。经过几天的奋斗,修改和检查这个工作快临近尾声了,我总是在希望我的图不要在出现其他的错误。这个星期虽然结束了,但是我还是有地方值得我去学习的,真的是不易乐呼。`, 102 | ], 103 | [ 104 | "图是弄好了,接下来是开始进行生产,调试。真是毛病重重,错误多多啊!产品刚出来进行调试微出现这样那样的毛病。后来才清楚知道是怎么一回事。不过通过这件事可以学到不少在学校所学不到的知识与经验,原来在设计绘图,这个零件是考虑的并不单单是把图绘出来,还要了解一些关于市场方面的信息,比如说价格,一些常用的毛坯,怎么做起来才方便简洁,如何把他设计成又好又方便的产品。还要考虑在加工过程中出现的误差,还有一些热处理方面的知识等等。如果不想到这些结果会是难以想象的,浪费时间上其次的,最重要的是公司经济的损失。", 105 | ], 106 | [ 107 | `经过一个多月的实习,虽然对公司不是那么的太了解,但是多少不等也有所了解。天天做着一样的事,感觉得无比的枯燥只有自己一个人坐在电脑面前一整天,只有电脑从早到晚的陪者我,觉得好孤独,没有了以前在学校的那种欢声笑语,没有在学校的那种轻松悠闲自在了,有的只是空虚和寂寞。有些时候闲下来就坐在电脑面前发呆,不知道做什么。 就这样一天一天的耗着,感觉除了工作以外,自己的生活中就没有其他的新鲜的事情,或者是值得人去回忆,留念的了,没有了色彩斑斓的生活,有的只是枯燥的工作有些时候都有点冲动想不干了,去换换别的工作,想给累积更多的社会知识和经验,但是想了想还没有那么的冲动,还是在原来的地方老实的呆着。`, 108 | ], 109 | [ 110 | `虽然时间是过的那么的艰苦,但是还是有快乐的时光的,那天我和师傅出去吃饭了,在饭桌上,师傅没有以前那一脸的严肃,让我感觉到自己和他们就象兄弟一样,并没有那么的陌生。在吃饭的时候叫我注意一些细节方面,并不象在学校大家在一起吃饭那么的随便,要有一定的规矩和礼数。叫我如何去喝酒,虽然我不会喝,他们就让我少喝点,意思一下,叫怎么在这里结交新朋友,也好为自己以后在社会混多一条路,多见见世面。那天我们吃的很高兴,也很开心,我第一次感觉这样无拘无束。回到厂里的宿舍,呼吸着外面的空气,感觉到无比的舒畅,来到厂里终于有了一次真正的放松,心理觉得乐滋滋的。`, 111 | ], 112 | [ 113 | `经过了一段时间的工作,又开始踏上了新的征程,进行新的锻炼。经过一段时间的匆匆忙碌后,终于有了可以闲下来的一点时间。可以稍微的偷懒一下,好好的享受一下工作之余的快乐。在这以后才上体验生活那种家庭生活的开始,开始我的新的工作:学习怎么做好日常生活中的细事,比如说说是挖排水沟,看似一件简单事,但是实际哂纳感做起来就显得的非常的棘手,对于我们刚步入社会的新大学生来说无疑是一个重大的考验,虽然我并不知道怎么去弄,更不知道如何弄好,但是我还是在其中努力的学习,领悟其中的心得。这些活原来在家里并要自己去做,但我在这里能够亲身的体验到家人的辛苦与劳累。只有自己亲身经历,才能深刻体会。`, 114 | ], 115 | [ 116 | `上一周的劳累与辛苦使我牢记心理,不过这一周又学到新的东西,虽然简单但是也很容易出错,我和我一个师傅去浇水泥板,在浇焊一块铁架子,放在里面来增加的它的强度,以防被什么大型__从上面走的时候压坏了,我看着师傅做,便好奇的问你为什么不做成和扳子一样大的架子呢?师傅起初并没有告诉我为什么这样做,我一直带着这样的疑问。后来和他一起浇的时候才发现,如果和它弄成一样大的话结果就放不进去,或者说以后弄出来,边上就会不平齐,不仅外观上面不怎么好看,而且有些时候不注意的话,他人从它旁边经过的会弄伤其他人。这个虽然简单,也许在书上的时候大家都会说,但你一旦在真正实践的时候就会想不到,只有实践了,才能更深的体会。`, 117 | ], 118 | [ 119 | `本周是我在公司C的第三周实习,我在这一周中积极参与工作,并不断学习和成长。在本周的实习中,我继续参与了公司的日常工作,并且承担了一些更具挑战性的任务。通过这些工作,我进一步提高了自己的专业知识和技能,并学会了更加高效地处理工作。与此同时,我也注意到了团队合作的重要性。在与同事的合作中,我学到了如何更好地沟通和协调,以实现共同的目标。大家相互支持和理解,共同努力,使我们能够充分发挥个人的优势,以最佳的方式完成工作。在这一周的实习中,我还有幸参与了一次行业内的研讨会。在研讨会中,专家们分享了他们的经验和见解,让我对行业的未来发展有了更清晰的认识。我也有机会与其他实习生和专业人士进行交流和讨论,拓宽了我的视野。尽管在实习过程中遇到了一些困难和挑战,但我通过积极的态度和不断努力克服了它们。我相信,挑战是成长的机遇,只有在面对困难时,我们才能够发挥出自己的潜力。总的来说,这一周的实习经历让我受益匪浅。我不仅学到了专业知识和技能,还提高了自己的团队合作能力和解决问题的能力。我期待在接下来的实习中,继续努力学习和成长,为公司做出更大的贡献。`, 120 | ], 121 | [ 122 | `不知不自觉中在实习已经两个多月了。很多时候觉得自己没有受到领导重用,所干的只是一些无关重要的杂活,自己的提议或工作不能得到老板的肯定。做不出成绩时,会有来自各方面的压力,老板的眼色同事的嘲讽。而在学校,有同学老师的关心和支持,每日只是上上课,很轻松。常言道:工作一两年胜过十多年的读书。两个月的实习时间虽然不长,但是我从中学到了很多知识,关于做人,做事,做学问。“天下英雄皆我辈,一入江湖立马催。”从学校到社会的大环境的转变,身边接触的人也完全换了角色,老师变成老板,同学变成同事,相处之道完全不同。在这巨大的转变中,我们可能彷徨,迷茫,无法马上适应新的环境。我们也许看不惯企业之间残酷的竞争,无法忍受同事之间漠不关心的眼神和言语。`, 123 | ], 124 | [ 125 | `这周星期一是我实习单位,_周年庆祝活动,同事们就提议说晚上搞个聚会,没有结婚的人都可以参加,结了婚的也可以参加,正式员工可以参加,实习员工也可以参加。虽然我来的时间不长,但是同事们说我必须参加,不许找借口不去。我想这是个很好的机会让我更加了解这些对我这么好,这么照顾我的同事们。我对他们说过,这里的工作氛围让人感觉好轻松,每个人都好亲切。他们告诉我,除了主任是本地人,其他的工作人员都是来自五湖四海,本来就是背井离乡,所以大家在一起就难免变得互相理解,互相帮助,人在外,谁没有个难处呢。是啊,人在外,谁没个难处呢。多么朴实却温暖的一句话。 126 | 127 | 这周即将结束,我发现工作作中遇到问题,我们最好采取请教的态度与口吻与他们说话,虽然他们现在的职位和你同等或者还不如你,但三人行必有我师,或许他们就掌握着很多工作中实用的东西。刚刚参加工作或者新到一个单位,应该如何与周围的同事相处,这对新走上工作岗位的年轻人来说极为重要。学会与人相处,可以让你少走弯路,尽早成功。其实, 128 | 129 | 每一个人要取得成功,仅有很强的工作能力是不够的,你必须两条腿走路,既要努力做好自己分内的工作,又要处理好人际关系。`, 130 | ], 131 | [ 132 | `周一开始我跟其他几位同事去分部工作,所以最近上班的场所一直都是在单位分部,每 133 | 134 | 天早上到总单位之后,就直奔单位分部。在单位分部虽然没有在办公室那么舒适和轻松,但是毕竟现在是有目标要去达成,所以比在前一段时间在办公室时更加的充实,时间也会觉得过得更加快。 135 | 136 | 在这期间,单位分部的工作人员都对我很好。在实际工作中,大学里面最专业的知识还是不够用,很多需要在工作中继续学习,因此我在工作岗位上遇到了一些麻烦。同事们在知道的我的工作任务后,都积极主动的帮助我,告诉我他们总结出来的区别,让我突然觉得每个任务都能轻车熟路,因为他们的帮助,让我完全加快了我的工作进程。想真正地做成一件事情,需要你有锲而不舍的精神。不管我们想在哪个领域做成一件事情,如果你已经认准了目标,那就一定坚持不懈地做下去。罗马不是一天建成的,只要你一天天用心地去做,总有一天,量变会发生质变。 137 | 138 | 这一周,我总结了工作过程中的关于挫折的感悟。在工作过程经过遇到一些挫折。关于挫折,早有职场高手总结出至理名言:“人在职场飘,哪能不挨刀?”这是一种对工作洒脱的态度。对待工作的挫折,就稍微转换一下努力的方向。说不定更好。另外一点也很重要,困境中请你自己鼓励自己,不到万不得已,请不要把自己的底牌亮给别人。要知道,困难时要求得到的帮助,价码总是会更贵一些的。`, 139 | ], 140 | [ 141 | `今天指导师父说十分钟后让我和陪他一起去其他单位参观学习,让我带上笔和笔记本,他还跟我说了一句,“上次的那个任务完成的很漂亮,圆满到达了我的要求,我很满意。”他还表扬我最专业相关基础知识非常扎实,是他见过最专业学生中动手能力比较强的学生。当时我差一点儿兴奋得尖叫出来。几天的努力总算我的努力没有白费,没有什么能比得上得到师父的认可更加让我激动了。 142 | 143 | 通过这段时间的了解,原来师父并不是看上去那样一个不起眼的人,听同事说了很多他厉害的事迹,如果能从他身上学到东西,对我这次实习所得和以后的职业发展之路一定有很大的帮助。在外面的路上,师父说,这几天我的任务就是在上次的基础进行扩展。 144 | 145 | 本周我总结出:在职场上取胜的黄金定律之一便是要有责任心,凡事尽力而为,并且要任劳任怨。在工作上,永远不要试图去敷衍自己的老板。有人曾经访问过许多在事业上功成名就的人,他们一个共同的特点便是,在工作上投入的时间及精力,远远要比工作本身所要求的多。我相信我能做的更好。`, 146 | ], 147 | [ 148 | `这一周,我开始深入学习与自己岗位相关业务知识,得到同事的帮助下,我先从规范下手,就是熟悉下当前最专业行业方面的规范,再就是记各种工作相关的必备知识。经过两天的苦研,我终于能基本看懂结构施工图了。经过前期实习后,我大概了解了整个工作程序。 149 | 150 | 今天我开始正式参与部分核心工作了,师傅给我布置了一个任务。大学里面学习的最专业的知识能真正得到实际应用,我很高兴,这是他对我的一次考验,同时也给了我一次机会。因此,我要尽力做好它。 151 | 152 | 工作过程我得出了一些体会:我工作过程要相信自己,如果做不到这一点,你就无法成为一个好的职员或者好的领导。一个相信自己的人,才会在走路时神采飞扬,让老板看上去你有无穷的精力;一个相信自己的人,才会在待人接物时落落大方,这一切能帮助老板培养对你的信心,必要时才会委你以重任。你怎么对待别人,别人就会怎么对待你。在工作中,要待人如待己。在你困难的时候,你的善行会衍生出另一个善行。在别人遇到困境时,热情地伸出援手。在职场上,尽可能地做一个与人为善的好人,这样,当你在工作上不小心出现纰漏,或当你面临加薪或升职的关键时刻,可尽可能减少别人放冷箭的危险。`, 153 | ], 154 | [ 155 | `渐渐的我也是进入到工作的一个状态上来了,当然这一周的工作任务也是加重了,毕竟之前也是适应了,每天要拨出的数量也是让我从早忙到晚,基本没有什么太多的休息时间,不过在这忙碌之中,我对于话术也是更加的熟练去掌握了,同时我也是通过量的积累,以及上周完成了目标的成就感,这周也是超额的完成,得到了部长的肯定,不过看到我的周排行在同事中的位置,我也是感到有些失落,的确实习的水平和那些优秀同事的业绩水平差距真的巨大啊。 156 | 157 | 不过我也是不气馁,我来到公司都还没有一个月,而且真的工作也才两周的时间,我想再努力努力,肯定可以迎头追上去的。毕竟我的能力我还是相信能做好的。`, 158 | ], 159 | [ 160 | `这周,我感受到自己遇到的客户真的特别的难缠,而且也是目标的增加,让我感觉到了压力,最终这周的业绩目标还是差一些,没有完成,我也是特别的懊恼,周五下班之后,部长也是找我谈话,对于我没有完成业绩,他也是没有说太多,也是鼓励了我,说虽然目标是没完成,但是和之前相比,其实也是一直都在进步的,而且工作之中,怎么可能不会遇到挫折。 161 | 162 | 遇到了,跌倒了,并不可怕,只要站起来,勇敢的前行,下次努力,达成就好了,也是让我觉得部长真的关心我们,照顾我们,虽然目标是差了一些,但是我并没有特别的低落,特别是部长说完之后,我也是想着,下周一定要做好,不能让部长失望,周末的时候,我也是要去多思考这周做的不好的地方是哪些,要去改进。`, 163 | ], 164 | [ 165 | `这一周,我又是重新的出发,重新的达成了目标,我也是感到特别的高兴,之前在周末的反思还是非常的有用,特别是部长跟我的谈话,也是让我意识到,一时的挫折并没有什么,再接再厉就是了,特别是我也是感受到自己的进步很大,和优秀的同事差距也是越拉越近了,虽然还没有超过他们,但是也不算差了。 166 | 167 | 况且我还是个实习的,我想等我经历得更多,对于客户更加的熟悉,有了更多的经验,那么我的业绩也是会名列前茅的,特别是我也是感受到看到我的成绩,其他和我一起来到公司实习的同事,也是更加的努力了,的确别人可以,那么我为什么就不行,其实也是努力,去执行,去多反思把方法用对,业绩的目标是完全可以达成的。`, 168 | ], 169 | ]; 170 | 171 | module.exports = { config, apis, reports }; 172 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const { getHeaders } = require("./utils/xyb.js"); 2 | let { config, apis, reports } = require("./config.js"); 3 | const { sendMsg } = require("./utils/qmsg.js"); 4 | const { sendWxMsg } = require("./utils/wxpusher.js") 5 | const axios = require("axios"); 6 | const fs = require("fs"); 7 | const FormData = require("form-data"); 8 | const md5 = require("blueimp-md5"); 9 | 10 | async function xybSign(config) { 11 | let results = ""; 12 | const baseUrl = "https://xcx.xybsyw.com/"; 13 | // const baseUrl2 = "https://app.xybsyw.com/"; 14 | const $http = { 15 | get: function(url, data) { 16 | return axios 17 | .get((duration ? baseUrl2 : baseUrl) + url, { 18 | params: data, 19 | headers: { 20 | ...getHeaders(url, data), 21 | cookie, 22 | }, 23 | }) 24 | .then((res) => { 25 | return res.data.data; 26 | }) 27 | .catch((err) => { 28 | throw new Error(err); 29 | }); 30 | }, 31 | post: function(url, data) { 32 | return axios 33 | .post(baseUrl + url, data, { 34 | headers: { 35 | ...getHeaders(url, data), 36 | cookie, 37 | }, 38 | }) 39 | .then((res) => { 40 | if (res.data.code != "200") { 41 | throw new Error(res.data.msg); 42 | } 43 | return res.data.data; 44 | }) 45 | .catch((err) => { 46 | throw new Error(err); 47 | }); 48 | }, 49 | upload: function(url, form) { 50 | return axios 51 | .post(url, form, { 52 | headers: { 53 | ...form.getHeaders(), // 设置适当的请求头 54 | }, 55 | }) 56 | .then((res) => { 57 | return res.data; 58 | }) 59 | .catch((err) => { 60 | throw new Error(err); 61 | }); 62 | }, 63 | location: function(data) { 64 | return axios 65 | .get(apis.map, { 66 | params: data, 67 | headers: { 68 | "user-agent": 69 | "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1", 70 | "Content-Type": "application/json", 71 | }, 72 | }) 73 | .then((res) => { 74 | if (res.data.info != "OK") { 75 | throw new Error(res.data.info); 76 | } 77 | return res.data.regeocode; 78 | }) 79 | .catch((err) => { 80 | throw new Error(err); 81 | }); 82 | }, 83 | }; 84 | let cookie = "JSESSIONID=6C7149CD82913F66EA0E66B52CDC9DD1"; 85 | let accountInfo = { 86 | loginer: "姓名", 87 | loginerId: "6666666", 88 | ip: "1.1.1.1", 89 | }; 90 | const SIGN_STATUS = { 91 | IN: 2, 92 | OUT: 1, 93 | }; 94 | 95 | const login = async () => { 96 | console.log(">> 执行登录"); 97 | const { sessionId, loginerId, loginKey } = await $http.post(apis.login, { 98 | username: config.username, 99 | password: config.password, 100 | openId: config.openId, 101 | unionId: config.unionId, 102 | model: "Macmini9,1", 103 | brand: "apple", 104 | platform: "mac", 105 | system: "Mac", 106 | deviceId: "", 107 | }); 108 | cookie = "JSESSIONID=" + sessionId; 109 | accountInfo.loginerId = loginerId; 110 | }; 111 | 112 | const getProjects = async () => { 113 | console.log(">> 获取实习项目"); 114 | const projects = await $http.post(apis.projects, {}); 115 | return ( 116 | projects 117 | // .filter((project) => !project.practiceEnd) 118 | .map((project) => { 119 | return { 120 | moduleId: project.moduleId, 121 | planId: project.planId, 122 | planName: project.planName, 123 | projectRuleId: project.projectRuleId, 124 | }; 125 | }) 126 | ); 127 | }; 128 | 129 | const getTasks = async () => { 130 | console.log(">> 获取任务列表"); 131 | const projects = await getProjects(); 132 | for (let i = 0; i < projects.length; i++) { 133 | const project = projects[i]; 134 | const taskInfo = await $http.post(apis.tasks, { 135 | moduleId: project.moduleId, 136 | planId: project.planId, 137 | projectRuleId: project.projectRuleId, 138 | }); 139 | projects[i] = { 140 | ...project, 141 | ...taskInfo, 142 | }; 143 | } 144 | return projects; 145 | }; 146 | 147 | const doTasks = async (taskInfos) => { 148 | console.log(">> 执行任务"); 149 | let results = []; 150 | for (let task of taskInfos) { 151 | if (task.needSign) { 152 | results.push(`${config.modeCN}:`); 153 | if (config.sign) { 154 | try { 155 | const { data } = await doClock(task); 156 | results.push(data); 157 | } catch (err) { 158 | results.push(`${config.modeCN}失败${err}`); 159 | } 160 | } else { 161 | results.push(`未开启自动${config.modeCN}`); 162 | } 163 | } 164 | if (task.needWeekBlogs) { 165 | // console.log("填写周报:"); 166 | results.push("填写周报:"); 167 | if (config.needReport) { 168 | try { 169 | let weekBlogRes = await doWeekBlogs(task); 170 | if (weekBlogRes) { 171 | results.push(weekBlogRes); 172 | } else { 173 | results.push("无"); 174 | } 175 | } catch (err) { 176 | results.push(`填写周报失败${err}`); 177 | } 178 | } else { 179 | results.push("未开启自动填写周报"); 180 | // console.log("未开启自动填写周报"); 181 | } 182 | } 183 | } 184 | if (!results.length) { 185 | return "今日没有还未完成的任务"; 186 | } 187 | return results.join("\n"); 188 | }; 189 | 190 | // 写周报 191 | const doWeekBlogs = async (taskInfo) => { 192 | const { planVo } = await $http.post(apis.weekBlogStatus, { 193 | blogType: 1, 194 | planId: taskInfo.planId, 195 | }); 196 | const traineeId = planVo?.traineeId; 197 | const date = await $http.post(apis.weekReportsDate, { traineeId }); 198 | const blogDates = []; 199 | for (let { id, months } of date) { 200 | for (let month of months) { 201 | blogDates.push({ year: id, month: month.id }); 202 | } 203 | } 204 | console.log( 205 | "*需要写周报的月份有*\n", 206 | blogDates.map((val) => `${val.year}.${val.month}`).join("\n") 207 | ); 208 | const blogTasks = []; 209 | for (let { year, month } of blogDates) { 210 | blogTasks.push(...(await getBlogTasks(year, month, traineeId))); 211 | } 212 | console.log( 213 | "*需要写的周报有*\n", 214 | blogTasks 215 | .map((val) => `第${val.week}周(${val.startDate}-${val.endDate})`) 216 | .join("\n") 217 | ); 218 | const results = []; 219 | for (let blogTask of blogTasks) { 220 | const res = await submitBlog(traineeId, blogTask); 221 | // console.log(`第${blogTask.week}周周报上交${res ? "成功" : "失败"}`); 222 | results.push(`第${blogTask.week}周周报上交${res ? "成功" : "失败"}`); 223 | } 224 | return results.join("\n"); 225 | }; 226 | 227 | const getBlogTasks = async (year, month, traineeId) => { 228 | const data = await $http.post(apis.weekReports, { 229 | traineeId, 230 | year, 231 | month, 232 | id: "", 233 | }); 234 | // console.log({ data }); 235 | return data.filter((item) => item.status == 2); 236 | }; 237 | const submitBlog = async (traineeId, blogTask) => { 238 | const blogType = 1; 239 | const blogs = reports[blogTask.week - 1]; 240 | console.log(">> 保存周报"); 241 | if (!blogs || !blogs.length) { 242 | return false; 243 | } 244 | const id = await $http.post(apis.weelBlogSave, { 245 | blogType, 246 | blogTitle: "实习周记", 247 | blogBody: blogs[Math.round(Math.random() * (blogs.length - 1))], 248 | blogOpenType: 2, 249 | traineeId: traineeId, 250 | isDraft: 0, 251 | startDate: blogTask.startDate, 252 | endDate: blogTask.endDate, 253 | backgroundTemplateId: 0, 254 | fileJson: "", 255 | blogId: "undefined", 256 | }); 257 | console.log(">> 提交周报"); 258 | const { submitNum } = await $http.post(apis.weelBlogSubmit, { 259 | blogType, 260 | traineeId, 261 | }); 262 | return submitNum > 0; 263 | }; 264 | 265 | // 签到/签退 266 | const doClock = async (taskInfo) => { 267 | const resp = await $http.post(apis.clockDefault, { 268 | planId: taskInfo.planId, 269 | }); 270 | const { clockVo, unStartClockVo } = resp; 271 | const traineeId = clockVo?.traineeId || unStartClockVo?.traineeId; 272 | console.log(">> 获取traineeId成功:", traineeId); 273 | const { res, postInfo, isSignin, isSignout } = await getClockInfo( 274 | traineeId 275 | ); 276 | postInfo.traineeId = traineeId; 277 | console.log("*签到模式*\n", config.modeCN); 278 | if (config.mode === "in") { 279 | //执行签到模式 280 | if (isSignin) { 281 | if (config.reSign) { 282 | if (!isSignout) { 283 | console.log("已签到,重新签到"); 284 | const form = await getClockForm(postInfo, SIGN_STATUS.IN); 285 | return await updateClock(form); 286 | } else { 287 | return { 288 | res: true, 289 | data: "已签退,无法进行签到", 290 | }; 291 | } 292 | } else { 293 | return { 294 | res: true, 295 | data: "已签到,未开启重新签到", 296 | }; 297 | } 298 | } else { 299 | // 首次签到 300 | const form = await getClockForm(postInfo, SIGN_STATUS.IN); 301 | // return await newClock(form); 302 | return await newClockOut(form); 303 | } 304 | } else { 305 | //执行签退模式 306 | if (isSignout) { 307 | if (config.reSign) { 308 | console.log("已签退,重新签退"); 309 | const form = await getClockForm(postInfo, SIGN_STATUS.OUT); 310 | return await updateClock(form); 311 | } else { 312 | return { 313 | res: true, 314 | data: "已签退,未开启重新签退", 315 | }; 316 | } 317 | } else { 318 | //首次签退 319 | const form = await getClockForm(postInfo, SIGN_STATUS.OUT); 320 | return await newClockOut(form); 321 | // const { isSignout: success } = await getClockInfo(traineeId); 322 | // return { 323 | // res: success, 324 | // data: success ? "签退成功" : "签退失败", 325 | // }; 326 | } 327 | } 328 | }; 329 | const getClockInfo = async (traineeId) => { 330 | const { clockInfo, postInfo, canSign } = await $http.post( 331 | apis.clockDetail, 332 | { 333 | traineeId, 334 | } 335 | ); 336 | console.log(">> 获取签到表单成功:"); 337 | if (!canSign) { 338 | console.log("当前无法签到!!"); 339 | return { 340 | res: 0, //0表示当前无法签到 341 | data: "当前无法签到", 342 | }; 343 | } 344 | const { inStatus, outStatus, inTime, outTime } = clockInfo; //TODO 用inStatus和outStatus来判断是否已签到 345 | return { 346 | res: !!inTime ? -1 : 1, //-1表示已签到,1表示未签到 347 | postInfo, 348 | isSignin: !!inTime, 349 | isSignout: !!outTime, 350 | }; 351 | }; 352 | const updateClock = async (form) => { 353 | await $http.post(apis.clockUpdate, form); 354 | return { 355 | res: true, 356 | data: `已重新${config.modeCN}`, 357 | }; 358 | }; 359 | const newClock = async (form) => { 360 | // await duration(); 361 | const { successCount } = await $http.post(apis.clock, form); 362 | const success = successCount > 0; 363 | return { 364 | res: success, 365 | data: `${config.modeCN}${success ? "成功" : "失败"}`, 366 | }; 367 | }; 368 | const newClockOut = async (form) => { 369 | // await duration(); 370 | const { startTraineeDayNum, signPersonNum } = await $http.post( 371 | apis.clockNew, 372 | form 373 | ); 374 | return { 375 | res: true, 376 | data: `${config.modeCN}成功,当前为${config.modeCN}的第${startTraineeDayNum}天,共${config.modeCN}${signPersonNum}人`, 377 | }; 378 | }; 379 | 380 | const getClockForm = async (postInfo, signStatus) => { 381 | const isCustom = !!config.location; 382 | let lat = "", 383 | lng = ""; 384 | if (isCustom) { 385 | [lng, lat] = config.location.split(","); 386 | } else { 387 | ({ lat, lng } = getRandomCoordinates( 388 | postInfo.lat, 389 | postInfo.lng, 390 | postInfo.distance 391 | )); //生成随机经纬度 392 | } 393 | 394 | const { adcode, formatted_address } = await getAdcode({ 395 | key: "c222383ff12d31b556c3ad6145bb95f4", 396 | location: config.location || `${lng},${lat}`, 397 | extensions: "all", 398 | s: "rsx", 399 | platform: "WXJS", 400 | appname: "c222383ff12d31b556c3ad6145bb95f4", 401 | sdkversion: "1.2.0", 402 | logversion: "2.0", 403 | }); 404 | 405 | if (!formatted_address) { 406 | throw new Error("获取自定义位置失败, 请检查"); 407 | } 408 | 409 | let result = { 410 | traineeId: postInfo.traineeId, 411 | adcode: adcode, 412 | lat, 413 | lng, 414 | address: isCustom ? formatted_address : postInfo.address || "", 415 | deviceName: getDeviceName() || "Macmini9,1", 416 | punchInStatus: 1, 417 | clockStatus: signStatus, 418 | addressId: postInfo.addressId, 419 | imgUrl: "", 420 | reason: "", 421 | }; 422 | let imgUrl = ""; 423 | if (config.signImagePath) { 424 | try { 425 | imgUrl = await clockUpload(config.signImagePath); 426 | } catch (error) { 427 | console.log("上传图片失败"); 428 | } 429 | result.imgUrl = imgUrl; 430 | result.reason = "签到"; 431 | } 432 | return result; 433 | }; 434 | 435 | //获取用户信息 436 | const getAccountInfo = async () => { 437 | const { loginer } = await $http.post(apis.accountInfo); 438 | accountInfo.loginer = loginer; 439 | }; 440 | //获取邮政编码 441 | const getAdcode = async (data) => { 442 | try { 443 | const res = await $http.location(data); 444 | const { addressComponent, formatted_address } = res || {}; 445 | const { adcode } = addressComponent || {}; 446 | return { 447 | adcode, 448 | formatted_address, 449 | }; 450 | } catch (error) { 451 | return { 452 | adcode: "", 453 | formatted_address: "", 454 | }; 455 | } 456 | }; 457 | 458 | const clockUpload = async (path) => { 459 | const { 460 | accessid: OSSAccessKeyId, 461 | callback, 462 | dir, 463 | expire, 464 | policy, 465 | signature, 466 | success_action_status, 467 | host, 468 | } = await $http.post(apis.uploadInfo, { 469 | customerType: "STUDENT", 470 | uploadType: "UPLOAD_STUDENT_CLOCK_IMGAGES", 471 | publicRead: true, 472 | }); 473 | const key = `${dir}/${expire}.jpeg`; 474 | const formData = new FormData(); 475 | formData.append("key", key); 476 | formData.append("OSSAccessKeyId", OSSAccessKeyId); 477 | formData.append("policy", policy); 478 | formData.append("signature", signature); 479 | formData.append("callback", callback); 480 | formData.append("success_action_status", success_action_status); 481 | const fileStream = fs.createReadStream(path); 482 | // 将文件添加到FormData对象 483 | formData.append("file", fileStream, { 484 | filename: `${expire}.jpeg`, // 自定义文件名 485 | }); 486 | const { status, vo } = await $http.upload(host, formData); 487 | return vo?.key; 488 | }; 489 | 490 | const duration = async () => { 491 | await $http.post( 492 | apis.duration, 493 | { 494 | fromType: "", 495 | urlParamsStr: "", 496 | app: "wx_student", 497 | appVersion: "1.6.36", 498 | userId: accountInfo.loginerId, 499 | deviceToken: config.openId, 500 | userName: accountInfo.loginer, 501 | operatingSystemVersion: "10", 502 | deviceModel: "microsoft", 503 | operatingSystem: "android", 504 | country: "none", 505 | province: "none", 506 | city: "none", 507 | screenHeight: "736", 508 | screenWidth: "414", 509 | eventTime: Math.floor(Date.now() / 1000), 510 | pageId: "5", 511 | pageUrl: "growUp/pages/sign/sign/sign", 512 | preferName: "成长", 513 | pageName: "成长-签到", 514 | preferPageId: "2", 515 | preferPageUrl: "pages/growup/growup", 516 | stayTime: "8", 517 | eventType: "read", 518 | eventName: "none", 519 | clientIP: accountInfo.ip, 520 | reportSrc: "2", 521 | login: "1", 522 | netType: "WIFI", 523 | itemID: "none", 524 | itemType: "其他", 525 | }, 526 | true 527 | ); 528 | }; 529 | const getIP = async () => { 530 | const { ip } = await $http.post(apis.ip); 531 | accountInfo.ip = ip; 532 | return ip; 533 | }; 534 | 535 | const getDeviceName = () => { 536 | const deviceNames = [ 537 | "iPhone 13 Pro", 538 | "MacBook Air", 539 | "Samsung Galaxy S21", 540 | "Amazon Echo Dot", 541 | "Sony PlayStation 5", 542 | "Canon EOS 5D Mark IV", 543 | "Fitbit Versa 3", 544 | "Google Nest Thermostat", 545 | "Logitech MX Master 3", 546 | "ASUS ROG Strix Gaming Laptop", 547 | ]; 548 | // 生成一个随机的索引 549 | const randomIndex = Math.floor(Math.random() * deviceNames.length); 550 | // 获取随机设备名称 551 | const randomDeviceName = deviceNames[randomIndex]; 552 | return randomDeviceName; 553 | }; 554 | //生成一个随机经纬度 555 | function getRandomCoordinates(latitude, longitude, distanceInMeters = 10) { 556 | // 地球半径(单位:米) 557 | const earthRadius = 6378137; // 地球平均半径 558 | 559 | // 随机方向(0到360度) 560 | const randomDirection = Math.random() * 360; 561 | 562 | // 随机距离(0到distanceInMeters) 563 | const randomDistance = Math.random() * distanceInMeters; 564 | 565 | // 将距离转换为弧度 566 | const distanceInRadians = randomDistance / earthRadius; 567 | 568 | // 将方向转换为弧度 569 | const directionInRadians = randomDirection * (Math.PI / 180); 570 | 571 | // 原始坐标的经度和纬度(弧度) 572 | const originalLatitudeRadians = latitude * (Math.PI / 180); 573 | const originalLongitudeRadians = longitude * (Math.PI / 180); 574 | 575 | // 使用Haversine公式计算新坐标的经度和纬度 576 | const newLatitudeRadians = Math.asin( 577 | Math.sin(originalLatitudeRadians) * Math.cos(distanceInRadians) + 578 | Math.cos(originalLatitudeRadians) * 579 | Math.sin(distanceInRadians) * 580 | Math.cos(directionInRadians) 581 | ); 582 | 583 | const newLongitudeRadians = 584 | originalLongitudeRadians + 585 | Math.atan2( 586 | Math.sin(directionInRadians) * 587 | Math.sin(distanceInRadians) * 588 | Math.cos(originalLatitudeRadians), 589 | Math.cos(distanceInRadians) - 590 | Math.sin(originalLatitudeRadians) * Math.sin(newLatitudeRadians) 591 | ); 592 | 593 | // 将新的经纬度坐标转换为度数,并保留与传入参数相同的小数位数 594 | const newLatitude = parseFloat(newLatitudeRadians * (180 / Math.PI)); 595 | const newLongitude = parseFloat(newLongitudeRadians * (180 / Math.PI)); 596 | 597 | return { lat: newLatitude, lng: newLongitude }; 598 | } 599 | 600 | const xyb = async () => { 601 | try { 602 | await login(); 603 | await getAccountInfo(); 604 | // await duration(); 605 | await getIP(); 606 | } catch (err) { 607 | results += `### 账号(${config.username.substr( 608 | config.username.length - 4 609 | )}) ###\n${err}\n`; 610 | return; 611 | } 612 | const tasks = await getTasks(); 613 | const result = await doTasks(tasks); 614 | results += `###${accountInfo.loginer}### 615 | ${result}`; 616 | // await sendMsg(result); 617 | }; 618 | await xyb(); 619 | return results; 620 | } 621 | 622 | const parseEnvArgv = (argv) => { 623 | const arguments = argv; 624 | let res = { 625 | accounts: [], 626 | }; 627 | 628 | if (!argv[2]) { 629 | return false; 630 | } 631 | const configStrArr = argv[2].split(";"); 632 | const accountStrs = []; 633 | const configStrs = []; 634 | for (const confStr of configStrArr) { 635 | if (!confStr) { 636 | continue; 637 | } 638 | if (confStr.includes("username")) { 639 | accountStrs.push(confStr); 640 | } else { 641 | configStrs.push(confStr); 642 | } 643 | } 644 | for (const acStr of accountStrs) { 645 | const info = {}; 646 | const acs = acStr.split("&"); 647 | for (const c of acs) { 648 | const cache = c.split("="); 649 | if ( 650 | cache[0] == "sign" || 651 | cache[0] == "reSign" || 652 | cache[0] == "needReport" 653 | ) { 654 | info[cache[0]] = cache[1] == "true" ? true : false; 655 | } else { 656 | info[cache[0]] = cache[1]; 657 | } 658 | } 659 | res.accounts.push(info); 660 | } 661 | for (const cfs of configStrs) { 662 | const cache = cfs.split("="); 663 | res[cache[0]] = cache[1]; 664 | } 665 | return res; 666 | }; 667 | 668 | async function run() { 669 | let results = []; 670 | 671 | let processConfig = parseEnvArgv(process.argv); 672 | if (processConfig) { 673 | console.log("====使用命令行配置===="); 674 | const confTemp = { 675 | username: "", 676 | password: "", 677 | openId: "", 678 | unionId: "", 679 | sign: true, 680 | reSign: false, 681 | location: "", 682 | signImagePath: "", 683 | needReport: false, 684 | }; 685 | processConfig.accounts = processConfig.accounts.map((e) => ({ 686 | ...confTemp, 687 | ...e, 688 | })); 689 | const modeMap = { 690 | in: "签到", 691 | out: "签退", 692 | }; 693 | processConfig.modeCN = modeMap[processConfig.mode]; 694 | config = processConfig; 695 | } else { 696 | console.log("====使用config.js中配置===="); 697 | } 698 | 699 | for (const account of config.accounts) { 700 | // console.log(account); 701 | account.mode = config.mode; 702 | account.modeCN = config.modeCN; 703 | account.password = md5(account.password); 704 | results.push(await xybSign(account)); 705 | console.log(`====当前账号(${account.username})执行结束====`); 706 | } 707 | console.log("====所有账号执行结束===="); 708 | console.log(results.join("\n")); 709 | if (config.qmsgKey) { 710 | await sendMsg(results.join("\n"), config); 711 | } 712 | if (config.wxPusherAppToken) { 713 | await sendWxMsg(results.join("\n"), config); 714 | } 715 | } 716 | 717 | run(); 718 | --------------------------------------------------------------------------------