GitLab Assistant

GitLab Viewer Publish and Deploy Project!

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

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         GitLab Assistant
// @namespace    http://tampermonkey.net/
// @version      1.09997
// @description  GitLab Viewer Publish and Deploy Project!
// @author       Sean
// @match        http://192.168.0.200*
// @match        http://192.168.0.200/*
// @match        http://192.168.0.200/fe3project/*
// @match        http://192.168.0.200/frontend_pc/project/*
// @match        https://oa.epoint.com.cn/interaction-design-portal/portal/pages/casestemplates/casetemplatesdetail*
// @match        https://oa.epoint.com.cn/interaction-design-portal/portal/pages/generalpagetemplates/generalpagetemplatesdetail*
// @match        https://oa.epoint.com.cn/interaction-design-portal/portal/pages/dynamiceffecttemplates/dynamiceffecttemplatesdetail*
// @match        http://192.168.201.159:9999/webapp/pages/default/onlinecase.html*
// @match        http://192.168.118.60:9999/webapp/pages/caselib/create.html*
// @match        https://oa.epoint.com.cn/epointoa9/frame/fui/pages/themes/aide/aide*
// @match        https://oa.epoint.com.cn/interaction-design-portal/portal/pages/casestemplates/casetemplateslist*
// @match        https://oa.epoint.com.cn:8080/OA9/oa9/mail/mailreceivedetail*
// @match        https://oa.epoint.com.cn/productrelease/cpzt/demandmanageznsb/demandbasicinfo_detail*
// @match        https://greasyfork.org/zh-CN/scripts/466808/versions/new*
// @icon         http://192.168.0.200/assets/favicon-7901bd695fb93edb07975966062049829afb56cf11511236e61bcf425070e36e.png
// @require      https://cdn.bootcdn.net/ajax/libs/vue/2.7.14/vue.min.js
// @require      https://unpkg.com/element-ui/lib/index.js
// @require      https://cdn.bootcdn.net/ajax/libs/jszip/3.7.1/jszip.min.js
// @grant        GM_getResourceURL
// @grant        GM_addStyle
// @grant        GM_getResourceText
// @resource     ElementCSS https://unpkg.com/element-ui/lib/theme-chalk/index.css
// @grant        GM_xmlhttpRequest
// @license      MIT
// @run-at       document-end
// ==/UserScript==


// 个性化 gitlab 样式,
// 满足项目详情多行显示,
// 项目列表中的链接新窗口打开,
// 搜索框 placeholder 个性化提示
// 增加CodePipeline 入口等
(function() {
    'use strict';

    let regs = [/^http:\/\/192\.168\.0\.200\/fe3project\//,
               /^http:\/\/192\.168\.0\.200\/frontend_pc\/project\//,
               /^http:\/\/192\.168\.0\.200/,
               /^http:\/\/192\.168\.0\.200\//];
    let match = false;

    for(let r = 0, lr = regs.length; r < lr; r++) {
        if(regs[r].test(location.href)) {
            match = true;
            break;
        }
    }

    if(!match) {
        return;
    }

    // 注入样式:改变容器宽度,项目描述多行展示
    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;}";

    injectStyle += ".container-fluid.container-limited.limit-container-width .file-holder.readme-holder.limited-width-container .file-content {max-width: none;}"
    injectStyle += 'button:focus {outline-color: transparent !important;}'
    injectStyle += '.has-description .description {word-break: break-all;}'
    // 添加注入样式
    let extraStyleElement = document.createElement("style");
    extraStyleElement.innerHTML = injectStyle;
    document.head.appendChild(extraStyleElement);

    const fontUrl = 'https://element.eleme.io/2.11/static/element-icons.535877f.woff';

    // 添加样式规则,将字体应用到指定元素上
    GM_addStyle(`
        @font-face {
            font-family: element-icons;
            src: url(${fontUrl}) format("woff");
        }
    `);

    GM_addStyle(GM_getResourceText('ElementCSS'));

    // 改变列表打开链接方式,改为新窗口打开
    let change = false;
    let tryTimes = 3;

    function changeOpenType() {
        if(!change){
            setTimeout(()=> {
                let links = document.querySelectorAll('.description a');
                if(links.length) {
                    for(let i = 0, l = links.length; i < l; i++) {
                        links[i].target = "_blank";
                        if(i === l - 1) {
                            change = true;
                        }
                    }
                } else {
                    changeOpenType();
                }
            }, 1000);
        }
    }

    function stopLinkProp() {
        setTimeout(()=> {
            const links = document.querySelectorAll('.description a');
            for(let i = 0, l = links.length; i < l; i++) {
                links[i].addEventListener('click', ()=> {
                    event.stopPropagation();
                });
            }
        }, 1000);
    }

    // 等待页面加载完成
    window.addEventListener('load', function() {

        var targetDiv = document.querySelector('section');

        if(targetDiv) {
            // 创建一个 Mutation Observer 实例
            var observer = new MutationObserver(function(mutations) {
                // 在这里处理 div 子元素的变化
                mutations.forEach(function(mutation) {
                    if(mutation.addedNodes && mutation.addedNodes.length) {
                        change = false;
                        changeOpenType();

                        stopLinkProp();
                    }
                });
            });

            // 配置 Mutation Observer
            var config = { childList: true, subtree: true };

            // 开始观察目标 div 元素
            observer.observe(targetDiv, config);
        }

        const placeholder = document.createElement('div');

        // 创建 Vue 实例并挂载到页面
        const vueInstance = new Vue({
            el: placeholder,
            methods: {
                // 进入管理平台 code pipeline
                manage() {
                    window.open('http://192.168.219.170/code-pipeline')
                }
            },
            template: `<div id="my-ext" style="margin-top:4px;">
              <el-tooltip content="进入 Code Pipeline 管理平台" placement="top" effect="light">
                <el-button type="primary" icon="el-icon-attract" size="small" circle @click="manage"></el-button>
              </el-tooltip>
            </div>`
        });

        // 将占位元素追加到 body 元素中
        document.querySelector('.title-container').appendChild(vueInstance.$el);

        // 修改 placehodler
        const listInput = document.getElementById('group-filter-form-field');
        const listInput2 = document.getElementById('project-filter-form-field');

        if(listInput) {
            listInput.setAttribute("placeholder", "按项目名称、日期、开发者搜索,关键字≥3");
            listInput.style.width = '305px';
        }
        if(listInput2) {
            listInput2.setAttribute("placeholder", "按项目名称、日期、开发者搜索,关键字≥3");
            listInput2.style.width = '305px';
        }
    });


})();

// 公共方法
(function(){
    function convertDateFormat(inputString) {
        // 匹配日期格式为yyyy-mm-dd或yyyy-m-dd或yyyy-mm-d或yyyy-m-d的正则表达式
        const dateRegex = /\d{4}-\d{1,2}-\d{1,2}/g;

        // 找到所有匹配的日期格式
        const dates = inputString.match(dateRegex);

        // 如果没有匹配到日期,则直接返回原始字符串
        if (!dates || dates.length === 0) {
            return inputString;
        }

        // 遍历所有匹配到的日期,进行转换
        dates.forEach((date) => {
            const [year, month, day] = date.split('-');
            const formattedDate = `${parseInt(year, 10)}-${parseInt(month, 10)}-${parseInt(day, 10)}`;
            inputString = inputString.replace(date, formattedDate);
        });

        return inputString;
    }

    function getUrlParameters() {
        var params = {};
        var search = window.location.search.substring(1);
        var urlParams = search.split('&');

        for (var i = 0; i < urlParams.length; i++) {
            var param = urlParams[i].split('=');
            var paramName = decodeURIComponent(param[0]);
            var paramValue = decodeURIComponent(param[1] || '');
            if(paramName) {
                params[paramName] = paramValue;
            }
        }

        return params;
    }

    // 检查脚本更新
    GM_xmlhttpRequest({
        method: 'GET',
        url: 'http://192.168.0.200/fe3group/gitlabassistant-web/-/raw/main/version.json',
        headers: {
            'Content-Type': 'application/json; charset=utf-8'
        },
        onload: function(res) {
            const data = JSON.parse(res.response);

            const version = GM_info.script.version;
            // 有新版本
            if(parseInt(version.replace(/\./g, '')) < parseInt(data.version.replace(/\./g, ''))) {
                const updateConfirm = confirm("Gitlab Assistant 脚本有更新,建议更新!");
                if (updateConfirm == true){
                    window.open('https://greasyfork.org/zh-CN/scripts/466808-gitlab-assistant')
                }
            }
        }
    });

    /*
    * 获取分支列表
    */
    function getBranches (fn) {
        GM_xmlhttpRequest({
            method: 'GET',
            url: location.href.split('/-/')[0] + '/refs',
            headers: {
                'Content-Type': 'application/json; charset=utf-8'
            },
            onload: function(res) {
                const data = JSON.parse(res.response);
                const branches = data.Branches;

                if(branches) {
                    fn && fn(branches);
                }
            }
        });
    }

    window.convertDateFormat = convertDateFormat;

    window.gitlabUtil = {
        getUrlParameters: getUrlParameters,
        getBranches: getBranches
    }
})();

