GitLab Assistant

GitLab Viewer Publish and Deploy Project!

目前为 2023-06-14 提交的版本。查看 最新版本

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