zoukankan      html  css  js  c++  java
  • 20200319 代码发布之任务发布钩子脚本

    昨日内容

    * ### 代码发布整体工作流程
    
      参考qq截图
    
      代码发布这个功能可以基于很多方式很多语言来实现
    
      我们这里主要用的是python相关的知识点来完成的,大体逻辑流程都是大差不差的
    
      额外补充:p2p(比特流技术),为了减轻服务器的压力,将所有人即是下载者又是资源的上传者
    
    * ### 服务器表的增删改查
    
      我们从头到位将增删改查自己实现了一遍,目的是为了搭建项目增删改查基本业务逻辑,方便后续其他表的操作
    
      #### **modelform使用**
    
      ```python
      from django.forms import ModelForm
      
      class MyModelForm(ModelForm):
        class Meta:
          	model = models.UserInfo
            fields = '__all__'  # 前端展示用户表所有的字段
            exclude = ['id']  # 排除id字段 不展示到前端
      
      # 渲染标签
      form_obj = MyModelForm()
      # 校验数据
      form_obj = MyModelForm(data=request.POST)
      # 新增数据
      form_obj.save()
      # 编辑数据 渲染标签
      form_obj = MyModelForm(instance=edit_obj)
      # 修改数据库中的数据
      form_obj = MyModelForm(instance=edit_obj,data=request.POST)
      form_obj.save()
      
        针对数据的删除功能,一般情况下都需要有一个二次确认的操作
    
      我们是直接利用BOM操作里面的confirm确认框实现的
    
      你还可以借助于第三方插件效果更好一点比如sweetalert插件
    
    ### 项目表的增删改查
    
    直接拷贝服务器表所有的代码,修改变量名即可
    
    ### 项目优化
    
    将modelform单独放到一个文件夹中
    
    然后再将各个模型表对应的modelform中相同的代码抽取出来形成基类
    
    给项目表再增两个字段
    
    线上项目地址、关联服务器
    
    ### 发布任务
    
    由于发布任务是针对项目的,所以为了之后新增任务的时候不需要自己选择项目,所以我们将发布任务做成项目表中的一个字段,点击该字段跳转到该项目对应的所有发布纪录中,之后在该发布纪录页面上开设新增按钮,将当前项目的主键值传递到后端,这样的话新增任务就无需自己选择项目了
    

    今日

    • 发布任务单新增页面
    • 发布流程前端实时展示

    任务发布数据

    任务列表的展示为了更加人性化,可以增加当前项目的项目名和环境

    formmodel
        # 剔除参与展示的字段
        exclude = ['uid','project','status']
        
        # form_obj.instance  就是当前的数据对象
        form_obj.instance.uid = '唯一标识'
        
        
        
    # tasklist有名分组需要传递参数,使用reverse反向解析
        url = reverse('task_list',args=(project_id,))
        return redirect(url)
    
        
    

    初步进行封装重写modelform类的save方法,实现数据的添加

    class TaskModelForm(BaseModelForm):
        class Meta:
            model = models.DeployTask
            fields = '__all__'
    
            # 剔除参与展示的字段
            exclude = ['uid','project','status']
    
        # 利用初始化获取project_id
        def __init__(self,project_id,*args,**kwargs):
            super().__init__(*args,**kwargs)
            self.project_id = project_id
    
    
        def save(self, commit=True):
            # 添加数据  (重写init方法进行数据的获取)
            # .instance 就是数据对象本身,重写save进行保存
            self.instance.uid = '唯一标识'
            self.instance.project_id = self.project_obj.pk
            # 调用父类save方法保存数据
            super().save(commit=True)
    

    接下来,我们针对任务的添加页面,单独开设一个html (task_form.html)

    并在该html页面上划分三块区域展示不同的信息

    • 当前任务关联的项目基本信息展示

    • 基本配置

    • 脚本书写

    获取用户输入的数据cleaned_data

    tag = self.cleaned_data.get('tag')
    

    钩子脚本展示

    img

    img

    针对四个钩子脚本,我们想要实现可以保存的功能

    # 初始化字段
        def __init__(self,project_obj,*args,**kwargs):
            super().__init__(*args,**kwargs)
            self.project_obj = project_obj
            # 初始化选择框内容
            self.init_hook()
    
        def init_hook(self):
            # 给所有的下拉框先添加一个 请选择选项
            # <option value="0">请选择</option>  (0,'请选择')
            self.fields['before_download_select'].choices = [(0,'请选择')]
            self.fields['after_download_select'].choices = [(0,'请选择')]
            self.fields['before_deploy_select'].choices = [(0,'请选择')]
            self.fields['after_deploy_select'].choices = [(0,'请选择')]
    

    生成新字段

    需要新添加字段

    # 利用之前定义的基类中的`exclude_bootstrap=[]`来控制样式的添加
        # checkbox无需添加样式
        exclude_bootstrap = [
            'before_download_template',
            'after_download_template',
            'before_deploy_template',
            'after_deploy_template'
    
        ]
        
    # 自己定义新的字段
        # 下拉框 checkbox 文本框
        before_download_select = forms.ChoiceField(required=False, label='下载前')
        before_download_title = forms.CharField(required=False, label='模板名称')
        before_download_template = forms.BooleanField(required=False, widget=forms.CheckboxInput, label='是否保存为模板')
    
        after_download_select = forms.ChoiceField(required=False, label='下载后')
        after_download_title = forms.CharField(required=False, label='模板名称')
        after_download_template = forms.BooleanField(required=False, widget=forms.CheckboxInput, label='是否保存为模板')
    
        before_deploy_select = forms.ChoiceField(required=False, label='发布前')
        before_deploy_title = forms.CharField(required=False, label='模板名称')
        before_deploy_template = forms.BooleanField(required=False, widget=forms.CheckboxInput, label='是否保存为模板')
    
        after_deploy_select = forms.ChoiceField(required=False, label='下载后')
        after_deploy_title = forms.CharField(required=False, label='模板名称')
        after_deploy_template = forms.BooleanField(required=False, widget=forms.CheckboxInput, label='是否保存为模板')
    
    

    下拉框的展示

    初始化选择框内容,是的前端进行展示下拉框内容 choices=

    img

    # 初始化字段
        def __init__(self,project_obj,*args,**kwargs):
            super().__init__(*args,**kwargs)
            self.project_obj = project_obj
            # 初始化选择框内容
            self.init_hook()
    
        def init_hook(self):
            # 给所有的下拉框先添加一个 请选择选项
            # <option value="0">请选择</option>  (0,'请选择')
            self.fields['before_download_select'].choices = [(0,'请选择')]
            self.fields['after_download_select'].choices = [(0,'请选择')]
            self.fields['before_deploy_select'].choices = [(0,'请选择')]
            self.fields['after_deploy_select'].choices = [(0,'请选择')]
    

    保存模板数据

    需要新建保存用户输入的模板数据表

    class HookTemplate(models.Model):
        """保存钩子脚本"""
        title = models.CharField(verbose_name='标题',max_length=32)
        content = models.TextField(verbose_name='脚本内容')
        # 我想实现钩子与钩子之间模版互不影响
        hook_type_choices = (
            (2,'下载前'),
            (4,'下载后'),
            (6,'发布前'),
            (8,'发布后')
        )
        hook_type = models.IntegerField(verbose_name='钩子类型',choices=hook_type_choices)
    
    
    

    什么时候操作数据表保存数据?

    • 判断用户是否点击了checkbox按钮
    • 在重写的save()方法中判断
        def save(self, commit=True):
            # 添加数据
            self.instance.uid = self.create_uid()
            self.instance.project_id = self.project_obj.pk
            # 调用父类的save方法保存数据
            super().save(commit=True)
            
        	# 判断用户是否点击checkbox (保存模板到数据库)
            if self.cleaned_data.get("before_download_template"):
                # 获取模版名称
                title = self.cleaned_data.get("before_download_title")
                # 获取脚本内容
                content = self.cleaned_data.get("before_download_script")
                # 保存到表中
                models.HookTemplate.objects.create(
                    title=title,
                    content=content,
                    hook_type=2
                )
            if self.cleaned_data.get("after_download_template"):
                # 获取模版名称
                title = self.cleaned_data.get("after_download_title")
                # 获取脚本内容
                content = self.cleaned_data.get("after_download_script")
                # 保存到表中
                models.HookTemplate.objects.create(
                    title=title,
                    content=content,
                    hook_type=4
                )
    
            if self.cleaned_data.get("before_deploy_template"):
                # 获取模版名称
                title = self.cleaned_data.get("before_deploy_title")
                # 获取脚本内容
                content = self.cleaned_data.get("before_deploy_script")
                # 保存到表中
                models.HookTemplate.objects.create(
                    title=title,
                    content=content,
                    hook_type=6
                )
    
            if self.cleaned_data.get("after_deploy_template"):
                # 获取模版名称
                title = self.cleaned_data.get("after_deploy_title")
                # 获取脚本内容
                content = self.cleaned_data.get("after_deploy_script")
                # 保存到表中
                models.HookTemplate.objects.create(
                    title=title,
                    content=content,
                    hook_type=8
                )
    

    下拉框显示钩子模板数据

    # 给所有的下拉框先添加一个 请选择选项
            # <option value="0">请选择</option>  (0,'请选择')
    
            before_download = [(0,'请选择')]
            # 还应该去数据库中查询是否有对应的模版名称
            extra_list = models.HookTemplate.objects.filter(hook_type=2).values_list('pk','title')
            # 利用extend扩展列表 (append只是添加)
            before_download.extend(extra_list)
            self.fields['before_download_select'].choices = before_download
    
            after_download = [(0,'请选择')]
            extra_list = models.HookTemplate.objects.filter(hook_type=4).values_list('pk', 'title')
            after_download.extend(extra_list)
            self.fields['after_download_select'].choices = after_download
    
            before_deploy = [(0,'请选择')]
            extra_list = models.HookTemplate.objects.filter(hook_type=6).values_list('pk', 'title')
            before_deploy.extend(extra_list)
            self.fields['before_deploy_select'].choices = before_deploy
    
    

    实时获取数据动态展示

    给前端所有的select标签绑定文本域变化事件(change事件)

    <script>
            // 直接给hooks类标签内所有的select绑定事件
            $('.hooks').find('select').change(function () {
                {#alert($(this).val())  获取用户输入的模版主键值 #}
                var $that = $(this);
                // 朝后端发送请求 获取对应的脚本内容
                $.ajax({
                    url:'/hook/template/'+$that.val()+'/',
                    type:'get',
                    dataType:'JSON',
                    success:function (args) {
                        // 获取脚本内容 渲染到对应下拉框下面的textarea框中
                        {#alert(args.content)#}
                        // 标签查找
                        $that.parent().parent().next().find('textarea').val(args.content);
                    }
    
                })
            })
        </script>
    
    def hook_template(request,hook_id):
        # 根据hook_id查询出hook对象
        hook_obj = models.HookTemplate.objects.filter(pk=hook_id).first()
        back_dic = {'status':1000,'content':''}
        back_dic['content'] = hook_obj.content
        return JsonResponse(back_dic)
    

    优化

    用户一旦点击了checkbox按钮,那么就必须填写模版名称(进行校验)def clean()

    钩子函数进行校验 # 钩子函数 全局钩子 局部钩子

        def clean(self):
            if self.cleaned_data.get('before_download_template'):
                # 获取用户输入的模版名称 判断是否有值
                title = self.cleaned_data.get("before_download_title")
                if not title:
                    # 展示提示信息
                    self.add_error('before_download_title','请输入模版名称')
    
            if self.cleaned_data.get('after_download_template'):
                # 获取用户输入的模版名称 判断是否有值
                title = self.cleaned_data.get("after_download_title")
                if not title:
                    # 展示提示信息
                    self.add_error('after_download_title','请输入模版名称')
    
            if self.cleaned_data.get('before_deploy_template'):
                # 获取用户输入的模版名称 判断是否有值
                title = self.cleaned_data.get("before_deploy_title")
                if not title:
                    # 展示提示信息
                    self.add_error('before_deploy_title','请输入模版名称')
    
            if self.cleaned_data.get('after_deploy_template'):
                # 获取用户输入的模版名称 判断是否有值
                title = self.cleaned_data.get("after_deploy_title")
                if not title:
                    # 展示提示信息
                    self.add_error('after_deploy_title','请输入模版名称')
    

    注意,前端需要预留一部分内容展示错误信息否则会出现布局错乱的问题

    <div class="form-group" style="height: 60px">
                                            <div class="col-sm-3">
                                                <div class="checkbox">
    
                                                    <label for="">{{ form_obj.after_deploy_template }}保存模版</label>
                                                </div>
                                            </div>
                                            <div class="col-sm-9">
                                                {{ form_obj.after_deploy_title }}
                                                <span style="color: red">{{ form_obj.after_deploy_title.errors.0 }}</span>
                                            </div>
    
                                        </div>
    

    发布任务

    Ps:静态文件可以全局也可以在局部

    • 静态文件的配置
    # 1 配置文件中直接配置
    STATICFILES_DIRS = [
      os.path.join(BASE_DIR,'static1'),
      os.path.join(BASE_DIR,'static2'),
    ]
    
    # 2 模版语法直接配置
    {% load staticfiles %}
    <script src="{% static 'js/go.js' %}"></script>
    

    新建发布任务接口

    url(r'^deploy/(?P<task_id>d+)/$',deploy.deploy_task,name='deploy_task')
    
    
    from django.shortcuts import HttpResponse,render,redirect,reverse
    from app01 import models
    
    def deploy_task(request,task_id):
        task_obj = models.DeployTask.objects.filter(pk=task_id).first()
        return render(request,'deploy.html',locals())
    

    使用gojs展示流程图

    <script>
            // 由于ws和diagram需要在其他函数内使用 所以定义成全局变量
            var ws;
            var diagram;
    
            function initWebSocket() {
                ws = new WebSocket('ws://127.0.0.1:8000/publish/{{ task_obj.pk }}/');
    
                // 一旦服务端有消息 会自动触发onmessage方法
                ws.onmessage = function (args) {
                    // args.data
                    var res = JSON.parse(args.data);
                    if (res.code==='init'){
                        // 操作gojs渲染图表
                        diagram.model = new go.TreeModel(res.data)
                    }
                }
            }
    
            function initTable() {
                var $ = go.GraphObject.make;
                diagram = $(go.Diagram, "diagramDiv", {
                    layout: $(go.TreeLayout, {
                        angle: 0,
                        nodeSpacing: 20,
                        layerSpacing: 70
                    })
                });
                // 生成一个节点模版
                diagram.nodeTemplate = $(go.Node, "Auto",
                    $(go.Shape, {
                        figure: "RoundedRectangle",
                        fill: 'yellow',
                        stroke: 'yellow'
                    }, new go.Binding("figure", "figure"), new go.Binding("fill", "color"), new go.Binding("stroke", "color")),
                    $(go.TextBlock, {margin: 8}, new go.Binding("text", "text"))
                );
                // 生成一个箭头模版
                diagram.linkTemplate = $(go.Link,
                    {routing: go.Link.Orthogonal},
                    $(go.Shape, {stroke: 'yellow'}, new go.Binding('stroke', 'link_color')),
                    $(go.Shape, {toArrow: "OpenTriangle", stroke: 'yellow'}, new go.Binding('stroke', 'link_color'))
                );
                // 数据集合  以后替换ajax请求   注意使用key和parent来规定箭头的指向
                {#var nodeDataArray = [#}
                {#    {key: "start", text: '开始', figure: 'Ellipse', color: "lightgreen"},#}
                {#    {key: "download", parent: 'start', text: '下载代码', color: "lightgreen", link_text: '执行中...'},#}
                {#    {key: "compile", parent: 'download', text: '本地编译', color: "lightgreen"},#}
                {#    {key: "zip", parent: 'compile', text: '打包', color: "red", link_color: 'red'},#}
                {#    {key: "c1", text: '服务器1', parent: "zip"},#}
                {#    {key: "c11", text: '服务重启', parent: "c1"},#}
                {#    {key: "c2", text: '服务器2', parent: "zip"},#}
                {#    {key: "c21", text: '服务重启', parent: "c2"},#}
                {#    {key: "c3", text: '服务器3', parent: "zip"},#}
                {#    {key: "c31", text: '服务重启', parent: "c3"},#}
                {#];#}
                {#diagram.model = new go.TreeModel(nodeDataArray);#}
                // 动态控制节点颜色变化   后端给一个key值 即可查找图表并修改
    
                /*
                var node = diagram.model.findNodeDataForKey("zip");
                diagram.model.setDataProperty(node, "color", "lightgreen");
                }
                */
    
            }
        
            // 页面加载完毕 先自动执行两个函数 给全局变量赋值
            $(function () {
                initWebSocket();
                initTable()
            });
    
            function createDiagram() {
                ws.send('init')
            }
    
    
    
        </script>
    

    利用channels实现群发的功能

    • 注册
    INSTALLED_APPS = [
        'django.contrib.admin',
        ...
        'channels',
    ]
    
    • 配置
    ASGI_APPLICATION = 'dm_fabu03.routing.application'
    
    • 新建routing
    from channels.routing import ProtocolTypeRouter,URLRouter
    from django.conf.urls import url
    from app01 import consumers
    
    
    
    """consumers.py 当逻辑也非常多的时候 你也可以建成文件夹里面包含多个文件的形式"""
    application = ProtocolTypeRouter({
        'websocket':URLRouter([
            url(r'^publish/(?P<task_id>d+)/$',consumers.PublishConsumer)
        ])
    })
    

    前端钩子脚本

    task_form.html

    {% extends 'base.html' %}
    
    
    
    {% block css %}
        <style>
            .outline .series .module {
                line-height: 100px;
                vertical-align: middle;
                 940px;
                margin: 0 auto;
                padding-bottom: 10px;
            }
    
            .outline .series .module .item .line {
                float: left;
                 80px;
    
            }
    
            .outline .series .module .item .line hr {
                margin-top: 49px
            }
    
            .outline .series .module .item .icon {
                float: left;
                color: #dddddd;
                position: relative;
    
            }
    
            .outline .series .module .item .icon .up, .outline .series .module .item .icon .down {
                position: absolute;
                line-height: 49px;
                min- 90px;
                left: 0;
                text-align: center;
                margin-left: -38px;
                color: #337ab7;
            }
    
            .outline .series .module .item:hover .icon, .outline .series .module .item.active .icon {
                color: green;
            }
    
            .outline .series .module .item .icon .up {
                top: 0;
            }
    
            .outline .series .module .item .icon .down {
                bottom: 0;
    
            }
        </style>
    {% endblock %}
    
    {% block content %}
        {#    1 基本信息展示#}
        <table class="table table-hover table-striped table-bordered">
            <tbody>
            <tr>
                <td>项目名称:{{ project_obj.title }}</td>
                <td>环境:{{ project_obj.get_env_display }}</td>
            </tr>
            <tr>
                <td colspan="2">仓库地址:{{ project_obj.repo }}</td>
            </tr>
            <tr>
                <td colspan="2">线上地址:{{ project_obj.path }}</td>
            </tr>
            <tr>
                <td colspan="2">
                    <div>关联服务器</div>
                    <ul>
                        {% for server_obj in project_obj.servers.all %}
                            <li>{{ server_obj.hostname }}</li>
                        {% endfor %}
    
                    </ul>
                </td>
            </tr>
            </tbody>
        </table>
        <form action="" method="post" novalidate>
            {% csrf_token %}
            {#    2 基本配置#}
            <div class="panel panel-default">
                <div class="panel-heading">
                    <h3 class="panel-title"><span class="glyphicon glyphicon-cog"></span>基本配置</h3>
                </div>
                <div class="panel-body">
                    <div class="form-horizontal">
                        <div class="form-group">
                            <label for="{{ form_obj.tag.id_for_label }}"
                                   class="col-sm-2 control-label">{{ form_obj.tag.label }}</label>
                            <div class="col-sm-10">
                                {{ form_obj.tag }}
                                <span>{{ form_obj.tag.errors.0 }}</span>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            {#    3 脚本钩子渲染#}
            <div class="panel panel-default">
                <div class="panel-heading">
                    <h3 class="panel-title"><span class="glyphicon glyphicon-tasks"></span>发布流程&脚本</h3>
                </div>
                <div class="panel-body">
                    {#            4 执行流程图即钩子脚本作用地展示#}
                    <div class="outline">
                        <div class="series">
                            <div class="module clearfix">
                                <div class="item left">
                                    <div class="line">
                                        <hr>
                                    </div>
                                    <div class="icon">
                                        <span class="glyphicon glyphicon-record" aria-hidden="true"></span>
                                        <a class="down">01 开始</a>
                                    </div>
                                </div>
    
                                <div class="item left active">
                                    <div class="line">
                                        <hr>
                                    </div>
                                    <div class="icon">
                                        <span class="glyphicon glyphicon-record" aria-hidden="true"></span>
                                        <a class="up">02 下载前</a>
                                    </div>
                                </div>
                                <div class="item left">
                                    <div class="line">
                                        <hr>
                                    </div>
                                    <div class="icon">
                                        <span class="glyphicon glyphicon-record" aria-hidden="true"></span>
                                        <a class="down">03 下载代码</a>
                                    </div>
                                </div>
    
                                <div class="item left active">
                                    <div class="line">
                                        <hr>
                                    </div>
                                    <div class="icon">
                                        <span class="glyphicon glyphicon-record" aria-hidden="true"></span>
                                        <a class="up">04 下载后</a>
                                    </div>
                                </div>
    
                                <div class="item left">
                                    <div class="line">
                                        <hr>
                                    </div>
                                    <div class="icon">
                                        <span class="glyphicon glyphicon-record" aria-hidden="true"></span>
                                        <a class="down">05 打包上传</a>
                                    </div>
                                </div>
    
                                <div class="item left active">
                                    <div class="line">
                                        <hr>
                                    </div>
                                    <div class="icon">
                                        <span class="glyphicon glyphicon-record" aria-hidden="true"></span>
                                        <a class="up">06 发布前</a>
                                    </div>
                                </div>
    
                                <div class="item left">
                                    <div class="line">
                                        <hr>
                                    </div>
                                    <div class="icon">
                                        <span class="glyphicon glyphicon-record" aria-hidden="true"></span>
                                        <a class="down">07 发布</a>
                                    </div>
                                </div>
    
                                <div class="item left active">
                                    <div class="line">
                                        <hr>
                                    </div>
                                    <div class="icon">
                                        <span class="glyphicon glyphicon-record" aria-hidden="true"></span>
                                        <a class="up">08 发布后</a>
                                    </div>
                                </div>
                                <div class="item left">
                                    <div class="line">
                                        <hr>
                                    </div>
                                </div>
    
                            </div>
                        </div>
                    </div>
                    {#            5 四个脚本展示#}
                    <div class="hooks">
                        <div class="col-md-6">
                            <div class="panel panel-default">
                                <div class="panel-heading">
                                    <h3 class="panel-title">02 下载前</h3>
                                </div>
                                <div class="panel-body">
                                    <div class="form-horizontal">
                                        <div class="form-group">
    {#                                        下拉框#}
                                            <div class="col-sm-12">
                                                {{ form_obj.before_download_select }}
                                            </div>
                                        </div>
                                        <div class="form-group">
                                            <div class="col-sm-12">
                                                {{ form_obj.before_download_script }}
                                            </div>
                                        </div>
                                        <div class="form-group" style="height: 60px">
                                            <div class="col-sm-3">
                                                <div class="checkbox">
    
                                                    <label for="">{{ form_obj.before_download_template }}保存模版</label>
                                                </div>
                                            </div>
                                            <div class="col-sm-9">
                                                {{ form_obj.before_download_title }}
                                                <span style="color: red">{{ form_obj.before_download_title.errors.0 }}</span>
                                            </div>
    
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div class="col-md-6">
                            <div class="panel panel-default">
                                <div class="panel-heading">
                                    <h3 class="panel-title">04 下载后</h3>
                                </div>
                                <div class="panel-body">
                                    <div class="form-horizontal">
                                        <div class="form-group">
    {#                                        下拉框#}
                                            <div class="col-sm-12">
                                                {{ form_obj.after_download_select }}
                                            </div>
                                        </div>
                                        <div class="form-group">
                                            <div class="col-sm-12">
                                                {{ form_obj.after_download_script }}
                                            </div>
                                        </div>
                                        <div class="form-group" style="height: 60px">
                                            <div class="col-sm-3">
                                                <div class="checkbox">
    
                                                    <label for="">{{ form_obj.after_download_template }}保存模版</label>
                                                </div>
                                            </div>
                                            <div class="col-sm-9">
                                                {{ form_obj.after_download_title }}
                                                <span style="color: red">{{ form_obj.after_download_title.errors.0 }}</span>
                                            </div>
    
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div class="col-md-6">
                            <div class="panel panel-default">
                                <div class="panel-heading">
                                    <h3 class="panel-title">06 发布前</h3>
                                </div>
                                <div class="panel-body">
                                    <div class="form-horizontal">
                                        <div class="form-group">
    {#                                        下拉框#}
                                            <div class="col-sm-12">
                                                {{ form_obj.before_deploy_select }}
                                            </div>
                                        </div>
                                        <div class="form-group">
                                            <div class="col-sm-12">
                                                {{ form_obj.before_deploy_script }}
                                            </div>
                                        </div>
                                        <div class="form-group" style="height: 60px">
                                            <div class="col-sm-3">
                                                <div class="checkbox">
    
                                                    <label for="">{{ form_obj.before_deploy_template }}保存模版</label>
                                                </div>
                                            </div>
                                            <div class="col-sm-9">
                                                {{ form_obj.before_deploy_title }}
                                                <span style="color: red">{{ form_obj.before_deploy_title.errors.0 }}</span>
                                            </div>
    
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div class="col-md-6">
                            <div class="panel panel-default">
                                <div class="panel-heading">
                                    <h3 class="panel-title">08 发布后</h3>
                                </div>
                                <div class="panel-body">
                                    <div class="form-horizontal">
                                        <div class="form-group">
    {#                                        下拉框#}
                                            <div class="col-sm-12">
                                                {{ form_obj.after_deploy_select }}
                                            </div>
                                        </div>
                                        <div class="form-group">
                                            <div class="col-sm-12">
                                                {{ form_obj.after_deploy_script }}
                                            </div>
                                        </div>
                                        <div class="form-group" style="height: 60px">
                                            <div class="col-sm-3">
                                                <div class="checkbox">
    
                                                    <label for="">{{ form_obj.after_deploy_template }}保存模版</label>
                                                </div>
                                            </div>
                                            <div class="col-sm-9">
                                                {{ form_obj.after_deploy_title }}
                                                <span style="color: red">{{ form_obj.after_deploy_title.errors.0 }}</span>
                                            </div>
    
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <input type="submit" class="btn btn-success">
        </form>
    
    {% endblock %}
    
    
    {% block js %}
        <script>
            // 直接给hooks类标签内所有的select绑定事件
            $('.hooks').find('select').change(function () {
                {#alert($(this).val())  获取用户输入的模版主键值 #}
                var $that = $(this);
                // 朝后端发送请求 获取对应的脚本内容
                $.ajax({
                    url:'/hook/template/'+$that.val()+'/',
                    type:'get',
                    dataType:'JSON',
                    success:function (args) {
                        // 获取脚本内容 渲染到对应下拉框下面的textarea框中
                        {#alert(args.content)#}
                        // 标签查找
                        $that.parent().parent().next().find('textarea').val(args.content);
                    }
                })
            })
        </script>
    {% endblock %}
    
  • 相关阅读:
    iOS开发UI篇—UITabBarController简单介绍
    iOS 开发 UI 搭建心得(一)—— 驾驭 StoryBoard
    The Swift Programming Language--语言指南--协议
    Swift 委托/代理设计模式
    Ping azure
    leetcode先刷_Maximum Subarray
    AsyncHandler
    HDU 1026 Ignatius and the Princess I 迷宫范围内的搜索剪枝问题
    Design Pattern Command 命令设计模式
    logstash高速入口
  • 原文地址:https://www.cnblogs.com/fwzzz/p/12733993.html
Copyright © 2011-2022 走看看