// GitLab Viewer Publish and Deploy Project
// 查看项目、部署项目、发布项目功能
// 添加搜索设计门户资源功能
(function() {
    'use strict';
    let regs = [/^http:\/\/192\.168\.0\.200\/fe3project\//,
               /^http:\/\/192\.168\.0\.200\/frontend_pc\/project\//,
               /^http:\/\/192\.168\.0\.200\/fepublic\//];
    let match = false;

    for(let r = 0, lr = regs.length; r < lr; r++) {
        if(regs[r].test(location.href)) {
            match = true;
            break;
        }
    }

    if(!match) {
        return;
    }
    /*
    const fontUrl = 'https://element.eleme.io/2.11/static/element-icons.535877f.woff';

    // 添加样式规则,将字体应用到指定元素上
    GM_addStyle(`
        @font-face {
            font-family: element-icons;
            src: url(${fontUrl}) format("woff");
        }
    `);

    GM_addStyle(GM_getResourceText('ElementCSS'));
    */

    let epointCss = ".epoint-tool {position: fixed; bottom: 0%; right:10px; transform: translateY(-40%);}";
    epointCss += ".el-row { padding: 6px 0;} .el-dialog__body .el-tree{min-height: 420px; max-height: 500px;overflow: auto;}";
    epointCss += ".view-toolbar {padding-bottom: 10px;}";
    epointCss += ".deploy-body {height: 306px;}"
    epointCss += ".el-loading-spinner {margin-top: -60px;} .el-button--primary:focus {outline: 0 !important;}";

    // 添加注入样式
    let extraStyleElement = document.createElement("style");
    extraStyleElement.innerHTML = epointCss;
    document.head.appendChild(extraStyleElement);

    const MyComponent = {
        template: `<div class="epoint-wrap">
            <div class="epoint-tool">
            <el-row>
                <el-tooltip content="查看项目页面和模块结构" placement="left" effect="light">
                <el-button type="primary" icon="el-icon-search" round @click="viewProject">查看</el-button>
                </el-tooltip>
            </el-row>
            <el-row>
                <el-tooltip content="一键部署到170服务器" placement="left" effect="light">
                    <el-button type="primary" icon="el-icon-s-unfold" round @click="doDeploy">部署</el-button>
                </el-tooltip>
            </el-row>
            <el-row>
                <el-tooltip content="一键发布到项目案例库" placement="left" effect="light">
                    <el-button type="primary" icon="el-icon-upload" round @click="publish">发布</el-button>
                </el-tooltip>
            </el-row>
            <el-row>
                <el-tooltip content="进入 Code Pipeline 管理平台进行更多操作" placement="left" effect="light">
                    <el-button type="primary" icon="el-icon-attract" round @click="manage">管理</el-button>
                </el-tooltip>
            </el-row>
            </div>
            <el-dialog
              title="目录结构"
              width="900px"
              :append-to-body="true"
              :visible.sync="dialogVisible"
              :before-close="handleClose">
                <div class="view-body">
                    <div class="view-toolbar" v-if="projectFtpUrl"><el-button type="primary" size="small" @click="viewAll">查看全部</el-button></div>
                    <div class="view-content">
                        <el-tree
                            class="filter-tree"
                            :data="data"
                            :props="defaultProps"
                            node-key="id"
                            default-expand-all
                            @node-click="handleNodeClick"
                            v-loading="loadingTree"
                            element-loading-background="rgba(255, 255, 255, 1)"
                            element-loading-text="拼命加载中......"
                            ref="tree">
                        </el-tree>
                    </div>
                </div>
            </el-dialog>
            <el-dialog
                title="部署"
                width="420px"
                :visible.sync="depDialogVisible">
                    <div class="deploy-body"
                        v-loading="loading"
                        element-loading-text="正在打包部署至 170 服务器,请耐心等待"
                        element-loading-spinner="el-icon-loading">
                    </div>
            </el-dialog>
            <el-dialog title="部署提示" width="640px" :visible.sync="dialogDeployVisible">
                <el-alert
                    title="此操作将把 GitLab 资源打包部署至 170 服务器,已部署过的项目会进行覆盖部署,是否继续?"
                    type="warning" :closable="false" style="margin-bottom: 20px;">
                </el-alert>
                <el-form :model="form" ref="form" :rules="rules">
                    <el-form-item label="框架类型" :label-width="formLabelWidth" prop="frame">
                        <el-select v-model="form.frame" placeholder="请框架类型">
                            <el-option v-for="item in framework" :key="item.value" :label="item.label" :value="item.value"></el-option>
                        </el-select>
                    </el-form-item>
                    <el-form-item label="分支" :label-width="formLabelWidth" prop="branch">
                        <el-select v-model="form.branch" placeholder="请选择分支">
                            <el-option v-for="item in branches" :key="item.value" :label="item.label" :value="item.value"></el-option>
                        </el-select>
                    </el-form-item>
                </el-form>
                <div slot="footer" class="dialog-footer">
                    <el-button @click="dialogDeployVisible = false">取 消</el-button>
                    <el-button type="primary" @click="doDeploy">确 定</el-button>
                </div>
            </el-dialog>
        </div>`,
        data() {
            return {
                dialogVisible: false, // 查看目录结构弹窗
                data: [], // 目录结构树的数据结构
                defaultProps: {
                    children: 'children',
                    label: 'label'
                },
                loadingTree: false,
                depDialogVisible: false, // 部署中弹窗
                loading: false,
                projectLibUrl: 'http://192.168.118.60:9999/webapp/pages/caselib/create.html', // 项目案例库地址
                projectIsDeployed: false, // 项目是否部署过
                projectFtpUrl: '', // ftp路径
                projectEntryUrl: '', // 项目案例库发布表单的入口页面
                supportDeploy: true, // 项目是否支持部署
                dialogDeployVisible: false,
                formLabelWidth: '120px',
                form: {
                    frame: '',
                    branch: ''
                },
                framework: [
                    {label: '重构模板', value: 1},
                    {label: 'f9x1.0', value: 2},
                    {label: 'f9x2.0', value: 3},
                    {label: 'f950', value: 4},
                    {label: 'f950sp1', value: 5},
                    {label: 'f950sp2', value: 6},
                    {label: 'f950sp3', value: 7},
                    {label: 'f951', value: 18},
                    {label: 'f940', value: 8},
                    {label: 'f941', value: 10},
                    {label: 'f942', value: 9},
                    {label: 'f934', value: 11},
                    {label: 'f933', value: 12},
                    {label: 'f932', value: 13},
                    {label: 'f9211', value: 14},
                    {label: '骨架', value: 15},
                    {label: 'Vue', value: 16},
                    {label: 'React', value: 17}
                ],
                rules: {
                    frame: [
                        { required: true, message: '请选择框架类型', trigger: 'change' }
                    ],
                    branch: [
                        { required: true, message: '请选择分支', trigger: 'change' }
                    ]
                },
                clickNodeEntry: null,
                branches: []
            };
        },
        methods: {
            handleClose(done) {
                done();
                /*
                this.$confirm('确认关闭?')
                    .then(_ => {
                        done();
                    })
                    .catch(_ => {});*/
            },
            handleNodeClick(data) {
                console.log(data);
                if(data.type === 'folder') {
                    return false;
                }
                var self = this;
                var entry = data.entry;
                self.clickNodeEntry = entry;
                if(self.projectFtpUrl) {
                    window.open('http://192.168.219.170' + self.projectFtpUrl + data.entry);
                    self.clickNodeEntry = null;
                } else {
                    if(this.supportDeploy === false) {
                        this.$message({
                            type: 'error',
                            message: '当前项目暂时只支持查看,请耐心等待功能升级。'
                        });
                        self.clickNodeEntry = null;
                        return false;
                    }

                    this.$confirm('资源未部署,部署至 170 服务器后可查看,是否部署?')
                        .then(_ => {

                        this.dialogDeployVisible = true;
                        /*
                        this.depDialogVisible = true;
                        this.loading = true;
                        // 部署
                        this.getDeployInfo({ type: '1' }, (data)=> {
                            this.loading = false;
                            this.depDialogVisible = false;

                            this.data = data.custom.detail;
                            this.projectFtpUrl = data.custom.ftpUrl;

                            this.$alert('部署成功!', '提示', {
                                confirmButtonText: '确定',
                                callback: action => {
                                    window.open('http://192.168.219.170' + self.projectFtpUrl + entry)
                                }
                            });

                        });*/
                    })
                    .catch(_ => {});
                }
            },
            // 部署
            doDeploy () {
                if(!this.isDownLoadPage()) {
                    return;
                }
                if(!this.dialogDeployVisible) {
                    this.dialogDeployVisible = true;
                    return;
                }

                let self = this;

                this.$refs['form'].validate((valid) => {
                    if (valid) {
                        this.dialogDeployVisible = false;
                        this.depDialogVisible = true;
                        this.loading = true;
                        // 部署
                        this.getDeployInfo({ type: '1', frame: this.form.frame, branch: this.form.branch }, (data)=> {
                            this.loading = false;
                            this.depDialogVisible = false;

                            if(!data.custom.text){

                                this.data = data.custom.pageTreeData;
                                this.projectFtpUrl = data.custom.projectRootPath;
                                this.supportDeploy = data.custom.supportDeploy;

                                this.setProjectEntry();
                                // 从部署按钮直接过来的
                                if(!this.clickNodeEntry) {
                                    this.$message({
                                        type: 'success',
                                        message: '部署成功!'
                                    });
                                    // 打开查看弹窗
                                    this.viewProject();
                                } else {// 从点击目录结构过来的,可以调整点击的树节点页面
                                    this.$alert('部署成功!', '提示', {
                                        confirmButtonText: '确定',
                                        callback: action => {
                                            window.open('http://192.168.219.170' + self.projectFtpUrl + self.clickNodeEntry);
                                            self.clickNodeEntry = null;
                                        }
                                    });
                                }

                            } else {
                                this.$message({
                                    type: 'error',
                                    message: data.custom.text
                                });
                            }
                        });
                    } else {
                        console.log('error submit!!');
                        return false;
                    }
                });

                /*
                this.$confirm('此操作将把 GitLab 资源打包部署至 170 服务器,已部署过的项目会进行覆盖部署,是否继续?', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                }).then(() => {
                }).catch(() => {
                    this.$message({
                        type: 'info',
                        message: '已取消部署'
                    });
                });*/
            },
            // 发布项目案例库
            publish () {
                this.$confirm('此操作将把项目发布至 <a href="'+ this.projectLibUrl +'" target="_blank">项目案例库</a>,已发布过的项目案例库会有重复项,是否继续?', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    dangerouslyUseHTMLString: true,
                    type: 'warning'
                }).then(() => {
                    const themes = document.querySelectorAll('.badge-secondary');
                    let keys = [];

                    for(let i = 0, l = themes.length; i < l; i++) {
                        if(themes[0].innerText == '智能设备' && i > 0) {
                            keys.push(themes[i].innerText);
                        } else if (themes[0].innerText !== '智能设备' && i > 1) {
                            keys.push(themes[i].innerText);
                        }
                    }
                    // 存在更多主题的情况
                    const moreKeyEl = document.querySelector('.gl-w-full .text-nowrap');
                    if(moreKeyEl) {
                        const moreKeyElContent = moreKeyEl.getAttribute('data-content');
                        const regex = />([^<]+)</g;
                        const matches = moreKeyElContent.match(regex);
                        const results = matches.filter(function(match) {
                            return match.length > 3;
                        });
                        const moreKeyData = results.map(function(match) {
                            return match.substring(2, match.length - 2);
                        });

                        if(moreKeyData && moreKeyData.length) {
                            keys = keys.concat(moreKeyData);
                        }
                    }

                    // 组织项目案例库所需参数
                    const projectName = document.querySelector('.home-panel-title').innerText;
                    const projectBU = themes[0] ? themes[0].innerText : null;
                    const projectKeys = keys.join(' ');
                    const entryUrl = this.projectEntryUrl;
                    let projectType = themes[1] ? themes[1].innerText : null;

                    if(themes[0]) {
                        if(themes[0].innerText == '智能设备') {
                            projectType = themes[1] ? themes[0].innerText : null;
                        } else {
                            projectType = themes[1] ? themes[1].innerText : null;
                        }
                    }

                    const destUrl = this.projectLibUrl + '?projectName=' + projectName + '&projectBU=' + projectBU + '&projectType=' + projectType + '&projectKeys=' + projectKeys + '&entryUrl=' + entryUrl + '&git=' + window.location.href;

                    this.$message({
                        type: 'success',
                        message: destUrl
                    });
debugger;
                    window.open(destUrl);

                }).catch(() => {
                    this.$message({
                        type: 'info',
                        message: '已取消发布'
                    });
                });
            },
            // 查看项目
            viewProject () {
                if(!this.isDownLoadPage()) {
                    return;
                }
                this.dialogVisible = true;
                this.loadingTree = true;
                let self = this;

                // 发送ajax请求,查看是否进行过部署
                this.getDeployInfo((data)=> {
                    // 有部署信息,直接赋值,
                    if(data) {
                        self.projectIsDeployed = true;
                        self.data = data.custom.pageTreeData;
                        self.projectFtpUrl = data.custom.projectRootPath;
                        self.supportDeploy = data.custom.supportDeploy;
                        self.loadingTree = false;

                        self.setProjectEntry();

                    } else {
                        // 无部署信息,仅查看文件目录
                        getZipResource((data)=> {
                            self.data = data;
                            self.loadingTree = false;
                        });
                    }
                });

            },
            // 查看项目的所有页面
            viewAll() {
                window.open('http://192.168.219.170/code-pipeline/#/project/deploy-preview?rowguid=' + document.body.getAttribute('data-project-id'));
            },
            // 项目部署信息
            getDeployInfo(params, callback) {
                const projectId = document.body.getAttribute('data-project-id');
                const downloadBtn = document.querySelector('.gl-button.btn-sm.btn-confirm');

                const sourceUrl = downloadBtn.getAttribute('href');
                const downloadUrl = window.location.origin + sourceUrl;
                const files = document.body.getAttribute('data-find-file').split('/');
                const name = document.body.getAttribute('data-project') + '-' + files[files.length - 1];
                const author = document.querySelector('.current-user .gl-font-weight-bold').innerText.trim();
                const projectName = document.querySelector('.sidebar-context-title').innerText.trim();
                const deployManOA = document.querySelector('.current-user>a').getAttribute('data-user');
                const projectGitUrl = 'http://192.168.0.200' + document.body.getAttribute('data-find-file').split('/-/')[0];

                if(typeof params == 'function') {
                    callback = params;
                    params = null;
                }

                if(projectId && projectId.length && sourceUrl) {
                    fetch('http://192.168.219.170:3008/api/getDeployInfo', {
                        method: 'POST',
                        // 允许跨域请求
                        mode: 'cors',
                        headers: {
                            'Accept': 'application/json',
                            'Content-Type': 'application/json'
                        },
                        body: JSON.stringify({//post请求参数
                            params: {
                                "type": (params && params.type !== undefined) ? params.type : '0',// 0 代表查看, 1代表部署
                                "name": name, // 项目路径英文名
                                "deployMan": author, // 部署人姓名
                                "deployManOA": deployManOA, // 部署人账号
                                "projectName": projectName, // 项目名称
                                "downloadUrl": downloadUrl, // 下载地址
                                "projectId": projectId, // 主键,gitlab上的项目id
                                "projectGitUrl": projectGitUrl,
                                "frame": (params && params.frame) ? params.frame : undefined
                            }
                        })
                    })
                    .then(response => response.text())
                    .then((result) => {
                        var data = JSON.parse(result);
                        callback && callback(data);
                    })
                    .catch(error => {
                        this.depDialogVisible = false;
                        this.dialogVisible = false;
                        this.$message({
                            type: 'error',
                            message: '系统故障,请联系管理员。'
                        });
                        console.error(error);
                    });
                } else {
                    this.$message({
                        type: 'error',
                        message: '本页不支持查看和部署,请至仓库页。'
                    });
                    console.error('部署信息请求参数error');
                }
            },
            // 进入管理平台 code pipeline
            manage() {
                window.open('http://192.168.219.170/code-pipeline')
            },
            // 设置入口
            setProjectEntry(){
                const firstNode = findFirstFileNode(this.data);
                if(firstNode) {
                    this.projectEntryUrl = 'http://192.168.219.170' + this.projectFtpUrl + firstNode.entry;
                }else {
                    this.projectEntryUrl = null;
                }
            },
            isDownLoadPage() {
                const downloadBtn = document.querySelector('.gl-button.btn-sm.btn-confirm');
                const sourceUrl = downloadBtn && downloadBtn.getAttribute('href');

                if(downloadBtn && sourceUrl) {
                    return true;
                } else {
                    this.$message({
                        type: 'error',
                        message: '本页面不支持查看和部署,请移至仓库页。'
                    });
                    return false;
                }
            }
        },
        mounted() {
            gitlabUtil.getBranches((branches) => {
                let tempArr = [];
                branches.forEach((item, index)=> {
                    tempArr.push({
                        label: item,
                        value: item
                    });
                });
                this.branches = tempArr;
            });

            const selectBranch = document.querySelector('.qa-branches-select').getAttribute('data-selected') || 'main';

            this.form.branch = selectBranch;
        }
    };

    const placeholder = document.createElement('div');

    // 创建 Vue 实例并挂载到页面
    const vueInstance = new Vue({
        el: placeholder,
        components: {
            MyComponent
        },
        methods: {
        },
        template: `<my-component></my-component>`
    });

    // 开始在项目仓库页添加搜索设计门户按钮 start
    const panel = document.querySelector('.project-home-panel');
    let vueInstance2;
    const description = document.querySelector('.read-more-container');
    const descriptionText = description && description.innerText;
    let haveDesignBackupUrl = /platesdetail\?guid=(?!$)/.test(descriptionText);

    if(panel && !haveDesignBackupUrl) {
        const btnPlaceholder = document.createElement('div');
        btnPlaceholder.setAttribute('class', 'epoint-portal-search');
        // 创建 Vue 实例并挂载到页面
        vueInstance2 = new Vue({
            el: btnPlaceholder,
            data: function() {
                return {
                    proName: document.querySelector('.home-panel-title').innerText.trim().substring(0, 4)
                };
            },
            methods: {
                manage() {
                    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)
                }
            },
            template: `<div style="margin-top:4px;">
              <el-tooltip content="新点设计门户中查找此项目" placement="top" effect="light">
                <el-button type="primary" icon="el-icon-search" size="small" @click="manage">查找UI备份地址</el-button>
              </el-tooltip>
            </div>`
        });
        // 开始在项目仓库页添加搜索设计门户按钮 end
    }


    // 等待页面加载完成
    window.addEventListener('load', function() {
        // 将占位元素追加到 body 元素中
        document.body.appendChild(vueInstance.$el);

        panel && !haveDesignBackupUrl && panel.appendChild(vueInstance2.$el);

        // 克隆按钮下增加sourcetree 快捷打开方式
        const dropMenu = document.querySelector('.clone-options-dropdown');

        if(dropMenu) {
            // 协议的方式 sourcetree://cloneRepo?type=stash&cloneUrl=http://192.168.0.200/fe3project/taicang-vue-website.git
            let sourceTreeHtml = '<li class="pt-2 gl-new-dropdown-item">\
            <label class="label-bold gl-px-4!" xt-marked="ok">在您的Sourcetree中打开</label>\
            <a class="dropdown-item open-with-link" href="sourcetree://cloneRepo?type=stash&cloneUrl='+ document.getElementById('http_project_clone').value +'">\
            <div class="gl-new-dropdown-item-text-wrapper" xt-marked="ok">Sourcetree (HTTPS)</div></a></li>';

            jQuery(dropMenu).append(sourceTreeHtml);
        }
    });

    // 将文件条目组织成嵌套结构
    function organizeFileEntries(fileEntries) {
        const root = {
            label: document.querySelector('.home-panel-title').innerText || document.getElementById('project_name_edit').value,
            type: 'folder',
            children: []
        };

        // 创建嵌套结构
        fileEntries.forEach(entry => {
            const pathSegments = entry.name.split('/');
            let currentFolder = root;

            // 遍历路径中的每个部分,创建相应的文件夹节点
            for (let i = 0; i < pathSegments.length - 1; i++) {
                const folderName = pathSegments[i];
                let folder = currentFolder.children.find(child => child.label === folderName);

                if(isExcludeFolder(entry.name)) {
                    continue;
                }

                if (!folder) {
                    folder = {
                        label: folderName,
                        type: 'folder',
                        children: []
                    };
                    currentFolder.children.push(folder);
                }

                currentFolder = folder;
            }

            // 创建文件节点并添加到相应的文件夹中
            const fileName = pathSegments[pathSegments.length - 1];

            if(fileName && fileName.length && isIncludeFile(fileName) && !isExcludeFolder(entry.name)) {
                const fileNode = {
                    label: fileName,
                    type: 'file',
                    entry: entry.name
                };
                currentFolder.children.push(fileNode);
            }
        });

        return [root];
    }
    // 是否排除的文件夹
    function isExcludeFolder(entry) {
        if(entry.indexOf('css') > -1 ||
           entry.indexOf('scss') > -1 ||
           entry.indexOf('js') > -1 ||
           entry.indexOf('images') > -1 ||
           entry.indexOf('fui') > -1 ||
           entry.indexOf('lib') > -1 ||
           entry.indexOf('test') > -1 ||
           entry.indexOf('font') > -1 ||
           entry.indexOf('frame/fui') > -1) {
            return true;
        } else {
            return false;
        }
    }
    // 是否包含的文件
    function isIncludeFile(fileName) {
        if(fileName.indexOf('.html') > -1) {
            return true;
        } else {
            return false;
        }
    }

    function getZipResource(callback) {
        const downloadUrl = window.location.origin + document.querySelector('.gl-button.btn-sm.btn-confirm').getAttribute('href');

        fetch(downloadUrl)
            .then(response => response.arrayBuffer())
            .then(data => {
            // 将 ZIP 文件的二进制数据传递给 JSZip 进行解析
            return JSZip.loadAsync(data);
        })
            .then(zip => {
            // 获取 ZIP 文件中的所有条目(文件和目录)
            const zipEntries = Object.values(zip.files);
            const treeData = organizeFileEntries(zipEntries)

            callback && callback(treeData);

        })
            .catch(error => {
            console.error(error);
        });
    }

    // 树结构第一个节点数据
    function findFirstFileNode(tree) {
        // 遍历树的节点
        for (let i = 0; i < tree.length; i++) {
            const node = tree[i];

            // 如果节点的类型为 file,则返回该节点
            if (node.type === 'file') {
                return node;
            }

            // 如果节点有子节点,则递归调用该函数查找子节点中的第一个 file 节点
            if (node.children && node.children.length > 0) {
                const fileNode = findFirstFileNode(node.children);
                if (fileNode) {
                    return fileNode;
                }
            }
        }

        // 如果没有找到 file 节点,则返回 null
        return null;
    }
})();

