GiteePlus

企业版Gitee增强

  1. // ==UserScript==
  2. // @name GiteePlus
  3. // @version 1.6.0
  4. // @description 企业版Gitee增强
  5. // @author Kason
  6. // @grant GM_addStyle
  7. // @grant unsafeWindow
  8. // @grant GM_notification
  9. // @grant GM_xmlhttpRequest
  10. // @license MIT
  11. // @match https://e.gitee.com/*
  12. // @icon https://e.gitee.com/assets/images/favicon.ico
  13. // @namespace https://gf.qytechs.cn/users/1186291
  14. // ==/UserScript==
  15.  
  16. (function () {
  17. "use strict";
  18. let script = document.createElement("script");
  19. script.setAttribute("type", "text/javascript");
  20. script.src = "https://cdn.jsdelivr.net/npm/vue@3";
  21. document.documentElement.appendChild(script);
  22. let link = document.createElement("link");
  23. link.setAttribute("rel", "stylesheet");
  24. link.href = "https://cdn.jsdelivr.net/npm/element-plus/dist/index.css";
  25. document.documentElement.appendChild(link);
  26. let fontAwesome = document.createElement("link");
  27. fontAwesome.setAttribute("rel", "stylesheet");
  28. fontAwesome.href =
  29. "https://cdn.bootcdn.net/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css";
  30. document.documentElement.appendChild(fontAwesome);
  31. let elscript = document.createElement("script");
  32. elscript.setAttribute("type", "text/javascript");
  33. elscript.src = "https://cdn.jsdelivr.net/npm/element-plus";
  34. document.documentElement.appendChild(elscript);
  35. let sortableScript = document.createElement("script");
  36. sortableScript.setAttribute("type", "text/javascript");
  37. sortableScript.src =
  38. "https://cdn.bootcdn.net/ajax/libs/Sortable/1.15.0/Sortable.min.js";
  39. sortableScript.async = true;
  40. document.documentElement.appendChild(sortableScript);
  41. window.onload = () => {
  42. // 样式单独抽离管理
  43. let app_styles = `position: absolute;
  44. display: flex;
  45. justify-content: flex-start;
  46. top: 58px;
  47. left: 240px;
  48. z-index:2;
  49. align-items: flex-start;
  50. margin-top: 5px;`;
  51. let badge_style = `margin-top: 10px;margin-right: 40px;`;
  52. let week_time_style = `text-align: center;margin-left: 70px;cursor: pointer;`;
  53. let last_week_time_style = `text-align: center;margin-left: 60px;cursor: pointer;`;
  54. let calendar_style = `position: absolute;top: 53px;width: 500px; right: -160px;text-align: center;`;
  55. let calendat_body_style = `margin-top:2px;`;
  56. let text = `<div id="app" style="${app_styles};">
  57. <el-tooltip class="box-item" effect="light" content="所有任务/需求/Bug" placement="bottom">
  58. <el-badge :value="sun_count" v-if="show_status" style="${badge_style};"><el-tag>总任务</el-tag></el-badge>
  59. </el-tooltip>
  60. <el-tooltip class="box-item" effect="light" content="24小时内将超时" placement="bottom">
  61. <el-badge :value="deadline_count" v-if="show_status" style="${badge_style};"><el-tag type="warning">临期任务</el-tag></el-badge>
  62. </el-tooltip>
  63. <el-tooltip class="box-item" effect="light" content="已延期" placement="bottom">
  64. <el-badge :value="expired_count" v-if="show_status" style="${badge_style};"><el-tag>延 期</el-tag></el-badge>
  65. </el-tooltip>
  66. <el-badge :value="feature_count" v-if="show_status" type="primary" style="${badge_style};"><el-tag >需 求</el-tag></el-badge>
  67. <el-badge :value="task_count" v-if="show_status" type="primary" style="${badge_style};"><el-tag>任 务</el-tag></el-badge>
  68. <el-badge :value="bug_count" v-if="show_status" type="warning" style="${badge_style};"><el-tag>Bug</el-tag></el-badge>
  69.  
  70. <el-popover placement="bottom" :width="360" trigger="hover" :popper-style="{ 'border-radius': '15px','cursor': 'pointer'}">
  71. <template #reference>
  72. <el-statistic style="${last_week_time_style}" v-if="show_status" title="上周工时(标准:40)" :value="last_work_time" @mouseenter="fetchTableData(0)">
  73. <template #suffix >
  74. <el-icon style="vertical-align: -0.125em">
  75. <svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" data-v-ea893728=""><path fill="currentColor" d="M512 896a384 384 0 1 0 0-768 384 384 0 0 0 0 768zm0 64a448 448 0 1 1 0-896 448 448 0 0 1 0 896z"></path><path fill="currentColor" d="M480 256a32 32 0 0 1 32 32v256a32 32 0 0 1-64 0V288a32 32 0 0 1 32-32z"></path><path fill="currentColor" d="M480 512h256q32 0 32 32t-32 32H480q-32 0-32-32t32-32z"></path></svg>
  76. </el-icon>
  77. </template>
  78. </el-statistic>
  79. </template>
  80. <el-table border stripe max-height="196" ref="tableRef" size="small" @selection-change="handleSelectionChange" :header-cell-style="{'text-align':'center'}" :cell-style="{'text-align':'center'}" :data="gridData" :table-layout="tableLayout">
  81. <el-table-column prop="xq" label="星期" width="85">
  82. <template #default="scope">
  83. <el-tag
  84. effect="light"
  85. disable-transitions
  86. >
  87. {{ scope.row.xq }}
  88. </el-tag>
  89. </template>
  90. </el-table-column>
  91. <el-table-column prop="rq" label="日期" width="85" ></el-table-column>
  92. <el-table-column prop="gs" label="工时" width="54">
  93. <template #default="scope">
  94. <div :style="{ color: (scope.row.gs > 8 ? 'red' : (scope.row.gs >= 0 && scope.row.gs <= 8 ? '#099877' : '')) }">{{ scope.row.gs }}</div>
  95. </template>
  96. </el-table-column>
  97. <el-table-column fixed="right" label="操作" width="110">
  98. <template #default="scope">
  99. <el-button link type="primary" size="small" @click="handleDetail(scope.row.xq, scope.row.rq, scope.row.gs,0)">详情</el-button>
  100. </template>
  101. </el-table-column>
  102. </el-table>
  103. </el-popover>
  104.  
  105. <el-popover placement="bottom" :width="360" trigger="hover" :popper-style="{ 'border-radius': '15px','cursor': 'pointer'}">
  106. <template #reference>
  107. <el-statistic style="${week_time_style}" v-if="show_status" title="本周工时(标准:40)" :value="work_time" @mouseenter="fetchTableData(1)">
  108. <template #suffix >
  109. <el-icon style="vertical-align: -0.125em" >
  110. <svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" data-v-ea893728=""><path fill="currentColor" d="M512 896a384 384 0 1 0 0-768 384 384 0 0 0 0 768zm0 64a448 448 0 1 1 0-896 448 448 0 0 1 0 896z"></path><path fill="currentColor" d="M480 256a32 32 0 0 1 32 32v256a32 32 0 0 1-64 0V288a32 32 0 0 1 32-32z"></path><path fill="currentColor" d="M480 512h256q32 0 32 32t-32 32H480q-32 0-32-32t32-32z"></path></svg>
  111. </el-icon>
  112. </template>
  113. </el-statistic>
  114. </template>
  115. <el-table border stripe max-height="196" ref="tableRef" size="small" @selection-change="handleSelectionChange" :header-cell-style="{'text-align':'center'}" :cell-style="{'text-align':'center'}" :data="gridData" :table-layout="tableLayout">
  116. <el-table-column prop="xq" label="星期" width="85">
  117. <template #default="scope">
  118. <el-tag
  119. effect="light"
  120. disable-transitions
  121. >
  122. {{ scope.row.xq }}
  123. </el-tag>
  124. </template>
  125. </el-table-column>
  126. <el-table-column prop="rq" label="日期" width="85" ></el-table-column>
  127. <el-table-column prop="gs" label="工时" width="54">
  128. <template #default="scope">
  129. <div :style="{ color: (scope.row.gs > 8 ? 'red' : (scope.row.gs >= 0 && scope.row.gs <= 8 ? '#099877' : '')) }">{{ scope.row.gs }}</div>
  130. </template>
  131. </el-table-column>
  132. <el-table-column fixed="right" label="操作" width="110">
  133. <template #default="scope">
  134. <el-button link type="primary" size="small" @click="handleDetail(scope.row.xq, scope.row.rq, scope.row.gs,1)">详情</el-button>
  135. </template>
  136. </el-table-column>
  137. </el-table>
  138. </el-popover>
  139.  
  140. <el-calendar ref="calendar" style="${calendar_style}" v-model="selectedDate" @mouseover="showCalendar = true" @mouseleave="showCalendar = false" v-show="showCalendar" :range="dateRange">
  141. <template #date-cell="{ data }">
  142. <div v-show="isInAllDate( data.day.split('-').slice(0).join('-') )" style="${calendat_body_style};">{{ data.day.split('-').slice(1).join('-') }}</div>
  143. <svg v-if="!isSpecifiedDate( data.day.split('-').slice(0).join('-') )&&isInAllDate( data.day.split('-').slice(0).join('-') )" style="${calendat_body_style};" t="1696519254340" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1893" width="20" height="20"><path d="M666.32 727.28L554.08 944.8a36.24 36.24 0 0 1-48.88 15.6c-7.12-3.68-12.8-9.52-16.16-16.8L384.64 722.24c-5.12-10.8-15.2-18.4-26.96-20.32L116.16 662.4a36.24 36.24 0 0 1-29.92-41.68c1.28-7.84 5.12-15.12 10.96-20.56l178.24-167.68a36.32 36.32 0 0 0 11.04-31.92l-37.12-241.92a36.264 36.264 0 0 1 53.36-37.28l214.56 117.68c10.48 5.76 23.12 5.92 33.76 0.56L769.6 129.6a36.24 36.24 0 0 1 51.92 39.2l-45.68 240.48c-2.24 11.76 1.44 23.84 9.84 32.32l172.16 173.92a36.264 36.264 0 0 1-0.24 51.28c-5.68 5.6-13.04 9.2-20.96 10.16l-242.8 30.88c-11.68 1.6-22.08 8.8-27.52 19.44z" fill="#bfbfbf" p-id="1894"></path><path d="M655.2 709.36l-104.4 202.4a33.8 33.8 0 0 1-45.52 14.56 33.824 33.824 0 0 1-15.04-15.6L393.04 704.72a33.744 33.744 0 0 0-25.12-18.96l-224.8-36.8a33.88 33.88 0 0 1-27.92-38.8c1.2-7.36 4.8-14.08 10.16-19.12l165.92-156.08a33.768 33.768 0 0 0 10.24-29.68l-34.48-225.2a33.784 33.784 0 0 1 28.24-38.48c7.36-1.12 14.88 0.24 21.36 3.76l199.76 109.52c9.76 5.36 21.52 5.52 31.44 0.56l203.44-102.4a33.792 33.792 0 0 1 48.4 36.48l-42.48 223.76c-2.08 10.88 1.36 22.16 9.2 30.08l160.24 161.84a33.752 33.752 0 0 1-0.24 47.76c-5.28 5.2-12.08 8.56-19.44 9.52L680.96 691.2a34.152 34.152 0 0 0-25.76 18.16z" fill="#bfbfbf" p-id="1895"></path><path d="M118.48 631.44l388.16-161.76 5.2 457.6a33.704 33.704 0 0 1-22.96-18.48L391.68 702.72a33.88 33.88 0 0 0-25.12-18.96l-224.8-36.72a33.504 33.504 0 0 1-23.28-15.6z m676.8-465.28c3.36 6.64 4.4 14.16 3.04 21.52l-42.48 223.76c-2.08 10.96 1.36 22.16 9.2 30.08l160.24 161.84c9.6 9.68 12.4 24.08 7.2 36.64L506.64 469.6l278.08-315.84c4.32 3.2 8 7.36 10.56 12.4z" fill="#bfbfbf" p-id="1896"></path></svg>
  144. <svg v-if="isSpecifiedDate( data.day.split('-').slice(0).join('-') )" style="${calendat_body_style};" t="1696518710705" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1608" width="20" height="20"><path d="M666.32 727.28L554.08 944.8a36.24 36.24 0 0 1-48.88 15.6c-7.12-3.68-12.8-9.52-16.16-16.8L384.64 722.24c-5.12-10.8-15.2-18.4-26.96-20.32L116.16 662.4a36.24 36.24 0 0 1-29.92-41.68c1.28-7.84 5.12-15.12 10.96-20.56l178.24-167.68a36.32 36.32 0 0 0 11.04-31.92l-37.12-241.92a36.264 36.264 0 0 1 53.36-37.28l214.56 117.68c10.48 5.76 23.12 5.92 33.76 0.56L769.6 129.6a36.24 36.24 0 0 1 51.92 39.2l-45.68 240.48c-2.24 11.76 1.44 23.84 9.84 32.32l172.16 173.92a36.264 36.264 0 0 1-0.24 51.28c-5.68 5.6-13.04 9.2-20.96 10.16l-242.8 30.88c-11.68 1.6-22.08 8.8-27.52 19.44z" fill="#6E6E96" p-id="1609"></path><path d="M655.2 709.36l-104.4 202.4a33.8 33.8 0 0 1-45.52 14.56 33.824 33.824 0 0 1-15.04-15.6L393.04 704.72a33.744 33.744 0 0 0-25.12-18.96l-224.8-36.8a33.88 33.88 0 0 1-27.92-38.8c1.2-7.36 4.8-14.08 10.16-19.12l165.92-156.08a33.768 33.768 0 0 0 10.24-29.68l-34.48-225.2a33.784 33.784 0 0 1 28.24-38.48c7.36-1.12 14.88 0.24 21.36 3.76l199.76 109.52c9.76 5.36 21.52 5.52 31.44 0.56l203.44-102.4a33.792 33.792 0 0 1 48.4 36.48l-42.48 223.76c-2.08 10.88 1.36 22.16 9.2 30.08l160.24 161.84a33.752 33.752 0 0 1-0.24 47.76c-5.28 5.2-12.08 8.56-19.44 9.52L680.96 691.2a34.152 34.152 0 0 0-25.76 18.16z" fill="#FECD34" p-id="1610"></path><path d="M118.48 631.44l388.16-161.76 5.2 457.6a33.704 33.704 0 0 1-22.96-18.48L391.68 702.72a33.88 33.88 0 0 0-25.12-18.96l-224.8-36.72a33.504 33.504 0 0 1-23.28-15.6z m676.8-465.28c3.36 6.64 4.4 14.16 3.04 21.52l-42.48 223.76c-2.08 10.96 1.36 22.16 9.2 30.08l160.24 161.84c9.6 9.68 12.4 24.08 7.2 36.64L506.64 469.6l278.08-315.84c4.32 3.2 8 7.36 10.56 12.4z" fill="#FEA935" p-id="1611"></path></svg>
  145. <div v-if="isInAllDate( data.day.split('-').slice(0).join('-') )" style="${calendat_body_style};">{{ registered_map[data.day] || 0 }}</div>
  146. </template>
  147. </el-calendar>
  148. <el-dialog v-model="showTable" width="800" draggable :show-close="false" :style="{ 'border-radius': '15px' }">
  149. <div slot="title" style="margin-top: -10px;font-size: 17px;font-weight: 800;margin-bottom: 10px; display: flex;align-items: center;flex-direction: row;justify-content: space-between;">任务选择|刷新任务状态<span><el-tooltip class="box-item" effect="dark" content="选中后,将直接推送周报内容" placement="left"><el-checkbox v-model="push">直接推送</el-checkbox></el-tooltip><span></div>
  150. <el-table border stripe max-height="250" ref="tableRef" @selection-change="handleSelectionChange" :header-cell-style="{'text-align':'center'}" :cell-style="{'text-align':'center'}" :data="tableData" :table-layout="tableLayout">
  151. <el-table-column type="selection" label="序号" width="35"></el-table-column>
  152. <el-table-column prop="title" label="任务名称" width="555" show-overflow-tooltip></el-table-column>
  153. <el-table-column prop="assignee" label="任务负责人" width="95">
  154. <template #default="scope">
  155. <el-avatar :src="scope.row.assignee.avatar_url" style="background: white; width:20px; height:20px"></el-avatar>
  156. </template>
  157. </el-table-column>
  158. <el-table-column prop="issue_state.title" label="状态"></el-table-column>
  159. </el-table>
  160. <el-input
  161. v-model="textarea"
  162. style="width: 100%"
  163. :rows="4"
  164. type="textarea"
  165. placeholder="稍等,我有话要说! 可重复补充信息\n 例如:在xxx任务中,虽然完成了,但是遇到了xxx困难,请求大佬支援...\n 例如:在本周任务中,我学会了xxx技能,并在飞书分享相关文档\n 例如:我遇到了些问题:1.新的技术;2.服务器问题"></el-input>
  166. <div style="display: flex; justify-content: center;">
  167. <el-button :loading="pushLoading" type="primary" style="margin: 15px;" @click="chatAI">
  168. <i class="fa fa-paper-plane"></i>&nbsp;&nbsp;GO GPT!
  169. </el-button>
  170. <el-button :loading="pushGiteeLoading" type="primary" style="margin: 15px;" @click="pushHtml">
  171. <i class="fa fa-envelope"></i>&nbsp;&nbsp;发送周报
  172. </el-button>
  173. </div>
  174. <el-input
  175. v-model="textareaByAI"
  176. style="width: 100%;height:auto"
  177. v-if="textareaByAIShow"
  178. type="textarea"
  179. :rows="6"
  180. placeholder=""></el-input>
  181. </el-dialog>
  182.  
  183. <el-dialog v-model="showIssueTable" width="800" draggable :show-close="false" :style="{ 'z-index': '99999', 'border-radius': '15px' }">
  184. <div slot="title" style="margin-top: -10px;font-size: 20px;margin-left: 50px;margin-right: 50px;font-weight: 800;margin-bottom: 12px; display: flex;align-items: center;flex-direction: row;justify-content: space-between;">
  185. <span>{{xq}}</span>
  186. <span>时间:{{rq}}</span>
  187. <span>总工时:{{gs}}</span>
  188. </div>
  189. <el-table border stripe max-height="450" ref="tableRef" :header-cell-style="{'text-align':'center'}" :cell-style="{'text-align':'center'}" :data="tableIssueData" :table-layout="tableLayout">
  190. <el-table-column prop="issue_type.title" label="类型" width="150"></el-table-column>
  191. <el-table-column prop="title" label="任务" width="350" show-overflow-tooltip></el-table-column>
  192. <el-table-column prop="gs" label="工时"></el-table-column>
  193. <el-table-column label="跳转">
  194. <template #default="scope">
  195. <a @click="openNewTab(scope.row.link)" style="cursor: pointer;">前往查看</a>
  196. </template>
  197. </el-table-column>
  198. </el-table>
  199. </el-dialog>
  200.  
  201. </div>`;
  202. var el = document.createElement("div");
  203. el.innerHTML = text;
  204. document.body.append(el);
  205.  
  206. // 登录(不可用)人对象
  207. class assignee {
  208. constructor() {
  209. this.data = {
  210. id: null,
  211. username: null,
  212. name: null,
  213. remark: null,
  214. pinyin: null,
  215. avatar_url: null,
  216. is_enterprise_member: null,
  217. is_history_member: null,
  218. outsourced: null,
  219. };
  220. }
  221. }
  222. // 创建者对象
  223. class author {
  224. constructor() {
  225. this.data = {
  226. id: null,
  227. username: null,
  228. name: null,
  229. remark: null,
  230. pinyin: null,
  231. avatar_url: null,
  232. is_enterprise_member: null,
  233. is_history_member: null,
  234. outsourced: null,
  235. };
  236. }
  237. }
  238. // 任务类型
  239. class issue_type {
  240. constructor() {
  241. this.data = {
  242. id: null,
  243. title: null,
  244. template: null,
  245. ident: null,
  246. color: null,
  247. is_system: null,
  248. created_at: null,
  249. updated_at: null,
  250. category: null,
  251. description: null,
  252. };
  253. }
  254. }
  255. // 任务状态
  256. class issue_state {
  257. constructor() {
  258. this.data = {
  259. id: null,
  260. title: null,
  261. color: null,
  262. icon: null,
  263. command: null,
  264. serial: null,
  265. issue_types: [new issue_type()],
  266. created_at: null,
  267. updated_at: null,
  268. };
  269. }
  270. }
  271. // 工作项数据
  272. class issue_data {
  273. constructor() {
  274. this.total_count = 0;
  275. this.data = [
  276. {
  277. id: null,
  278. root_id: null,
  279. parent_id: null,
  280. project_id: null,
  281. ident: null,
  282. title: null,
  283. issue_state_id: null,
  284. program_id: null,
  285. state: null,
  286. comments_count: null,
  287. priority: null,
  288. branch: null,
  289. priority_human: null,
  290. assignee: new assignee(),
  291. duration: null,
  292. created_at: null,
  293. updated_at: null,
  294. collaborators: [],
  295. author: new author(),
  296. milestone: null,
  297. issue_state: new issue_state(),
  298. issue_type: new issue_type(),
  299. labels: [],
  300. issue_extra: [],
  301. plan_started_at: null,
  302. deadline: null,
  303. finished_at: null,
  304. started_at: null,
  305. security_hole: null,
  306. is_star: null,
  307. kanban_info: null,
  308. estimated_duration: null,
  309. // 任务单登记时间
  310. registered_duration: 0,
  311.  
  312. },
  313. ];
  314. }
  315. }
  316.  
  317. const App = {
  318. data() {
  319. return {
  320. roult_path: null,
  321. message: "Hello Gitee Plus",
  322. elements: null,
  323. work_time: 0,
  324. last_work_time: 0,
  325. issurDataTotal: null,
  326. show_status: true,
  327. sun_count: 0,
  328. deadline_count: 0,
  329. task_count: 0,
  330. feature_count: 0,
  331. bug_count: 0,
  332. expired_count: 0,
  333. calendar: null,
  334. dateRange: null,
  335. registered_map: {},
  336. selectedDate: new Date(), // 添加选中的日期
  337. showCalendar: false, // 控制日历组件的显示
  338. tableData: [], // 任务表格数据
  339. tableIssueData: [], // 工时表格数据
  340. showTable: false, // 表格可见开关
  341. showIssueTable: false, // 工时任务可见开关
  342. dialogTableVisible: true,
  343. tableLayout: "fixed",
  344. selectionDatas: [], // 选中数据集合
  345. textarea: "", // 补充内容文本域
  346. push: false, // 直接推送开关
  347. pushLoading: false, // loading开关
  348. parentMessageId: 0, //上一次消息id
  349. textareaByAI: "", // AI返回文本域
  350. textareaByAIShow: false, //AI文本域展示开关
  351. pushGiteeLoading: false,
  352. gridData: [],
  353. xq: "",
  354. rq: "",
  355. gs: ""
  356. };
  357. },
  358. mounted() {
  359. this.gridData = [
  360. {
  361. rq: '',
  362. xq: '星期一',
  363. gs: '',
  364. },
  365. {
  366. rq: '',
  367. xq: '星期二',
  368. gs: '',
  369. },
  370. {
  371. rq: '',
  372. xq: '星期三',
  373. gs: '',
  374. },
  375. {
  376. rq: '',
  377. xq: '星期四',
  378. gs: '',
  379. },
  380. {
  381. rq: '',
  382. xq: '星期五',
  383. gs: '',
  384. },
  385. {
  386. rq: '',
  387. xq: '星期六',
  388. gs: '',
  389. },
  390. {
  391. rq: '',
  392. xq: '星期天',
  393. gs: '',
  394. },
  395. ],
  396. // 获取当前公司的路由前缀
  397. this.getRoluteStr()
  398. .then((result) => {
  399. this.roult_path = result.id;
  400. })
  401. .catch(function (error) {
  402. console.error("Gitee客户端异常,获取公司路由失败");
  403. });
  404. // 设置左侧标题为会员,右侧多余按钮
  405. this.hideComp();
  406. // 页面可见性的改变
  407. document.addEventListener("visibilitychange", () => {
  408. if (document.visibilityState === "visible") {
  409. this.showNotification(
  410. "Hi " +
  411. JSON.parse(localStorage.getItem("gitee.user")).userInfo.name,
  412. "欢迎回来 GiteePlus"
  413. );
  414. console.log("当前页面在浏览器打开标签");
  415. // TODO 获取焦点,主动获取一次通知中,是否存在新的任务,如果有新的任务,将和上次离开时间对比,共有多少任务派出
  416. // TODO 计算出任务数量,并显示在页面中
  417. } else {
  418. // TODO 页面进入后台,进行新的修改 记录时间
  419. }
  420. });
  421. // 路由判定
  422. window.addEventListener("popstate", (event) => {
  423. if (window.location.pathname.includes("dashboard")) {
  424. this.show_status = true;
  425. } else {
  426. this.show_status = false;
  427. }
  428. });
  429. // 周报滚动条显示
  430. this.$nextTick(async () => {
  431. try {
  432. const { current_week, last_week } = await this.get_week_reports();
  433. await this.send_todo_num_request();
  434. if (
  435. (last_week.id != null && current_week.id == null) ||
  436. (last_week.id != undefined && current_week.id == undefined)
  437. ) {
  438. const article = document.createElement("div");
  439. article.setAttribute("id", "team-members");
  440. article.innerHTML =
  441. `
  442. <article class="team-member">
  443. <img
  444. class="team-member-avatar"
  445. src="`+ JSON.parse(localStorage.getItem("gitee.user")).userInfo.avatar_url + `"
  446. alt="Team Member"
  447. />
  448. <div class="team-member-name">
  449. <h3>周报汇报</h3>
  450. <p>本周周报还没写</p>
  451. </div>
  452. <ul class="social-links">
  453. <a class="zb" href="#"><i class="fa-solid fa-calendar"></i></a>
  454. </ul>
  455. </article>
  456. <article class="team-member">
  457. <div class="team-member-name">
  458. <h3>贴心通知</h3>
  459. <p>24h内需完成任务, ` +
  460. this.deadline_count +
  461. ` 条</p>
  462. </div>
  463. <ul class="social-links">
  464. <li>
  465. <a href="#"><i class="fa-solid fa-ellipsis" style="color: #f3de53;"></i></a>
  466. </li>
  467. </ul>
  468. </article>
  469. <article class="team-member">
  470. <div class="team-member-name">
  471. <h3>超时提醒</h3>
  472. <p>当前累计超时单, ` +
  473. this.expired_count +
  474. ` 条</p>
  475. </div>
  476. <ul class="social-links">
  477. <li>
  478. <a href="#"><i class="fa-solid fa-bell" style="color: #de7cc9;"></i></a>
  479. </li>
  480. </ul>
  481. </article>
  482. `;
  483. let style = document.createElement("style");
  484. style.innerHTML = `
  485. h3{
  486. margin: 0;
  487. }
  488. #team-members {
  489. display: flex;
  490. font-size: 1rem;
  491. background-position: center center;
  492. background-size: cover;
  493. display: flex;
  494. flex-direction: column;
  495. gap: 16px;
  496. width: 100%;
  497. max-width: 550px;
  498. margin: auto;
  499. padding: 50px;
  500. background: rgba(255, 255, 255, 0.25);
  501. backdrop-filter: blur(10px);
  502. border-radius: 10px;
  503. border: 1px solid rgba(255, 255, 255, 0.08);
  504. filter: drop-shadow(0px 20px 10px rgba(0, 0, 0, 0.3));
  505. }
  506. .team-member {
  507. position: relative;
  508. display: flex;
  509. align-items: center;
  510. flex-wrap: wrap;
  511. gap: 5px;
  512. min-height: 60px;
  513. padding-top: 4px;
  514. padding-bottom: 4px;
  515. padding-left: 15px;
  516. padding-right: 15px;
  517. background-color: #ffffff;
  518. border-radius: 25px;
  519. font-size: large;
  520. z-index: 1;
  521. }
  522. .team-member:hover {
  523. cursor: grab;
  524. }
  525. .team-member-avatar {
  526. width: 3.75rem;
  527. height: 3.75rem;
  528. object-fit: cover;
  529. border-radius: 50%;
  530. }
  531. .team-member-name {
  532. display: grid;
  533. gap: 0.125rem;
  534. }
  535. .team-member-name h3 {
  536. color: #2a70dc;
  537. font-size: large;
  538. }
  539. .team-member-name p {
  540. font-size: smaller;
  541. }
  542. .team-member-chosen {
  543. box-shadow: 8px 8px 32px rgba(0, 0, 0, 0.3);
  544. }
  545. .team-member-drag {
  546. opacity: 0;
  547. }
  548. .social-links {
  549. display: flex;
  550. flex-direction: row;
  551. gap: 6px;
  552. margin-left: auto;
  553. padding: 0;
  554. list-style-type: none;
  555. }
  556. .social-links i {
  557. width: 1.25rem;
  558. height: 1.25rem;
  559. font-size: 1.25rem;
  560. }
  561. `;
  562. document.head.appendChild(style);
  563. this.addWeekReportTips(article);
  564. new Sortable(article, {
  565. animation: 350,
  566. chosenClass: "team-member-chosen",
  567. dragClass: "team-member-drag",
  568. });
  569. const currentDate = new Date();
  570. const currentDay = currentDate.getDay();
  571. if (currentDay >= 5) {
  572. // TODO 对今天是周五的情况下,且周报也未获取到,继续处理
  573. }
  574. }
  575. // 去除不写周报的提示
  576. } catch (error) {
  577. console.error("Gitee客户端异常,获取周报失败");
  578. }
  579. this.$nextTick(() => {
  580. const img = document.querySelector(".zb");
  581. if (img) {
  582. img.addEventListener("click", this.showTableData);
  583. }
  584. });
  585. });
  586. this.send_todo_num_request()
  587. .then((issue_str) => {
  588. return this.send_issue_data_request(issue_str);
  589. })
  590. .then((issue) => {
  591. // 处理返回的 issue 数据
  592. this.issurDataTotal = issue;
  593. // 获取到的数据
  594. this.sun_count = this.issurDataTotal.total_count;
  595. if (
  596. this.issurDataTotal.total_count != 0 &&
  597. this.issurDataTotal.data.length > 0
  598. ) {
  599. for (let info of this.issurDataTotal.data) {
  600. // 截止时间
  601. if (info.deadline != null) {
  602. var currentTime = new Date();
  603. if (new Date(info.deadline) >= currentTime) {
  604. var time = this.get_hour_difference(info.deadline);
  605. if (time != null && time <= 24) {
  606. this.deadline_count++;
  607. }
  608. } else {
  609. // 逾期任务
  610. this.expired_count++;
  611. }
  612. }
  613. // 将数据分类,摘选出需求/任务/bug
  614. if (info.issue_type.id == 626337) {
  615. this.bug_count++;
  616. }
  617. if (info.issue_type.id == 626336) {
  618. this.feature_count++;
  619. }
  620. const validIssueTypeIds = new Set([
  621. 16690, 662615, 757073, 757074, 766555,
  622. ]);
  623. if (validIssueTypeIds.has(info.issue_type.id)) {
  624. this.task_count++;
  625. }
  626. }
  627. // 调用element-plus的通知,可以等待通知消息接收到再处理
  628. if (this.deadline_count > 0) {
  629. this.$notify({
  630. title: "贴心通知",
  631. type: "warning",
  632. message:
  633. "注意!您有24小时内需完成的任务,共 " +
  634. this.deadline_count +
  635. " 条",
  636. position: "bottom-right",
  637. showClose: false,
  638. offset: 50,
  639. duration: 3000,
  640. });
  641. }
  642. }
  643. })
  644. .catch((error) => {
  645. console.error("Gitee客户端异常", error);
  646. });
  647. // 工时获取,本周工时,上周工时
  648. this.get_week_time()
  649. .then((result) => {
  650. if (result != null) {
  651. var dates = result.dates;
  652. var all_registered_duration = result.all_registered_duration;
  653. var daily_registered_duration_count =
  654. result.daily_registered_duration_count;
  655. this.work_time = all_registered_duration;
  656. // 设置期限为本周
  657. this.allDate = dates;
  658. this.dateRange = [new Date(dates[0]), new Date(dates[6])];
  659. var registered_count = [];
  660. for (let i = 0; i < dates.length; i++) {
  661. var key = dates[i].replace(/"/g, "");
  662. var value = daily_registered_duration_count[key];
  663. registered_count[key] = value;
  664. }
  665. this.registered_map = registered_count;
  666. }
  667. })
  668. .catch(function (error) {
  669. console.error("Gitee客户端异常,获取工时失败");
  670. });
  671. this.get_last_week_time()
  672. .then((result) => {
  673. if (result != null) {
  674. var all_registered_duration = result.all_registered_duration;
  675. this.last_work_time = all_registered_duration;
  676. }
  677. })
  678. .catch(function (error) {
  679. console.error("Gitee客户端异常,获取工时失败");
  680. });
  681. // 获取截止到本周日的所有工作任务,排除需求,并赋值给talbeData
  682. this.send_issue_week_data_request();
  683. },
  684. methods: {
  685. // 查看任务和工时分布情况
  686. handleDetail(xq, rq, gs, type) {
  687. this.tableIssueData = [];
  688. this.showIssueTable = true;
  689. this.xq = xq;
  690. this.rq = rq;
  691. this.gs = gs;
  692. var enterprisePath = localStorage.getItem("enterprisePath");
  693. if (type == 1) {
  694. // 拿到日期和工时,重新打开弹窗表格,显示当前内容
  695. for (const key in this.tableData) {
  696. // 获取任务的编码
  697. const id = this.tableData[key].id;
  698. // 发送请求,获取登记工时日志
  699. this.getWorkLog(id).then((result) => {
  700. const data_list = result.data;
  701. if (data_list.length != 0) {
  702. for (const _key in data_list) {
  703. if (data_list[_key].registered_at == rq) {
  704. this.tableData[key].gs = data_list[_key].duration
  705. this.tableData[key].link = "https://e.gitee.com/" + enterprisePath + "/dashboard?issue=" + this.tableData[key].ident + "&issue_detail_tab=work-time"
  706. this.tableIssueData.push(this.tableData[key])
  707. }
  708. }
  709. }
  710. })
  711. .catch(function (error) {
  712. console.error("Gitee客户端异常,获取本周任务列表工时");
  713. });
  714. }
  715. } else {
  716. this.getIssuseLastWeekDataByUserAndPlanTime().then((result) => {
  717. // 获取到上周的任务列表
  718. const last_data_list = result.data;
  719. for (const key in last_data_list) {
  720. // 获取任务的编码
  721. const id = last_data_list[key].id;
  722. // 发送请求,获取登记工时日志
  723. this.getWorkLog(id).then((result) => {
  724. const data_list = result.data;
  725. if (data_list.length != 0) {
  726. for (const _key in data_list) {
  727. if (data_list[_key].registered_at == rq) {
  728. last_data_list[key].gs = data_list[_key].duration
  729. last_data_list[key].link = "https://e.gitee.com/" + enterprisePath + "/dashboard?issue=" + last_data_list[key].ident + "&issue_detail_tab=work-time"
  730. this.getPrograms().then((result) => {
  731. const programs_list = result.data;
  732. for (const program_key in programs_list) {
  733. if (programs_list[program_key].id == last_data_list[key].program_id) {
  734. // 继续发送请求,获取任务的类型列表
  735. this.getIssuseTypeByProgram(programs_list[program_key].id).then((result) => {
  736. const issuseType_list = result.data;
  737. for (const type in issuseType_list) {
  738. if (issuseType_list[type].id == last_data_list[key].issue_type_id) {
  739. last_data_list[key].issue_type = {
  740. title: issuseType_list[type].title
  741. };
  742. this.tableIssueData.push(last_data_list[key])
  743. }
  744. }
  745. }).catch(function (error) {
  746. console.error("Gitee客户端异常,获取项目任务类型异常");
  747. });
  748. }
  749. }
  750. }).catch(function (error) {
  751. console.error("Gitee客户端异常,获取项目异常");
  752. });
  753.  
  754. }
  755. }
  756. }
  757. })
  758. .catch(function (error) {
  759. console.error("Gitee客户端异常,获取本周任务列表工时");
  760. });
  761.  
  762. }
  763. })
  764. .catch(function (error) {
  765. console.error("Gitee客户端异常,获取上周任务列表工时");
  766. });
  767. }
  768. },
  769. openNewTab(url) {
  770. window.open(url, '_blank');
  771. },
  772. // 鼠标浮动,重新获取数据
  773. fetchTableData(type) {
  774. if (type === 1) {
  775. // 当前属于获取本周的登记的工时详情
  776. this.get_week_time()
  777. .then((result) => {
  778. if (result != null) {
  779. var dates = result.dates;
  780. var daily_registered_duration_count =
  781. result.daily_registered_duration_count;
  782. for (const key in dates) {
  783. this.gridData[key].rq = dates[key]
  784. this.gridData[key].gs = daily_registered_duration_count[this.gridData[key].rq]
  785. }
  786. }
  787. })
  788. .catch(function (error) {
  789. console.error("Gitee客户端异常,获取工时失败");
  790. });
  791. } else {
  792. // 当前属于获取上周的工时详情
  793. this.get_last_week_time()
  794. .then((result) => {
  795. if (result != null) {
  796. var dates = result.dates;
  797. var all_registered_duration = result.daily_registered_duration_count;
  798. for (const key in dates) {
  799. this.gridData[key].rq = dates[key]
  800. this.gridData[key].gs = all_registered_duration[this.gridData[key].rq]
  801. }
  802. }
  803. })
  804. .catch(function (error) {
  805. console.error("Gitee客户端异常,获取工时失败");
  806. });
  807. }
  808.  
  809. },
  810. // 获取当前选中的选项
  811. handleSelectionChange(selection) {
  812. // 此处能够获取到当前选中的数据,我们可以通过将数据保存在一个新的数组中
  813. this.selectionDatas = selection;
  814. for (let index = 0; index < this.selectionDatas.length; index++) {
  815. const element = this.selectionDatas[index];
  816. console.log(element);
  817. }
  818. },
  819. // 显示任务清单表格
  820. showTableData() {
  821. this.showTable = !this.showTable;
  822. },
  823. // 隐藏多余按钮
  824. display_none_btn() {
  825. this.elements = document.querySelectorAll(
  826. ".ge-app-top-right .ge-app-top-nav"
  827. );
  828. for (let i = 0; i < this.elements.length; i++) {
  829. if (i === 0 || i === 1 || i === 3) {
  830. this.elements[i].style.display = "none";
  831. }
  832. }
  833. },
  834. // 创建GoogleChrome软件系统通知显示,需要开通GoogleChrome的通知权限
  835. showNotification(title, message) {
  836. var notification = new unsafeWindow.Notification(title, {
  837. body: message,
  838. icon: "https://e.gitee.com/assets/images/favicon.ico",
  839. });
  840. setTimeout(function () {
  841. notification.close();
  842. }, 4000);
  843. },
  844. // 获取周报状态
  845. get_week_reports() {
  846. const _this = this; // 保存正确的上下文
  847. const currentYear = new Date().getFullYear();
  848. return new Promise(function (resolve, reject) {
  849. _this
  850. .getRoluteStr()
  851. .then(function () {
  852. const xhr = new XMLHttpRequest();
  853. xhr.open(
  854. "GET",
  855. "https://api.gitee.com/enterprises/" +
  856. _this.roult_path +
  857. "/week_reports/my_reports?year=" +
  858. currentYear,
  859. true
  860. );
  861. // 设置XMLHttpRequest自动获取Cookie
  862. xhr.withCredentials = true;
  863.  
  864. xhr.onload = function () {
  865. if (xhr.readyState === 4) {
  866. if (xhr.status === 200) {
  867. const respbody = JSON.parse(xhr.responseText);
  868. const current_week = respbody.data[0];
  869. const last_week = respbody.data[1];
  870. resolve({
  871. current_week: current_week,
  872. last_week: last_week,
  873. });
  874. } else {
  875. reject("Gitee客户端异常");
  876. }
  877. }
  878. };
  879.  
  880. xhr.onerror = function () {
  881. reject("周报获取异常");
  882. };
  883.  
  884. // 发送请求
  885. xhr.send(null);
  886. })
  887. .catch(function (error) {
  888. reject(error);
  889. });
  890. });
  891. },
  892. // 获取todo_num数量
  893. send_todo_num_request() {
  894. const _this = this;
  895. return new Promise(async function (resolve, reject) {
  896. await _this.getRoluteStr();
  897. var xhr = new XMLHttpRequest();
  898. xhr.open(
  899. "GET",
  900. "https://api.gitee.com/enterprises/" +
  901. _this.roult_path +
  902. "/issues/stat_count?todo=true&today=true&week=true&overdue=true&star=true&all=true",
  903. true
  904. );
  905. // 设置XMLHttpRequest 自动获取Cookie
  906. xhr.withCredentials = true;
  907. xhr.onload = function (e) {
  908. if (xhr.readyState === 4) {
  909. if (xhr.status === 200) {
  910. var respbody = JSON.parse(xhr.responseText);
  911. var issue_str = respbody.todo;
  912. resolve(issue_str); // 将获取到的值传递给 Promise 的 resolve 方法
  913. } else {
  914. reject("Gitee客户端异常");
  915. }
  916. }
  917. };
  918. xhr.onerror = function (e) {
  919. reject("信息获取异常");
  920. };
  921. // 发送请求
  922. xhr.send(null);
  923. });
  924. },
  925. // 获取任务总集合
  926. send_issue_data_request(todo_nums) {
  927. const _this = this;
  928. return new Promise(async function (resolve, reject) {
  929. await _this.getRoluteStr();
  930. var xhr = new XMLHttpRequest();
  931. xhr.open(
  932. "GET",
  933. "https://api.gitee.com/enterprises/" +
  934. _this.roult_path +
  935. "/issues?state=open,progressing&only_related_me=1&page=1&offset=0&per_page=" +
  936. todo_nums,
  937. true
  938. );
  939. // 设置XMLHttpRequest 自动获取Cookie
  940. xhr.withCredentials = true;
  941. xhr.onload = function (e) {
  942. if (xhr.readyState === 4) {
  943. if (xhr.status === 200) {
  944. var work_json = xhr.responseText;
  945. var issueData = new issue_data();
  946. issueData = JSON.parse(work_json);
  947. var issue = Object.assign(new issue_data(), issueData);
  948. resolve(issue);
  949. } else {
  950. reject("Gitee客户端异常");
  951. }
  952. }
  953. };
  954. xhr.onerror = function (e) {
  955. reject("信息获取异常");
  956. };
  957. // 发送请求
  958. xhr.send(null);
  959. });
  960. },
  961. // 获取本周任务总集合
  962. send_issue_week_data_request() {
  963. const _this = this;
  964. return new Promise(async function (resolve, reject) {
  965. await _this.getRoluteStr();
  966. var xhr = new XMLHttpRequest();
  967. xhr.open(
  968. "GET",
  969. "https://api.gitee.com/enterprises/" +
  970. _this.roult_path +
  971. "/issues?deadline_type=week&only_related_me=1",
  972. true
  973. );
  974. // 设置XMLHttpRequest 自动获取Cookie
  975. xhr.withCredentials = true;
  976. xhr.onload = function (e) {
  977. if (xhr.readyState === 4) {
  978. if (xhr.status === 200) {
  979. var work_json = xhr.responseText;
  980. var issueData = new issue_data();
  981. issueData = JSON.parse(work_json);
  982. for (let index = 0; index < issueData.data.length; index++) {
  983. const element = issueData.data[index];
  984. // 需要是自己的任务
  985. if (
  986. element.assignee.id ==
  987. JSON.parse(localStorage.getItem("gitee.user")).userInfo.id
  988. ) {
  989. // 不需要计算需求类型
  990. if (element.issue_type.id != 626336) {
  991. _this.tableData.push(element);
  992. }
  993. }
  994. }
  995. var issue = Object.assign(new issue_data(), issueData);
  996. resolve(issue);
  997. } else {
  998. reject("Gitee客户端异常");
  999. }
  1000. }
  1001. };
  1002. xhr.onerror = function (e) {
  1003. reject("信息获取异常");
  1004. };
  1005. // 发送请求
  1006. xhr.send(null);
  1007. });
  1008. },
  1009. // 计算时间差
  1010. get_hour_difference(deadline) {
  1011. var currentTime = new Date();
  1012. var specifiedTime = new Date(deadline);
  1013. if (currentTime <= specifiedTime) {
  1014. var diffMs = specifiedTime - currentTime;
  1015. var diffHours = Math.floor(diffMs / 1000 / 60 / 60);
  1016. return diffHours;
  1017. }
  1018. return null;
  1019. },
  1020. // 获取工时状态
  1021. get_week_time() {
  1022. // 获取当前日期
  1023. var currentDate = new Date();
  1024. // 获取当前日期是一周中的第几天(0-6,其中0表示星期日)
  1025. var currentDay = currentDate.getDay();
  1026. // 计算当前一周的第一天和最后一天的日期
  1027. var firstDayOfWeek = new Date(
  1028. currentDate.setDate(currentDate.getDate() - currentDay + 1)
  1029. );
  1030. var lastDayOfWeek = new Date(
  1031. currentDate.setDate(currentDate.getDate() - currentDay + 7)
  1032. );
  1033. // 创建一个数组来存储一周的日期
  1034. var weekDates = [];
  1035. // 循环获取一周的日期并将其存入数组
  1036. for (var i = 0; i <= 6; i++) {
  1037. var date = new Date(firstDayOfWeek);
  1038. date.setDate(firstDayOfWeek.getDate() + i);
  1039. weekDates.push(date);
  1040. }
  1041. // 遍历时间,格式化日期为"YYYY-MM-DD"的格式
  1042. var formattedDates = weekDates.map(function (date) {
  1043. var year = date.getFullYear();
  1044. var month = ("0" + (date.getMonth() + 1)).slice(-2);
  1045. var day = ("0" + date.getDate()).slice(-2);
  1046. return year + "-" + month + "-" + day;
  1047. });
  1048. // 当前一周的日期,传入工时接口
  1049. const _this = this;
  1050. return new Promise(async function (resolve, reject) {
  1051. await _this.getRoluteStr();
  1052. var xhr = new XMLHttpRequest();
  1053. xhr.open(
  1054. "GET",
  1055. "https://api.gitee.com/enterprises/" +
  1056. _this.roult_path +
  1057. "/statistics/user_daily_workloads_overview?search=" +
  1058. JSON.parse(localStorage.getItem("gitee.user")).userInfo
  1059. .username +
  1060. "&start_date=" +
  1061. formattedDates[0] +
  1062. "&end_date=" +
  1063. formattedDates[6],
  1064. true
  1065. );
  1066. xhr.withCredentials = true;
  1067. xhr.onload = function (e) {
  1068. if (xhr.readyState === 4) {
  1069. if (xhr.status === 200) {
  1070. var respbody = JSON.parse(xhr.responseText);
  1071. var all_registered_duration =
  1072. respbody.all_registered_duration;
  1073. var daily_registered_duration_count =
  1074. respbody.daily_registered_duration_count;
  1075. var dates = respbody.dates;
  1076. resolve({
  1077. all_registered_duration: all_registered_duration,
  1078. daily_registered_duration_count:
  1079. daily_registered_duration_count,
  1080. dates: dates,
  1081. });
  1082. } else {
  1083. reject("Gitee客户端异常");
  1084. }
  1085. }
  1086. };
  1087. xhr.onerror = function (e) {
  1088. reject("工时获取异常");
  1089. };
  1090. xhr.send(null);
  1091. });
  1092. },
  1093. // 获取上周的工时
  1094. get_last_week_time() {
  1095. // 获取当前日期
  1096. var currentDate = new Date();
  1097. // 计算上周的第一天和最后一天的日期
  1098. var firstDayOfLastWeek = new Date(
  1099. currentDate.setDate(
  1100. currentDate.getDate() - currentDate.getDay() - 6
  1101. )
  1102. );
  1103. // 创建一个数组来存储上周的日期
  1104. var weekDates = [];
  1105. // 循环获取上周的日期并将其存入数组
  1106. for (var i = 0; i <= 6; i++) {
  1107. var date = new Date(firstDayOfLastWeek);
  1108. date.setDate(firstDayOfLastWeek.getDate() + i);
  1109. weekDates.push(date);
  1110. }
  1111. // 遍历时间,格式化日期为"YYYY-MM-DD"的格式
  1112. var formattedDates = weekDates.map(function (date) {
  1113. var year = date.getFullYear();
  1114. var month = ("0" + (date.getMonth() + 1)).slice(-2);
  1115. var day = ("0" + date.getDate()).slice(-2);
  1116. return year + "-" + month + "-" + day;
  1117. });
  1118. // 当前一周的日期,传入工时接口
  1119. const _this = this;
  1120. return new Promise(async function (resolve, reject) {
  1121. await _this.getRoluteStr();
  1122. var xhr = new XMLHttpRequest();
  1123. xhr.open(
  1124. "GET",
  1125. "https://api.gitee.com/enterprises/" +
  1126. _this.roult_path +
  1127. "/statistics/user_daily_workloads_overview?search=" +
  1128. JSON.parse(localStorage.getItem("gitee.user")).userInfo
  1129. .username +
  1130. "&start_date=" +
  1131. formattedDates[0] +
  1132. "&end_date=" +
  1133. formattedDates[6],
  1134. true
  1135. );
  1136. xhr.withCredentials = true;
  1137. xhr.onload = function (e) {
  1138. if (xhr.readyState === 4) {
  1139. if (xhr.status === 200) {
  1140. var respbody = JSON.parse(xhr.responseText);
  1141. var all_registered_duration =
  1142. respbody.all_registered_duration;
  1143. var daily_registered_duration_count =
  1144. respbody.daily_registered_duration_count;
  1145. var dates = respbody.dates;
  1146. resolve({
  1147. all_registered_duration: all_registered_duration,
  1148. daily_registered_duration_count:
  1149. daily_registered_duration_count,
  1150. dates: dates,
  1151. });
  1152. } else {
  1153. reject("上周工时获取异常");
  1154. }
  1155. }
  1156. };
  1157. xhr.onerror = function (e) {
  1158. reject("上周工时获取异常");
  1159. };
  1160. xhr.send(null);
  1161. });
  1162. },
  1163. showCalendarOnMouseover() {
  1164. this.showCalendar = true;
  1165. },
  1166. isSpecifiedDate(date) {
  1167. // 根据你的指定日期进行判断逻辑
  1168. var current_time = new Date(date);
  1169. const specifiedDate = new Date();
  1170. // 分别获取日期对象的年、月、日
  1171. const yearMatched =
  1172. current_time.getFullYear() === specifiedDate.getFullYear();
  1173. const monthMatched =
  1174. current_time.getMonth() === specifiedDate.getMonth();
  1175. const dayMatched = current_time.getDate() === specifiedDate.getDate();
  1176. // 判断年、月、日是否都匹配
  1177. return yearMatched && monthMatched && dayMatched;
  1178. },
  1179. isInAllDate(dateTime) {
  1180. // 获取当前日期
  1181. var currentDate = new Date();
  1182.  
  1183. // 获取当前日期是一周中的第几天(0-6,其中0表示星期日)
  1184. var currentDay = currentDate.getDay();
  1185.  
  1186. // 计算当前一周的第一天和最后一天的日期
  1187. var firstDayOfWeek = new Date(
  1188. currentDate.setDate(currentDate.getDate() - currentDay + 1)
  1189. );
  1190. var lastDayOfWeek = new Date(
  1191. currentDate.setDate(currentDate.getDate() - currentDay + 7)
  1192. );
  1193.  
  1194. // 创建一个数组来存储一周的日期
  1195. var weekDates = [];
  1196.  
  1197. // 循环获取一周的日期并将其存入数组
  1198. for (var i = 0; i <= 6; i++) {
  1199. var date = new Date(firstDayOfWeek);
  1200. date.setDate(firstDayOfWeek.getDate() + i);
  1201. weekDates.push(date);
  1202. }
  1203.  
  1204. // 格式化日期为"YYYY-MM-DD"的格式
  1205. var formattedDates = weekDates.map(function (date) {
  1206. var year = date.getFullYear();
  1207. var month = ("0" + (date.getMonth() + 1)).slice(-2);
  1208. var day = ("0" + date.getDate()).slice(-2);
  1209. return year + "-" + month + "-" + day;
  1210. });
  1211. if (formattedDates.includes(dateTime)) {
  1212. return true;
  1213. } else {
  1214. return false;
  1215. }
  1216. },
  1217. getRoluteStr() {
  1218. const _this = this;
  1219. return new Promise(function (resolve, reject) {
  1220. var enterprisePath = localStorage.getItem("enterprisePath");
  1221. var xhr = new XMLHttpRequest();
  1222. xhr.open(
  1223. "GET",
  1224. "https://api.gitee.com/enterprises/basic_info?enterprise_path=" +
  1225. enterprisePath,
  1226. true
  1227. );
  1228. xhr.withCredentials = true;
  1229. xhr.onload = function (e) {
  1230. if (xhr.readyState === 4) {
  1231. if (xhr.status === 200) {
  1232. var respbody = JSON.parse(xhr.responseText);
  1233. var enterprises = respbody.enterprises;
  1234. const result = enterprises.find(
  1235. (obj) => obj.path === enterprisePath
  1236. );
  1237. resolve({ id: result.id });
  1238. } else {
  1239. reject("公司id获取异常");
  1240. }
  1241. }
  1242. };
  1243. xhr.onerror = function (e) {
  1244. reject("上周工时获取异常");
  1245. };
  1246. xhr.send(null);
  1247. });
  1248. },
  1249. getNoUseElement() {
  1250. return new Promise((resolve, reject) => {
  1251. const observer = new MutationObserver((mutationsList, observer) => {
  1252. const element = document.querySelector(
  1253. ".level-label.level-label--standard"
  1254. );
  1255. const avator = document.querySelector(".nav-item.user");
  1256. const reportView = document.querySelector(".reports-view");
  1257. const topNav = document.querySelectorAll(
  1258. ".ge-app-top-right .ge-app-top-nav"
  1259. );
  1260. if (element && avator && topNav && reportView) {
  1261. observer.disconnect(); // 停止观察DOM变化
  1262. resolve({ element, avator, topNav, reportView });
  1263. }
  1264. });
  1265. observer.observe(document.body, {
  1266. attributes: true,
  1267. childList: true,
  1268. subtree: true,
  1269. });
  1270. setTimeout(() => {
  1271. observer.disconnect();
  1272. reject(new Error("超时,未找到组件"));
  1273. }, 5000);
  1274. });
  1275. },
  1276. async hideComp() {
  1277. try {
  1278. const { element, avator, topNav, reportView } =
  1279. await this.getNoUseElement();
  1280. element.innerHTML = "Plus";
  1281. element.style.background = "linear-gradient(90deg,#c9e7ff,#f3bc4c)";
  1282. element.style.fontSize = "16px";
  1283. element.style.color = "#093978";
  1284. const svgContainer = document.createElement("div");
  1285. svgContainer.innerHTML = `<svg t="1696521690855" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="14197" width="16" height="16"><path d="M308.586 388.462c10.932 6.596 25.134 3.01 31.496-7.902 33.666-57.784 92.488-158.71 131.688-225.968 17.562-30.122 61.848-30.122 79.408 0 39.2 67.26 98.024 168.184 131.712 225.968 6.362 10.912 20.564 14.5 31.472 7.902 57.792-34.924 123.604-78.328 173.824-112.194 32.056-21.624 75.466 2.736 71.568 40.698-12.946 126.192-39.312 349.476-76.764 499.802-5.286 21.168-17.764 39.334-38.864 46.166-40.656 13.126-132.452 30.666-332.64 30.666-195.328 0-287.46-16.688-329.594-29.702-23.206-7.168-36.354-27.306-41.418-50.646-36.69-169.816-62.832-376.206-76.18-495.084-4.28-38.124 39.31-62.924 71.544-41.19 50.086 33.762 115.382 76.804 172.748 111.484z" fill="#FCBF28" p-id="14198"></path><path d="M646.4 602.4c0 33.6-100.8 179.2-134.4 179.2-33.6 0-134.4-145.6-134.4-179.2 0-33.6 100.8-179.2 134.4-179.2 33.6 0 134.4 145.6 134.4 179.2z" fill="#FFFFFF" p-id="14199"></path></svg>`;
  1286. avator.appendChild(svgContainer);
  1287. avator.style.position = "relative";
  1288. svgContainer.style.position = "absolute";
  1289. svgContainer.style.top = "3px";
  1290. svgContainer.style.left = "12px";
  1291. for (let i = 0; i < topNav.length; i++) {
  1292. if (i === 0 || i === 1 || i === 3) {
  1293. topNav[i].style.display = "none";
  1294. }
  1295. }
  1296. reportView.style.display = "flex";
  1297. } catch (error) {
  1298. console.error(error);
  1299. }
  1300. },
  1301. getWeekReportElement() {
  1302. return new Promise((resolve, reject) => {
  1303. const element = document.querySelector(".reports-view");
  1304. const ele = document.querySelector(".markdown-body.text-disabled");
  1305.  
  1306. if (element && ele) {
  1307. resolve({ element, ele });
  1308. } else {
  1309. const observer = new MutationObserver(
  1310. (mutationsList, observer) => {
  1311. const element = document.querySelector(".reports-view");
  1312. const ele = document.querySelector(
  1313. ".markdown-body.text-disabled"
  1314. );
  1315.  
  1316. if (element && ele) {
  1317. observer.disconnect();
  1318. resolve({ element, ele });
  1319. }
  1320. }
  1321. );
  1322.  
  1323. observer.observe(document.body, {
  1324. attributes: true,
  1325. childList: true,
  1326. subtree: true,
  1327. });
  1328.  
  1329. setTimeout(() => {
  1330. observer.disconnect();
  1331. reject(new Error("超时,未找到组件"));
  1332. }, 10000);
  1333. }
  1334. });
  1335. },
  1336. // api信息
  1337. chatAI() {
  1338. const _this = this; // 保存正确的上下文
  1339. _this.pushLoading = true;
  1340. var datas = _this.selectionDatas //选中的数据
  1341. var sendStr = "";
  1342. var respHtml = "";
  1343. _this.textarea // 文本域数据
  1344. _this.push // 直接推送开关
  1345. // 根据上面条件,进行逻辑处理
  1346. if (datas) {
  1347. for (let index = 0; index < datas.length; index++) {
  1348. const element = datas[index];
  1349. sendStr = sendStr + "完成了" + element.title + ";\n"
  1350. }
  1351. }
  1352. // 追加文本域内容
  1353. sendStr += _this.textarea + "\n下面,请按照我给的周报模版,根据上面的信息,给我生成一份精美的周报,丰富我的语句,语言表达简单清楚。除了周报模版的内容,不要输出多余的字\n### 本周工作总结\n1.\n2.\n#### 存在问题\n1.\n2.\n### 下周工作计划\n1.\n2.\n#### 需要支持\n1.\n2.";
  1354. var dataToSend = {
  1355. prompt: sendStr,
  1356. options: {
  1357. parentMessageId: ""
  1358. },
  1359. systemMessage: "You are ChatGPT, a large language model trained by OpenAI. Follow the user's instructions carefully. Respond using markdown.",
  1360. temperature: 0.8,
  1361. top_p: 1
  1362. };
  1363. GM_xmlhttpRequest({
  1364. method: 'POST',
  1365. url: 'http://w9.xjai.cc/api/chat-process',
  1366. data: JSON.stringify(dataToSend),
  1367. headers: {
  1368. 'Content-Type': 'application/json'
  1369. },
  1370. onload: function (response) {
  1371. if (response.status === 200) {
  1372. const resp = response.responseText;
  1373. let splittedText = resp.split("&KFw6loC9Qvy&");
  1374. let separator = '_______________________';
  1375. let codeStr = '希望以上内容能够为您清晰地呈现本周工作情况和下周计划,谢谢!';
  1376. const splitStr = splittedText[1].split(separator)[0].trim()
  1377. respHtml = splitStr.split(codeStr)[0].trim();
  1378. _this.textareaByAIShow = true;
  1379. _this.textareaByAI = respHtml;
  1380. if (_this.push) {
  1381. // 获取今天的日期
  1382. let now = new Date();
  1383. // 获取当前年份
  1384. let currentYear = now.getFullYear();
  1385. // 获取今年的第一天
  1386. let startOfYear = new Date(now.getFullYear(), 0, 1);
  1387. // 计算今天是今年的第几天
  1388. let diff = now.getTime() - startOfYear.getTime();
  1389. let oneDay = 1000 * 60 * 60 * 24;
  1390. let dayOfYear = Math.floor(diff / oneDay) + 1;
  1391. // 计算今天是第几周
  1392. let weekNumber = Math.ceil(dayOfYear / 7);
  1393.  
  1394. var xhr = new XMLHttpRequest();
  1395. const contentText = {
  1396. content: respHtml,
  1397. pull_request_ids: [],
  1398. issue_ids: [],
  1399. event_ids: []
  1400. }
  1401. xhr.open(
  1402. "PUT",
  1403. "https://api.gitee.com/enterprises/" + _this.roult_path + "/week_reports/" + JSON.parse(localStorage.getItem("gitee.user")).userInfo.username + "/" + currentYear + "/" + weekNumber,
  1404. true
  1405. );
  1406. xhr.setRequestHeader('Content-Type', 'application/json');
  1407. xhr.withCredentials = true;
  1408. xhr.onload = function (e) {
  1409. if (xhr.readyState === 4) {
  1410. if (xhr.status === 200) {
  1411. _this.pushLoading = false;
  1412. _this.showTable = !_this.showTable;
  1413. _this.$message({
  1414. type: "success",
  1415. message: "周报推送成功"
  1416. });
  1417. } else {
  1418. _this.pushLoading = false;
  1419. _this.$message({
  1420. type: "error",
  1421. message: "周报推送失败"
  1422. });
  1423. }
  1424. }
  1425. };
  1426. xhr.onerror = function (e) {
  1427. };
  1428. xhr.send(JSON.stringify(contentText));
  1429. } else {
  1430. _this.pushLoading = false;
  1431. }
  1432. } else {
  1433. _this.pushLoading = false;
  1434. console.error('GPT网络异常:', response.status);
  1435. }
  1436. },
  1437. onerror: function (err) {
  1438. _this.pushLoading = false;
  1439. console.error('发送错误,请重试', err);
  1440. }
  1441. });
  1442. },
  1443. // 发送周报
  1444. pushHtml() {
  1445. const _this = this; // 保存正确的上下文
  1446. _this.pushGiteeLoading = true;
  1447. // 获取今天的日期
  1448. let now = new Date();
  1449. // 获取当前年份
  1450. let currentYear = now.getFullYear();
  1451. // 获取今年的第一天
  1452. let startOfYear = new Date(now.getFullYear(), 0, 1);
  1453. // 计算今天是今年的第几天
  1454. let diff = now.getTime() - startOfYear.getTime();
  1455. let oneDay = 1000 * 60 * 60 * 24;
  1456. let dayOfYear = Math.floor(diff / oneDay) + 1;
  1457. // 计算今天是第几周
  1458. let weekNumber = Math.ceil(dayOfYear / 7);
  1459.  
  1460. var xhr = new XMLHttpRequest();
  1461. const contentText = {
  1462. content: _this.textareaByAI,
  1463. pull_request_ids: [],
  1464. issue_ids: [],
  1465. event_ids: []
  1466. }
  1467. xhr.open(
  1468. "PUT",
  1469. "https://api.gitee.com/enterprises/" + _this.roult_path + "/week_reports/" + JSON.parse(localStorage.getItem("gitee.user")).userInfo.username + "/" + currentYear + "/" + weekNumber,
  1470. true
  1471. );
  1472. xhr.setRequestHeader('Content-Type', 'application/json');
  1473. xhr.withCredentials = true;
  1474. xhr.onload = function (e) {
  1475. if (xhr.readyState === 4) {
  1476. if (xhr.status === 200) {
  1477. _this.pushGiteeLoading = false;
  1478. _this.showTable = !_this.showTable;
  1479. _this.$message({
  1480. type: "success",
  1481. message: "周报推送成功"
  1482. });
  1483. } else {
  1484. _this.pushGiteeLoading = false;
  1485. _this.$message({
  1486. type: "error",
  1487. message: "周报推送失败"
  1488. });
  1489. }
  1490. }
  1491. };
  1492. xhr.onerror = function (e) {
  1493. };
  1494. xhr.send(JSON.stringify(contentText));
  1495. },
  1496. getWorkLog(id) {
  1497. const _this = this;
  1498. return new Promise(function (resolve, reject) {
  1499. _this.getRoluteStr()
  1500. var xhr = new XMLHttpRequest();
  1501. xhr.open(
  1502. "GET",
  1503. "https://api.gitee.com/enterprises/" +
  1504. _this.roult_path + "/issues/" + id + "/workloads/logs",
  1505. true
  1506. );
  1507. xhr.withCredentials = true;
  1508. xhr.onload = function (e) {
  1509. if (xhr.readyState === 4) {
  1510. if (xhr.status === 200) {
  1511. var respbody = JSON.parse(xhr.responseText);
  1512. resolve({ data: respbody.data });
  1513. } else {
  1514. reject("任务单工时获取异常");
  1515. }
  1516. }
  1517. };
  1518. xhr.onerror = function (e) {
  1519. reject("任务单工时获取异常");
  1520. };
  1521. xhr.send(null);
  1522. });
  1523. },
  1524. getPrograms() {
  1525. const _this = this;
  1526. return new Promise(function (resolve, reject) {
  1527. _this.getRoluteStr()
  1528. var xhr = new XMLHttpRequest();
  1529. xhr.open(
  1530. "GET",
  1531. "https://api.gitee.com/enterprises/" +
  1532. _this.roult_path + "/programs",
  1533. true
  1534. );
  1535. xhr.withCredentials = true;
  1536. xhr.onload = function (e) {
  1537. if (xhr.readyState === 4) {
  1538. if (xhr.status === 200) {
  1539. var respbody = JSON.parse(xhr.responseText);
  1540. resolve({ data: respbody.data });
  1541. } else {
  1542. reject("公司项目获取异常");
  1543. }
  1544. }
  1545. };
  1546. xhr.onerror = function (e) {
  1547. reject("公司项目获取异常");
  1548. };
  1549. xhr.send(null);
  1550. });
  1551. },
  1552. getIssuseTypeByProgram(programId) {
  1553. const _this = this;
  1554. return new Promise(function (resolve, reject) {
  1555. _this.getRoluteStr()
  1556. var xhr = new XMLHttpRequest();
  1557. xhr.open(
  1558. "GET",
  1559. "https://api.gitee.com/enterprises/" +
  1560. _this.roult_path + "/issue_types/program_issue_types?program_id=" + programId,
  1561. true
  1562. );
  1563. xhr.withCredentials = true;
  1564. xhr.onload = function (e) {
  1565. if (xhr.readyState === 4) {
  1566. if (xhr.status === 200) {
  1567. var respbody = JSON.parse(xhr.responseText);
  1568. resolve({ data: respbody.data });
  1569. } else {
  1570. reject("公司项目获取异常");
  1571. }
  1572. }
  1573. };
  1574. xhr.onerror = function (e) {
  1575. reject("公司项目获取异常");
  1576. };
  1577. xhr.send(null);
  1578. });
  1579. },
  1580. getIssuseLastWeekDataByUserAndPlanTime() {
  1581. // 获取当前日期
  1582. const today = new Date();
  1583.  
  1584. // 获取今天是周几,周日为0,周一为1,依次类推
  1585. const currentDayOfWeek = today.getDay();
  1586.  
  1587. // 计算上周周一和周日的日期
  1588. const lastWeekMonday = new Date(today);
  1589. lastWeekMonday.setDate(today.getDate() - currentDayOfWeek - 6);
  1590.  
  1591. const lastWeekSunday = new Date(today);
  1592. lastWeekSunday.setDate(today.getDate() - currentDayOfWeek);
  1593.  
  1594. // 格式化日期为指定格式
  1595. function formatDate(date) {
  1596. const year = date.getFullYear();
  1597. const month = (date.getMonth() + 1).toString().padStart(2, '0');
  1598. const day = date.getDate().toString().padStart(2, '0');
  1599. return `${year}.${month}.${day}`;
  1600. }
  1601.  
  1602. // 获取格式化后的日期范围
  1603. const lastWeekStart = formatDate(lastWeekMonday);
  1604. const lastWeekEnd = formatDate(lastWeekSunday);
  1605. const timeBetween = `${lastWeekStart}-${lastWeekEnd}`;
  1606. const userId = JSON.parse(localStorage.getItem("gitee.user")).userInfo.id;
  1607. // 当前用户信息
  1608. const _this = this;
  1609. var params = {
  1610. "filter_conditions": [
  1611. { "property": "issue_plan_date", "comparator": "between", "value": timeBetween }
  1612. , { "property": "issue_assignee", "comparator": "contains", "value": [userId] }
  1613. ],
  1614. "mode": "tree",
  1615. "result_version": "v2"
  1616. };
  1617. return new Promise(function (resolve, reject) {
  1618. _this.getRoluteStr()
  1619. var xhr = new XMLHttpRequest();
  1620. xhr.open(
  1621. "POST",
  1622. "https://api.gitee.com/enterprises/" +
  1623. _this.roult_path + "/issues/as_table",
  1624. true
  1625. );
  1626. xhr.setRequestHeader('Content-Type', 'application/json');
  1627. xhr.withCredentials = true;
  1628. xhr.onload = function (e) {
  1629. if (xhr.readyState === 4) {
  1630. if (xhr.status === 201) {
  1631. var respbody = JSON.parse(xhr.responseText);
  1632. resolve({ data: respbody.issues });
  1633. }
  1634. }
  1635. };
  1636. xhr.onerror = function (e) {
  1637. };
  1638. xhr.send(JSON.stringify(params));
  1639. })
  1640. },
  1641. async addWeekReportTips(marquee) {
  1642. try {
  1643. const { element, ele } = await this.getWeekReportElement();
  1644. element.appendChild(marquee);
  1645. ele.style.display = "none";
  1646. } catch (error) {
  1647. console.error(error);
  1648. }
  1649. },
  1650. },
  1651. };
  1652. const app = Vue.createApp(App);
  1653. app.use(ElementPlus);
  1654. app.mount("#app");
  1655. };
  1656. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址