GitLab Assistant

GitLab Viewer Publish and Deploy Project!

当前为 2023-09-12 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name GitLab Assistant
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.09992
  5. // @description GitLab Viewer Publish and Deploy Project!
  6. // @author Sean
  7. // @match http://192.168.0.200*
  8. // @match http://192.168.0.200/*
  9. // @match http://192.168.0.200/fe3project/*
  10. // @match http://192.168.0.200/frontend_pc/project/*
  11. // @match https://oa.epoint.com.cn/interaction-design-portal/portal/pages/casestemplates/casetemplatesdetail*
  12. // @match https://oa.epoint.com.cn/interaction-design-portal/portal/pages/generalpagetemplates/generalpagetemplatesdetail*
  13. // @match https://oa.epoint.com.cn/interaction-design-portal/portal/pages/dynamiceffecttemplates/dynamiceffecttemplatesdetail*
  14. // @match http://192.168.201.159:9999/webapp/pages/default/onlinecase.html*
  15. // @match http://192.168.118.60:9999/webapp/pages/caselib/create.html*
  16. // @match https://oa.epoint.com.cn/epointoa9/frame/fui/pages/themes/aide/aide*
  17. // @match https://oa.epoint.com.cn/interaction-design-portal/portal/pages/casestemplates/casetemplateslist*
  18. // @match https://oa.epoint.com.cn:8080/OA9/oa9/mail/mailreceivedetail*
  19. // @icon http://192.168.0.200/assets/favicon-7901bd695fb93edb07975966062049829afb56cf11511236e61bcf425070e36e.png
  20. // @require https://cdn.bootcdn.net/ajax/libs/vue/2.7.14/vue.min.js
  21. // @require https://unpkg.com/element-ui/lib/index.js
  22. // @require https://cdn.bootcdn.net/ajax/libs/jszip/3.7.1/jszip.min.js
  23. // @grant GM_getResourceURL
  24. // @grant GM_addStyle
  25. // @grant GM_getResourceText
  26. // @resource ElementCSS https://unpkg.com/element-ui/lib/theme-chalk/index.css
  27. // @grant GM_xmlhttpRequest
  28. // @license MIT
  29. // @run-at document-end
  30. // ==/UserScript==
  31.  
  32.  
  33. // 个性化 gitlab 样式,
  34. // 满足项目详情多行显示,
  35. // 项目列表中的链接新窗口打开,
  36. // 搜索框 placeholder 个性化提示
  37. // 增加CodePipeline 入口等
  38. (function() {
  39. 'use strict';
  40.  
  41. let regs = [/^http:\/\/192\.168\.0\.200\/fe3project\//,
  42. /^http:\/\/192\.168\.0\.200\/frontend_pc\/project\//,
  43. /^http:\/\/192\.168\.0\.200/,
  44. /^http:\/\/192\.168\.0\.200\//];
  45. let match = false;
  46.  
  47. for(let r = 0, lr = regs.length; r < lr; r++) {
  48. if(regs[r].test(location.href)) {
  49. match = true;
  50. break;
  51. }
  52. }
  53.  
  54. if(!match) {
  55. return;
  56. }
  57.  
  58. // 注入样式:改变容器宽度,项目描述多行展示
  59. let injectStyle = ".group-list-tree .group-row-contents .description p { white-space: normal; } .container-limited.limit-container-width { max-width: 1400px } .limit-container-width .info-well {max-width: none;}";
  60.  
  61. injectStyle += ".container-fluid.container-limited.limit-container-width .file-holder.readme-holder.limited-width-container .file-content {max-width: none;}"
  62. injectStyle += 'button:focus {outline-color: transparent !important;}'
  63. injectStyle += '.has-description .description {word-break: break-all;}'
  64. // 添加注入样式
  65. let extraStyleElement = document.createElement("style");
  66. extraStyleElement.innerHTML = injectStyle;
  67. document.head.appendChild(extraStyleElement);
  68.  
  69. const fontUrl = 'https://element.eleme.io/2.11/static/element-icons.535877f.woff';
  70.  
  71. // 添加样式规则,将字体应用到指定元素上
  72. GM_addStyle(`
  73. @font-face {
  74. font-family: element-icons;
  75. src: url(${fontUrl}) format("woff");
  76. }
  77. `);
  78.  
  79. GM_addStyle(GM_getResourceText('ElementCSS'));
  80.  
  81. // 改变列表打开链接方式,改为新窗口打开
  82. let change = false;
  83. let tryTimes = 3;
  84.  
  85. function changeOpenType() {
  86. if(!change){
  87. setTimeout(()=> {
  88. let links = document.querySelectorAll('.description a');
  89. if(links.length) {
  90. for(let i = 0, l = links.length; i < l; i++) {
  91. links[i].target = "_blank";
  92. if(i === l - 1) {
  93. change = true;
  94. }
  95. }
  96. } else {
  97. changeOpenType();
  98. }
  99. }, 1000);
  100. }
  101. }
  102.  
  103. function stopLinkProp() {
  104. setTimeout(()=> {
  105. const links = document.querySelectorAll('.description a');
  106. for(let i = 0, l = links.length; i < l; i++) {
  107. links[i].addEventListener('click', ()=> {
  108. event.stopPropagation();
  109. });
  110. }
  111. }, 1000);
  112. }
  113.  
  114. // 等待页面加载完成
  115. window.addEventListener('load', function() {
  116.  
  117. var targetDiv = document.querySelector('section');
  118.  
  119. if(targetDiv) {
  120. // 创建一个 Mutation Observer 实例
  121. var observer = new MutationObserver(function(mutations) {
  122. // 在这里处理 div 子元素的变化
  123. mutations.forEach(function(mutation) {
  124. if(mutation.addedNodes && mutation.addedNodes.length) {
  125. change = false;
  126. changeOpenType();
  127.  
  128. stopLinkProp();
  129. }
  130. });
  131. });
  132.  
  133. // 配置 Mutation Observer
  134. var config = { childList: true, subtree: true };
  135.  
  136. // 开始观察目标 div 元素
  137. observer.observe(targetDiv, config);
  138. }
  139.  
  140. const placeholder = document.createElement('div');
  141.  
  142. // 创建 Vue 实例并挂载到页面
  143. const vueInstance = new Vue({
  144. el: placeholder,
  145. methods: {
  146. // 进入管理平台 code pipeline
  147. manage() {
  148. window.open('http://192.168.219.170/code-pipeline')
  149. }
  150. },
  151. template: `<div id="my-ext" style="margin-top:4px;">
  152. <el-tooltip content="进入 Code Pipeline 管理平台" placement="top" effect="light">
  153. <el-button type="primary" icon="el-icon-attract" size="small" circle @click="manage"></el-button>
  154. </el-tooltip>
  155. </div>`
  156. });
  157.  
  158. // 将占位元素追加到 body 元素中
  159. document.querySelector('.title-container').appendChild(vueInstance.$el);
  160.  
  161. // 修改 placehodler
  162. const listInput = document.getElementById('group-filter-form-field');
  163. const listInput2 = document.getElementById('project-filter-form-field');
  164.  
  165. if(listInput) {
  166. listInput.setAttribute("placeholder", "按项目名称、日期、开发者搜索,关键字≥3");
  167. listInput.style.width = '305px';
  168. }
  169. if(listInput2) {
  170. listInput2.setAttribute("placeholder", "按项目名称、日期、开发者搜索,关键字≥3");
  171. listInput2.style.width = '305px';
  172. }
  173. });
  174.  
  175.  
  176. })();
  177.  
  178. (function(){
  179. function convertDateFormat(inputString) {
  180. // 匹配日期格式为yyyy-mm-dd或yyyy-m-dd或yyyy-mm-d或yyyy-m-d的正则表达式
  181. const dateRegex = /\d{4}-\d{1,2}-\d{1,2}/g;
  182.  
  183. // 找到所有匹配的日期格式
  184. const dates = inputString.match(dateRegex);
  185.  
  186. // 如果没有匹配到日期,则直接返回原始字符串
  187. if (!dates || dates.length === 0) {
  188. return inputString;
  189. }
  190.  
  191. // 遍历所有匹配到的日期,进行转换
  192. dates.forEach((date) => {
  193. const [year, month, day] = date.split('-');
  194. const formattedDate = `${parseInt(year, 10)}-${parseInt(month, 10)}-${parseInt(day, 10)}`;
  195. inputString = inputString.replace(date, formattedDate);
  196. });
  197.  
  198. return inputString;
  199. }
  200.  
  201. function getUrlParameters() {
  202. var params = {};
  203. var search = window.location.search.substring(1);
  204. var urlParams = search.split('&');
  205.  
  206. for (var i = 0; i < urlParams.length; i++) {
  207. var param = urlParams[i].split('=');
  208. var paramName = decodeURIComponent(param[0]);
  209. var paramValue = decodeURIComponent(param[1] || '');
  210. if(paramName) {
  211. params[paramName] = paramValue;
  212. }
  213. }
  214.  
  215. return params;
  216. }
  217.  
  218. window.convertDateFormat = convertDateFormat;
  219.  
  220. window.gitlabUtil = {
  221. getUrlParameters: getUrlParameters
  222. }
  223. })();
  224.  
  225. // GitLab Viewer Publish and Deploy Project
  226. // 查看项目、部署项目、发布项目功能
  227. // 添加搜索设计门户资源功能
  228. (function() {
  229. 'use strict';
  230. let regs = [/^http:\/\/192\.168\.0\.200\/fe3project\//,
  231. /^http:\/\/192\.168\.0\.200\/frontend_pc\/project\//];
  232. let match = false;
  233.  
  234. for(let r = 0, lr = regs.length; r < lr; r++) {
  235. if(regs[r].test(location.href)) {
  236. match = true;
  237. break;
  238. }
  239. }
  240.  
  241. if(!match) {
  242. return;
  243. }
  244. /*
  245. const fontUrl = 'https://element.eleme.io/2.11/static/element-icons.535877f.woff';
  246.  
  247. // 添加样式规则,将字体应用到指定元素上
  248. GM_addStyle(`
  249. @font-face {
  250. font-family: element-icons;
  251. src: url(${fontUrl}) format("woff");
  252. }
  253. `);
  254.  
  255. GM_addStyle(GM_getResourceText('ElementCSS'));
  256. */
  257.  
  258. let epointCss = ".epoint-tool {position: fixed; bottom: 0%; right:10px; transform: translateY(-40%);}";
  259. epointCss += ".el-row { padding: 6px 0;} .el-dialog__body .el-tree{min-height: 420px; max-height: 500px;overflow: auto;}";
  260. epointCss += ".view-toolbar {padding-bottom: 10px;}";
  261. epointCss += ".deploy-body {height: 306px;}"
  262. epointCss += ".el-loading-spinner {margin-top: -60px;} .el-button--primary:focus {outline: 0 !important;}";
  263.  
  264. // 添加注入样式
  265. let extraStyleElement = document.createElement("style");
  266. extraStyleElement.innerHTML = epointCss;
  267. document.head.appendChild(extraStyleElement);
  268.  
  269. const MyComponent = {
  270. template: `<div class="epoint-wrap">
  271. <div class="epoint-tool">
  272. <el-row>
  273. <el-tooltip content="查看项目页面和模块结构" placement="left" effect="light">
  274. <el-button type="primary" icon="el-icon-search" round @click="viewProject">查看</el-button>
  275. </el-tooltip>
  276. </el-row>
  277. <el-row>
  278. <el-tooltip content="一键部署到170服务器" placement="left" effect="light">
  279. <el-button type="primary" icon="el-icon-s-unfold" round @click="doDeploy">部署</el-button>
  280. </el-tooltip>
  281. </el-row>
  282. <el-row>
  283. <el-tooltip content="一键发布到项目案例库" placement="left" effect="light">
  284. <el-button type="primary" icon="el-icon-upload" round @click="publish">发布</el-button>
  285. </el-tooltip>
  286. </el-row>
  287. <el-row>
  288. <el-tooltip content="进入 Code Pipeline 管理平台进行更多操作" placement="left" effect="light">
  289. <el-button type="primary" icon="el-icon-attract" round @click="manage">管理</el-button>
  290. </el-tooltip>
  291. </el-row>
  292. </div>
  293. <el-dialog
  294. title="目录结构"
  295. width="900px"
  296. :append-to-body="true"
  297. :visible.sync="dialogVisible"
  298. :before-close="handleClose">
  299. <div class="view-body">
  300. <div class="view-toolbar" v-if="projectFtpUrl"><el-button type="primary" size="small" @click="viewAll">查看全部</el-button></div>
  301. <div class="view-content">
  302. <el-tree
  303. class="filter-tree"
  304. :data="data"
  305. :props="defaultProps"
  306. node-key="id"
  307. default-expand-all
  308. @node-click="handleNodeClick"
  309. v-loading="loadingTree"
  310. element-loading-background="rgba(255, 255, 255, 1)"
  311. element-loading-text="拼命加载中......"
  312. ref="tree">
  313. </el-tree>
  314. </div>
  315. </div>
  316. </el-dialog>
  317. <el-dialog
  318. title="部署"
  319. width="420px"
  320. :visible.sync="depDialogVisible">
  321. <div class="deploy-body"
  322. v-loading="loading"
  323. element-loading-text="正在打包部署至 170 服务器,请耐心等待"
  324. element-loading-spinner="el-icon-loading">
  325. </div>
  326. </el-dialog>
  327. <el-dialog title="部署提示" width="640px" :visible.sync="dialogDeployVisible">
  328. <el-alert
  329. title="此操作将把 GitLab 资源打包部署至 170 服务器,已部署过的项目会进行覆盖部署,是否继续?"
  330. type="warning" :closable="false" style="margin-bottom: 20px;">
  331. </el-alert>
  332. <el-form :model="form" ref="form" :rules="rules">
  333. <el-form-item label="框架类型" :label-width="formLabelWidth" prop="frame">
  334. <el-select v-model="form.frame" placeholder="请框架类型">
  335. <el-option v-for="item in framework" :key="item.value" :label="item.label" :value="item.value"></el-option>
  336. </el-select>
  337. </el-form-item>
  338. </el-form>
  339. <div slot="footer" class="dialog-footer">
  340. <el-button @click="dialogDeployVisible = false">取 消</el-button>
  341. <el-button type="primary" @click="doDeploy">确 定</el-button>
  342. </div>
  343. </el-dialog>
  344. </div>`,
  345. data() {
  346. return {
  347. dialogVisible: false, // 查看目录结构弹窗
  348. data: [], // 目录结构树的数据结构
  349. defaultProps: {
  350. children: 'children',
  351. label: 'label'
  352. },
  353. loadingTree: false,
  354. depDialogVisible: false, // 部署中弹窗
  355. loading: false,
  356. projectLibUrl: 'http://192.168.118.60:9999/webapp/pages/caselib/create.html', // 项目案例库地址
  357. projectIsDeployed: false, // 项目是否部署过
  358. projectFtpUrl: '', // ftp路径
  359. projectEntryUrl: '', // 项目案例库发布表单的入口页面
  360. supportDeploy: true, // 项目是否支持部署
  361. dialogDeployVisible: false,
  362. formLabelWidth: '120px',
  363. form: {
  364. frame: ''
  365. },
  366. framework: [
  367. {label: '重构模板', value: 1},
  368. {label: 'f9x1.0', value: 2},
  369. {label: 'f9x2.0', value: 3},
  370. {label: 'f950', value: 4},
  371. {label: 'f950sp1', value: 5},
  372. {label: 'f950sp2', value: 6},
  373. {label: 'f950sp3', value: 7},
  374. {label: 'f951', value: 18},
  375. {label: 'f940', value: 8},
  376. {label: 'f941', value: 10},
  377. {label: 'f942', value: 9},
  378. {label: 'f934', value: 11},
  379. {label: 'f933', value: 12},
  380. {label: 'f932', value: 13},
  381. {label: 'f9211', value: 14},
  382. {label: '骨架', value: 15},
  383. {label: 'Vue', value: 16},
  384. {label: 'React', value: 17}
  385. ],
  386. rules: {
  387. frame: [
  388. { required: true, message: '请选择框架类型', trigger: 'change' }
  389. ]
  390. },
  391. clickNodeEntry: null
  392. };
  393. },
  394. methods: {
  395. handleClose(done) {
  396. done();
  397. /*
  398. this.$confirm('确认关闭?')
  399. .then(_ => {
  400. done();
  401. })
  402. .catch(_ => {});*/
  403. },
  404. handleNodeClick(data) {
  405. console.log(data);
  406. if(data.type === 'folder') {
  407. return false;
  408. }
  409. var self = this;
  410. var entry = data.entry;
  411. self.clickNodeEntry = entry;
  412. if(self.projectFtpUrl) {
  413. window.open('http://192.168.219.170' + self.projectFtpUrl + data.entry);
  414. self.clickNodeEntry = null;
  415. } else {
  416. if(this.supportDeploy === false) {
  417. this.$message({
  418. type: 'error',
  419. message: '当前项目暂时只支持查看,请耐心等待功能升级。'
  420. });
  421. self.clickNodeEntry = null;
  422. return false;
  423. }
  424.  
  425. this.$confirm('资源未部署,部署至 170 服务器后可查看,是否部署?')
  426. .then(_ => {
  427.  
  428. this.dialogDeployVisible = true;
  429. /*
  430. this.depDialogVisible = true;
  431. this.loading = true;
  432. // 部署
  433. this.getDeployInfo({ type: '1' }, (data)=> {
  434. this.loading = false;
  435. this.depDialogVisible = false;
  436.  
  437. this.data = data.custom.detail;
  438. this.projectFtpUrl = data.custom.ftpUrl;
  439.  
  440. this.$alert('部署成功!', '提示', {
  441. confirmButtonText: '确定',
  442. callback: action => {
  443. window.open('http://192.168.219.170' + self.projectFtpUrl + entry)
  444. }
  445. });
  446.  
  447. });*/
  448. })
  449. .catch(_ => {});
  450. }
  451. },
  452. // 部署
  453. doDeploy () {
  454. if(!this.isDownLoadPage()) {
  455. return;
  456. }
  457. if(!this.dialogDeployVisible) {
  458. this.dialogDeployVisible = true;
  459. return;
  460. }
  461.  
  462. let self = this;
  463.  
  464. this.$refs['form'].validate((valid) => {
  465. if (valid) {
  466. this.dialogDeployVisible = false;
  467. this.depDialogVisible = true;
  468. this.loading = true;
  469. // 部署
  470. this.getDeployInfo({ type: '1', frame: this.form.frame }, (data)=> {
  471. this.loading = false;
  472. this.depDialogVisible = false;
  473.  
  474. if(!data.custom.text){
  475.  
  476. this.data = data.custom.pageTreeData;
  477. this.projectFtpUrl = data.custom.projectRootPath;
  478. this.supportDeploy = data.custom.supportDeploy;
  479.  
  480. this.setProjectEntry();
  481. // 从部署按钮直接过来的
  482. if(!this.clickNodeEntry) {
  483. this.$message({
  484. type: 'success',
  485. message: '部署成功!'
  486. });
  487. // 打开查看弹窗
  488. this.viewProject();
  489. } else {// 从点击目录结构过来的,可以调整点击的树节点页面
  490. this.$alert('部署成功!', '提示', {
  491. confirmButtonText: '确定',
  492. callback: action => {
  493. window.open('http://192.168.219.170' + self.projectFtpUrl + self.clickNodeEntry);
  494. self.clickNodeEntry = null;
  495. }
  496. });
  497. }
  498.  
  499. } else {
  500. this.$message({
  501. type: 'error',
  502. message: data.custom.text
  503. });
  504. }
  505. });
  506. } else {
  507. console.log('error submit!!');
  508. return false;
  509. }
  510. });
  511.  
  512. /*
  513. this.$confirm('此操作将把 GitLab 资源打包部署至 170 服务器,已部署过的项目会进行覆盖部署,是否继续?', '提示', {
  514. confirmButtonText: '确定',
  515. cancelButtonText: '取消',
  516. type: 'warning'
  517. }).then(() => {
  518. }).catch(() => {
  519. this.$message({
  520. type: 'info',
  521. message: '已取消部署'
  522. });
  523. });*/
  524. },
  525. // 发布项目案例库
  526. publish () {
  527. this.$confirm('此操作将把项目发布至 <a href="'+ this.projectLibUrl +'" target="_blank">项目案例库</a>,已发布过的项目案例库会有重复项,是否继续?', '提示', {
  528. confirmButtonText: '确定',
  529. cancelButtonText: '取消',
  530. dangerouslyUseHTMLString: true,
  531. type: 'warning'
  532. }).then(() => {
  533. const themes = document.querySelectorAll('.badge-secondary');
  534. let keys = [];
  535.  
  536. for(let i = 0, l = themes.length; i < l; i++) {
  537. if(themes[0].innerText == '智能设备' && i > 0) {
  538. keys.push(themes[i].innerText);
  539. } else if (themes[0].innerText !== '智能设备' && i > 1) {
  540. keys.push(themes[i].innerText);
  541. }
  542. }
  543. // 存在更多主题的情况
  544. const moreKeyEl = document.querySelector('.gl-w-full .text-nowrap');
  545. if(moreKeyEl) {
  546. const moreKeyElContent = moreKeyEl.getAttribute('data-content');
  547. const regex = />([^<]+)</g;
  548. const matches = moreKeyElContent.match(regex);
  549. const results = matches.filter(function(match) {
  550. return match.length > 3;
  551. });
  552. const moreKeyData = results.map(function(match) {
  553. return match.substring(2, match.length - 2);
  554. });
  555.  
  556. if(moreKeyData && moreKeyData.length) {
  557. keys = keys.concat(moreKeyData);
  558. }
  559. }
  560.  
  561. // 组织项目案例库所需参数
  562. const projectName = document.querySelector('.home-panel-title').innerText;
  563. const projectBU = themes[0] ? themes[0].innerText : null;
  564. const projectKeys = keys.join(' ');
  565. const entryUrl = this.projectEntryUrl;
  566. let projectType = themes[1] ? themes[1].innerText : null;
  567.  
  568. if(themes[0]) {
  569. if(themes[0].innerText == '智能设备') {
  570. projectType = themes[1] ? themes[0].innerText : null;
  571. } else {
  572. projectType = themes[1] ? themes[1].innerText : null;
  573. }
  574. }
  575.  
  576. const destUrl = this.projectLibUrl + '?projectName=' + projectName + '&projectBU=' + projectBU + '&projectType=' + projectType + '&projectKeys=' + projectKeys + '&entryUrl=' + entryUrl + '&git=' + window.location.href;
  577.  
  578. this.$message({
  579. type: 'success',
  580. message: destUrl
  581. });
  582.  
  583. window.open(destUrl);
  584.  
  585. }).catch(() => {
  586. this.$message({
  587. type: 'info',
  588. message: '已取消发布'
  589. });
  590. });
  591. },
  592. // 查看项目
  593. viewProject () {
  594. if(!this.isDownLoadPage()) {
  595. return;
  596. }
  597. this.dialogVisible = true;
  598. this.loadingTree = true;
  599. let self = this;
  600.  
  601. // 发送ajax请求,查看是否进行过部署
  602. this.getDeployInfo((data)=> {
  603. // 有部署信息,直接赋值,
  604. if(data) {
  605. self.projectIsDeployed = true;
  606. self.data = data.custom.pageTreeData;
  607. self.projectFtpUrl = data.custom.projectRootPath;
  608. self.supportDeploy = data.custom.supportDeploy;
  609. self.loadingTree = false;
  610.  
  611. self.setProjectEntry();
  612.  
  613. } else {
  614. // 无部署信息,仅查看文件目录
  615. getZipResource((data)=> {
  616. self.data = data;
  617. self.loadingTree = false;
  618. });
  619. }
  620. });
  621.  
  622. },
  623. // 查看项目的所有页面
  624. viewAll() {
  625. window.open('http://192.168.219.170/code-pipeline/#/project/deploy-preview?rowguid=' + document.body.getAttribute('data-project-id'));
  626. },
  627. // 项目部署信息
  628. getDeployInfo(params, callback) {
  629. const projectId = document.body.getAttribute('data-project-id');
  630. const downloadBtn = document.querySelector('.gl-button.btn-sm.btn-confirm');
  631.  
  632. const sourceUrl = downloadBtn.getAttribute('href');
  633. const downloadUrl = window.location.origin + sourceUrl;
  634. const files = document.body.getAttribute('data-find-file').split('/');
  635. const name = document.body.getAttribute('data-project') + '-' + files[files.length - 1];
  636. const author = document.querySelector('.current-user .gl-font-weight-bold').innerText.trim();
  637. const projectName = document.querySelector('.sidebar-context-title').innerText.trim();
  638. const deployManOA = document.querySelector('.current-user>a').getAttribute('data-user');
  639. const projectGitUrl = 'http://192.168.0.200' + document.body.getAttribute('data-find-file').split('/-/')[0];
  640.  
  641. if(typeof params == 'function') {
  642. callback = params;
  643. params = null;
  644. }
  645.  
  646. if(projectId && projectId.length && sourceUrl) {
  647. fetch('http://192.168.219.170:3008/api/getDeployInfo', {
  648. method: 'POST',
  649. // 允许跨域请求
  650. mode: 'cors',
  651. headers: {
  652. 'Accept': 'application/json',
  653. 'Content-Type': 'application/json'
  654. },
  655. body: JSON.stringify({//post请求参数
  656. params: {
  657. "type": (params && params.type !== undefined) ? params.type : '0',// 0 代表查看, 1代表部署
  658. "name": name, // 项目路径英文名
  659. "deployMan": author, // 部署人姓名
  660. "deployManOA": deployManOA, // 部署人账号
  661. "projectName": projectName, // 项目名称
  662. "downloadUrl": downloadUrl, // 下载地址
  663. "projectId": projectId, // 主键,gitlab上的项目id
  664. "projectGitUrl": projectGitUrl,
  665. "frame": (params && params.frame) ? params.frame : undefined
  666. }
  667. })
  668. })
  669. .then(response => response.text())
  670. .then((result) => {
  671. var data = JSON.parse(result);
  672. callback && callback(data);
  673. })
  674. .catch(error => {
  675. this.depDialogVisible = false;
  676. this.dialogVisible = false;
  677. this.$message({
  678. type: 'error',
  679. message: '系统故障,请联系管理员。'
  680. });
  681. console.error(error);
  682. });
  683. } else {
  684. this.$message({
  685. type: 'error',
  686. message: '本页不支持查看和部署,请至仓库页。'
  687. });
  688. console.error('部署信息请求参数error');
  689. }
  690. },
  691. // 进入管理平台 code pipeline
  692. manage() {
  693. window.open('http://192.168.219.170/code-pipeline')
  694. },
  695. // 设置入口
  696. setProjectEntry(){
  697. const firstNode = findFirstFileNode(this.data);
  698. if(firstNode) {
  699. this.projectEntryUrl = 'http://192.168.219.170' + this.projectFtpUrl + firstNode.entry;
  700. }else {
  701. this.projectEntryUrl = null;
  702. }
  703. },
  704. isDownLoadPage() {
  705. const downloadBtn = document.querySelector('.gl-button.btn-sm.btn-confirm');
  706. const sourceUrl = downloadBtn && downloadBtn.getAttribute('href');
  707.  
  708. if(downloadBtn && sourceUrl) {
  709. return true;
  710. } else {
  711. this.$message({
  712. type: 'error',
  713. message: '本页面不支持查看和部署,请移至仓库页。'
  714. });
  715. return false;
  716. }
  717. }
  718. },
  719. mounted() {
  720. }
  721. };
  722.  
  723. const placeholder = document.createElement('div');
  724.  
  725. // 创建 Vue 实例并挂载到页面
  726. const vueInstance = new Vue({
  727. el: placeholder,
  728. components: {
  729. MyComponent
  730. },
  731. methods: {
  732. },
  733. template: `<my-component></my-component>`
  734. });
  735.  
  736. // 开始在项目仓库页添加搜索设计门户按钮 start
  737. const panel = document.querySelector('.project-home-panel');
  738. let vueInstance2;
  739. const description = document.querySelector('.read-more-container');
  740. const descriptionText = description && description.innerText;
  741. let haveDesignBackupUrl = /casetemplatesdetail\?guid=(?!$)/.test(descriptionText);
  742.  
  743. if(panel && !haveDesignBackupUrl) {
  744. const btnPlaceholder = document.createElement('div');
  745. btnPlaceholder.setAttribute('class', 'epoint-portal-search');
  746. // 创建 Vue 实例并挂载到页面
  747. vueInstance2 = new Vue({
  748. el: btnPlaceholder,
  749. data: function() {
  750. return {
  751. proName: document.querySelector('.home-panel-title').innerText.trim().substring(0, 4)
  752. };
  753. },
  754. methods: {
  755. manage() {
  756. window.open('https://oa.epoint.com.cn/epointoa9/frame/fui/pages/themes/aide/aide?pageId=aide&redirect=https://oa.epoint.com.cn/interaction-design-portal/portal/pages/casestemplates/casetemplateslist?projectname' + this.proName)
  757. }
  758. },
  759. template: `<div style="margin-top:4px;">
  760. <el-tooltip content="新点设计门户中查找此项目" placement="top" effect="light">
  761. <el-button type="primary" icon="el-icon-search" size="small" @click="manage">查找UI备份地址</el-button>
  762. </el-tooltip>
  763. </div>`
  764. });
  765. // 开始在项目仓库页添加搜索设计门户按钮 end
  766. }
  767.  
  768.  
  769. // 等待页面加载完成
  770. window.addEventListener('load', function() {
  771. // 将占位元素追加到 body 元素中
  772. document.body.appendChild(vueInstance.$el);
  773.  
  774. panel && !haveDesignBackupUrl && panel.appendChild(vueInstance2.$el);
  775.  
  776. // 克隆按钮下增加sourcetree 快捷打开方式
  777. const dropMenu = document.querySelector('.clone-options-dropdown');
  778.  
  779. if(dropMenu) {
  780. // TODO 协议的方式需要优化,目前会多一个 sourcetree://
  781. let sourceTreeHtml = '<li class="pt-2 gl-new-dropdown-item">\
  782. <label class="label-bold gl-px-4!" xt-marked="ok">在您的Sourcetree中打开</label>\
  783. <a class="dropdown-item open-with-link" href="sourcetree://'+ document.getElementById('http_project_clone').value +'">\
  784. <div class="gl-new-dropdown-item-text-wrapper" xt-marked="ok">Sourcetree (HTTPS)</div></a></li>';
  785.  
  786. jQuery(dropMenu).append(sourceTreeHtml);
  787. }
  788. });
  789.  
  790. // 将文件条目组织成嵌套结构
  791. function organizeFileEntries(fileEntries) {
  792. const root = {
  793. label: document.querySelector('.home-panel-title').innerText || document.getElementById('project_name_edit').value,
  794. type: 'folder',
  795. children: []
  796. };
  797.  
  798. // 创建嵌套结构
  799. fileEntries.forEach(entry => {
  800. const pathSegments = entry.name.split('/');
  801. let currentFolder = root;
  802.  
  803. // 遍历路径中的每个部分,创建相应的文件夹节点
  804. for (let i = 0; i < pathSegments.length - 1; i++) {
  805. const folderName = pathSegments[i];
  806. let folder = currentFolder.children.find(child => child.label === folderName);
  807.  
  808. if(isExcludeFolder(entry.name)) {
  809. continue;
  810. }
  811.  
  812. if (!folder) {
  813. folder = {
  814. label: folderName,
  815. type: 'folder',
  816. children: []
  817. };
  818. currentFolder.children.push(folder);
  819. }
  820.  
  821. currentFolder = folder;
  822. }
  823.  
  824. // 创建文件节点并添加到相应的文件夹中
  825. const fileName = pathSegments[pathSegments.length - 1];
  826.  
  827. if(fileName && fileName.length && isIncludeFile(fileName) && !isExcludeFolder(entry.name)) {
  828. const fileNode = {
  829. label: fileName,
  830. type: 'file',
  831. entry: entry.name
  832. };
  833. currentFolder.children.push(fileNode);
  834. }
  835. });
  836.  
  837. return [root];
  838. }
  839. // 是否排除的文件夹
  840. function isExcludeFolder(entry) {
  841. if(entry.indexOf('css') > -1 ||
  842. entry.indexOf('scss') > -1 ||
  843. entry.indexOf('js') > -1 ||
  844. entry.indexOf('images') > -1 ||
  845. entry.indexOf('fui') > -1 ||
  846. entry.indexOf('lib') > -1 ||
  847. entry.indexOf('test') > -1 ||
  848. entry.indexOf('font') > -1 ||
  849. entry.indexOf('frame/fui') > -1) {
  850. return true;
  851. } else {
  852. return false;
  853. }
  854. }
  855. // 是否包含的文件
  856. function isIncludeFile(fileName) {
  857. if(fileName.indexOf('.html') > -1) {
  858. return true;
  859. } else {
  860. return false;
  861. }
  862. }
  863.  
  864. function getZipResource(callback) {
  865. const downloadUrl = window.location.origin + document.querySelector('.gl-button.btn-sm.btn-confirm').getAttribute('href');
  866.  
  867. fetch(downloadUrl)
  868. .then(response => response.arrayBuffer())
  869. .then(data => {
  870. // 将 ZIP 文件的二进制数据传递给 JSZip 进行解析
  871. return JSZip.loadAsync(data);
  872. })
  873. .then(zip => {
  874. // 获取 ZIP 文件中的所有条目(文件和目录)
  875. const zipEntries = Object.values(zip.files);
  876. const treeData = organizeFileEntries(zipEntries)
  877.  
  878. callback && callback(treeData);
  879.  
  880. })
  881. .catch(error => {
  882. console.error(error);
  883. });
  884. }
  885.  
  886. // 树结构第一个节点数据
  887. function findFirstFileNode(tree) {
  888. // 遍历树的节点
  889. for (let i = 0; i < tree.length; i++) {
  890. const node = tree[i];
  891.  
  892. // 如果节点的类型为 file,则返回该节点
  893. if (node.type === 'file') {
  894. return node;
  895. }
  896.  
  897. // 如果节点有子节点,则递归调用该函数查找子节点中的第一个 file 节点
  898. if (node.children && node.children.length > 0) {
  899. const fileNode = findFirstFileNode(node.children);
  900. if (fileNode) {
  901. return fileNode;
  902. }
  903. }
  904. }
  905.  
  906. // 如果没有找到 file 节点,则返回 null
  907. return null;
  908. }
  909. })();
  910.  
  911. // 修改项目描述的长度
  912. (function() {
  913. 'use strict';
  914. let regs = [/^http:\/\/192\.168\.0\.200\/fe3project\//,
  915. /^http:\/\/192\.168\.0\.200\/frontend_pc\/project\//];
  916. let match = false;
  917.  
  918. for(let r = 0, lr = regs.length; r < lr; r++) {
  919. if(regs[r].test(location.href)) {
  920. match = true;
  921. break;
  922. }
  923. }
  924.  
  925. if(!match) {
  926. return;
  927. }
  928.  
  929. let tryTimes = 6;
  930. let changed = false;
  931.  
  932. // 增加项目描述的输入长度
  933. function modifyTextareaLen() {
  934. if(tryTimes > 0 && !changed) {
  935. setTimeout(() => {
  936. const textarea = document.getElementById('project_description');
  937. tryTimes--;
  938. if(textarea) {
  939. textarea.setAttribute("maxlength", "1000");
  940.  
  941. jQuery(textarea).blur(function(event) {
  942. this.value = this.value.replace(/,/g, ',').replace(/&isfwqfb=1/g, '');
  943. this.value = convertDateFormat(this.value);
  944. jQuery(this).trigger('change');
  945. });
  946. changed = true;
  947. } else {
  948. modifyTextareaLen();
  949. }
  950. }, 1000);
  951. }
  952. }
  953.  
  954. window.onload = function() {
  955. modifyTextareaLen();
  956. }
  957. })();
  958.  
  959. // 设计门户增加通往前端仓库的跳板
  960. (function() {
  961. 'use strict';
  962.  
  963. let regs = [/^https:\/\/oa\.epoint\.com\.cn\/interaction-design-portal\/portal\/pages\/casestemplates\/casetemplatesdetail/,
  964. /^https:\/\/oa\.epoint\.com\.cn\/interaction-design-portal\/portal\/pages\/generalpagetemplates\/generalpagetemplatesdetail/,
  965. /^https:\/\/oa\.epoint\.com\.cn\/interaction-design-portal\/portal\/pages\/dynamiceffecttemplates\/dynamiceffecttemplatesdetail/];
  966. let match = false;
  967.  
  968. for(let r = 0, lr = regs.length; r < lr; r++) {
  969. if(regs[r].test(location.href)) {
  970. match = true;
  971. break;
  972. }
  973. }
  974.  
  975. if(!match) {
  976. return;
  977. }
  978.  
  979. function addStyle() {
  980. // 注入样式:增加按钮
  981. let injectStyle = ".content { position: relative; } .front-proto { position: absolute; top: 20px; right: 20px; width: 106px; height: 36px; border-radius: 4px; cursor: pointer; line-height: 36px; background: #25c2c9; color: #fff; text-align: center; font-size: 14px}";
  982.  
  983.  
  984. // 添加注入样式
  985. let extraStyleElement = document.createElement("style");
  986. extraStyleElement.innerHTML = injectStyle;
  987. document.head.appendChild(extraStyleElement);
  988. }
  989.  
  990. function getUrlParameters() {
  991. var params = {};
  992. var search = window.location.search.substring(1);
  993. var urlParams = search.split('&');
  994.  
  995. for (var i = 0; i < urlParams.length; i++) {
  996. var param = urlParams[i].split('=');
  997. var paramName = decodeURIComponent(param[0]);
  998. var paramValue = decodeURIComponent(param[1] || '');
  999. params[paramName] = paramValue;
  1000. }
  1001.  
  1002. return params;
  1003. }
  1004.  
  1005. window.onload = ()=> {
  1006. addStyle();
  1007. const $content = jQuery('.content');
  1008.  
  1009. $content.append('<div class="front-proto">前端原型</div>');
  1010.  
  1011. const $frontBtn = jQuery('.front-proto', $content);
  1012.  
  1013. $frontBtn.on('click', ()=> {
  1014. window.open('http://192.168.0.200/?name=' + getUrlParameters().guid);
  1015. });
  1016. };
  1017. })();
  1018.  
  1019. // 前端项目案例库增加获取参数的能力
  1020. // 前端项目案例库增加部署能力
  1021. (function() {
  1022. 'use strict';
  1023.  
  1024. let regs = [/^http:\/\/192\.168\.118\.60:9999\/webapp\/pages\/caselib\/create\.html/,
  1025. /^http:\/\/192\.168\.201\.159:9999\/webapp\/pages\/default\/onlinecase.html/];
  1026. let match = false;
  1027.  
  1028. for(let r = 0, lr = regs.length; r < lr; r++) {
  1029. if(regs[r].test(location.href)) {
  1030. match = true;
  1031. break;
  1032. }
  1033. }
  1034.  
  1035. if(!match) {
  1036. return;
  1037. }
  1038.  
  1039. const fontUrl = 'https://element.eleme.io/2.11/static/element-icons.535877f.woff';
  1040.  
  1041. // 添加样式规则,将字体应用到指定元素上
  1042. GM_addStyle(`
  1043. @font-face {
  1044. font-family: element-icons;
  1045. src: url(${fontUrl}) format("woff");
  1046. }
  1047. `);
  1048.  
  1049. GM_addStyle(GM_getResourceText('ElementCSS'));
  1050.  
  1051. const businessType = [
  1052. { Value: '7a20e23c-30b8-47e2-8d8d-f2691c9c63c4', Text: '政务服务' },
  1053. { Value: 'c12150bb-b358-452f-87f0-8a2254df87cb', Text: '政务协同' },
  1054. { Value: '3845804e-de68-421c-9402-7b238cfb5a70', Text: '大数据' },
  1055. { Value: '3c28ee56-f24d-4843-b9a2-93e6b96264f4', Text: '电子交易' },
  1056. { Value: '673b5918-51bc-4f1a-ab73-fca86e54d7d1', Text: '数字建设' },
  1057. { Value: '6d9e7d84-7de3-4e0f-bd4f-ed4722ed25b5', Text: '建筑企业' },
  1058. { Value: 'c22f8d2f-518d-4381-b88c-1da68536ed3a', Text: '公共安全' },
  1059. { Value: 'c5810829-1b21-4b22-85cd-390b1edd9614', Text: '智能设备' },
  1060. { Value: '080c7560-c261-428b-a45d-b86b57b47ffb', Text: '中央研究院' }
  1061. ];
  1062.  
  1063. const projectType = [
  1064. { Value: 'dca44f63-be3f-4e9c-b78f-d786571c22c9', Text: '网站' },
  1065. { Value: 'c7861460-163b-4060-80ec-d60604c50435', Text: '业务系统' },
  1066. { Value: '49accc71-6f7d-43f3-b726-58decf58b6fa', Text: '智能设备' },
  1067. { Value: '90209c65-1a55-4d8c-a836-2e5c6b834ada', Text: '大屏可视化' },
  1068. { Value: 'fb0415fb-65ee-42c1-895a-dca042c2568e', Text: '中屏可视化' },
  1069. { Value: '2b83f9b1-ec78-4819-a400-d7d49ea1ecc5', Text: '其他' }
  1070. ];
  1071.  
  1072. let $businesstype;
  1073. let $projecttype;
  1074.  
  1075. function getUrlParameters() {
  1076. var params = {};
  1077. var search = window.location.search.substring(1);
  1078. var urlParams = search.split('&');
  1079.  
  1080. for (var i = 0; i < urlParams.length; i++) {
  1081. var param = urlParams[i].split('=');
  1082. var paramName = decodeURIComponent(param[0]);
  1083. var paramValue = decodeURIComponent(param[1] || '');
  1084. if(paramName) {
  1085. params[paramName] = paramValue;
  1086. }
  1087. }
  1088.  
  1089. return params;
  1090. }
  1091.  
  1092. function initForm (params) {
  1093. if(typeof params === 'object') {
  1094. document.getElementsByName('Title')[0].value = params.projectName ? params.projectName : '';
  1095. document.getElementsByName('KeyWords')[0].value = params.projectKeys ? params.projectKeys : '';
  1096. document.getElementsByName('Entry')[0].value = params.entryUrl ? params.entryUrl : '';
  1097. document.getElementsByName('SourceCode')[0].value = params.git ? params.git : '';
  1098. }
  1099. }
  1100.  
  1101. let setSuccess = false;
  1102. let setTimes = 5;
  1103.  
  1104. function initSelect(params) {
  1105. if(typeof params !== 'object') {
  1106. return;
  1107. }
  1108.  
  1109. if(setTimes > 0 && !setSuccess) {
  1110. setTimeout(()=> {
  1111. setTimes--;
  1112.  
  1113. businessType.forEach((item)=> {
  1114. if(params.projectBU) {
  1115. if(item.Text === params.projectBU.trim()) {
  1116. $businesstype.val(item.Value);
  1117. } else if( params.projectBU.trim() == '一网统管' || params.projectBU.trim() == '一网协同' || params.projectBU.trim() == '一网通办' ) {
  1118. $businesstype.val('7a20e23c-30b8-47e2-8d8d-f2691c9c63c4');
  1119. }
  1120. $businesstype.trigger("chosen:updated");
  1121. }
  1122. });
  1123.  
  1124. projectType.forEach((item)=> {
  1125. if(params.projectType && item.Text === params.projectType.trim()) {
  1126. $projecttype.val(item.Value);
  1127. $projecttype.trigger("chosen:updated");
  1128. }
  1129. });
  1130.  
  1131. setSuccess = true;
  1132.  
  1133. }, 1000);
  1134. } else {
  1135. initSelect(params);
  1136. }
  1137. }
  1138.  
  1139. function addRelatedDom() {
  1140. const sourceInput = document.getElementsByName('SourceCode')[0];
  1141. const $sourceInput = jQuery(sourceInput);
  1142.  
  1143. $sourceInput.after('<a class="btn" style="cursor: pointer;margin-left:10px;" id="deploy">部署</a><a class="btn hidden" style="cursor: pointer;margin-left:10px" id="view">查看</a>')
  1144. }
  1145.  
  1146. function addStyle() {
  1147. let epointCss = ".el-loading-spinner {margin-top: -50px;} .el-button--primary:focus {outline: 0 !important;}";
  1148. // 添加注入样式
  1149. let extraStyleElement = document.createElement("style");
  1150. extraStyleElement.innerHTML = epointCss;
  1151. document.head.appendChild(extraStyleElement);
  1152. }
  1153.  
  1154. window.onload = ()=> {
  1155. const params = getUrlParameters();
  1156.  
  1157. // 有参数,进行填充表单
  1158. if(params && params.git) {
  1159. $businesstype = jQuery('#businesstype');
  1160. $projecttype = jQuery('#projecttype');
  1161.  
  1162. initForm(params);
  1163. initSelect(params);
  1164.  
  1165. return false;
  1166. }
  1167.  
  1168. // 没有url参数填充,则做部署功能展示
  1169. addRelatedDom();
  1170. addStyle();
  1171.  
  1172. const placeholder = document.createElement('div');
  1173.  
  1174. // 创建 Vue 实例并挂载到页面
  1175. const vueInstance = new Vue({
  1176. el: placeholder,
  1177. data() {
  1178. return {
  1179. framework: [
  1180. {label: '重构模板', value: 1},
  1181. {label: 'f9x1.0', value: 2},
  1182. {label: 'f9x2.0', value: 3},
  1183. {label: 'f950', value: 4},
  1184. {label: 'f950sp1', value: 5},
  1185. {label: 'f950sp2', value: 6},
  1186. {label: 'f950sp3', value: 7},
  1187. {label: 'f951', value: 18},
  1188. {label: 'f940', value: 8},
  1189. {label: 'f941', value: 10},
  1190. {label: 'f942', value: 9},
  1191. {label: 'f934', value: 11},
  1192. {label: 'f933', value: 12},
  1193. {label: 'f932', value: 13},
  1194. {label: 'f9211', value: 14},
  1195. {label: '骨架', value: 15},
  1196. {label: 'Vue', value: 16},
  1197. {label: 'React', value: 17}
  1198. ],
  1199. data: [], // 目录结构树
  1200. defaultProps: {
  1201. children: 'children',
  1202. label: 'label'
  1203. },
  1204. loadingTree: false,
  1205. dialogVisible: false,
  1206. dialogDeployVisible: false,
  1207. showDeployPath: false,
  1208. depDialogVisible: false,
  1209. loading: false,
  1210. formLabelWidth: '120px',
  1211. supportDeploy: false,
  1212. form: {
  1213. frame: '',
  1214. deployPath: ''
  1215. },
  1216. rules: {
  1217. frame: [
  1218. { required: true, message: '请选择框架类型', trigger: 'change' }
  1219. ],
  1220. deployPath: [
  1221. { required: true, message: '请输入部署到 170/showcase 下的目标路径名称', trigger: 'change' }
  1222. ]
  1223. }
  1224. }
  1225. },
  1226. methods: {
  1227. // 部署
  1228. doDeploy() {
  1229. let self = this;
  1230.  
  1231. this.$refs['form'].validate((valid) => {
  1232. if (valid) {
  1233. this.dialogDeployVisible = false;
  1234. this.depDialogVisible = true;
  1235. this.loading = true;
  1236. // 部署
  1237. this.getDeployInfo({ type: '1', frame: this.form.frame, deployPath: this.form.deployPath }, (data)=> {
  1238. this.loading = false;
  1239. this.depDialogVisible = false;
  1240.  
  1241. if(!data.custom.text){
  1242.  
  1243. this.data = data.custom.pageTreeData;
  1244. this.projectFtpUrl = data.custom.projectRootPath;
  1245. this.supportDeploy = data.custom.supportDeploy;
  1246.  
  1247. this.$message({
  1248. type: 'success',
  1249. message: '部署成功!'
  1250. });
  1251. // 打开查看弹窗
  1252. this.viewProject();
  1253. this.toggleViewButton(true);
  1254.  
  1255. } else {
  1256. this.$message({
  1257. type: 'error',
  1258. message: data.custom.text
  1259. });
  1260. }
  1261. });
  1262. } else {
  1263. console.log('error submit!!');
  1264. return false;
  1265. }
  1266. });
  1267. },
  1268. // 项目部署
  1269. getDeployInfo(params, callback) {
  1270. const author = document.querySelector('#account a').innerText.trim().substring(4);
  1271. const projectName = document.getElementsByName('Title')[0].value.trim();
  1272. const projectGitUrl = document.getElementsByName('SourceCode')[0].value.trim();
  1273.  
  1274. if(typeof params == 'function') {
  1275. callback = params;
  1276. params = null;
  1277. }
  1278. if(author && author.length && projectGitUrl) {
  1279. fetch('http://192.168.219.170:3008/api/getDeployInfo', {
  1280. method: 'POST',
  1281. // 允许跨域请求
  1282. mode: 'cors',
  1283. headers: {
  1284. 'Accept': 'application/json',
  1285. 'Content-Type': 'application/json'
  1286. },
  1287. body: JSON.stringify({//post请求参数
  1288. params: {
  1289. "type": (params && params.type !== undefined) ? params.type : '0',// 0 代表查看, 1代表部署
  1290. "deployMan": author, // 部署人姓名
  1291. "projectName": projectName, // 项目名称
  1292. "projectGitUrl": projectGitUrl,
  1293. "frame": (params && params.frame) ? params.frame : undefined,
  1294. "deployPath": (params && params.deployPath) ? params.deployPath : undefined // 部署的目标目录
  1295. }
  1296. })
  1297. })
  1298. .then(response => response.text())
  1299. .then((result) => {
  1300. var data = JSON.parse(result);
  1301. callback && callback(data);
  1302. })
  1303. .catch(error => {
  1304. this.depDialogVisible = false;
  1305. this.dialogVisible = false;
  1306. this.$message({
  1307. type: 'error',
  1308. message: '系统故障,请联系管理员。'
  1309. });
  1310. console.error(error);
  1311. });
  1312. } else {
  1313. this.$message({
  1314. type: 'error',
  1315. message: '本页面不支持查看和部署,请先登录。'
  1316. });
  1317. console.error('部署信息请求参数error');
  1318. }
  1319. },
  1320. // 查看项目
  1321. viewProject () {
  1322. this.dialogVisible = true;
  1323. let self = this;
  1324.  
  1325. if(this.data) {
  1326. this.loadingTree = false;
  1327. } else {
  1328. this.loadingTree = true;
  1329. // 发送ajax请求,查看是否进行过部署
  1330. this.getDeployInfo((data)=> {
  1331. // 有部署信息,直接赋值,
  1332. if(data) {
  1333. self.projectIsDeployed = true;
  1334. self.data = data.custom.pageTreeData;
  1335. self.projectFtpUrl = data.custom.projectRootPath;
  1336. self.supportDeploy = data.custom.supportDeploy;
  1337. self.loadingTree = false;
  1338.  
  1339. self.toggleViewButton(true);
  1340.  
  1341. }
  1342. });
  1343. }
  1344. },
  1345. handleNodeClick(data) {
  1346. console.log(data);
  1347. if(data.type === 'folder') {
  1348. return false;
  1349. }
  1350. var self = this;
  1351. var entry = data.entry;
  1352. self.clickNodeEntry = entry;
  1353. if(self.projectFtpUrl) {
  1354. window.open('http://192.168.219.170' + self.projectFtpUrl + data.entry);
  1355. self.clickNodeEntry = null;
  1356. } else {
  1357. if(this.supportDeploy === false) {
  1358. this.$message({
  1359. type: 'error',
  1360. message: '当前项目暂时只支持查看,请耐心等待功能升级。'
  1361. });
  1362. self.clickNodeEntry = null;
  1363. return false;
  1364. }
  1365.  
  1366. this.$confirm('资源未部署,部署至 170 服务器后可查看,是否部署?')
  1367. .then(_ => {
  1368.  
  1369. this.dialogDeployVisible = true;
  1370. })
  1371. .catch(_ => {});
  1372. }
  1373. },
  1374. // svn 需要制定目录名称,showDeployPath
  1375. showDialog(showDeployPath) {
  1376. this.showDeployPath = showDeployPath;
  1377. this.dialogDeployVisible = true;
  1378. },
  1379. // 查看按钮显影控制
  1380. toggleViewButton(show) {
  1381. const $viewBtn = jQuery('#view');
  1382.  
  1383. if(!$viewBtn.length) {
  1384. return;
  1385. }
  1386.  
  1387. if(show) {
  1388. $viewBtn.removeClass('hidden');
  1389. } else {
  1390. $viewBtn.addClass('hidden');
  1391. }
  1392. }
  1393. },
  1394. mounted() {
  1395. const $btnDeloy = jQuery('#deploy');
  1396. const $btnView = jQuery('#view');
  1397.  
  1398. // 绑定vue组件外的事件
  1399. $btnDeloy.on('click', function() {
  1400. // 源码地址和项目名称判断
  1401. const sourceInput = document.getElementsByName('SourceCode');
  1402. const projectNameInput = document.getElementsByName('Title');
  1403.  
  1404. let sourceInputVal = sourceInput[0].value.trim(),
  1405. projectNameInputVal = projectNameInput[0].value.trim();
  1406.  
  1407. const gitpattern = /^http:\/\/192\.168/;
  1408. const svnpattern = /^svn:\/\/192\.168/;
  1409. const sourcepattern = /^(svn:\/\/192\.168|http:\/\/192\.168)/;
  1410.  
  1411. if (!sourceInputVal) {
  1412. vueInstance.$message({
  1413. type: 'error',
  1414. message: '请输入源码地址!'
  1415. });
  1416. return
  1417. }
  1418.  
  1419. if (!sourcepattern.test(sourceInputVal)) {
  1420. vueInstance.$message({
  1421. type: 'error',
  1422. message: '请输入准确的源码 gitlab 或 svn 地址!'
  1423. });
  1424. return
  1425. }
  1426.  
  1427. if (svnpattern.test(sourceInputVal) && !projectNameInputVal) {
  1428. vueInstance.$message({
  1429. type: 'error',
  1430. message: ' svn 仓库地址部署需要填写项目(案例)名称!'
  1431. });
  1432. return
  1433. }
  1434.  
  1435. vueInstance.showDialog(svnpattern.test(sourceInputVal));
  1436. });
  1437. // 查看项目
  1438. $btnView.on('click', function() {
  1439. vueInstance.viewProject();
  1440. });
  1441.  
  1442. },
  1443. template: `<div id="my-form">
  1444. <el-dialog title="部署提示" width="640px" :visible.sync="dialogDeployVisible">
  1445. <el-alert
  1446. title="此操作将把 GitLab / SVN 资源打包部署至 170 服务器,已部署过的项目会进行覆盖部署,是否继续?"
  1447. type="warning" :closable="false" style="margin-bottom: 20px;">
  1448. </el-alert>
  1449. <el-form :model="form" ref="form" :rules="rules">
  1450. <el-form-item label="框架类型" :label-width="formLabelWidth" prop="frame">
  1451. <el-select v-model="form.frame" placeholder="请框架类型" style="width:380px;">
  1452. <el-option v-for="item in framework" :key="item.value" :label="item.label" :value="item.value"></el-option>
  1453. </el-select>
  1454. </el-form-item>
  1455. <el-form-item label="部署路径" :label-width="formLabelWidth" prop="deployPath" v-if="showDeployPath">
  1456. <el-input v-model="form.deployPath" placeholder="请输入部署至服务器 170/showcase 下的目标路径名称" style="width:380px;"></el-input>
  1457. </el-form-item>
  1458. </el-form>
  1459. <div slot="footer" class="dialog-footer">
  1460. <el-button @click="dialogDeployVisible = false">取 消</el-button>
  1461. <el-button type="primary" @click="doDeploy">确 定</el-button>
  1462. </div>
  1463. </el-dialog>
  1464. <el-dialog
  1465. title="部署"
  1466. width="420px"
  1467. :visible.sync="depDialogVisible">
  1468. <div class="deploy-body"
  1469. style="height: 306px;"
  1470. v-loading="loading"
  1471. element-loading-text="正在打包部署至 170 服务器,请耐心等待"
  1472. element-loading-spinner="el-icon-loading">
  1473. </div>
  1474. </el-dialog>
  1475. <el-dialog
  1476. title="目录结构"
  1477. width="900px"
  1478. :append-to-body="true"
  1479. :visible.sync="dialogVisible">
  1480. <el-tree
  1481. class="filter-tree"
  1482. :data="data"
  1483. :props="defaultProps"
  1484. node-key="id"
  1485. default-expand-all
  1486. @node-click="handleNodeClick"
  1487. v-loading="loadingTree"
  1488. element-loading-background="rgba(255, 255, 255, 1)"
  1489. element-loading-text="拼命加载中......"
  1490. ref="tree">
  1491. </el-tree>
  1492. </el-dialog>
  1493. </div>`
  1494. });
  1495.  
  1496. // 将占位元素追加到 body 元素中
  1497. jQuery('.form-container').after(vueInstance.$el);
  1498. };
  1499. })();
  1500.  
  1501. // 新建项目提示
  1502. // 新建项目查找重复项目
  1503. (function() {
  1504. 'use strict';
  1505. let regs = [/^http:\/\/192\.168\.0\.200\/projects\/new/];
  1506. let match = false;
  1507.  
  1508. for(let r = 0, lr = regs.length; r < lr; r++) {
  1509. if(regs[r].test(location.href)) {
  1510. match = true;
  1511. break;
  1512. }
  1513. }
  1514.  
  1515. if(!match) {
  1516. return;
  1517. }
  1518.  
  1519. // 等待页面加载完成
  1520. window.addEventListener('load', function() {
  1521. const $projectName = jQuery('#project_name');
  1522. const $projectDescription = jQuery('#project_description');
  1523. const $check = jQuery('#project_visibility_level_10');
  1524. const $projectPath = jQuery('#project_path');
  1525.  
  1526. // 页面参数
  1527. const p = gitlabUtil.getUrlParameters();
  1528. const projectName = p.projectName;
  1529. const projectBu = p.bu;
  1530. const projectType = p.projectType;
  1531. const frame = p.frame;
  1532. let vueInstance;
  1533. let uiUrl = p.uiUrl;
  1534. if(uiUrl && uiUrl !== '后补' && uiUrl.indexOf('interaction-design-portal') > -1 ) {
  1535. uiUrl += '=' + location.href.substr(location.href.length - 50, 36);
  1536. }
  1537.  
  1538. if($projectName && $projectName.length) {
  1539. $projectName.attr('placeholder', '以需求或项目管理系统中的项目名称为准');
  1540. if(projectName) {
  1541. $projectName.val(projectName);
  1542. $projectName.trigger('change');
  1543. // 防止项目名称中有英文单词时,会自动填充项目标识串。
  1544. $projectPath.val('');
  1545. }
  1546.  
  1547. // 添加检索重复项目按钮
  1548. const btnPlaceholder = document.createElement('div');
  1549.  
  1550. // 创建 Vue 实例并挂载到页面
  1551. vueInstance = new Vue({
  1552. el: btnPlaceholder,
  1553. data: function() {
  1554. return {
  1555. showBtn: false
  1556. };
  1557. },
  1558. methods: {
  1559. // 打开检索弹窗
  1560. check: function() {
  1561. let name = $projectName.val().trim();
  1562. // 去除临时
  1563. name = name.replace('(临时)', '').replace('临时', '');
  1564. // 去除项目
  1565. // name = name.replace('项目', '');
  1566. // 去除子系统,即第一个 - 后面的字符串
  1567. name = name.split('-')[0];
  1568. name = name.split('——')[0];
  1569. if(name.length > 20) {
  1570. name = name.substring(0, 20);
  1571. }
  1572. window.open('http://192.168.0.200/?name=' + name);
  1573.  
  1574. },
  1575. // 同步输入框和按钮状态
  1576. checkInput: function() {
  1577. if($projectName.val().trim() != '') {
  1578. this.showBtn = true;
  1579. } else {
  1580. this.showBtn = false;
  1581. }
  1582. }
  1583. },
  1584. mounted: function() {
  1585. let self = this;
  1586. self.checkInput();
  1587.  
  1588. $projectName.on('change', function() {
  1589. self.checkInput();
  1590. });
  1591. },
  1592. template: `<div>
  1593. <div style="position:absolute; top: 29px; left: 343px;" v-show="showBtn">
  1594. <el-tooltip content="检索已创建的项目,避免重复创建" placement="top" effect="light">
  1595. <el-button type="primary" style="vertical-align: top;" icon="el-icon-search" size="small" id="create-project" @click="check">检索</el-button>
  1596. </el-tooltip>
  1597. </div>
  1598. </div>`
  1599. });
  1600.  
  1601. // 将占位元素追加到 项目名称输入框 后面
  1602. $projectName.parent('.form-group')[0].appendChild(vueInstance.$el);
  1603. }
  1604.  
  1605. if($projectDescription && $projectDescription.length) {
  1606. let date = new Date();
  1607. const imgEl = document.querySelector('.header-user-avatar');
  1608. let name = imgEl ? imgEl.getAttribute('alt') : '张三';
  1609. name = name.replace('(前端研发3部)', '');
  1610. $projectDescription.attr('placeholder', 'YYYY-M-D,张三,UI:https://oa.epoint.com.cn/interaction-design-portal/portal/pages/casestemplates/casetemplatesdetail?guid=');
  1611. $projectDescription.val(date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate() + ','+ name +',UI:' + (uiUrl ? uiUrl : 'https://oa.epoint.com.cn/interaction-design-portal/portal/pages/casestemplates/casetemplatesdetail?guid='));
  1612. $projectDescription.prev('.label-bold').find('span').text(' (UI备份地址完善后会自动获取项目名称、业务条线和项目类型)')
  1613.  
  1614. // 增加主题表单
  1615. var themeHtml = '<div class="row">\
  1616. <div class="form-group col-md-9">\
  1617. <label class="label-bold" for="project_topics">主题<i style="color:red; font-style:normal; font-weight: 400; padding-left: 5px;">业务系统类型关键字添加框架版本</i></label>\
  1618. <input value="" maxlength="2000" class="form-control gl-form-input" placeholder="业务条线(政务服务|一网协同...),项目类型(网站|业务系统|中屏可视化...),关键字(f950sp2|gojs|vue...)" size="2000" type="text" name="project[topics]" id="project_topics" data-is-dirty-submit-input="true" data-dirty-submit-original-value="">\
  1619. <p class="form-text text-muted">用逗号分隔主题。</p>\
  1620. <p class="form-text text-muted">业务条线:政务服务、大数据、一网统管、一网协同、智能设备、电子交易、数字建设、公共安全、支撑产品;</p>\
  1621. <p class="form-text text-muted">项目类型:网站、业务系统、智能设备、大屏可视化、中屏可视化、在线表单;</p>\
  1622. <p class="form-text text-muted">关键字:f942f951f950sp2f9x2.0f9x1.0、骨架、vuereact、单页、gojselementAntDesign、全景、关系图、流程图、响应式、svg、视频、miniuiegisegis3d、高德、百度、超图、three、主题、瀑布流、上传、自定义用户控件等;</p>\
  1623. </div></div>';
  1624.  
  1625. $projectDescription.closest('.form-group').after(themeHtml);
  1626.  
  1627. var $theme = jQuery('#project_topics');
  1628.  
  1629. // 规避中文,
  1630. $projectDescription.blur(function(event) {
  1631. this.value = this.value.replace(/,/g, ',').replace(/&isfwqfb=1/g, '');
  1632. // 日期转换
  1633. this.value = convertDateFormat(this.value);
  1634.  
  1635. // 检测主题是否为空,且是否已输入uiUrl
  1636. if ($theme.val().trim() == '') {
  1637. var regex = /guid=([0-9a-fA-F-]{36})/; // 匹配整个URL字符串中的guid后的36位字符
  1638.  
  1639. var match = this.value.match(regex);
  1640.  
  1641. if (match) {
  1642. var extractedGuid = match[1];
  1643. // console.log(extractedGuid);
  1644. // 通过 guid 请求数据
  1645. var apiUrl = 'https://oa.epoint.com.cn/interaction-design-portal/rest/portal/pages/casestemplates/casestemplatesdetailaction/page_load'
  1646. if(this.value.indexOf('dynamiceffecttemplates') > -1) {
  1647. apiUrl = 'https://oa.epoint.com.cn/interaction-design-portal/rest/portal/pages/dynamiceffecttemplates/dynamiceffecttemplatesdetailaction/page_load';
  1648. }
  1649.  
  1650. // 获取项目信息
  1651. GM_xmlhttpRequest({
  1652. method: 'GET',
  1653. url: apiUrl + '?guid='+ extractedGuid +'&isCommondto=true',
  1654. headers: {
  1655. 'Content-Type': 'application/json; charset=utf-8'
  1656. },
  1657. onload: function(res) {
  1658. const data = JSON.parse(res.response);
  1659. let pData = data.custom.casetemplatedata || data.custom.dynamiceffecttemplatesdata;
  1660. let proBu = pData.stripline || pData.line;
  1661. const proType = pData.type;
  1662. const proName = pData.project || pData.title;
  1663. switch(proBu) {
  1664. case '政务BG':
  1665. proBu = '政务服务';
  1666. break;
  1667. case '建设BG':
  1668. proBu = '数字建设';
  1669. break;
  1670. case '交易BG':
  1671. proBu = '电子交易';
  1672. break;
  1673. case '智能设备BU':
  1674. proBu = '智能设备';
  1675. break;
  1676. }
  1677. proName && $projectName.val(proName);
  1678. proBu && proType && $theme.val(proBu + ', ' + proType);
  1679. $projectName.trigger('change');
  1680. }
  1681. });
  1682. }
  1683. }
  1684. });
  1685.  
  1686.  
  1687. if(projectBu) {
  1688. $theme.val(projectBu);
  1689. }
  1690.  
  1691. if(projectType && projectType !== '智能化设备') {
  1692. $theme.val($theme.val() + ', ' + projectType);
  1693. }
  1694.  
  1695. if(frame) {
  1696. $theme.val($theme.val() + ', ' + frame);
  1697. }
  1698.  
  1699. $theme.blur(function(event) {
  1700. this.value = this.value.replaceAll(',', ',');
  1701.  
  1702. });
  1703. }
  1704.  
  1705. if($check && $check.length) {
  1706. $check.trigger('click');
  1707. }
  1708. });
  1709.  
  1710. })();
  1711.  
  1712. // 通过 oa 首页中转,跳过跨站访问的限制
  1713. (function(){
  1714. 'use strict';
  1715. let regs = [/^https:\/\/oa\.epoint\.com\.cn\/epointoa9\/frame\/fui\/pages\/themes\/aide/];
  1716. let match = false;
  1717.  
  1718. for(let r = 0, lr = regs.length; r < lr; r++) {
  1719. if(regs[r].test(location.href)) {
  1720. match = true;
  1721. break;
  1722. }
  1723. }
  1724.  
  1725. if(!match) {
  1726. return;
  1727. }
  1728.  
  1729. let redirectUlr = gitlabUtil.getUrlParameters().redirect;
  1730.  
  1731. if(redirectUlr) {
  1732. window.location.href = redirectUlr;
  1733. }
  1734. })();
  1735.  
  1736. // 设计门户瀑布流页面,查找对应项目
  1737. (function(){
  1738. 'use strict';
  1739. let regs = [/^https:\/\/oa\.epoint\.com\.cn\/interaction-design-portal\/portal\/pages\/casestemplates\/casetemplateslist/];
  1740. let match = false;
  1741.  
  1742. for(let r = 0, lr = regs.length; r < lr; r++) {
  1743. if(regs[r].test(location.href)) {
  1744. match = true;
  1745. break;
  1746. }
  1747. }
  1748.  
  1749. if(!match) {
  1750. return;
  1751. }
  1752.  
  1753. let projectName = location.href.split('projectname');
  1754.  
  1755. window.addEventListener('load', function() {
  1756. if(projectName[1]) {
  1757. projectName = decodeURIComponent(projectName[1]);
  1758.  
  1759. const $input = jQuery('#search-input');
  1760. const $searchBtn = jQuery('.search-icon');
  1761.  
  1762. setTimeout(() => {
  1763. $input.val(projectName);
  1764. $searchBtn.trigger('click');
  1765. }, 1000);
  1766. }
  1767. });
  1768. })();
  1769.  
  1770. // 邮件详情页可以创建项目
  1771. (function() {
  1772. 'use strict';
  1773. let regs = [/^https:\/\/oa\.epoint\.com\.cn\:8080\/OA9\/oa9\/mail\/mailreceivedetail/,
  1774. /^https:\/\/oa\.epoint\.com\.cn\/OA9\/oa9\/mail\/mailreceivedetail/];
  1775. let match = false;
  1776.  
  1777. for(let r = 0, lr = regs.length; r < lr; r++) {
  1778. if(regs[r].test(location.href)) {
  1779. match = true;
  1780. break;
  1781. }
  1782. }
  1783.  
  1784. if(!match) {
  1785. return;
  1786. }
  1787.  
  1788. const fontUrl = 'https://element.eleme.io/2.11/static/element-icons.535877f.woff';
  1789.  
  1790. // 添加样式规则,将字体应用到指定元素上
  1791. GM_addStyle(`
  1792. @font-face {
  1793. font-family: element-icons;
  1794. src: url(${fontUrl}) format("woff");
  1795. }
  1796. `);
  1797.  
  1798. GM_addStyle(GM_getResourceText('ElementCSS'));
  1799.  
  1800. // 在邮件签收情况后添加按钮-新建项目
  1801. function initCreate() {
  1802. const title = document.querySelector('#mail-detail-container .dtt');
  1803. let vueInstance;
  1804. let gitUrl = 'http://192.168.0.200/projects/new?namespace_id=4817';
  1805.  
  1806. if(title) {
  1807. const btnPlaceholder = document.createElement('div');
  1808. const tds = jQuery('#mailcontent table').find("td[colspan='3']");
  1809. const projectName = tds.eq(0).text().replace('(临时)', '').replace('(临时)', '');
  1810. const isFrontEndEmail = jQuery('#mailcontent table').length;
  1811. let bu = '政务服务';
  1812. let projectType = '';
  1813. let frame = '';
  1814. const demandUrl = tds.eq(1).text();
  1815. let uiUrl = '';
  1816.  
  1817. // 由于表格格式不固定,重新遍历一遍获取 uiUrl 和 frame
  1818. tds.each(function(i, el) {
  1819. if(jQuery(el).prev().text() == '备份地址') {
  1820. uiUrl = jQuery(el).text();
  1821. }
  1822. if(jQuery(el).prev().text() == '框架版本') {
  1823. frame = jQuery(el).text();
  1824. }
  1825. if(jQuery(el).prev().text() == '设计类型') {
  1826. projectType = jQuery(el).text();
  1827. }
  1828. });
  1829.  
  1830. uiUrl = uiUrl ? removeQueryStringParameter(uiUrl, 'isfwqfb') : '';
  1831. const backGuid = extractGuidFromUrl(uiUrl);
  1832.  
  1833. if(!isFrontEndEmail) {
  1834. return;
  1835. }
  1836.  
  1837. // 请求项目信息地址
  1838. let apiUrl = '';
  1839.  
  1840. apiUrl = uiUrl.split('?')[0];
  1841. apiUrl = apiUrl.split('interaction-design-portal')[0] + 'interaction-design-portal/rest' + apiUrl.split('interaction-design-portal')[1] + 'action/page_load';
  1842.  
  1843. if(apiUrl.indexOf('casetemplatesdetailaction') > -1) {
  1844. apiUrl = apiUrl.replace('casetemplatesdetailaction', 'casestemplatesdetailaction');
  1845. }
  1846.  
  1847. // 创建 Vue 实例并挂载到页面
  1848. vueInstance = new Vue({
  1849. el: btnPlaceholder,
  1850. data: function() {
  1851. return {
  1852. proBu: bu,
  1853. proType: projectType
  1854. };
  1855. },
  1856. methods: {
  1857. create: function() {
  1858. window.open(gitUrl + '&projectName=' + projectName + '&bu=' + this.proBu + '&projectType=' + this.proType + '&frame=' + frame + '&uiUrl=' + uiUrl + '#blank_project');
  1859. },
  1860. search: function() {
  1861. window.open('http://192.168.0.200/?name=' + projectName);
  1862. }
  1863. },
  1864. mounted: function() {
  1865. let self = this;
  1866. // 获取项目信息
  1867. GM_xmlhttpRequest({
  1868. method: 'GET',
  1869. url: apiUrl + '?guid='+ backGuid +'&isfwqfb=1&isCommondto=true',
  1870. headers: {
  1871. 'Content-Type': 'application/json; charset=utf-8'
  1872. },
  1873. onload: function(res) {
  1874. const data = JSON.parse(res.response);
  1875. let pData = data.custom.casetemplatedata || data.custom.dynamiceffecttemplatesdata;
  1876. self.proBu = pData.stripline || pData.line;
  1877. self.proType = pData.type;
  1878. switch(self.proBu) {
  1879. case '政务BG':
  1880. self.proBu = '政务服务';
  1881. break;
  1882. case '建设BG':
  1883. self.proBu = '数字建设';
  1884. break;
  1885. case '交易BG':
  1886. self.proBu = '电子交易';
  1887. break;
  1888. case '智能设备BU':
  1889. self.proBu = '智能设备';
  1890. break;
  1891. }
  1892. }
  1893. });
  1894. },
  1895. template: `<div style="display:inline-block; margin-left: 5px; vertical-align: top;">
  1896. <el-tooltip content="去 GitLab 创建项目" placement="top" effect="light">
  1897. <el-button type="primary" style="vertical-align: top;" icon="el-icon-folder-add" circle size="mini" id="create-project" @click="create"></el-button>
  1898. </el-tooltip>
  1899. <el-tooltip content="去 GitLab 查找项目" placement="top" effect="light">
  1900. <el-button type="primary" style="vertical-align: top;" icon="el-icon-search" circle size="mini" @click="search"></el-button>
  1901. </el-tooltip>
  1902. </div>`
  1903. });
  1904.  
  1905. // 将占位元素追加到 邮件标题后 元素中
  1906. // f9 框架会冲突
  1907. title.appendChild(vueInstance.$el);
  1908. // jQuery(title).append(vueInstance.$el.outerHTML);
  1909.  
  1910. /*
  1911. jQuery('#create-project').on('click', function() {
  1912. window.open(gitUrl);
  1913. });*/
  1914. }
  1915. }
  1916.  
  1917. function extractGuidFromUrl(url) {
  1918. const regex = /[?&]guid=([^&]+)/;
  1919. const match = url.match(regex);
  1920.  
  1921. if (match) {
  1922. return match[1]; // 第一个捕获组中的值即为 guid
  1923. } else {
  1924. return null; // 如果没有匹配到 guid,则返回 null
  1925. }
  1926. }
  1927.  
  1928. function removeQueryStringParameter(url, parameterName) {
  1929. const urlParts = url.split('?');
  1930.  
  1931. if (urlParts.length === 2) {
  1932. const baseUrl = urlParts[0];
  1933. const queryString = urlParts[1];
  1934.  
  1935. const parameters = queryString.split('&').filter(param => {
  1936. const paramName = param.split('=')[0];
  1937. return paramName !== parameterName;
  1938. });
  1939.  
  1940. if (parameters.length > 0) {
  1941. return baseUrl + '?' + parameters.join('&');
  1942. } else {
  1943. return baseUrl;
  1944. }
  1945. }
  1946.  
  1947. return url;
  1948. }
  1949.  
  1950. window.addEventListener('load', function() {
  1951. setTimeout(function() {
  1952. initCreate();
  1953. }, 500);
  1954. });
  1955.  
  1956. })();