// 修改项目描述的长度
(function() {
    'use strict';
    let regs = [/^http:\/\/192\.168\.0\.200\/fe3project\//,
               /^http:\/\/192\.168\.0\.200\/frontend_pc\/project\//];
    let match = false;

    for(let r = 0, lr = regs.length; r < lr; r++) {
        if(regs[r].test(location.href)) {
            match = true;
            break;
        }
    }

    if(!match) {
        return;
    }

    let tryTimes = 6;
    let changed = false;

    // 增加项目描述的输入长度
    function modifyTextareaLen() {
        if(tryTimes > 0 && !changed) {
            setTimeout(() => {
                const textarea = document.getElementById('project_description');
                tryTimes--;
                if(textarea) {
                    textarea.setAttribute("maxlength", "1000");

                    jQuery(textarea).blur(function(event) {
                        this.value = this.value.replace(/,/g, ',').replace(/&isfwqfb=1/g, '');
                        this.value = convertDateFormat(this.value);
                        jQuery(this).trigger('change');
                    });
                    changed = true;
                } else {
                    modifyTextareaLen();
                }
            }, 1000);
        }
    }

    window.onload = function() {
        modifyTextareaLen();
    }
})();

// 设计门户增加通往前端仓库的跳板
(function() {
    'use strict';

    let regs = [/^https:\/\/oa\.epoint\.com\.cn\/interaction-design-portal\/portal\/pages\/casestemplates\/casetemplatesdetail/,
               /^https:\/\/oa\.epoint\.com\.cn\/interaction-design-portal\/portal\/pages\/generalpagetemplates\/generalpagetemplatesdetail/,
               /^https:\/\/oa\.epoint\.com\.cn\/interaction-design-portal\/portal\/pages\/dynamiceffecttemplates\/dynamiceffecttemplatesdetail/];
    let match = false;

    for(let r = 0, lr = regs.length; r < lr; r++) {
        if(regs[r].test(location.href)) {
            match = true;
            break;
        }
    }

    if(!match) {
        return;
    }

    function addStyle() {
        // 注入样式:增加按钮
        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}";


        // 添加注入样式
        let extraStyleElement = document.createElement("style");
        extraStyleElement.innerHTML = injectStyle;
        document.head.appendChild(extraStyleElement);
    }

    function getUrlParameters() {
        var params = {};
        var search = window.location.search.substring(1);
        var urlParams = search.split('&');

        for (var i = 0; i < urlParams.length; i++) {
            var param = urlParams[i].split('=');
            var paramName = decodeURIComponent(param[0]);
            var paramValue = decodeURIComponent(param[1] || '');
            params[paramName] = paramValue;
        }

        return params;
    }

    window.onload = ()=> {
        addStyle();
        const $content = jQuery('.content');

        $content.append('<div class="front-proto">前端原型</div>');

        const $frontBtn = jQuery('.front-proto', $content);

        $frontBtn.on('click', ()=> {
            window.open('http://192.168.0.200/?name=' + getUrlParameters().guid);
        });
    };
})();

