GitLab Assistant

GitLab Viewer Publish and Deploy Project!

当前为 2023-08-04 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name GitLab Assistant
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.0998
  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 http://192.168.201.159:9999/webapp/pages/default/onlinecase.html*
  14. // @match http://192.168.118.60:9999/webapp/pages/caselib/create.html*
  15. // @icon http://192.168.0.200/assets/favicon-7901bd695fb93edb07975966062049829afb56cf11511236e61bcf425070e36e.png
  16. // @require https://cdn.bootcdn.net/ajax/libs/vue/2.7.14/vue.min.js
  17. // @require https://unpkg.com/element-ui/lib/index.js
  18. // @require https://cdn.bootcdn.net/ajax/libs/jszip/3.7.1/jszip.min.js
  19. // @grant GM_getResourceURL
  20. // @grant GM_addStyle
  21. // @grant GM_getResourceText
  22. // @resource ElementCSS https://unpkg.com/element-ui/lib/theme-chalk/index.css
  23. // @grant GM_xmlhttpRequest
  24. // @license MIT
  25. // @run-at document-end
  26. // ==/UserScript==
  27.  
  28.  
  29. // 个性化 gitlab 样式,
  30. // 满足项目详情多行显示,
  31. // 项目列表中的链接新窗口打开,
  32. // 搜索框 placeholder 个性化提示
  33. // 增加CodePipeline 入口等
  34. (function() {
  35. 'use strict';
  36.  
  37. let regs = [/^http:\/\/192\.168\.0\.200\/fe3project\//,
  38. /^http:\/\/192\.168\.0\.200\/frontend_pc\/project\//,
  39. /^http:\/\/192\.168\.0\.200/,
  40. /^http:\/\/192\.168\.0\.200\//];
  41. let match = false;
  42.  
  43. for(let r = 0, lr = regs.length; r < lr; r++) {
  44. if(regs[r].test(location.href)) {
  45. match = true;
  46. break;
  47. }
  48. }
  49.  
  50. if(!match) {
  51. return;
  52. }
  53.  
  54. // 注入样式:改变容器宽度,项目描述多行展示
  55. 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;}";
  56.  
  57. injectStyle += ".container-fluid.container-limited.limit-container-width .file-holder.readme-holder.limited-width-container .file-content {max-width: none;}"
  58. injectStyle += 'button:focus {outline-color: transparent !important;}'
  59. injectStyle += '.has-description .description {word-break: break-all;}'
  60. // 添加注入样式
  61. let extraStyleElement = document.createElement("style");
  62. extraStyleElement.innerHTML = injectStyle;
  63. document.head.appendChild(extraStyleElement);
  64.  
  65. const fontUrl = 'https://element.eleme.io/2.11/static/element-icons.535877f.woff';
  66.  
  67. // 添加样式规则,将字体应用到指定元素上
  68. GM_addStyle(`
  69. @font-face {
  70. font-family: element-icons;
  71. src: url(${fontUrl}) format("woff");
  72. }
  73. `);
  74.  
  75. GM_addStyle(GM_getResourceText('ElementCSS'));
  76.  
  77. // 改变列表打开链接方式,改为新窗口打开
  78. let change = false;
  79. let tryTimes = 3;
  80.  
  81. function changeOpenType() {
  82. if(!change){
  83. setTimeout(()=> {
  84. let links = document.querySelectorAll('.description a');
  85. if(links.length) {
  86. for(let i = 0, l = links.length; i < l; i++) {
  87. links[i].target = "_blank";
  88. if(i === l - 1) {
  89. change = true;
  90. }
  91. }
  92. } else {
  93. changeOpenType();
  94. }
  95. }, 1000);
  96. }
  97. }
  98.  
  99. function stopLinkProp() {
  100. setTimeout(()=> {
  101. const links = document.querySelectorAll('.description a');
  102. for(let i = 0, l = links.length; i < l; i++) {
  103. links[i].addEventListener('click', ()=> {
  104. event.stopPropagation();
  105. });
  106. }
  107. }, 1000);
  108. }
  109.  
  110. // 等待页面加载完成
  111. window.addEventListener('load', function() {
  112.  
  113. var targetDiv = document.querySelector('section');
  114.  
  115. if(targetDiv) {
  116. // 创建一个 Mutation Observer 实例
  117. var observer = new MutationObserver(function(mutations) {
  118. // 在这里处理 div 子元素的变化
  119. mutations.forEach(function(mutation) {
  120. if(mutation.addedNodes && mutation.addedNodes.length) {
  121. change = false;
  122. changeOpenType();
  123.  
  124. stopLinkProp();
  125. }
  126. });
  127. });
  128.  
  129. // 配置 Mutation Observer
  130. var config = { childList: true, subtree: true };
  131.  
  132. // 开始观察目标 div 元素
  133. observer.observe(targetDiv, config);
  134. }
  135.  
  136. const placeholder = document.createElement('div');
  137.  
  138. // 创建 Vue 实例并挂载到页面
  139. const vueInstance = new Vue({
  140. el: placeholder,
  141. methods: {
  142. // 进入管理平台 code pipeline
  143. manage() {
  144. window.open('http://192.168.219.170/code-pipeline')
  145. }
  146. },
  147. template: `<div id="my-ext" style="margin-top:4px;">
  148. <el-tooltip content="进入 Code Pipeline 管理平台" placement="top" effect="light">
  149. <el-button type="primary" icon="el-icon-attract" size="small" circle @click="manage"></el-button>
  150. </el-tooltip>
  151. </div>`
  152. });
  153.  
  154. // 将占位元素追加到 body 元素中
  155. document.querySelector('.title-container').appendChild(vueInstance.$el);
  156.  
  157. // 修改 placehodler
  158. const listInput = document.getElementById('group-filter-form-field');
  159. const listInput2 = document.getElementById('project-filter-form-field');
  160.  
  161. if(listInput) {
  162. listInput.setAttribute("placeholder", "按项目名称、日期、开发者搜索,关键字≥3");
  163. listInput.style.width = '305px';
  164. }
  165. if(listInput2) {
  166. listInput2.setAttribute("placeholder", "按项目名称、日期、开发者搜索,关键字≥3");
  167. listInput2.style.width = '305px';
  168. }
  169. });
  170.  
  171.  
  172. })();
  173.  
  174. (function(){
  175. function convertDateFormat(inputString) {
  176. // 匹配日期格式为yyyy-mm-dd或yyyy-m-dd或yyyy-mm-d或yyyy-m-d的正则表达式
  177. const dateRegex = /\d{4}-\d{1,2}-\d{1,2}/g;
  178.  
  179. // 找到所有匹配的日期格式
  180. const dates = inputString.match(dateRegex);
  181.  
  182. // 如果没有匹配到日期,则直接返回原始字符串
  183. if (!dates || dates.length === 0) {
  184. return inputString;
  185. }
  186.  
  187. // 遍历所有匹配到的日期,进行转换
  188. dates.forEach((date) => {
  189. const [year, month, day] = date.split('-');
  190. const formattedDate = `${parseInt(year, 10)}-${parseInt(month, 10)}-${parseInt(day, 10)}`;
  191. inputString = inputString.replace(date, formattedDate);
  192. });
  193.  
  194. return inputString;
  195. }
  196.  
  197. window.convertDateFormat = convertDateFormat;
  198. })();
  199.  
  200. // GitLab Viewer Publish and Deploy Project
  201. // 查看项目、部署项目、发布项目功能
  202. (function() {
  203. 'use strict';
  204. let regs = [/^http:\/\/192\.168\.0\.200\/fe3project\//,
  205. /^http:\/\/192\.168\.0\.200\/frontend_pc\/project\//];
  206. let match = false;
  207.  
  208. for(let r = 0, lr = regs.length; r < lr; r++) {
  209. if(regs[r].test(location.href)) {
  210. match = true;
  211. break;
  212. }
  213. }
  214.  
  215. if(!match) {
  216. return;
  217. }
  218. /*
  219. const fontUrl = 'https://element.eleme.io/2.11/static/element-icons.535877f.woff';
  220.  
  221. // 添加样式规则,将字体应用到指定元素上
  222. GM_addStyle(`
  223. @font-face {
  224. font-family: element-icons;
  225. src: url(${fontUrl}) format("woff");
  226. }
  227. `);
  228.  
  229. GM_addStyle(GM_getResourceText('ElementCSS'));
  230. */
  231.  
  232. let epointCss = ".epoint-tool {position: fixed; bottom: 0%; right:10px; transform: translateY(-40%);}";
  233. epointCss += ".el-row { padding: 3px 0;} .el-dialog__body .el-tree{min-height: 420px; max-height: 500px;overflow: auto;}";
  234. epointCss += ".view-toolbar {padding-bottom: 10px;}";
  235. epointCss += ".deploy-body {height: 306px;}"
  236. epointCss += ".el-loading-spinner {margin-top: -60px;} .el-button--primary:focus {outline: 0 !important;}";
  237.  
  238. // 添加注入样式
  239. let extraStyleElement = document.createElement("style");
  240. extraStyleElement.innerHTML = epointCss;
  241. document.head.appendChild(extraStyleElement);
  242.  
  243. const MyComponent = {
  244. template: `<div class="epoint-wrap">
  245. <div class="epoint-tool">
  246. <el-row><el-button type="primary" icon="el-icon-search" round @click="viewProject">查看</el-button></el-row>
  247. <el-row>
  248. <el-tooltip content="一键部署到170服务器" placement="top" effect="light">
  249. <el-button type="primary" icon="el-icon-s-unfold" round @click="doDeploy">部署</el-button>
  250. </el-tooltip>
  251. </el-row>
  252. <el-row>
  253. <el-tooltip content="一键发布到项目案例库" placement="top" effect="light">
  254. <el-button type="primary" icon="el-icon-upload" round @click="publish">发布</el-button>
  255. </el-tooltip>
  256. </el-row>
  257. <el-row>
  258. <el-tooltip content="进入 Code Pipeline 管理平台进行更多操作" placement="top" effect="light">
  259. <el-button type="primary" icon="el-icon-attract" round @click="manage">管理</el-button>
  260. </el-tooltip>
  261. </el-row>
  262. </div>
  263. <el-dialog
  264. title="目录结构"
  265. width="900px"
  266. :append-to-body="true"
  267. :visible.sync="dialogVisible"
  268. :before-close="handleClose">
  269. <div class="view-body">
  270. <div class="view-toolbar" v-if="projectFtpUrl"><el-button type="primary" size="small" @click="viewAll">查看全部</el-button></div>
  271. <div class="view-content">
  272. <el-tree
  273. class="filter-tree"
  274. :data="data"
  275. :props="defaultProps"
  276. node-key="id"
  277. default-expand-all
  278. @node-click="handleNodeClick"
  279. v-loading="loadingTree"
  280. element-loading-background="rgba(255, 255, 255, 1)"
  281. element-loading-text="拼命加载中......"
  282. ref="tree">
  283. </el-tree>
  284. </div>
  285. </div>
  286. </el-dialog>
  287. <el-dialog
  288. title="部署"
  289. width="420px"
  290. :visible.sync="depDialogVisible">
  291. <div class="deploy-body"
  292. v-loading="loading"
  293. element-loading-text="正在打包部署至 170 服务器,请耐心等待"
  294. element-loading-spinner="el-icon-loading">
  295. </div>
  296. </el-dialog>
  297. <el-dialog title="部署提示" width="640px" :visible.sync="dialogDeployVisible">
  298. <el-alert
  299. title="此操作将把 GitLab 资源打包部署至 170 服务器,已部署过的项目会进行覆盖部署,是否继续?"
  300. type="warning" :closable="false" style="margin-bottom: 20px;">
  301. </el-alert>
  302. <el-form :model="form" ref="form" :rules="rules">
  303. <el-form-item label="框架类型" :label-width="formLabelWidth" prop="frame">
  304. <el-select v-model="form.frame" placeholder="请框架类型">
  305. <el-option v-for="item in framework" :key="item.value" :label="item.label" :value="item.value"></el-option>
  306. </el-select>
  307. </el-form-item>
  308. </el-form>
  309. <div slot="footer" class="dialog-footer">
  310. <el-button @click="dialogDeployVisible = false">取 消</el-button>
  311. <el-button type="primary" @click="doDeploy">确 定</el-button>
  312. </div>
  313. </el-dialog>
  314. </div>`,
  315. data() {
  316. return {
  317. dialogVisible: false, // 查看目录结构弹窗
  318. data: [], // 目录结构树的数据结构
  319. defaultProps: {
  320. children: 'children',
  321. label: 'label'
  322. },
  323. loadingTree: false,
  324. depDialogVisible: false, // 部署中弹窗
  325. loading: false,
  326. projectLibUrl: 'http://192.168.118.60:9999/webapp/pages/caselib/create.html', // 项目案例库地址
  327. projectIsDeployed: false, // 项目是否部署过
  328. projectFtpUrl: '', // ftp路径
  329. projectEntryUrl: '', // 项目案例库发布表单的入口页面
  330. supportDeploy: true, // 项目是否支持部署
  331. dialogDeployVisible: false,
  332. formLabelWidth: '120px',
  333. form: {
  334. frame: ''
  335. },
  336. framework: [
  337. {label: '重构模板', value: 1},
  338. {label: 'f9x1.0', value: 2},
  339. {label: 'f9x2.0', value: 3},
  340. {label: 'f950', value: 4},
  341. {label: 'f950sp1', value: 5},
  342. {label: 'f950sp2', value: 6},
  343. {label: 'f950sp3', value: 7},
  344. {label: 'f951', value: 18},
  345. {label: 'f940', value: 8},
  346. {label: 'f941', value: 10},
  347. {label: 'f942', value: 9},
  348. {label: 'f934', value: 11},
  349. {label: 'f933', value: 12},
  350. {label: 'f932', value: 13},
  351. {label: 'f9211', value: 14},
  352. {label: '骨架', value: 15},
  353. {label: 'Vue', value: 16},
  354. {label: 'React', value: 17}
  355. ],
  356. rules: {
  357. frame: [
  358. { required: true, message: '请选择框架类型', trigger: 'change' }
  359. ]
  360. },
  361. clickNodeEntry: null
  362. };
  363. },
  364. methods: {
  365. handleClose(done) {
  366. done();
  367. /*
  368. this.$confirm('确认关闭?')
  369. .then(_ => {
  370. done();
  371. })
  372. .catch(_ => {});*/
  373. },
  374. handleNodeClick(data) {
  375. console.log(data);
  376. if(data.type === 'folder') {
  377. return false;
  378. }
  379. var self = this;
  380. var entry = data.entry;
  381. self.clickNodeEntry = entry;
  382. if(self.projectFtpUrl) {
  383. window.open('http://192.168.219.170' + self.projectFtpUrl + data.entry);
  384. self.clickNodeEntry = null;
  385. } else {
  386. if(this.supportDeploy === false) {
  387. this.$message({
  388. type: 'error',
  389. message: '当前项目暂时只支持查看,请耐心等待功能升级。'
  390. });
  391. self.clickNodeEntry = null;
  392. return false;
  393. }
  394.  
  395. this.$confirm('资源未部署,部署至 170 服务器后可查看,是否部署?')
  396. .then(_ => {
  397.  
  398. this.dialogDeployVisible = true;
  399. /*
  400. this.depDialogVisible = true;
  401. this.loading = true;
  402. // 部署
  403. this.getDeployInfo({ type: '1' }, (data)=> {
  404. this.loading = false;
  405. this.depDialogVisible = false;
  406.  
  407. this.data = data.custom.detail;
  408. this.projectFtpUrl = data.custom.ftpUrl;
  409.  
  410. this.$alert('部署成功!', '提示', {
  411. confirmButtonText: '确定',
  412. callback: action => {
  413. window.open('http://192.168.219.170' + self.projectFtpUrl + entry)
  414. }
  415. });
  416.  
  417. });*/
  418. })
  419. .catch(_ => {});
  420. }
  421. },
  422. // 部署
  423. doDeploy () {
  424. if(!this.isDownLoadPage()) {
  425. return;
  426. }
  427. if(!this.dialogDeployVisible) {
  428. this.dialogDeployVisible = true;
  429. return;
  430. }
  431.  
  432. let self = this;
  433.  
  434. this.$refs['form'].validate((valid) => {
  435. if (valid) {
  436. this.dialogDeployVisible = false;
  437. this.depDialogVisible = true;
  438. this.loading = true;
  439. // 部署
  440. this.getDeployInfo({ type: '1', frame: this.form.frame }, (data)=> {
  441. this.loading = false;
  442. this.depDialogVisible = false;
  443.  
  444. if(!data.custom.text){
  445.  
  446. this.data = data.custom.pageTreeData;
  447. this.projectFtpUrl = data.custom.projectRootPath;
  448. this.supportDeploy = data.custom.supportDeploy;
  449.  
  450. this.setProjectEntry();
  451. // 从部署按钮直接过来的
  452. if(!this.clickNodeEntry) {
  453. this.$message({
  454. type: 'success',
  455. message: '部署成功!'
  456. });
  457. // 打开查看弹窗
  458. this.viewProject();
  459. } else {// 从点击目录结构过来的,可以调整点击的树节点页面
  460. this.$alert('部署成功!', '提示', {
  461. confirmButtonText: '确定',
  462. callback: action => {
  463. window.open('http://192.168.219.170' + self.projectFtpUrl + self.clickNodeEntry);
  464. self.clickNodeEntry = null;
  465. }
  466. });
  467. }
  468.  
  469. } else {
  470. this.$message({
  471. type: 'error',
  472. message: data.custom.text
  473. });
  474. }
  475. });
  476. } else {
  477. console.log('error submit!!');
  478. return false;
  479. }
  480. });
  481.  
  482. /*
  483. this.$confirm('此操作将把 GitLab 资源打包部署至 170 服务器,已部署过的项目会进行覆盖部署,是否继续?', '提示', {
  484. confirmButtonText: '确定',
  485. cancelButtonText: '取消',
  486. type: 'warning'
  487. }).then(() => {
  488. }).catch(() => {
  489. this.$message({
  490. type: 'info',
  491. message: '已取消部署'
  492. });
  493. });*/
  494. },
  495. // 发布项目案例库
  496. publish () {
  497. this.$confirm('此操作将把项目发布至 <a href="'+ this.projectLibUrl +'" target="_blank">项目案例库</a>,已发布过的项目案例库会有重复项,是否继续?', '提示', {
  498. confirmButtonText: '确定',
  499. cancelButtonText: '取消',
  500. dangerouslyUseHTMLString: true,
  501. type: 'warning'
  502. }).then(() => {
  503. const themes = document.querySelectorAll('.badge-secondary');
  504. let keys = [];
  505.  
  506. for(let i = 0, l = themes.length; i < l; i++) {
  507. if(themes[0].innerText == '智能设备' && i > 0) {
  508. keys.push(themes[i].innerText);
  509. } else if (themes[0].innerText !== '智能设备' && i > 1) {
  510. keys.push(themes[i].innerText);
  511. }
  512. }
  513. // 存在更多主题的情况
  514. const moreKeyEl = document.querySelector('.gl-w-full .text-nowrap');
  515. if(moreKeyEl) {
  516. const moreKeyElContent = moreKeyEl.getAttribute('data-content');
  517. const regex = />([^<]+)</g;
  518. const matches = moreKeyElContent.match(regex);
  519. const results = matches.filter(function(match) {
  520. return match.length > 3;
  521. });
  522. const moreKeyData = results.map(function(match) {
  523. return match.substring(2, match.length - 2);
  524. });
  525.  
  526. if(moreKeyData && moreKeyData.length) {
  527. keys = keys.concat(moreKeyData);
  528. }
  529. }
  530.  
  531. // 组织项目案例库所需参数
  532. const projectName = document.querySelector('.home-panel-title').innerText;
  533. const projectBU = themes[0] ? themes[0].innerText : null;
  534. const projectKeys = keys.join(' ');
  535. const entryUrl = this.projectEntryUrl;
  536. let projectType = themes[1] ? themes[1].innerText : null;
  537.  
  538. if(themes[0]) {
  539. if(themes[0].innerText == '智能设备') {
  540. projectType = themes[1] ? themes[0].innerText : null;
  541. } else {
  542. projectType = themes[1] ? themes[1].innerText : null;
  543. }
  544. }
  545.  
  546. const destUrl = this.projectLibUrl + '?projectName=' + projectName + '&projectBU=' + projectBU + '&projectType=' + projectType + '&projectKeys=' + projectKeys + '&entryUrl=' + entryUrl + '&git=' + window.location.href;
  547.  
  548. this.$message({
  549. type: 'success',
  550. message: destUrl
  551. });
  552.  
  553. window.open(destUrl);
  554.  
  555. }).catch(() => {
  556. this.$message({
  557. type: 'info',
  558. message: '已取消发布'
  559. });
  560. });
  561. },
  562. // 查看项目
  563. viewProject () {
  564. if(!this.isDownLoadPage()) {
  565. return;
  566. }
  567. this.dialogVisible = true;
  568. this.loadingTree = true;
  569. let self = this;
  570.  
  571. // 发送ajax请求,查看是否进行过部署
  572. this.getDeployInfo((data)=> {
  573. // 有部署信息,直接赋值,
  574. if(data) {
  575. self.projectIsDeployed = true;
  576. self.data = data.custom.pageTreeData;
  577. self.projectFtpUrl = data.custom.projectRootPath;
  578. self.supportDeploy = data.custom.supportDeploy;
  579. self.loadingTree = false;
  580.  
  581. self.setProjectEntry();
  582.  
  583. } else {
  584. // 无部署信息,仅查看文件目录
  585. getZipResource((data)=> {
  586. self.data = data;
  587. self.loadingTree = false;
  588. });
  589. }
  590. });
  591.  
  592. },
  593. // 查看项目的所有页面
  594. viewAll() {
  595. window.open('http://192.168.219.170/code-pipeline/#/project/deploy-preview?rowguid=' + document.body.getAttribute('data-project-id'));
  596. },
  597. // 项目部署信息
  598. getDeployInfo(params, callback) {
  599. const projectId = document.body.getAttribute('data-project-id');
  600. const downloadBtn = document.querySelector('.gl-button.btn-sm.btn-confirm');
  601.  
  602. const sourceUrl = downloadBtn.getAttribute('href');
  603. const downloadUrl = window.location.origin + sourceUrl;
  604. const files = document.body.getAttribute('data-find-file').split('/');
  605. const name = document.body.getAttribute('data-project') + '-' + files[files.length - 1];
  606. const author = document.querySelector('.current-user .gl-font-weight-bold').innerText.trim();
  607. const projectName = document.querySelector('.sidebar-context-title').innerText.trim();
  608. const deployManOA = document.querySelector('.current-user>a').getAttribute('data-user');
  609. const projectGitUrl = 'http://192.168.0.200' + document.body.getAttribute('data-find-file').split('/-/')[0];
  610.  
  611. if(typeof params == 'function') {
  612. callback = params;
  613. params = null;
  614. }
  615.  
  616. if(projectId && projectId.length && sourceUrl) {
  617. fetch('http://192.168.219.170:3008/api/getDeployInfo', {
  618. method: 'POST',
  619. // 允许跨域请求
  620. mode: 'cors',
  621. headers: {
  622. 'Accept': 'application/json',
  623. 'Content-Type': 'application/json'
  624. },
  625. body: JSON.stringify({//post请求参数
  626. params: {
  627. "type": (params && params.type !== undefined) ? params.type : '0',// 0 代表查看, 1代表部署
  628. "name": name, // 项目路径英文名
  629. "deployMan": author, // 部署人姓名
  630. "deployManOA": deployManOA, // 部署人账号
  631. "projectName": projectName, // 项目名称
  632. "downloadUrl": downloadUrl, // 下载地址
  633. "projectId": projectId, // 主键,gitlab上的项目id
  634. "projectGitUrl": projectGitUrl,
  635. "frame": (params && params.frame) ? params.frame : undefined
  636. }
  637. })
  638. })
  639. .then(response => response.text())
  640. .then((result) => {
  641. var data = JSON.parse(result);
  642. callback && callback(data);
  643. })
  644. .catch(error => {
  645. this.depDialogVisible = false;
  646. this.dialogVisible = false;
  647. this.$message({
  648. type: 'error',
  649. message: '系统故障,请联系管理员。'
  650. });
  651. console.error(error);
  652. });
  653. } else {
  654. this.$message({
  655. type: 'error',
  656. message: '本页不支持查看和部署,请至仓库页。'
  657. });
  658. console.error('部署信息请求参数error');
  659. }
  660. },
  661. // 进入管理平台 code pipeline
  662. manage() {
  663. window.open('http://192.168.219.170/code-pipeline')
  664. },
  665. // 设置入口
  666. setProjectEntry(){
  667. const firstNode = findFirstFileNode(this.data);
  668. if(firstNode) {
  669. this.projectEntryUrl = 'http://192.168.219.170' + this.projectFtpUrl + firstNode.entry;
  670. }else {
  671. this.projectEntryUrl = null;
  672. }
  673. },
  674. isDownLoadPage() {
  675. const downloadBtn = document.querySelector('.gl-button.btn-sm.btn-confirm');
  676. const sourceUrl = downloadBtn && downloadBtn.getAttribute('href');
  677.  
  678. if(downloadBtn && sourceUrl) {
  679. return true;
  680. } else {
  681. this.$message({
  682. type: 'error',
  683. message: '本页面不支持查看和部署,请移至仓库页。'
  684. });
  685. return false;
  686. }
  687. }
  688. },
  689. mounted() {
  690. }
  691. };
  692.  
  693. const placeholder = document.createElement('div');
  694.  
  695. // 创建 Vue 实例并挂载到页面
  696. const vueInstance = new Vue({
  697. el: placeholder,
  698. components: {
  699. MyComponent
  700. },
  701. methods: {
  702. },
  703. template: `<my-component></my-component>`
  704. });
  705.  
  706. // 等待页面加载完成
  707. window.addEventListener('load', function() {
  708. // 将占位元素追加到 body 元素中
  709. document.body.appendChild(vueInstance.$el);
  710. });
  711.  
  712. // 将文件条目组织成嵌套结构
  713. function organizeFileEntries(fileEntries) {
  714. const root = {
  715. label: document.querySelector('.home-panel-title').innerText || document.getElementById('project_name_edit').value,
  716. type: 'folder',
  717. children: []
  718. };
  719.  
  720. // 创建嵌套结构
  721. fileEntries.forEach(entry => {
  722. const pathSegments = entry.name.split('/');
  723. let currentFolder = root;
  724.  
  725. // 遍历路径中的每个部分,创建相应的文件夹节点
  726. for (let i = 0; i < pathSegments.length - 1; i++) {
  727. const folderName = pathSegments[i];
  728. let folder = currentFolder.children.find(child => child.label === folderName);
  729.  
  730. if(isExcludeFolder(entry.name)) {
  731. continue;
  732. }
  733.  
  734. if (!folder) {
  735. folder = {
  736. label: folderName,
  737. type: 'folder',
  738. children: []
  739. };
  740. currentFolder.children.push(folder);
  741. }
  742.  
  743. currentFolder = folder;
  744. }
  745.  
  746. // 创建文件节点并添加到相应的文件夹中
  747. const fileName = pathSegments[pathSegments.length - 1];
  748.  
  749. if(fileName && fileName.length && isIncludeFile(fileName) && !isExcludeFolder(entry.name)) {
  750. const fileNode = {
  751. label: fileName,
  752. type: 'file',
  753. entry: entry.name
  754. };
  755. currentFolder.children.push(fileNode);
  756. }
  757. });
  758.  
  759. return [root];
  760. }
  761. // 是否排除的文件夹
  762. function isExcludeFolder(entry) {
  763. if(entry.indexOf('css') > -1 ||
  764. entry.indexOf('scss') > -1 ||
  765. entry.indexOf('js') > -1 ||
  766. entry.indexOf('images') > -1 ||
  767. entry.indexOf('fui') > -1 ||
  768. entry.indexOf('lib') > -1 ||
  769. entry.indexOf('test') > -1 ||
  770. entry.indexOf('font') > -1 ||
  771. entry.indexOf('frame/fui') > -1) {
  772. return true;
  773. } else {
  774. return false;
  775. }
  776. }
  777. // 是否包含的文件
  778. function isIncludeFile(fileName) {
  779. if(fileName.indexOf('.html') > -1) {
  780. return true;
  781. } else {
  782. return false;
  783. }
  784. }
  785.  
  786. function getZipResource(callback) {
  787. const downloadUrl = window.location.origin + document.querySelector('.gl-button.btn-sm.btn-confirm').getAttribute('href');
  788.  
  789. fetch(downloadUrl)
  790. .then(response => response.arrayBuffer())
  791. .then(data => {
  792. // 将 ZIP 文件的二进制数据传递给 JSZip 进行解析
  793. return JSZip.loadAsync(data);
  794. })
  795. .then(zip => {
  796. // 获取 ZIP 文件中的所有条目(文件和目录)
  797. const zipEntries = Object.values(zip.files);
  798. const treeData = organizeFileEntries(zipEntries)
  799.  
  800. callback && callback(treeData);
  801.  
  802. })
  803. .catch(error => {
  804. console.error(error);
  805. });
  806. }
  807.  
  808. // 树结构第一个节点数据
  809. function findFirstFileNode(tree) {
  810. // 遍历树的节点
  811. for (let i = 0; i < tree.length; i++) {
  812. const node = tree[i];
  813.  
  814. // 如果节点的类型为 file,则返回该节点
  815. if (node.type === 'file') {
  816. return node;
  817. }
  818.  
  819. // 如果节点有子节点,则递归调用该函数查找子节点中的第一个 file 节点
  820. if (node.children && node.children.length > 0) {
  821. const fileNode = findFirstFileNode(node.children);
  822. if (fileNode) {
  823. return fileNode;
  824. }
  825. }
  826. }
  827.  
  828. // 如果没有找到 file 节点,则返回 null
  829. return null;
  830. }
  831. })();
  832.  
  833. // 修改项目描述的长度
  834. (function() {
  835. 'use strict';
  836. let regs = [/^http:\/\/192\.168\.0\.200\/fe3project\//,
  837. /^http:\/\/192\.168\.0\.200\/frontend_pc\/project\//];
  838. let match = false;
  839.  
  840. for(let r = 0, lr = regs.length; r < lr; r++) {
  841. if(regs[r].test(location.href)) {
  842. match = true;
  843. break;
  844. }
  845. }
  846.  
  847. if(!match) {
  848. return;
  849. }
  850.  
  851. let tryTimes = 6;
  852. let changed = false;
  853.  
  854. // 增加项目描述的输入长度
  855. function modifyTextareaLen() {
  856. if(tryTimes > 0 && !changed) {
  857. setTimeout(() => {
  858. const textarea = document.getElementById('project_description');
  859. tryTimes--;
  860. if(textarea) {
  861. textarea.setAttribute("maxlength", "1000");
  862.  
  863. jQuery(textarea).blur(function(event) {
  864. this.value = this.value.replace(/,/g, ',').replace(/&isfwqfb=1/g, '');
  865. this.value = convertDateFormat(this.value);
  866. jQuery(this).trigger('change');
  867. });
  868. changed = true;
  869. } else {
  870. modifyTextareaLen();
  871. }
  872. }, 1000);
  873. }
  874. }
  875.  
  876. window.onload = function() {
  877. modifyTextareaLen();
  878. }
  879. })();
  880.  
  881. // 设计门户增加通往前端仓库的跳板
  882. (function() {
  883. 'use strict';
  884.  
  885. let regs = [/^https:\/\/oa\.epoint\.com\.cn\/interaction-design-portal\/portal\/pages\/casestemplates\/casetemplatesdetail/,
  886. /^https:\/\/oa\.epoint\.com\.cn\/interaction-design-portal\/portal\/pages\/generalpagetemplates\/generalpagetemplatesdetail/];
  887. let match = false;
  888.  
  889. for(let r = 0, lr = regs.length; r < lr; r++) {
  890. if(regs[r].test(location.href)) {
  891. match = true;
  892. break;
  893. }
  894. }
  895.  
  896. if(!match) {
  897. return;
  898. }
  899.  
  900.  
  901. function addStyle() {
  902. // 注入样式:增加按钮
  903. 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}";
  904.  
  905.  
  906. // 添加注入样式
  907. let extraStyleElement = document.createElement("style");
  908. extraStyleElement.innerHTML = injectStyle;
  909. document.head.appendChild(extraStyleElement);
  910. }
  911.  
  912. function getUrlParameters() {
  913. var params = {};
  914. var search = window.location.search.substring(1);
  915. var urlParams = search.split('&');
  916.  
  917. for (var i = 0; i < urlParams.length; i++) {
  918. var param = urlParams[i].split('=');
  919. var paramName = decodeURIComponent(param[0]);
  920. var paramValue = decodeURIComponent(param[1] || '');
  921. params[paramName] = paramValue;
  922. }
  923.  
  924. return params;
  925. }
  926.  
  927. window.onload = ()=> {
  928. addStyle();
  929. const $content = jQuery('.content');
  930.  
  931. $content.append('<div class="front-proto">前端原型</div>');
  932.  
  933. const $frontBtn = jQuery('.front-proto', $content);
  934.  
  935. $frontBtn.on('click', ()=> {
  936. window.open('http://192.168.0.200/?name=' + getUrlParameters().guid);
  937. });
  938. };
  939. })();
  940.  
  941. // 前端项目案例库增加获取参数的能力
  942. // 前端项目案例库增加部署能力
  943. (function() {
  944. 'use strict';
  945.  
  946. let regs = [/^http:\/\/192\.168\.118\.60:9999\/webapp\/pages\/caselib\/create\.html/,
  947. /^http:\/\/192\.168\.201\.159:9999\/webapp\/pages\/default\/onlinecase.html/];
  948. let match = false;
  949.  
  950. for(let r = 0, lr = regs.length; r < lr; r++) {
  951. if(regs[r].test(location.href)) {
  952. match = true;
  953. break;
  954. }
  955. }
  956.  
  957. if(!match) {
  958. return;
  959. }
  960.  
  961. const fontUrl = 'https://element.eleme.io/2.11/static/element-icons.535877f.woff';
  962.  
  963. // 添加样式规则,将字体应用到指定元素上
  964. GM_addStyle(`
  965. @font-face {
  966. font-family: element-icons;
  967. src: url(${fontUrl}) format("woff");
  968. }
  969. `);
  970.  
  971. GM_addStyle(GM_getResourceText('ElementCSS'));
  972.  
  973. const businessType = [
  974. { Value: '7a20e23c-30b8-47e2-8d8d-f2691c9c63c4', Text: '政务服务' },
  975. { Value: 'c12150bb-b358-452f-87f0-8a2254df87cb', Text: '政务协同' },
  976. { Value: '3845804e-de68-421c-9402-7b238cfb5a70', Text: '大数据' },
  977. { Value: '3c28ee56-f24d-4843-b9a2-93e6b96264f4', Text: '电子交易' },
  978. { Value: '673b5918-51bc-4f1a-ab73-fca86e54d7d1', Text: '数字建设' },
  979. { Value: '6d9e7d84-7de3-4e0f-bd4f-ed4722ed25b5', Text: '建筑企业' },
  980. { Value: 'c22f8d2f-518d-4381-b88c-1da68536ed3a', Text: '公共安全' },
  981. { Value: 'c5810829-1b21-4b22-85cd-390b1edd9614', Text: '智能设备' },
  982. { Value: '080c7560-c261-428b-a45d-b86b57b47ffb', Text: '中央研究院' }
  983. ];
  984.  
  985. const projectType = [
  986. { Value: 'dca44f63-be3f-4e9c-b78f-d786571c22c9', Text: '网站' },
  987. { Value: 'c7861460-163b-4060-80ec-d60604c50435', Text: '业务系统' },
  988. { Value: '49accc71-6f7d-43f3-b726-58decf58b6fa', Text: '智能设备' },
  989. { Value: '90209c65-1a55-4d8c-a836-2e5c6b834ada', Text: '大屏可视化' },
  990. { Value: 'fb0415fb-65ee-42c1-895a-dca042c2568e', Text: '中屏可视化' },
  991. { Value: '2b83f9b1-ec78-4819-a400-d7d49ea1ecc5', Text: '其他' }
  992. ];
  993.  
  994. let $businesstype;
  995. let $projecttype;
  996.  
  997. function getUrlParameters() {
  998. var params = {};
  999. var search = window.location.search.substring(1);
  1000. var urlParams = search.split('&');
  1001.  
  1002. for (var i = 0; i < urlParams.length; i++) {
  1003. var param = urlParams[i].split('=');
  1004. var paramName = decodeURIComponent(param[0]);
  1005. var paramValue = decodeURIComponent(param[1] || '');
  1006. if(paramName) {
  1007. params[paramName] = paramValue;
  1008. }
  1009. }
  1010.  
  1011. return params;
  1012. }
  1013.  
  1014. function initForm (params) {
  1015. if(typeof params === 'object') {
  1016. document.getElementsByName('Title')[0].value = params.projectName ? params.projectName : '';
  1017. document.getElementsByName('KeyWords')[0].value = params.projectKeys ? params.projectKeys : '';
  1018. document.getElementsByName('Entry')[0].value = params.entryUrl ? params.entryUrl : '';
  1019. document.getElementsByName('SourceCode')[0].value = params.git ? params.git : '';
  1020. }
  1021. }
  1022.  
  1023. let setSuccess = false;
  1024. let setTimes = 5;
  1025.  
  1026. function initSelect(params) {
  1027. if(typeof params !== 'object') {
  1028. return;
  1029. }
  1030.  
  1031. if(setTimes > 0 && !setSuccess) {
  1032. setTimeout(()=> {
  1033. setTimes--;
  1034.  
  1035. businessType.forEach((item)=> {
  1036. if(params.projectBU) {
  1037. if(item.Text === params.projectBU.trim()) {
  1038. $businesstype.val(item.Value);
  1039. } else if( params.projectBU.trim() == '一网统管' || params.projectBU.trim() == '一网协同' || params.projectBU.trim() == '一网通办' ) {
  1040. $businesstype.val('7a20e23c-30b8-47e2-8d8d-f2691c9c63c4');
  1041. }
  1042. $businesstype.trigger("chosen:updated");
  1043. }
  1044. });
  1045.  
  1046. projectType.forEach((item)=> {
  1047. if(params.projectType && item.Text === params.projectType.trim()) {
  1048. $projecttype.val(item.Value);
  1049. $projecttype.trigger("chosen:updated");
  1050. }
  1051. });
  1052.  
  1053. setSuccess = true;
  1054.  
  1055. }, 1000);
  1056. } else {
  1057. initSelect(params);
  1058. }
  1059. }
  1060.  
  1061. function addRelatedDom() {
  1062. const sourceInput = document.getElementsByName('SourceCode')[0];
  1063. const $sourceInput = jQuery(sourceInput);
  1064.  
  1065. $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>')
  1066. }
  1067.  
  1068. function addStyle() {
  1069. let epointCss = ".el-loading-spinner {margin-top: -50px;} .el-button--primary:focus {outline: 0 !important;}";
  1070. // 添加注入样式
  1071. let extraStyleElement = document.createElement("style");
  1072. extraStyleElement.innerHTML = epointCss;
  1073. document.head.appendChild(extraStyleElement);
  1074. }
  1075.  
  1076. window.onload = ()=> {
  1077. const params = getUrlParameters();
  1078.  
  1079. // 有参数,进行填充表单
  1080. if(params && params.git) {
  1081. $businesstype = jQuery('#businesstype');
  1082. $projecttype = jQuery('#projecttype');
  1083.  
  1084. initForm(params);
  1085. initSelect(params);
  1086.  
  1087. return false;
  1088. }
  1089.  
  1090. // 没有url参数填充,则做部署功能展示
  1091. addRelatedDom();
  1092. addStyle();
  1093.  
  1094. const placeholder = document.createElement('div');
  1095.  
  1096. // 创建 Vue 实例并挂载到页面
  1097. const vueInstance = new Vue({
  1098. el: placeholder,
  1099. data() {
  1100. return {
  1101. framework: [
  1102. {label: '重构模板', value: 1},
  1103. {label: 'f9x1.0', value: 2},
  1104. {label: 'f9x2.0', value: 3},
  1105. {label: 'f950', value: 4},
  1106. {label: 'f950sp1', value: 5},
  1107. {label: 'f950sp2', value: 6},
  1108. {label: 'f950sp3', value: 7},
  1109. {label: 'f951', value: 18},
  1110. {label: 'f940', value: 8},
  1111. {label: 'f941', value: 10},
  1112. {label: 'f942', value: 9},
  1113. {label: 'f934', value: 11},
  1114. {label: 'f933', value: 12},
  1115. {label: 'f932', value: 13},
  1116. {label: 'f9211', value: 14},
  1117. {label: '骨架', value: 15},
  1118. {label: 'Vue', value: 16},
  1119. {label: 'React', value: 17}
  1120. ],
  1121. data: [], // 目录结构树
  1122. defaultProps: {
  1123. children: 'children',
  1124. label: 'label'
  1125. },
  1126. loadingTree: false,
  1127. dialogVisible: false,
  1128. dialogDeployVisible: false,
  1129. showDeployPath: false,
  1130. depDialogVisible: false,
  1131. loading: false,
  1132. formLabelWidth: '120px',
  1133. supportDeploy: false,
  1134. form: {
  1135. frame: '',
  1136. deployPath: ''
  1137. },
  1138. rules: {
  1139. frame: [
  1140. { required: true, message: '请选择框架类型', trigger: 'change' }
  1141. ],
  1142. deployPath: [
  1143. { required: true, message: '请输入部署到 170/showcase 下的目标路径名称', trigger: 'change' }
  1144. ]
  1145. }
  1146. }
  1147. },
  1148. methods: {
  1149. // 部署
  1150. doDeploy() {
  1151. let self = this;
  1152.  
  1153. this.$refs['form'].validate((valid) => {
  1154. if (valid) {
  1155. this.dialogDeployVisible = false;
  1156. this.depDialogVisible = true;
  1157. this.loading = true;
  1158. // 部署
  1159. this.getDeployInfo({ type: '1', frame: this.form.frame, deployPath: this.form.deployPath }, (data)=> {
  1160. this.loading = false;
  1161. this.depDialogVisible = false;
  1162.  
  1163. if(!data.custom.text){
  1164.  
  1165. this.data = data.custom.pageTreeData;
  1166. this.projectFtpUrl = data.custom.projectRootPath;
  1167. this.supportDeploy = data.custom.supportDeploy;
  1168.  
  1169. this.$message({
  1170. type: 'success',
  1171. message: '部署成功!'
  1172. });
  1173. // 打开查看弹窗
  1174. this.viewProject();
  1175. this.toggleViewButton(true);
  1176.  
  1177. } else {
  1178. this.$message({
  1179. type: 'error',
  1180. message: data.custom.text
  1181. });
  1182. }
  1183. });
  1184. } else {
  1185. console.log('error submit!!');
  1186. return false;
  1187. }
  1188. });
  1189. },
  1190. // 项目部署
  1191. getDeployInfo(params, callback) {
  1192. const author = document.querySelector('#account a').innerText.trim().substring(4);
  1193. const projectName = document.getElementsByName('Title')[0].value.trim();
  1194. const projectGitUrl = document.getElementsByName('SourceCode')[0].value.trim();
  1195.  
  1196. if(typeof params == 'function') {
  1197. callback = params;
  1198. params = null;
  1199. }
  1200. if(author && author.length && projectGitUrl) {
  1201. fetch('http://192.168.219.170:3008/api/getDeployInfo', {
  1202. method: 'POST',
  1203. // 允许跨域请求
  1204. mode: 'cors',
  1205. headers: {
  1206. 'Accept': 'application/json',
  1207. 'Content-Type': 'application/json'
  1208. },
  1209. body: JSON.stringify({//post请求参数
  1210. params: {
  1211. "type": (params && params.type !== undefined) ? params.type : '0',// 0 代表查看, 1代表部署
  1212. "deployMan": author, // 部署人姓名
  1213. "projectName": projectName, // 项目名称
  1214. "projectGitUrl": projectGitUrl,
  1215. "frame": (params && params.frame) ? params.frame : undefined,
  1216. "deployPath": (params && params.deployPath) ? params.deployPath : undefined // 部署的目标目录
  1217. }
  1218. })
  1219. })
  1220. .then(response => response.text())
  1221. .then((result) => {
  1222. var data = JSON.parse(result);
  1223. callback && callback(data);
  1224. })
  1225. .catch(error => {
  1226. this.depDialogVisible = false;
  1227. this.dialogVisible = false;
  1228. this.$message({
  1229. type: 'error',
  1230. message: '系统故障,请联系管理员。'
  1231. });
  1232. console.error(error);
  1233. });
  1234. } else {
  1235. this.$message({
  1236. type: 'error',
  1237. message: '本页面不支持查看和部署,请先登录。'
  1238. });
  1239. console.error('部署信息请求参数error');
  1240. }
  1241. },
  1242. // 查看项目
  1243. viewProject () {
  1244. this.dialogVisible = true;
  1245. let self = this;
  1246.  
  1247. if(this.data) {
  1248. this.loadingTree = false;
  1249. } else {
  1250. this.loadingTree = true;
  1251. // 发送ajax请求,查看是否进行过部署
  1252. this.getDeployInfo((data)=> {
  1253. // 有部署信息,直接赋值,
  1254. if(data) {
  1255. self.projectIsDeployed = true;
  1256. self.data = data.custom.pageTreeData;
  1257. self.projectFtpUrl = data.custom.projectRootPath;
  1258. self.supportDeploy = data.custom.supportDeploy;
  1259. self.loadingTree = false;
  1260.  
  1261. self.toggleViewButton(true);
  1262.  
  1263. }
  1264. });
  1265. }
  1266. },
  1267. handleNodeClick(data) {
  1268. console.log(data);
  1269. if(data.type === 'folder') {
  1270. return false;
  1271. }
  1272. var self = this;
  1273. var entry = data.entry;
  1274. self.clickNodeEntry = entry;
  1275. if(self.projectFtpUrl) {
  1276. window.open('http://192.168.219.170' + self.projectFtpUrl + data.entry);
  1277. self.clickNodeEntry = null;
  1278. } else {
  1279. if(this.supportDeploy === false) {
  1280. this.$message({
  1281. type: 'error',
  1282. message: '当前项目暂时只支持查看,请耐心等待功能升级。'
  1283. });
  1284. self.clickNodeEntry = null;
  1285. return false;
  1286. }
  1287.  
  1288. this.$confirm('资源未部署,部署至 170 服务器后可查看,是否部署?')
  1289. .then(_ => {
  1290.  
  1291. this.dialogDeployVisible = true;
  1292. })
  1293. .catch(_ => {});
  1294. }
  1295. },
  1296. // svn 需要制定目录名称,showDeployPath
  1297. showDialog(showDeployPath) {
  1298. this.showDeployPath = showDeployPath;
  1299. this.dialogDeployVisible = true;
  1300. },
  1301. // 查看按钮显影控制
  1302. toggleViewButton(show) {
  1303. const $viewBtn = jQuery('#view');
  1304.  
  1305. if(!$viewBtn.length) {
  1306. return;
  1307. }
  1308.  
  1309. if(show) {
  1310. $viewBtn.removeClass('hidden');
  1311. } else {
  1312. $viewBtn.addClass('hidden');
  1313. }
  1314. }
  1315. },
  1316. mounted() {
  1317. const $btnDeloy = jQuery('#deploy');
  1318. const $btnView = jQuery('#view');
  1319.  
  1320. // 绑定vue组件外的事件
  1321. $btnDeloy.on('click', function() {
  1322. // 源码地址和项目名称判断
  1323. const sourceInput = document.getElementsByName('SourceCode');
  1324. const projectNameInput = document.getElementsByName('Title');
  1325.  
  1326. let sourceInputVal = sourceInput[0].value.trim(),
  1327. projectNameInputVal = projectNameInput[0].value.trim();
  1328.  
  1329. const gitpattern = /^http:\/\/192\.168/;
  1330. const svnpattern = /^svn:\/\/192\.168/;
  1331. const sourcepattern = /^(svn:\/\/192\.168|http:\/\/192\.168)/;
  1332.  
  1333. if (!sourceInputVal) {
  1334. vueInstance.$message({
  1335. type: 'error',
  1336. message: '请输入源码地址!'
  1337. });
  1338. return
  1339. }
  1340.  
  1341. if (!sourcepattern.test(sourceInputVal)) {
  1342. vueInstance.$message({
  1343. type: 'error',
  1344. message: '请输入准确的源码 gitlab 或 svn 地址!'
  1345. });
  1346. return
  1347. }
  1348.  
  1349. if (svnpattern.test(sourceInputVal) && !projectNameInputVal) {
  1350. vueInstance.$message({
  1351. type: 'error',
  1352. message: ' svn 仓库地址部署需要填写项目(案例)名称!'
  1353. });
  1354. return
  1355. }
  1356.  
  1357. vueInstance.showDialog(svnpattern.test(sourceInputVal));
  1358. });
  1359. // 查看项目
  1360. $btnView.on('click', function() {
  1361. vueInstance.viewProject();
  1362. });
  1363.  
  1364. },
  1365. template: `<div id="my-form">
  1366. <el-dialog title="部署提示" width="640px" :visible.sync="dialogDeployVisible">
  1367. <el-alert
  1368. title="此操作将把 GitLab / SVN 资源打包部署至 170 服务器,已部署过的项目会进行覆盖部署,是否继续?"
  1369. type="warning" :closable="false" style="margin-bottom: 20px;">
  1370. </el-alert>
  1371. <el-form :model="form" ref="form" :rules="rules">
  1372. <el-form-item label="框架类型" :label-width="formLabelWidth" prop="frame">
  1373. <el-select v-model="form.frame" placeholder="请框架类型" style="width:380px;">
  1374. <el-option v-for="item in framework" :key="item.value" :label="item.label" :value="item.value"></el-option>
  1375. </el-select>
  1376. </el-form-item>
  1377. <el-form-item label="部署路径" :label-width="formLabelWidth" prop="deployPath" v-if="showDeployPath">
  1378. <el-input v-model="form.deployPath" placeholder="请输入部署至服务器 170/showcase 下的目标路径名称" style="width:380px;"></el-input>
  1379. </el-form-item>
  1380. </el-form>
  1381. <div slot="footer" class="dialog-footer">
  1382. <el-button @click="dialogDeployVisible = false">取 消</el-button>
  1383. <el-button type="primary" @click="doDeploy">确 定</el-button>
  1384. </div>
  1385. </el-dialog>
  1386. <el-dialog
  1387. title="部署"
  1388. width="420px"
  1389. :visible.sync="depDialogVisible">
  1390. <div class="deploy-body"
  1391. style="height: 306px;"
  1392. v-loading="loading"
  1393. element-loading-text="正在打包部署至 170 服务器,请耐心等待"
  1394. element-loading-spinner="el-icon-loading">
  1395. </div>
  1396. </el-dialog>
  1397. <el-dialog
  1398. title="目录结构"
  1399. width="900px"
  1400. :append-to-body="true"
  1401. :visible.sync="dialogVisible">
  1402. <el-tree
  1403. class="filter-tree"
  1404. :data="data"
  1405. :props="defaultProps"
  1406. node-key="id"
  1407. default-expand-all
  1408. @node-click="handleNodeClick"
  1409. v-loading="loadingTree"
  1410. element-loading-background="rgba(255, 255, 255, 1)"
  1411. element-loading-text="拼命加载中......"
  1412. ref="tree">
  1413. </el-tree>
  1414. </el-dialog>
  1415. </div>`
  1416. });
  1417.  
  1418. // 将占位元素追加到 body 元素中
  1419. jQuery('.form-container').after(vueInstance.$el);
  1420. };
  1421. })();
  1422.  
  1423. // 新建项目提示
  1424. (function() {
  1425. 'use strict';
  1426. let regs = [/^http:\/\/192\.168\.0\.200\/projects\/new/];
  1427. let match = false;
  1428.  
  1429. for(let r = 0, lr = regs.length; r < lr; r++) {
  1430. if(regs[r].test(location.href)) {
  1431. match = true;
  1432. break;
  1433. }
  1434. }
  1435.  
  1436. if(!match) {
  1437. return;
  1438. }
  1439.  
  1440. // 等待页面加载完成
  1441. window.addEventListener('load', function() {
  1442. const $projectName = jQuery('#project_name');
  1443. const $projectDescription = jQuery('#project_description');
  1444. const $check = jQuery('#project_visibility_level_10');
  1445.  
  1446. if($projectName && $projectName.length) {
  1447. $projectName.attr('placeholder', '以需求或项目管理系统中的项目名称为准')
  1448. }
  1449.  
  1450. if($projectDescription && $projectDescription.length) {
  1451. $projectDescription.attr('placeholder', 'YYYY-M-D,张三,UI:https://oa.epoint.com.cn/interaction-design-portal/portal/pages/casestemplates/casetemplatesdetail?guid=');
  1452. $projectDescription.val('2023-M-D,张三,UI:https://oa.epoint.com.cn/interaction-design-portal/portal/pages/casestemplates/casetemplatesdetail?guid=');
  1453.  
  1454. // 增加主题表单
  1455. var themeHtml = '<div class="row">\
  1456. <div class="form-group col-md-9">\
  1457. <label class="label-bold" for="project_topics">主题</label>\
  1458. <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="">\
  1459. <p class="form-text text-muted">用逗号分隔主题。</p>\
  1460. <p class="form-text text-muted">业务条线:政务服务、大数据、一网统管、一网协同、智能设备、电子交易、数字建设、公共安全、支撑产品;</p>\
  1461. <p class="form-text text-muted">项目类型:网站、业务系统、智能设备、大屏可视化、中屏可视化、在线表单;</p>\
  1462. <p class="form-text text-muted">关键字:f942f951f950sp2f9x2.0f9x1.0vuereact、单页、gojselementAntDesign、全景、关系图、流程图、响应式、svg、视频、miniuiegisegis3d、高德、百度、超图、three、主题、瀑布流、上传、自定义用户控件等;</p>\
  1463. </div></div>';
  1464.  
  1465. $projectDescription.closest('.form-group').after(themeHtml);
  1466. // 规避中文,
  1467. $projectDescription.blur(function(event) {
  1468. this.value = this.value.replace(/,/g, ',').replace(/&isfwqfb=1/g, '');
  1469. // 日期转换
  1470. this.value = convertDateFormat(this.value);
  1471. });
  1472.  
  1473. var $theme = jQuery('#project_topics');
  1474.  
  1475. $theme.blur(function(event) {
  1476. this.value = this.value.replaceAll(',', ',');
  1477. });
  1478. }
  1479.  
  1480. if($check && $check.length) {
  1481. $check.trigger('click');
  1482. }
  1483. });
  1484.  
  1485. })();