// 前端项目案例库增加获取参数的能力
// 前端项目案例库增加部署能力
(function() {
    'use strict';

    let regs = [/^http:\/\/192\.168\.118\.60:9999\/webapp\/pages\/caselib\/create\.html/,
               /^http:\/\/192\.168\.201\.159:9999\/webapp\/pages\/default\/onlinecase.html/];
    let match = false;

    for(let r = 0, lr = regs.length; r < lr; r++) {
        if(regs[r].test(location.href)) {
            match = true;
            break;
        }
    }

    if(!match) {
        return;
    }

    const fontUrl = 'https://element.eleme.io/2.11/static/element-icons.535877f.woff';

    // 添加样式规则,将字体应用到指定元素上
    GM_addStyle(`
        @font-face {
            font-family: element-icons;
            src: url(${fontUrl}) format("woff");
        }
    `);

    GM_addStyle(GM_getResourceText('ElementCSS'));

    const businessType = [
        { Value: '7a20e23c-30b8-47e2-8d8d-f2691c9c63c4', Text: '政务服务' },
        { Value: 'c12150bb-b358-452f-87f0-8a2254df87cb', Text: '政务协同' },
        { Value: '3845804e-de68-421c-9402-7b238cfb5a70', Text: '大数据' },
        { Value: '3c28ee56-f24d-4843-b9a2-93e6b96264f4', Text: '电子交易' },
        { Value: '673b5918-51bc-4f1a-ab73-fca86e54d7d1', Text: '数字建设' },
        { Value: '6d9e7d84-7de3-4e0f-bd4f-ed4722ed25b5', Text: '建筑企业' },
        { Value: 'c22f8d2f-518d-4381-b88c-1da68536ed3a', Text: '公共安全' },
        { Value: 'c5810829-1b21-4b22-85cd-390b1edd9614', Text: '智能设备' },
        { Value: '080c7560-c261-428b-a45d-b86b57b47ffb', Text: '中央研究院' }
    ];

    const projectType = [
        { Value: 'dca44f63-be3f-4e9c-b78f-d786571c22c9', Text: '网站' },
        { Value: 'c7861460-163b-4060-80ec-d60604c50435', Text: '业务系统' },
        { Value: '49accc71-6f7d-43f3-b726-58decf58b6fa', Text: '智能设备' },
        { Value: '90209c65-1a55-4d8c-a836-2e5c6b834ada', Text: '大屏可视化' },
        { Value: 'fb0415fb-65ee-42c1-895a-dca042c2568e', Text: '中屏可视化' },
        { Value: '2b83f9b1-ec78-4819-a400-d7d49ea1ecc5', Text: '其他' }
    ];

    let $businesstype;
    let $projecttype;

    function getUrlParameters() {
        var params = {};
        var search = window.location.search.substring(1);
        var urlParams = search.split('&');

        for (var i = 0; i < urlParams.length; i++) {
            var param = urlParams[i].split('=');
            var paramName = decodeURIComponent(param[0]);
            var paramValue = decodeURIComponent(param[1] || '');
            if(paramName) {
                params[paramName] = paramValue;
            }
        }

        return params;
    }

    function initForm (params) {
        if(typeof params === 'object') {
            document.getElementsByName('Title')[0].value = params.projectName ? params.projectName : '';
            document.getElementsByName('KeyWords')[0].value = params.projectKeys ? params.projectKeys : '';
            document.getElementsByName('Entry')[0].value = params.entryUrl ? params.entryUrl : '';
            document.getElementsByName('SourceCode')[0].value = params.git ? params.git : '';
        }
    }

    let setSuccess = false;
    let setTimes = 5;

    function initSelect(params) {
        if(typeof params !== 'object') {
            return;
        }

        if(setTimes > 0 && !setSuccess) {
            setTimeout(()=> {
                setTimes--;

                businessType.forEach((item)=> {
                    if(params.projectBU) {
                        if(item.Text === params.projectBU.trim()) {
                            $businesstype.val(item.Value);
                        } else if( params.projectBU.trim() == '一网统管' || params.projectBU.trim() == '一网协同' || params.projectBU.trim() == '一网通办' ) {
                            $businesstype.val('7a20e23c-30b8-47e2-8d8d-f2691c9c63c4');
                        }
                        $businesstype.trigger("chosen:updated");
                    }
                });

                projectType.forEach((item)=> {
                    if(params.projectType && item.Text === params.projectType.trim()) {
                        $projecttype.val(item.Value);
                        $projecttype.trigger("chosen:updated");
                    }
                });

                setSuccess = true;

            }, 1000);
        } else {
            initSelect(params);
        }
    }

    function addRelatedDom() {
        const sourceInput = document.getElementsByName('SourceCode')[0];
        const $sourceInput = jQuery(sourceInput);

        $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>')
    }

    function addStyle() {
        let epointCss = ".el-loading-spinner {margin-top: -50px;} .el-button--primary:focus {outline: 0 !important;}";
        // 添加注入样式
        let extraStyleElement = document.createElement("style");
        extraStyleElement.innerHTML = epointCss;
        document.head.appendChild(extraStyleElement);
    }

    window.onload = ()=> {
        const params = getUrlParameters();

        // 有参数,进行填充表单
        if(params && params.git) {
            $businesstype = jQuery('#businesstype');
            $projecttype = jQuery('#projecttype');

            initForm(params);
            initSelect(params);

            return false;
        }

        // 没有url参数填充,则做部署功能展示
        addRelatedDom();
        addStyle();

        const placeholder = document.createElement('div');

        // 创建 Vue 实例并挂载到页面
        const vueInstance = new Vue({
            el: placeholder,
            data() {
                return {
                    framework: [
                        {label: '重构模板', value: 1},
                        {label: 'f9x1.0', value: 2},
                        {label: 'f9x2.0', value: 3},
                        {label: 'f950', value: 4},
                        {label: 'f950sp1', value: 5},
                        {label: 'f950sp2', value: 6},
                        {label: 'f950sp3', value: 7},
                        {label: 'f951', value: 18},
                        {label: 'f940', value: 8},
                        {label: 'f941', value: 10},
                        {label: 'f942', value: 9},
                        {label: 'f934', value: 11},
                        {label: 'f933', value: 12},
                        {label: 'f932', value: 13},
                        {label: 'f9211', value: 14},
                        {label: '骨架', value: 15},
                        {label: 'Vue', value: 16},
                        {label: 'React', value: 17}
                    ],
                    data: [], // 目录结构树
                    defaultProps: {
                        children: 'children',
                        label: 'label'
                    },
                    loadingTree: false,
                    dialogVisible: false,
                    dialogDeployVisible: false,
                    showDeployPath: false,
                    depDialogVisible: false,
                    loading: false,
                    formLabelWidth: '120px',
                    supportDeploy: false,
                    form: {
                        frame: '',
                        deployPath: ''
                    },
                    rules: {
                        frame: [
                            { required: true, message: '请选择框架类型', trigger: 'change' }
                        ],
                        deployPath: [
                            { required: true, message: '请输入部署到 170/showcase 下的目标路径名称', trigger: 'change' }
                        ]
                    }
                }
            },
            methods: {
                // 部署
                doDeploy() {
                    let self = this;

                    this.$refs['form'].validate((valid) => {
                        if (valid) {
                            this.dialogDeployVisible = false;
                            this.depDialogVisible = true;
                            this.loading = true;
                            // 部署
                            this.getDeployInfo({ type: '1', frame: this.form.frame, deployPath: this.form.deployPath }, (data)=> {
                                this.loading = false;
                                this.depDialogVisible = false;

                                if(!data.custom.text){

                                    this.data = data.custom.pageTreeData;
                                    this.projectFtpUrl = data.custom.projectRootPath;
                                    this.supportDeploy = data.custom.supportDeploy;

                                    this.$message({
                                        type: 'success',
                                        message: '部署成功!'
                                    });
                                    // 打开查看弹窗
                                    this.viewProject();
                                    this.toggleViewButton(true);

                                } else {
                                    this.$message({
                                        type: 'error',
                                        message: data.custom.text
                                    });
                                }
                            });
                        } else {
                            console.log('error submit!!');
                            return false;
                        }
                    });
                },
                // 项目部署
                getDeployInfo(params, callback) {
                    const author = document.querySelector('#account a').innerText.trim().substring(4);
                    const projectName = document.getElementsByName('Title')[0].value.trim();
                    const projectGitUrl = document.getElementsByName('SourceCode')[0].value.trim();

                    if(typeof params == 'function') {
                        callback = params;
                        params = null;
                    }
                    if(author && author.length && projectGitUrl) {
                        fetch('http://192.168.219.170:3008/api/getDeployInfo', {
                            method: 'POST',
                            // 允许跨域请求
                            mode: 'cors',
                            headers: {
                                'Accept': 'application/json',
                                'Content-Type': 'application/json'
                            },
                            body: JSON.stringify({//post请求参数
                                params: {
                                    "type": (params && params.type !== undefined) ? params.type : '0',// 0 代表查看, 1代表部署
                                    "deployMan": author, // 部署人姓名
                                    "projectName": projectName, // 项目名称
                                    "projectGitUrl": projectGitUrl,
                                    "frame": (params && params.frame) ? params.frame : undefined,
                                    "deployPath": (params && params.deployPath) ? params.deployPath : undefined // 部署的目标目录
                                }
                            })
                        })
                            .then(response => response.text())
                            .then((result) => {
                            var data = JSON.parse(result);
                            callback && callback(data);
                        })
                            .catch(error => {
                            this.depDialogVisible = false;
                            this.dialogVisible = false;
                            this.$message({
                                type: 'error',
                                message: '系统故障,请联系管理员。'
                            });
                            console.error(error);
                        });
                    } else {
                        this.$message({
                            type: 'error',
                            message: '本页面不支持查看和部署,请先登录。'
                        });
                        console.error('部署信息请求参数error');
                    }
                },
                // 查看项目
                viewProject () {
                    this.dialogVisible = true;
                    let self = this;

                    if(this.data) {
                        this.loadingTree = false;
                    } else {
                        this.loadingTree = true;
                        // 发送ajax请求,查看是否进行过部署
                        this.getDeployInfo((data)=> {
                            // 有部署信息,直接赋值,
                            if(data) {
                                self.projectIsDeployed = true;
                                self.data = data.custom.pageTreeData;
                                self.projectFtpUrl = data.custom.projectRootPath;
                                self.supportDeploy = data.custom.supportDeploy;
                                self.loadingTree = false;

                                self.toggleViewButton(true);

                            }
                        });
                    }
                },
                handleNodeClick(data) {
                    console.log(data);
                    if(data.type === 'folder') {
                        return false;
                    }
                    var self = this;
                    var entry = data.entry;
                    self.clickNodeEntry = entry;
                    if(self.projectFtpUrl) {
                        window.open('http://192.168.219.170' + self.projectFtpUrl + data.entry);
                        self.clickNodeEntry = null;
                    } else {
                        if(this.supportDeploy === false) {
                            this.$message({
                                type: 'error',
                                message: '当前项目暂时只支持查看,请耐心等待功能升级。'
                            });
                            self.clickNodeEntry = null;
                            return false;
                        }

                        this.$confirm('资源未部署,部署至 170 服务器后可查看,是否部署?')
                            .then(_ => {

                            this.dialogDeployVisible = true;
                            })
                            .catch(_ => {});
                    }
                },
                // svn 需要制定目录名称,showDeployPath
                showDialog(showDeployPath) {
                    this.showDeployPath = showDeployPath;
                    this.dialogDeployVisible = true;
                },
                // 查看按钮显影控制
                toggleViewButton(show) {
                    const $viewBtn = jQuery('#view');

                    if(!$viewBtn.length) {
                        return;
                    }

                    if(show) {
                        $viewBtn.removeClass('hidden');
                    } else {
                        $viewBtn.addClass('hidden');
                    }
                }
            },
            mounted() {
                const $btnDeloy = jQuery('#deploy');
                const $btnView = jQuery('#view');

                // 绑定vue组件外的事件
                $btnDeloy.on('click', function() {
                    // 源码地址和项目名称判断
                    const sourceInput = document.getElementsByName('SourceCode');
                    const projectNameInput = document.getElementsByName('Title');

                    let sourceInputVal = sourceInput[0].value.trim(),
                        projectNameInputVal = projectNameInput[0].value.trim();

                    const gitpattern = /^http:\/\/192\.168/;
                    const svnpattern = /^svn:\/\/192\.168/;
                    const sourcepattern = /^(svn:\/\/192\.168|http:\/\/192\.168)/;

                    if (!sourceInputVal) {
                        vueInstance.$message({
                            type: 'error',
                            message: '请输入源码地址!'
                        });
                        return
                    }

                    if (!sourcepattern.test(sourceInputVal)) {
                        vueInstance.$message({
                            type: 'error',
                            message: '请输入准确的源码 gitlab 或 svn 地址!'
                        });
                        return
                    }

                    if (svnpattern.test(sourceInputVal) && !projectNameInputVal) {
                        vueInstance.$message({
                            type: 'error',
                            message: ' svn 仓库地址部署需要填写项目(案例)名称!'
                        });
                        return
                    }

                    vueInstance.showDialog(svnpattern.test(sourceInputVal));
                });
                // 查看项目
                $btnView.on('click', function() {
                    vueInstance.viewProject();
                });

            },
            template: `<div id="my-form">
            <el-dialog title="部署提示" width="640px" :visible.sync="dialogDeployVisible">
                <el-alert
                    title="此操作将把 GitLab / SVN 资源打包部署至 170 服务器,已部署过的项目会进行覆盖部署,是否继续?"
                    type="warning" :closable="false" style="margin-bottom: 20px;">
                </el-alert>
                <el-form :model="form" ref="form" :rules="rules">
                    <el-form-item label="框架类型" :label-width="formLabelWidth" prop="frame">
                        <el-select v-model="form.frame" placeholder="请框架类型" style="width:380px;">
                            <el-option v-for="item in framework" :key="item.value" :label="item.label" :value="item.value"></el-option>
                        </el-select>
                    </el-form-item>
                    <el-form-item label="部署路径" :label-width="formLabelWidth" prop="deployPath" v-if="showDeployPath">
                        <el-input v-model="form.deployPath" placeholder="请输入部署至服务器 170/showcase 下的目标路径名称" style="width:380px;"></el-input>
                    </el-form-item>
                </el-form>
                <div slot="footer" class="dialog-footer">
                    <el-button @click="dialogDeployVisible = false">取 消</el-button>
                    <el-button type="primary" @click="doDeploy">确 定</el-button>
                </div>
            </el-dialog>
            <el-dialog
                title="部署"
                width="420px"
                :visible.sync="depDialogVisible">
                    <div class="deploy-body"
                        style="height: 306px;"
                        v-loading="loading"
                        element-loading-text="正在打包部署至 170 服务器,请耐心等待"
                        element-loading-spinner="el-icon-loading">
                    </div>
            </el-dialog>
            <el-dialog
              title="目录结构"
              width="900px"
              :append-to-body="true"
              :visible.sync="dialogVisible">
                <el-tree
                    class="filter-tree"
                    :data="data"
                    :props="defaultProps"
                    node-key="id"
                    default-expand-all
                    @node-click="handleNodeClick"
                    v-loading="loadingTree"
                    element-loading-background="rgba(255, 255, 255, 1)"
                    element-loading-text="拼命加载中......"
                    ref="tree">
                </el-tree>
            </el-dialog>
          </div>`
        });

        // 将占位元素追加到 body 元素中
        jQuery('.form-container').after(vueInstance.$el);
    };
})();

// 新建项目提示
// 新建项目查找重复项目
(function() {
    'use strict';
    let regs = [/^http:\/\/192\.168\.0\.200\/projects\/new/];
    let match = false;

    for(let r = 0, lr = regs.length; r < lr; r++) {
        if(regs[r].test(location.href)) {
            match = true;
            break;
        }
    }

    if(!match) {
        return;
    }

    // 等待页面加载完成
    window.addEventListener('load', function() {
        const $projectName = jQuery('#project_name');
        const $projectDescription = jQuery('#project_description');
        const $check = jQuery('#project_visibility_level_10');
        const $projectPath = jQuery('#project_path');

        // 页面参数
        const p = gitlabUtil.getUrlParameters();
        const projectName = p.projectName;
        const projectBu = p.bu;
        const projectType = p.projectType;
        const frame = p.frame;
        let vueInstance;
        let uiUrl = p.uiUrl;
        if(uiUrl && uiUrl !== '后补' && uiUrl.indexOf('interaction-design-portal') > -1 ) {
            uiUrl += '=' + location.href.substr(location.href.length - 50, 36);
        }

        if($projectName && $projectName.length) {
            $projectName.attr('placeholder', '以需求或项目管理系统中的项目名称为准');
            if(projectName) {
                $projectName.val(projectName);
                $projectName.trigger('change');
                // 防止项目名称中有英文单词时,会自动填充项目标识串。
                $projectPath.val('');
            }

            // 添加检索重复项目按钮
            const btnPlaceholder = document.createElement('div');

            // 创建 Vue 实例并挂载到页面
            vueInstance = new Vue({
                el: btnPlaceholder,
                data: function() {
                    return {
                        showBtn: false
                    };
                },
                methods: {
                    // 打开检索弹窗
                    check: function() {
                        let name = $projectName.val().trim();
                        // 去除临时
                        name = name.replace('(临时)', '').replace('临时', '');
                        // 去除项目
                        // name = name.replace('项目', '');
                        // 去除子系统,即第一个 - 后面的字符串
                        name = name.split('-')[0];
                        name = name.split('——')[0];
                        if(name.length > 20) {
                            name = name.substring(0, 20);
                        }
                        window.open('http://192.168.0.200/?name=' + name);

                    },
                    // 同步输入框和按钮状态
                    checkInput: function() {
                        if($projectName.val().trim() != '') {
                            this.showBtn = true;
                        } else {
                            this.showBtn = false;
                        }
                    }
                },
                mounted: function() {
                    let self = this;
                    self.checkInput();

                    $projectName.on('change', function() {
                        self.checkInput();
                    });
                },
                template: `<div>
              <div style="position:absolute; top: 29px; left: 343px;" v-show="showBtn">
              <el-tooltip content="检索已创建的项目,避免重复创建" placement="top" effect="light">
                <el-button type="primary" style="vertical-align: top;" icon="el-icon-search" size="small" id="create-project" @click="check">检索</el-button>
              </el-tooltip>
              </div>
            </div>`
            });

            // 将占位元素追加到 项目名称输入框 后面
            $projectName.parent('.form-group')[0].appendChild(vueInstance.$el);
        }

        if($projectDescription && $projectDescription.length) {
            let date = new Date();
            const imgEl = document.querySelector('.header-user-avatar');
            let name = imgEl ? imgEl.getAttribute('alt') : '张三';
            name = name.replace('(前端研发3部)', '');
            $projectDescription.attr('placeholder', 'YYYY-M-D,张三,UI:https://oa.epoint.com.cn/interaction-design-portal/portal/pages/casestemplates/casetemplatesdetail?guid=');
            $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='));
            $projectDescription.prev('.label-bold').find('span').text(' (UI备份地址完善后会自动获取项目名称、业务条线和项目类型)')

            $projectDescription[0].setAttribute("maxlength", "1000");
            // 增加主题表单
            var themeHtml = '<div class="row">\
                <div class="form-group col-md-9">\
                <label class="label-bold" for="project_topics">主题<i style="color:red; font-style:normal; font-weight: 400; padding-left: 5px;">业务系统类型关键字添加框架版本</i></label>\
                <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="">\
                <p class="form-text text-muted">用逗号分隔主题。</p>\
                <p class="form-text text-muted">业务条线:政务服务、大数据、一网统管、一网协同、智能设备、电子交易、数字建设、公共安全、支撑产品;</p>\
                <p class="form-text text-muted">项目类型:网站、业务系统、智能设备、大屏可视化、中屏可视化、在线表单;</p>\
                <p class="form-text text-muted">关键字:f942、f951、f950sp2、f9x2.0、f9x1.0、骨架、vue、react、单页、gojs、element、AntDesign、全景、关系图、流程图、响应式、svg、视频、miniui、egis、egis3d、高德、百度、超图、three、主题、瀑布流、上传、自定义用户控件等;</p>\
            </div></div>';

            $projectDescription.closest('.form-group').after(themeHtml);

            var $theme = jQuery('#project_topics');

            // 规避中文,
            $projectDescription.blur(function(event) {
                this.value = this.value.replace(/,/g, ',').replace(/&isfwqfb=1/g, '');
                // 日期转换
                this.value = convertDateFormat(this.value);

                // 检测主题是否为空,且是否已输入uiUrl
                if ($theme.val().trim() == '') {
                    var regex = /guid=([0-9a-fA-F-]{36})/; // 匹配整个URL字符串中的guid后的36位字符

                    var match = this.value.match(regex);

                    if (match) {
                        var extractedGuid = match[1];
                        // console.log(extractedGuid);
                        // 通过 guid 请求数据
                        var apiUrl = 'https://oa.epoint.com.cn/interaction-design-portal/rest/portal/pages/casestemplates/casestemplatesdetailaction/page_load'
                        if(this.value.indexOf('dynamiceffecttemplates') > -1) {
                            apiUrl = 'https://oa.epoint.com.cn/interaction-design-portal/rest/portal/pages/dynamiceffecttemplates/dynamiceffecttemplatesdetailaction/page_load';
                        }

                        // 获取项目信息
                        GM_xmlhttpRequest({
                            method: 'GET',
                            url: apiUrl + '?guid='+ extractedGuid +'&isCommondto=true',
                            headers: {
                                'Content-Type': 'application/json; charset=utf-8'
                            },
                            onload: function(res) {
                                const data = JSON.parse(res.response);
                                let pData = data.custom.casetemplatedata || data.custom.dynamiceffecttemplatesdata;
                                let proBu = pData.stripline || pData.line;
                                const proType = pData.type;
                                const proName = pData.project || pData.title;
                                switch(proBu) {
                                    case '政务BG':
                                        proBu = '政务服务';
                                        break;
                                    case '建设BG':
                                        proBu = '数字建设';
                                        break;
                                    case '交易BG':
                                        proBu = '电子交易';
                                        break;
                                    case '智能设备BU':
                                        proBu = '智能设备';
                                        break;
                                }
                                proName && $projectName.val(proName);
                                proBu && proType && $theme.val(proBu + ', ' + proType);
                                $projectName.trigger('change');
                            }
                        });
                    }
                }
            });


            if(projectBu) {
                $theme.val(projectBu);
            }

            if(projectType && projectType !== '智能化设备') {
                $theme.val($theme.val() + ', ' + projectType);
            }

            if(frame) {
                $theme.val($theme.val() + ', ' + frame);
            }

            $theme.blur(function(event) {
                this.value = this.value.replaceAll(',', ',');

            });
        }

        if($check && $check.length) {
            $check.trigger('click');
        }
    });

})();

// 通过 oa 首页中转,跳过跨站访问的限制
(function(){
    'use strict';
    let regs = [/^https:\/\/oa\.epoint\.com\.cn\/epointoa9\/frame\/fui\/pages\/themes\/aide/];
    let match = false;

    for(let r = 0, lr = regs.length; r < lr; r++) {
        if(regs[r].test(location.href)) {
            match = true;
            break;
        }
    }

    if(!match) {
        return;
    }

    let redirectUlr = gitlabUtil.getUrlParameters().redirect;

    if(redirectUlr) {
        window.location.href = redirectUlr;
    }
})();

// 设计门户瀑布流页面,查找对应项目
(function(){
    'use strict';
    let regs = [/^https:\/\/oa\.epoint\.com\.cn\/interaction-design-portal\/portal\/pages\/casestemplates\/casetemplateslist/];
    let match = false;

    for(let r = 0, lr = regs.length; r < lr; r++) {
        if(regs[r].test(location.href)) {
            match = true;
            break;
        }
    }

    if(!match) {
        return;
    }

    let projectName = location.href.split('projectname');

    window.addEventListener('load', function() {
        if(projectName[1]) {
            projectName = decodeURIComponent(projectName[1]);

            const $input = jQuery('#search-input');
            const $searchBtn = jQuery('.search-icon');

             setTimeout(() => {
                 $input.val(projectName);
                 $searchBtn.trigger('click');
             }, 1000);
        }
    });
})();

// 邮件详情页可以创建项目
(function() {
    'use strict';
    let regs = [/^https:\/\/oa\.epoint\.com\.cn\:8080\/OA9\/oa9\/mail\/mailreceivedetail/,
               /^https:\/\/oa\.epoint\.com\.cn\/OA9\/oa9\/mail\/mailreceivedetail/];
    let match = false;

    for(let r = 0, lr = regs.length; r < lr; r++) {
        if(regs[r].test(location.href)) {
            match = true;
            break;
        }
    }

    if(!match) {
        return;
    }

    const fontUrl = 'https://element.eleme.io/2.11/static/element-icons.535877f.woff';

    // 添加样式规则,将字体应用到指定元素上
    GM_addStyle(`
        @font-face {
            font-family: element-icons;
            src: url(${fontUrl}) format("woff");
        }
    `);

    GM_addStyle(GM_getResourceText('ElementCSS'));

    //  在邮件签收情况后添加按钮-新建项目
    function initCreate() {
        const title = document.querySelector('#mail-detail-container .dtt');
        let vueInstance;
        let gitUrl = 'http://192.168.0.200/projects/new?namespace_id=4817';

        if(title) {
            const btnPlaceholder = document.createElement('div');
            let tds = jQuery('#mailcontent table').find("td[colspan='3']");
            tds = tds.length ? tds : jQuery('#mailcontent table').find("td:nth-child(2)");
            const projectName = tds.eq(0).text().trim().replace('(临时)', '').replace('(临时)', '');
            const firstTdtext = jQuery('#mailcontent table').find("th,td").eq(0).text().trim();
            const isFrontEndEmail = jQuery('#mailcontent table').length && firstTdtext && (firstTdtext == '项目名称' || firstTdtext == '产品名称');
            let bu = '政务服务';
            let projectType = '';
            let frame = '';
            const demandUrl = tds.eq(1).text();
            let uiUrl = '';

            // 由于表格格式不固定,重新遍历一遍获取 uiUrl 和 frame
            tds.each(function(i, el) {
                if(jQuery(el).prev().text().trim() == '备份地址') {
                    uiUrl = jQuery(el).text().trim();
                }
                if(jQuery(el).prev().text().trim() == '框架版本') {
                    frame = jQuery(el).text().trim();
                }
                if(jQuery(el).prev().text().trim() == '设计类型') {
                    projectType = jQuery(el).text().trim();
                }
            });

            uiUrl = uiUrl ? removeQueryStringParameter(uiUrl, 'isfwqfb') : '';
            const backGuid = extractGuidFromUrl(uiUrl);

            if(!isFrontEndEmail) {
                return;
            }

            // 请求项目信息地址
            let apiUrl = '';

            apiUrl = uiUrl.split('?')[0];
            apiUrl = apiUrl.split('interaction-design-portal')[0] + 'interaction-design-portal/rest' + apiUrl.split('interaction-design-portal')[1] + 'action/page_load';

            if(apiUrl.indexOf('casetemplatesdetailaction') > -1) {
                apiUrl = apiUrl.replace('casetemplatesdetailaction', 'casestemplatesdetailaction');
            }

            // 创建 Vue 实例并挂载到页面
            vueInstance = new Vue({
                el: btnPlaceholder,
                data: function() {
                    return {
                        proBu: bu,
                        proType: projectType
                    };
                },
                methods: {
                    create: function() {
                        window.open(gitUrl + '&projectName=' + projectName + '&bu=' + this.proBu + '&projectType=' + this.proType + '&frame=' + frame + '&uiUrl=' + uiUrl + '#blank_project');
                    },
                    search: function() {
                        window.open('http://192.168.0.200/?name=' + projectName);
                    }
                },
                mounted: function() {
                    let self = this;
                    // 获取项目信息
                    GM_xmlhttpRequest({
                        method: 'GET',
                        url: apiUrl + '?guid='+ backGuid +'&isfwqfb=1&isCommondto=true',
                        headers: {
                            'Content-Type': 'application/json; charset=utf-8'
                        },
                        onload: function(res) {
                            const data = JSON.parse(res.response);
                            let pData = data.custom.casetemplatedata || data.custom.dynamiceffecttemplatesdata;
                            self.proBu = pData.stripline || pData.line;
                            self.proType = pData.type;
                            switch(self.proBu) {
                                case '政务BG':
                                    self.proBu = '政务服务';
                                    break;
                                case '建设BG':
                                    self.proBu = '数字建设';
                                    break;
                                case '交易BG':
                                    self.proBu = '电子交易';
                                    break;
                                case '智能设备BU':
                                    self.proBu = '智能设备';
                                    break;
                            }
                        }
                    });
                },
                template: `<div style="display:inline-block; margin-left: 5px; vertical-align: top;">
              <el-tooltip content="去 GitLab 创建项目" placement="top" effect="light">
                <el-button type="primary" style="vertical-align: top;" icon="el-icon-folder-add" circle size="mini" id="create-project" @click="create"></el-button>
              </el-tooltip>
              <el-tooltip content="去 GitLab 查找项目" placement="top" effect="light">
                <el-button type="primary" style="vertical-align: top;" icon="el-icon-search" circle size="mini" @click="search"></el-button>
              </el-tooltip>
            </div>`
            });

            // 将占位元素追加到 邮件标题后 元素中
            // f9 框架会冲突
            title.appendChild(vueInstance.$el);
            // jQuery(title).append(vueInstance.$el.outerHTML);

            /*
                jQuery('#create-project').on('click', function() {
                    window.open(gitUrl);
                });*/
        }
    }

    function extractGuidFromUrl(url) {
        const regex = /[?&]guid=([^&]+)/;
        const match = url.match(regex);

        if (match) {
            return match[1]; // 第一个捕获组中的值即为 guid
        } else {
            return null; // 如果没有匹配到 guid,则返回 null
        }
    }

    function removeQueryStringParameter(url, parameterName) {
        const urlParts = url.split('?');

        if (urlParts.length === 2) {
            const baseUrl = urlParts[0];
            const queryString = urlParts[1];

            const parameters = queryString.split('&').filter(param => {
                const paramName = param.split('=')[0];
                return paramName !== parameterName;
            });

            if (parameters.length > 0) {
                return baseUrl + '?' + parameters.join('&');
            } else {
                return baseUrl;
            }
        }

        return url;
    }

    window.addEventListener('load', function() {
        setTimeout(function() {
            initCreate();
        }, 500);
    });

})();

// 需求详情页,增加设为待办功能
(function() {
    'use strict';
    let regs = [/^https:\/\/oa\.epoint\.com\.cn\/productrelease\/cpzt\/demandmanageznsb\/demandbasicinfo_detail/];
    let match = false;

    for(let r = 0, lr = regs.length; r < lr; r++) {
        if(regs[r].test(location.href)) {
            match = true;
            break;
        }
    }

    if(!match) {
        return;
    }

    window.addEventListener('load', function() {
        const $toolbar = jQuery('.fui-toolbar');

        $toolbar.find('.btn-group').eq(0).after('<div class="fe-add"><span class="mini-button mini-btn-danger" state="danger" id="mark">在飞书中标记待办</span></div>');

        mini.parse($toolbar);

        const markbtn = mini.get('mark');
        const guid = gitlabUtil.getUrlParameters().ProcessVersionInstanceGuid;

        markbtn.on('click', function(e) {
            window.open('https://k7n084n7rx.feishu.cn/base/bascnxklVJQ9VqGGkc4bmu3YJPb?table=tblJhJ9dr4N3AKDr&view=vewNNJTfJp&demandGuid=' + guid );
        });
    });

})();

// 更新脚本同步版本信息
(function() {
    'use strict';
    let regs = [/^https:\/\/greasyfork\.org\/zh-CN\/scripts\/466808\/versions\/new/];
    let match = false;

    for(let r = 0, lr = regs.length; r < lr; r++) {
        if(regs[r].test(location.href)) {
            match = true;
            break;
        }
    }

    if(!match) {
        return;
    }

    const p = document.getElementById('script-description');
    const href = 'http://192.168.0.200/-/ide/project/fe3group/gitlabassistant-web/edit/main/-/version.json';

    const linkElement = document.createElement("a");

    linkElement.href = href; // 设置超链接的URL
    linkElement.textContent = "去同步脚本版本"; // 设置超链接的文本内容
    linkElement.target = '_blank';

    // 将超链接元素插入到目标元素的后面
    p.parentNode.insertBefore(linkElement, p.nextSibling);
})();