mirror of
https://github.com/TeaOSLab/EdgeAdmin.git
synced 2025-12-08 06:00:24 +08:00
实现基础的通知媒介管理
This commit is contained in:
6
web/views/@default/admins/recipients/@menu.html
Normal file
6
web/views/@default/admins/recipients/@menu.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<first-menu>
|
||||
<menu-item href="/admins/recipients" code="recipient">接收人</menu-item>
|
||||
<menu-item href="/admins/recipients/groups" code="group">接收人分组</menu-item>
|
||||
<menu-item href="/admins/recipients/instances" code="instance">媒介</menu-item>
|
||||
<menu-item href="/admins/recipients/logs" code="log">发送记录</menu-item>
|
||||
</first-menu>
|
||||
@@ -0,0 +1,7 @@
|
||||
<first-menu>
|
||||
<menu-item href="/admins/recipients">所有接收人</menu-item>
|
||||
<span class="item">|</span>
|
||||
<menu-item :href="'/admins/recipients/recipient?recipientId=' + recipient.id" code="recipient">"{{recipient.admin.fullname}} <span class="small grey">({{recipient.instance.name}})</span>"详情</menu-item>
|
||||
<menu-item :href="'/admins/recipients/update?recipientId=' + recipient.id" code="update">修改</menu-item>
|
||||
<menu-item :href="'/admins/recipients/test?recipientId=' + recipient.id" code="test">测试</menu-item>
|
||||
</first-menu>
|
||||
45
web/views/@default/admins/recipients/createPopup.html
Normal file
45
web/views/@default/admins/recipients/createPopup.html
Normal file
@@ -0,0 +1,45 @@
|
||||
{$layout "layout_popup"}
|
||||
{$template "/code_editor"}
|
||||
|
||||
<h3>创建接收人媒介</h3>
|
||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">系统用户 *</td>
|
||||
<td>
|
||||
<admin-selector></admin-selector>
|
||||
<p class="comment">选择关联的系统用户。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>媒介 *</td>
|
||||
<td>
|
||||
<message-media-instance-selector @change="changeInstance"></message-media-instance-selector>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>接收人标识</td>
|
||||
<td>
|
||||
<input type="text" name="user" maxlength="300"/>
|
||||
<p class="comment">{{userDescription}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>分组</td>
|
||||
<td>
|
||||
<message-recipient-group-selector></message-recipient-group-selector>
|
||||
<p class="comment">选择当前接收人所属分组。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>备注</td>
|
||||
<td>
|
||||
<textarea rows="3" name="description" maxlength="100"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
11
web/views/@default/admins/recipients/createPopup.js
Normal file
11
web/views/@default/admins/recipients/createPopup.js
Normal file
@@ -0,0 +1,11 @@
|
||||
Tea.context(function () {
|
||||
this.userDescription = ""
|
||||
|
||||
this.changeInstance = function (instance) {
|
||||
if (instance != null) {
|
||||
this.userDescription = instance.media.userDescription
|
||||
} else {
|
||||
this.userDescription = ""
|
||||
}
|
||||
}
|
||||
})
|
||||
18
web/views/@default/admins/recipients/groups/createPopup.html
Normal file
18
web/views/@default/admins/recipients/groups/createPopup.html
Normal file
@@ -0,0 +1,18 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>创建分组</h3>
|
||||
|
||||
<form class="ui form" data-tea-success="success" data-tea-action="$">
|
||||
<csrf-token></csrf-token>
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">分组名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="name" maxlength="50" ref="focus"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
28
web/views/@default/admins/recipients/groups/index.html
Normal file
28
web/views/@default/admins/recipients/groups/index.html
Normal file
@@ -0,0 +1,28 @@
|
||||
{$layout}
|
||||
{$template "../menu"}
|
||||
|
||||
<second-menu>
|
||||
<menu-item @click.prevent="createGroup">[创建]</menu-item>
|
||||
</second-menu>
|
||||
|
||||
<p class="comment" v-if="groups.length == 0">暂时还没有分组。</p>
|
||||
|
||||
<table class="ui table selectable celled" v-if="groups.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>分组名称</th>
|
||||
<th class="two wide">状态</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="group in groups">
|
||||
<td>{{group.name}}</td>
|
||||
<td>
|
||||
<label-on :v-is-on="group.isOn"></label-on>
|
||||
</td>
|
||||
<td>
|
||||
<a href="" @click.prevent="updateGroup(group.id)">修改</a>
|
||||
<a href="" @click.prevent="deleteGroup(group.id)">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
33
web/views/@default/admins/recipients/groups/index.js
Normal file
33
web/views/@default/admins/recipients/groups/index.js
Normal file
@@ -0,0 +1,33 @@
|
||||
Tea.context(function () {
|
||||
this.createGroup = function () {
|
||||
teaweb.popup(Tea.url(".createPopup"), {
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.updateGroup = function (groupId) {
|
||||
teaweb.popup(Tea.url(".updatePopup", {groupId: groupId}), {
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.deleteGroup = function (groupId) {
|
||||
teaweb.confirm("确定要删除此分组吗?", function () {
|
||||
this.$post(".delete")
|
||||
.params({groupId: groupId})
|
||||
.success(function () {
|
||||
teaweb.success("删除成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
15
web/views/@default/admins/recipients/groups/selectPopup.html
Normal file
15
web/views/@default/admins/recipients/groups/selectPopup.html
Normal file
@@ -0,0 +1,15 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
|
||||
<h3>选择分组</h3>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">选择分组</td>
|
||||
<td>
|
||||
<p class="comment" v-if="groups.length == 0">暂时没有可以选择的分组。</p>
|
||||
<div v-if="groups.length > 0">
|
||||
<a class="ui label small basic" v-for="group in groups" @click.prevent="selectGroup(group)">{{group.name}}</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
10
web/views/@default/admins/recipients/groups/selectPopup.js
Normal file
10
web/views/@default/admins/recipients/groups/selectPopup.js
Normal file
@@ -0,0 +1,10 @@
|
||||
Tea.context(function () {
|
||||
this.selectGroup = function (group) {
|
||||
NotifyPopup({
|
||||
code: 200,
|
||||
data: {
|
||||
group: group
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
24
web/views/@default/admins/recipients/groups/updatePopup.html
Normal file
24
web/views/@default/admins/recipients/groups/updatePopup.html
Normal file
@@ -0,0 +1,24 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>修改分组</h3>
|
||||
|
||||
<form class="ui form" data-tea-success="success" data-tea-action="$">
|
||||
<csrf-token></csrf-token>
|
||||
<input type="hidden" name="groupId" :value="group.id"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">分组名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="name" maxlength="50" ref="focus" v-model="group.name"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>是否启用</td>
|
||||
<td>
|
||||
<checkbox name="isOn" value="1" v-model="group.isOn"></checkbox>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
51
web/views/@default/admins/recipients/index.html
Normal file
51
web/views/@default/admins/recipients/index.html
Normal file
@@ -0,0 +1,51 @@
|
||||
{$layout}
|
||||
{$template "menu"}
|
||||
|
||||
<second-menu>
|
||||
<menu-item @click.prevent="createRecipient">[创建]</menu-item>
|
||||
</second-menu>
|
||||
|
||||
<p class="comment" v-if="recipients.length == 0">暂时还没有媒介接收人。</p>
|
||||
|
||||
<table class="ui table selectable celled" v-if="recipients.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>系统用户</th>
|
||||
<th>媒介类型</th>
|
||||
<th>接收人标识</th>
|
||||
<th>所属分组</th>
|
||||
<th>备注</th>
|
||||
<th class="two wide">状态</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="recipient in recipients">
|
||||
<td>{{recipient.admin.fullname}} <span class="small grey">({{recipient.admin.username}})</span> <link-icon :href="'/admins/admin?adminId=' + recipient.admin.id"></link-icon></td>
|
||||
<td>{{recipient.instance.name}}</td>
|
||||
<td>
|
||||
<span v-if="recipient.user.length > 0">{{recipient.user}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td>
|
||||
<div v-if="recipient.groups != null && recipient.groups.length > 0">
|
||||
<div v-for="group in recipient.groups" class="ui label small basic">{{group.name}}</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<span class="disabled">-</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="recipient.description.length > 0">{{recipient.description}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td>
|
||||
<label-on :v-is-on="recipient.isOn"></label-on>
|
||||
</td>
|
||||
<td>
|
||||
<a :href="'/admins/recipients/recipient?recipientId=' + recipient.id">详情</a>
|
||||
<a href="" @click.prevent="deleteRecipient(recipient.id)">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
24
web/views/@default/admins/recipients/index.js
Normal file
24
web/views/@default/admins/recipients/index.js
Normal file
@@ -0,0 +1,24 @@
|
||||
Tea.context(function () {
|
||||
this.createRecipient = function () {
|
||||
teaweb.popup(Tea.url(".createPopup"), {
|
||||
height: "26em",
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.deleteRecipient = function (recipientId) {
|
||||
teaweb.confirm("确定要删除此接收媒介吗?", function () {
|
||||
this.$post(".delete")
|
||||
.params({recipientId: recipientId})
|
||||
.success(function () {
|
||||
teaweb.success("删除成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,7 @@
|
||||
<first-menu>
|
||||
<menu-item href="/admins/recipients/instances">所有媒介</menu-item>
|
||||
<span class="item">|</span>
|
||||
<menu-item :href="'/admins/recipients/instances/instance?instanceId=' + instance.id" code="instance">"{{instance.media.name}}"详情</menu-item>
|
||||
<menu-item :href="'/admins/recipients/instances/update?instanceId=' + instance.id" code="update">修改</menu-item>
|
||||
<menu-item :href="'/admins/recipients/instances/test?instanceId=' + instance.id" code="test">测试</menu-item>
|
||||
</first-menu>
|
||||
@@ -0,0 +1,12 @@
|
||||
.CodeMirror {
|
||||
border: 1px solid #eee;
|
||||
height: auto !important;
|
||||
}
|
||||
.CodeMirror-vscrollbar {
|
||||
width: 6px;
|
||||
border-radius: 3px !important;
|
||||
}
|
||||
.CodeMirror-vscrollbar::-webkit-scrollbar-thumb {
|
||||
border-radius: 2px;
|
||||
}
|
||||
/*# sourceMappingURL=createPopup.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["createPopup.less"],"names":[],"mappings":"AACA;EACC,sBAAA;EACA,uBAAA;;AAGD;EACC,UAAA;EACA,6BAAA;;AAGD,sBAAsB;EACrB,kBAAA","file":"createPopup.css"}
|
||||
354
web/views/@default/admins/recipients/instances/createPopup.html
Normal file
354
web/views/@default/admins/recipients/instances/createPopup.html
Normal file
@@ -0,0 +1,354 @@
|
||||
{$layout "layout_popup"}
|
||||
{$template "/code_editor"}
|
||||
|
||||
<h3>创建媒介</h3>
|
||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td>媒介名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="name" ref="focus" maxlength="100"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border title">媒介类型 *</td>
|
||||
<td>
|
||||
<message-media-selector @change="changeMediaType"></message-media-selector>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- E-mail -->
|
||||
<tbody v-show="mediaType == 'email'">
|
||||
<tr>
|
||||
<td class="color-border">SMTP *</td>
|
||||
<td>
|
||||
<input type="text" name="emailSmtp" maxlength="100" placeholder="类似于 smtp.xxx.com:465"/>
|
||||
<p class="comment">只支持SSL(或TLS)连接,端口通常为:465或587。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">账号 *</td>
|
||||
<td>
|
||||
<input type="text" name="emailUsername" v-model="emailUsername" maxlength="500" placeholder="类似于 xxx@xxx.com" @input="changeEmailUsername()"/>
|
||||
<p class="comment">邮箱账号,比如 123456@qq.com<span v-html="emailUsernameHelp"></span>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">密码 *</td>
|
||||
<td>
|
||||
<input type="text" name="emailPassword" maxlength="100"/>
|
||||
<p class="comment">账号对应的密码或者授权码(比如QQ邮箱就需要授权码)。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">发送者Email</td>
|
||||
<td>
|
||||
<input type="text" name="emailFrom" maxlength="500" placeholder="类似于 xxx@xxx.com"/>
|
||||
<p class="comment">默认和账号一致</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- webHook -->
|
||||
<tbody v-show="mediaType == 'webHook'">
|
||||
<tr>
|
||||
<td class="color-border">URL *</td>
|
||||
<td>
|
||||
<input type="text" name="webHookURL" maxlength="500" placeholder="http://..."/>
|
||||
<p class="comment">可以在URL中使用<span class="ui label tiny">${MessageUser}</span>、<span class="ui label tiny">${MessageSubject}</span>和<span class="ui label tiny">${MessageBody}</span>来代表接收人标识、标题和内容。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">请求方法 *</td>
|
||||
<td>
|
||||
<select name="webHookMethod" v-model="webHookMethod" class="ui dropdown" style="width:10em">
|
||||
<option v-for="method in methods" :value="method">{{method}}</option>
|
||||
</select>
|
||||
<p class="comment" v-if="webHookMethod == 'POST'">将以POST方式发送<span class="ui label tiny">MessageUser</span>、<span class="ui label tiny">MessageSubject</span>和<span class="ui label tiny">MessageBody</span>参数,分别代表接收人标识、标题和内容</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="advancedOptionsVisible">
|
||||
<td class="color-border">自定义Header</td>
|
||||
<td>
|
||||
<div class="webHook-headers-box">
|
||||
<span class="ui label tiny" v-for="(header,index) in webHookHeaders">{{header.name}}:{{header.value}}
|
||||
<input type="hidden" name="webHookHeaderNames" :value="header.name"/>
|
||||
<input type="hidden" name="webHookHeaderValues" :value="header.value"/>
|
||||
<a href="" title="删除" @click.prevent="removeWebHookHeader(index)"><i class="icon remove"></i></a>
|
||||
</span>
|
||||
</div>
|
||||
<button class="ui button tiny" type="button" @click.prevent="addWebHookHeader()" v-if="!webHookHeadersAdding">+</button>
|
||||
<div v-if="webHookHeadersAdding">
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="webHookHeaderName" v-model="webHookHeadersAddingName" placeholder="名称" maxlength="100" @keyup.enter="confirmWebHookHeadersAdding" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">:</div>
|
||||
<div class="ui field">
|
||||
<input type="text" placeholder="值" v-model="webHookHeadersAddingValue" size="50" maxlength="256" @keyup.enter="confirmWebHookHeadersAdding" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui button tiny" type="button" @click.prevent="confirmWebHookHeadersAdding()">确认添加</button>
|
||||
<a href="" @click.prevent="cancelWebHookHeadersAdding()">取消</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="webHookMethod == 'POST' && advancedOptionsVisible">
|
||||
<td class="color-border">自定义内容</td>
|
||||
<td>
|
||||
<div class="ui menu tabular small attached">
|
||||
<a href="" class="item" :class="{active:webHookContentType == 'params'}" @click.prevent="selectWebHookContentType('params')">参数对</a>
|
||||
<a href="" class="item" :class="{active:webHookContentType == 'body'}" @click.prevent="selectWebHookContentType('body')">文本内容</a>
|
||||
</div>
|
||||
<div class="ui segment attached" v-if="webHookContentType == 'params'">
|
||||
<input type="hidden" name="webHookContentType" value="params"/>
|
||||
<div class="webHook-headers-box">
|
||||
<span class="ui label tiny" v-for="(param,index) in webHookParams">{{param.name}}:{{param.value}}
|
||||
<input type="hidden" name="webHookParamNames" :value="param.name"/>
|
||||
<input type="hidden" name="webHookParamValues" :value="param.value"/>
|
||||
<a href="" title="删除" @click.prevent="removeWebHookParam(index)"><i class="icon remove"></i></a>
|
||||
</span>
|
||||
</div>
|
||||
<button class="ui button tiny" type="button" @click.prevent="addWebHookParam()" v-if="!webHookParamsAdding">+</button>
|
||||
<div v-if="webHookParamsAdding">
|
||||
<input type="hidden" name="webHookContentType" value="params"/>
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="webHookParamName" v-model="webHookParamsAddingName" placeholder="名称" maxlength="100" @keyup.enter="confirmWebHookParamsAdding" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">:</div>
|
||||
<div class="ui field">
|
||||
<textarea type="text" placeholder="值" v-model="webHookParamsAddingValue" cols="50" maxlength="1024" rows="2"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui button tiny" type="button" @click.prevent="confirmWebHookParamsAdding()">确认添加</button>
|
||||
<a href="" @click.prevent="cancelWebHookParamsAdding()">取消</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui segment attached" v-if="webHookContentType == 'body'">
|
||||
<input type="hidden" name="webHookContentType" value="body"/>
|
||||
<textarea name="webHookBody" v-model="webHookBody" rows="5" placeholder="发送的内容"></textarea>
|
||||
<p class="comment">
|
||||
内容中可以使用三个变量:<span class="ui label tiny">${MessageUser}</span>、<span class="ui label tiny">${MessageSubject}</span>和<span class="ui label tiny">${MessageBody}</span>参数,分别代表接收人标识、标题和内容
|
||||
</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 脚本 -->
|
||||
<tbody v-show="mediaType == 'script'">
|
||||
<tr>
|
||||
<td class="color-border">脚本 *</td>
|
||||
<td>
|
||||
<input type="hidden" name="scriptType" :value="scriptTab"/>
|
||||
<input type="hidden" name="scriptLang" :value="scriptLang"/>
|
||||
<div class="ui tabular menu attached small">
|
||||
<a class="item" :class="{active:scriptTab == 'path'}" @click.prevent="selectScriptTab('path')">脚本文件</a>
|
||||
<a class="item" :class="{active:scriptTab == 'code'}" @click.prevent="selectScriptTab('code')">脚本代码</a>
|
||||
</div>
|
||||
<div class="ui bottom segment attached" v-show="scriptTab == 'path'">
|
||||
<input type="text" name="scriptPath" maxlength="500"/>
|
||||
<p class="comment">如果是Shell脚本,请不要忘记在头部添加 <em>#!脚本解释工具</em>,比如 <em>#!/bin/bash</em><br/>
|
||||
执行此脚本时,在脚本中可以使用<span class="ui label tiny">${MessageUser}</span>、<span class="ui label tiny">${MessageSubject}</span>和<span class="ui label tiny">${MessageBody}</span>三个环境变量分别代表通知的接收人标识、标题和内容。
|
||||
</p>
|
||||
</div>
|
||||
<div class="ui bottom segment attached" v-show="scriptTab == 'code'" style="padding-top:0">
|
||||
<div class="ui menu text small">
|
||||
<a class="item" v-for="lang in scriptLangs" :class="{active:lang.code == scriptLang}" @click.prevent="selectScriptLang(lang.code)">{{lang.name}}</a>
|
||||
</div>
|
||||
<textarea name="scriptCode" id="script-code-editor" rows="1"></textarea>
|
||||
<p class="comment">如果是Shell脚本,请不要忘记在头部添加 <em>#!脚本解释工具</em>,比如 <em>#!/bin/bash</em><br/>
|
||||
执行此脚本时,在脚本中可以使用<span class="ui label tiny">${MessageUser}</span>、<span class="ui label tiny">${MessageSubject}</span>和<span class="ui label tiny">${MessageBody}</span>三个环境变量分别代表通知的接收人标识、标题和内容。
|
||||
</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="advancedOptionsVisible">
|
||||
<td class="color-border">当前工作目录<em>(CWD)</em></td>
|
||||
<td>
|
||||
<input type="text" name="scriptCwd" maxlength="500"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="advancedOptionsVisible">
|
||||
<td class="color-border">环境变量<em>(ENV)</em></td>
|
||||
<td>
|
||||
<div class="ui field">
|
||||
<span class="ui label small" v-for="(var1, index) in env">
|
||||
<input type="hidden" name="scriptEnvNames" :value="var1.name"/>
|
||||
<input type="hidden" name="scriptEnvValues" :value="var1.value"/>
|
||||
<em>{{var1.name}}</em>: {{var1.value}}
|
||||
<a href="" @click.prevent="removeEnv(index)"><i class="icon remove"></i></a>
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="envAdding" class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="envAddingName" v-model="envAddingName" placeholder="变量名" style="width:9em" @keyup.enter="confirmAddEnv" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<input type="text" name="envAddingValue" v-model="envAddingValue" placeholder="变量值" style="width:15em" @keyup.enter="confirmAddEnv" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button" type="button" @click="confirmAddEnv()">添加</button>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<a href="" @click.prevent="cancelEnv()"><i class="icon remove"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button small" type="button" @click="addEnv()">+</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 钉钉群机器人 -->
|
||||
<tbody v-show="mediaType == 'dingTalk'">
|
||||
<tr>
|
||||
<td class="color-border">Hook地址 *</td>
|
||||
<td>
|
||||
<textarea name="dingTalkWebHookURL" maxlength="500" placeholder="https://oapi.dingtalk.com/robot/send?access_token=xxx" rows="2"></textarea>
|
||||
<p class="comment">填入自定义群机器人的Hook地址,<a href="https://developers.dingtalk.com/document/app/custom-robot-access" target="_blank">获取方法»</a></p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 企业微信 -->
|
||||
<tbody v-show="mediaType == 'qyWeixin'">
|
||||
<tr>
|
||||
<td class="color-border">企业ID *</td>
|
||||
<td>
|
||||
<input type="text" name="qyWeixinCorporateId" maxlength="100" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">应用AgentId *</td>
|
||||
<td>
|
||||
<input type="text" name="qyWeixinAgentId" maxlength="100"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">应用Secret *</td>
|
||||
<td>
|
||||
<input type="text" name="qyWeixinAppSecret" maxlength="100"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">内容文本格式</td>
|
||||
<td>
|
||||
<select name="qyWeixinTextFormat" v-model="qyWeixinTextFormat" class="ui dropdown" style="width:10em">
|
||||
<option value="text">普通文本</option>
|
||||
<option value="markdown">Markdown</option>
|
||||
</select>
|
||||
<p class="comment" v-if="qyWeixinTextFormat == 'markdown'">企业微信目前只支持少数的Markdown语法,<a href="https://work.weixin.qq.com/api/doc#90000/90135/90236/%E6%94%AF%E6%8C%81%E7%9A%84markdown%E8%AF%AD%E6%B3%95" target="_blank">点击这里了解»</a> </p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 企业微信群机器人 -->
|
||||
<tbody v-show="mediaType == 'qyWeixinRobot'">
|
||||
<tr>
|
||||
<td class="color-border">WebHook地址 *</td>
|
||||
<td>
|
||||
<textarea name="qyWeixinRobotWebHookURL" maxlength="500" placeholder="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx" rows="2"></textarea>
|
||||
<p class="comment">填入自定义群机器人的WebHook地址</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">内容文本格式</td>
|
||||
<td>
|
||||
<select name="qyWeixinRobotTextFormat" v-model="qyWeixinRobotTextFormat" class="ui dropdown" style="width:10em">
|
||||
<option value="text">普通文本</option>
|
||||
<option value="markdown">Markdown</option>
|
||||
</select>
|
||||
<p class="comment" v-if="qyWeixinRobotTextFormat == 'markdown'">企业微信目前只支持少数的Markdown语法,<a href="https://work.weixin.qq.com/api/doc#90000/90135/91760/markdown%E7%B1%BB%E5%9E%8B" target="_blank">点击这里了解»</a> </p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 阿里云短信 -->
|
||||
<tbody v-show="mediaType == 'aliyunSms'">
|
||||
<tr>
|
||||
<td class="color-border">签名名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="aliyunSmsSign" maxlength="100"/>
|
||||
<p class="comment">已经审核通过的短信签名名称</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">模板CODE *</td>
|
||||
<td>
|
||||
<input type="text" name="aliyunSmsTemplateCode" maxlength="100" placeholder="类似于SMS_12345"/>
|
||||
<p class="comment">已经审核通过的模板CODE</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">模板变量 *</td>
|
||||
<td>
|
||||
<div class="ui field">
|
||||
<span class="ui label small" v-for="(var1, index) in aliyunSmsTemplateVars">
|
||||
<input type="hidden" name="aliyunSmsTemplateVarNames" :value="var1.name"/>
|
||||
<input type="hidden" name="aliyunSmsTemplateVarValues" :value="var1.value"/>
|
||||
<em>{{var1.name}}</em>: {{var1.value}}
|
||||
<a href="" @click.prevent="removeAliyunSmsTemplateVar(index)"><i class="icon remove"></i></a>
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="aliyunSmsTemplateVarAdding" class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="aliyunSmsTemplateVarAddingName" v-model="aliyunSmsTemplateVarAddingName" placeholder="变量名" style="width:9em" @keyup.enter="confirmAddAliyunSmsTemplateVar" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<input type="text" name="aliyunSmsTemplateVarAddingValue" v-model="aliyunSmsTemplateVarAddingValue" placeholder="变量值" style="width:15em" @keyup.enter="confirmAddAliyunSmsTemplateVar" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button" type="button" @click="confirmAddAliyunSmsTemplateVar()">添加</button>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<a href="" @click.prevent="cancelAliyunSmsTemplateVar()"><i class="icon remove"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button small" type="button" @click="addAliyunSmsTemplateVar()">+</button>
|
||||
</div>
|
||||
<p class="comment">模板中使用的变量,在变量中可以使用<span class="ui label tiny">${MessageUser}</span>、<span class="ui label tiny">${MessageSubject}</span>和<span class="ui label tiny">${MessageBody}</span>来代表接收人标识、标题和内容。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">AccessKey ID *</td>
|
||||
<td>
|
||||
<input type="text" name="aliyunSmsAccessKeyId" maxlength="100"/>
|
||||
<p class="comment">在阿里云控制台中的访问控制中某个用户的AccessKey ID</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">AccessKey Secret *</td>
|
||||
<td>
|
||||
<input type="text" name="aliyunSmsAccessKeySecret" maxlength="100"/>
|
||||
<p class="comment">在阿里云控制台中的访问控制中某个用户的AccessKey Secret,和上面的AccessKey ID匹配</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- Telegram -->
|
||||
<tbody v-if="mediaType == 'telegram'">
|
||||
<tr>
|
||||
<td class="color-border">机器人Token</td>
|
||||
<td>
|
||||
<input type="text" name="telegramToken"/>
|
||||
<p class="comment">在创建机器人的时候可以获得,类似于 123456:AAAA-AAAAAAAAAAAAAAAAAAAA</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<tr>
|
||||
<td>备注</td>
|
||||
<td>
|
||||
<textarea rows="3" name="description" maxlength="100"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
334
web/views/@default/admins/recipients/instances/createPopup.js
Normal file
334
web/views/@default/admins/recipients/instances/createPopup.js
Normal file
@@ -0,0 +1,334 @@
|
||||
Tea.context(function () {
|
||||
this.mediaType = ""
|
||||
this.advancedOptionsVisible = true
|
||||
|
||||
let that = this
|
||||
this.changeMediaType = function (media) {
|
||||
that.mediaType = media.type
|
||||
}
|
||||
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
this.emailUsername = "";
|
||||
this.emailUsernameHelp = "";
|
||||
|
||||
this.changeEmailUsername = function () {
|
||||
this.emailUsernameHelp = "";
|
||||
if (this.emailUsername.indexOf("qq.com") > 0) {
|
||||
this.emailUsernameHelp = ",<a href=\"https://service.mail.qq.com/cgi-bin/help?id=28\" target='_blank'>QQ邮箱相关设置帮助</a>";
|
||||
} else if (this.emailUsername.indexOf("163.com") > 0) {
|
||||
this.emailUsernameHelp = ",<a href=\"https://help.mail.163.com/faqDetail.do?code=d7a5dc8471cd0c0e8b4b8f4f8e49998b374173cfe9171305fa1ce630d7f67ac22dc0e9af8168582a\" target='_blank'>网易邮箱相关设置帮助</a>";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* webHook
|
||||
*/
|
||||
this.methods = ["GET", "POST"]
|
||||
this.webHookMethod = "GET";
|
||||
|
||||
this.webHookHeadersAdding = false;
|
||||
this.webHookHeaders = [];
|
||||
this.webHookHeadersAddingName = "";
|
||||
this.webHookHeadersAddingValue = "";
|
||||
|
||||
this.addWebHookHeader = function () {
|
||||
this.webHookHeadersAdding = true;
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='webHookHeaderName']").focus();
|
||||
});
|
||||
};
|
||||
|
||||
this.cancelWebHookHeadersAdding = function () {
|
||||
this.webHookHeadersAdding = false;
|
||||
};
|
||||
|
||||
this.confirmWebHookHeadersAdding = function () {
|
||||
this.webHookHeaders.push({
|
||||
"name": this.webHookHeadersAddingName,
|
||||
"value": this.webHookHeadersAddingValue
|
||||
});
|
||||
this.webHookHeadersAddingName = "";
|
||||
this.webHookHeadersAddingValue = "";
|
||||
this.webHookHeadersAdding = false;
|
||||
};
|
||||
|
||||
this.removeWebHookHeader = function (index) {
|
||||
if (!window.confirm("确定要删除此Header吗?")) {
|
||||
return;
|
||||
}
|
||||
this.webHookHeaders.$remove(index);
|
||||
};
|
||||
|
||||
this.webHookContentType = "params";
|
||||
|
||||
this.selectWebHookContentType = function (contentType) {
|
||||
this.webHookContentType = contentType;
|
||||
this.$delay(function () {
|
||||
if (contentType == "params") {
|
||||
|
||||
} else if (contentType == "body") {
|
||||
this.$find("form textarea[name='webHookBody']").focus();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.webHookParamsAdding = false;
|
||||
this.webHookParams = [];
|
||||
this.webHookParamsAddingName = "";
|
||||
this.webHookParamsAddingValue = "";
|
||||
|
||||
this.addWebHookParam = function () {
|
||||
this.webHookParamsAdding = true;
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='webHookParamName']").focus();
|
||||
});
|
||||
};
|
||||
|
||||
this.cancelWebHookParamsAdding = function () {
|
||||
this.webHookParamsAdding = false;
|
||||
};
|
||||
|
||||
this.confirmWebHookParamsAdding = function () {
|
||||
this.webHookParams.push({
|
||||
"name": this.webHookParamsAddingName,
|
||||
"value": this.webHookParamsAddingValue
|
||||
});
|
||||
this.webHookParamsAddingName = "";
|
||||
this.webHookParamsAddingValue = "";
|
||||
this.webHookParamsAdding = false;
|
||||
};
|
||||
|
||||
this.removeWebHookParam = function (index) {
|
||||
if (!window.confirm("确定要删除此参数吗?")) {
|
||||
return;
|
||||
}
|
||||
this.webHookParams.$remove(index);
|
||||
};
|
||||
|
||||
this.webHookBody = "";
|
||||
|
||||
/**
|
||||
* 企业微信
|
||||
*/
|
||||
this.qyWeixinTextFormat = "text";
|
||||
|
||||
/**
|
||||
* 企业微信群机器人
|
||||
*/
|
||||
this.qyWeixinRobotTextFormat = "text";
|
||||
|
||||
/**
|
||||
* 脚本
|
||||
*/
|
||||
let scriptEditor = null
|
||||
this.scriptTab = "path";
|
||||
this.scriptLang = "shell";
|
||||
this.scriptLangs = [
|
||||
{
|
||||
"name": "Shell",
|
||||
"code": "shell"
|
||||
},
|
||||
{
|
||||
"name": "批处理(bat)",
|
||||
"code": "bat"
|
||||
},
|
||||
{
|
||||
"name": "PHP",
|
||||
"code": "php"
|
||||
},
|
||||
{
|
||||
"name": "Python",
|
||||
"code": "python"
|
||||
},
|
||||
{
|
||||
"name": "Ruby",
|
||||
"code": "ruby"
|
||||
},
|
||||
{
|
||||
"name": "NodeJS",
|
||||
"code": "nodejs"
|
||||
}
|
||||
];
|
||||
|
||||
this.selectScriptTab = function (tab) {
|
||||
this.scriptTab = tab;
|
||||
|
||||
if (tab == "path") {
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='scriptPath']").focus();
|
||||
});
|
||||
} else if (tab == "code") {
|
||||
this.$delay(function () {
|
||||
this.loadEditor();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.selectScriptLang = function (lang) {
|
||||
this.scriptLang = lang;
|
||||
switch (lang) {
|
||||
case "shell":
|
||||
scriptEditor.setValue("#!/usr/bin/env bash\n\n# your commands here\n");
|
||||
var info = CodeMirror.findModeByMIME("text/x-sh");
|
||||
if (info != null) {
|
||||
scriptEditor.setOption("mode", info.mode);
|
||||
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
|
||||
CodeMirror.autoLoadMode(scriptEditor, info.mode);
|
||||
}
|
||||
break;
|
||||
case "bat":
|
||||
scriptEditor.setValue("");
|
||||
break;
|
||||
case "php":
|
||||
scriptEditor.setValue("#!/usr/bin/env php\n\n<?php\n// your PHP codes here");
|
||||
var info = CodeMirror.findModeByMIME("text/x-php");
|
||||
if (info != null) {
|
||||
scriptEditor.setOption("mode", info.mode);
|
||||
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
|
||||
CodeMirror.autoLoadMode(scriptEditor, info.mode);
|
||||
}
|
||||
break;
|
||||
case "python":
|
||||
scriptEditor.setValue("#!/usr/bin/env python\n\n''' your Python codes here '''");
|
||||
var info = CodeMirror.findModeByMIME("text/x-python");
|
||||
if (info != null) {
|
||||
scriptEditor.setOption("mode", info.mode);
|
||||
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
|
||||
CodeMirror.autoLoadMode(scriptEditor, info.mode);
|
||||
}
|
||||
break;
|
||||
case "ruby":
|
||||
scriptEditor.setValue("#!/usr/bin/env ruby\n\n# your Ruby codes here");
|
||||
var info = CodeMirror.findModeByMIME("text/x-ruby");
|
||||
if (info != null) {
|
||||
scriptEditor.setOption("mode", info.mode);
|
||||
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
|
||||
CodeMirror.autoLoadMode(scriptEditor, info.mode);
|
||||
}
|
||||
break;
|
||||
case "nodejs":
|
||||
scriptEditor.setValue("#!/usr/bin/env node\n\n// your javascript codes here");
|
||||
var info = CodeMirror.findModeByMIME("text/javascript");
|
||||
if (info != null) {
|
||||
scriptEditor.setOption("mode", info.mode);
|
||||
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
|
||||
CodeMirror.autoLoadMode(scriptEditor, info.mode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
scriptEditor.save();
|
||||
scriptEditor.focus();
|
||||
};
|
||||
|
||||
this.loadEditor = function () {
|
||||
if (scriptEditor == null) {
|
||||
scriptEditor = CodeMirror.fromTextArea(document.getElementById("script-code-editor"), {
|
||||
theme: "idea",
|
||||
lineNumbers: true,
|
||||
value: "",
|
||||
readOnly: false,
|
||||
showCursorWhenSelecting: true,
|
||||
height: "auto",
|
||||
//scrollbarStyle: null,
|
||||
viewportMargin: Infinity,
|
||||
lineWrapping: true,
|
||||
highlightFormatting: false,
|
||||
indentUnit: 4,
|
||||
indentWithTabs: true
|
||||
});
|
||||
}
|
||||
scriptEditor.setValue("#!/usr/bin/env bash\n\n# your commands here\n");
|
||||
scriptEditor.save();
|
||||
scriptEditor.focus();
|
||||
|
||||
var info = CodeMirror.findModeByMIME("text/x-sh");
|
||||
if (info != null) {
|
||||
scriptEditor.setOption("mode", info.mode);
|
||||
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
|
||||
CodeMirror.autoLoadMode(scriptEditor, info.mode);
|
||||
}
|
||||
|
||||
scriptEditor.on("change", function () {
|
||||
scriptEditor.save();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 环境变量
|
||||
*/
|
||||
this.env = [];
|
||||
this.envAdding = false;
|
||||
this.envAddingName = "";
|
||||
this.envAddingValue = "";
|
||||
|
||||
this.addEnv = function () {
|
||||
this.envAdding = !this.envAdding;
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='envAddingName']").focus();
|
||||
});
|
||||
};
|
||||
|
||||
this.confirmAddEnv = function () {
|
||||
if (this.envAddingName.length == 0) {
|
||||
alert("请输入变量名");
|
||||
this.$find("form input[name='envAddingName']").focus();
|
||||
return;
|
||||
}
|
||||
this.env.push({
|
||||
"name": this.envAddingName,
|
||||
"value": this.envAddingValue
|
||||
});
|
||||
this.envAdding = false;
|
||||
this.envAddingName = "";
|
||||
this.envAddingValue = "";
|
||||
};
|
||||
|
||||
this.removeEnv = function (index) {
|
||||
this.env.$remove(index);
|
||||
};
|
||||
|
||||
this.cancelEnv = function () {
|
||||
this.envAdding = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* 阿里云短信模板
|
||||
*/
|
||||
this.aliyunSmsTemplateVars = [];
|
||||
this.aliyunSmsTemplateVarAdding = false;
|
||||
this.aliyunSmsTemplateVarAddingName = "";
|
||||
this.aliyunSmsTemplateVarAddingValue = "";
|
||||
|
||||
this.addAliyunSmsTemplateVar = function () {
|
||||
this.aliyunSmsTemplateVarAdding = !this.aliyunSmsTemplateVarAdding;
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='aliyunSmsTemplateVarAddingName']").focus();
|
||||
});
|
||||
};
|
||||
|
||||
this.confirmAddAliyunSmsTemplateVar = function () {
|
||||
if (this.aliyunSmsTemplateVarAddingName.length == 0) {
|
||||
alert("请输入变量名");
|
||||
this.$find("form input[name='aliyunSmsTemplateVarAddingName']").focus();
|
||||
return;
|
||||
}
|
||||
this.aliyunSmsTemplateVars.push({
|
||||
"name": this.aliyunSmsTemplateVarAddingName,
|
||||
"value": this.aliyunSmsTemplateVarAddingValue
|
||||
});
|
||||
this.aliyunSmsTemplateVarAdding = false;
|
||||
this.aliyunSmsTemplateVarAddingName = "";
|
||||
this.aliyunSmsTemplateVarAddingValue = "";
|
||||
};
|
||||
|
||||
this.removeAliyunSmsTemplateVar = function (index) {
|
||||
this.aliyunSmsTemplateVars.$remove(index);
|
||||
};
|
||||
|
||||
this.cancelAliyunSmsTemplateVar = function () {
|
||||
this.aliyunSmsTemplateVarAdding = false;
|
||||
};
|
||||
})
|
||||
@@ -0,0 +1,14 @@
|
||||
// code mirror
|
||||
.CodeMirror {
|
||||
border: 1px solid #eee;
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
.CodeMirror-vscrollbar {
|
||||
width: 6px;
|
||||
border-radius: 3px !important;
|
||||
}
|
||||
|
||||
.CodeMirror-vscrollbar::-webkit-scrollbar-thumb {
|
||||
border-radius: 2px;
|
||||
}
|
||||
35
web/views/@default/admins/recipients/instances/index.html
Normal file
35
web/views/@default/admins/recipients/instances/index.html
Normal file
@@ -0,0 +1,35 @@
|
||||
{$layout}
|
||||
{$template "../menu"}
|
||||
|
||||
<second-menu>
|
||||
<menu-item @click.prevent="createInstance">[创建]</menu-item>
|
||||
</second-menu>
|
||||
|
||||
<p class="comment" v-if="instances.length == 0">暂时还没有媒介接收人。</p>
|
||||
|
||||
<table class="ui table selectable celled" v-if="instances.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="three wide">媒介类型</th>
|
||||
<th>备注</th>
|
||||
<th class="two wide">状态</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="instance in instances">
|
||||
<td>{{instance.media.name}}</td>
|
||||
<td>
|
||||
<span v-if="instance.description.length > 0">{{instance.description}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td>
|
||||
<label-on :v-is-on="instance.isOn"></label-on>
|
||||
</td>
|
||||
<td>
|
||||
<a :href="'/admins/recipients/instances/instance?instanceId=' + instance.id">详情</a>
|
||||
<a href="" @click.prevent="deleteInstance(instance.id)">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
24
web/views/@default/admins/recipients/instances/index.js
Normal file
24
web/views/@default/admins/recipients/instances/index.js
Normal file
@@ -0,0 +1,24 @@
|
||||
Tea.context(function () {
|
||||
this.createInstance = function () {
|
||||
teaweb.popup(Tea.url(".createPopup"), {
|
||||
height: "30em",
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.deleteInstance = function (instanceId) {
|
||||
teaweb.confirm("确定要删除此接收媒介吗?", function () {
|
||||
this.$post(".delete")
|
||||
.params({instanceId: instanceId})
|
||||
.success(function () {
|
||||
teaweb.success("删除成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
12
web/views/@default/admins/recipients/instances/instance.css
Normal file
12
web/views/@default/admins/recipients/instances/instance.css
Normal file
@@ -0,0 +1,12 @@
|
||||
.CodeMirror {
|
||||
border: 1px solid #eee;
|
||||
height: auto!important;
|
||||
}
|
||||
.CodeMirror-vscrollbar {
|
||||
width: 6px;
|
||||
border-radius: 3px!important;
|
||||
}
|
||||
.CodeMirror-vscrollbar::-webkit-scrollbar-thumb {
|
||||
border-radius: 2px;
|
||||
}
|
||||
/*# sourceMappingURL=instance.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["instance.less"],"names":[],"mappings":"AACA;EACC,sBAAA;EACA,sBAAA;;AAGD;EACC,UAAA;EACA,4BAAA;;AAGD,sBAAsB;EACrB,kBAAA","file":"instance.css"}
|
||||
237
web/views/@default/admins/recipients/instances/instance.html
Normal file
237
web/views/@default/admins/recipients/instances/instance.html
Normal file
@@ -0,0 +1,237 @@
|
||||
{$layout}
|
||||
{$template "instance_menu"}
|
||||
{$template "/code_editor"}
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">媒介名称</td>
|
||||
<td>{{instance.name}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>状态</td>
|
||||
<td>
|
||||
<label-on :v-is-on="instance.isOn"></label-on>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">媒介类型</td>
|
||||
<td>
|
||||
{{instance.media.name}}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- E-mail -->
|
||||
<tbody v-if="instance.media.type == 'email'">
|
||||
<tr>
|
||||
<td class="color-border">SMTP</td>
|
||||
<td>
|
||||
{{instance.params.smtp}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">账号</td>
|
||||
<td>
|
||||
{{instance.params.username}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">密码</td>
|
||||
<td>
|
||||
{{instance.params.password}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">发送者Email</td>
|
||||
<td>
|
||||
<span v-if="instance.params.from.length > 0">{{instance.params.from}}</span>
|
||||
<span v-if="instance.params.from.length == 0" class="disabled">没有设置</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- WebHook -->
|
||||
<tbody v-if="instance.media.type == 'webHook'">
|
||||
<tr>
|
||||
<td class="color-border">URL</td>
|
||||
<td>
|
||||
{{instance.params.url}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">请求方法</td>
|
||||
<td>
|
||||
{{instance.params.method}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">自定义Header</td>
|
||||
<td>
|
||||
<span v-if="instance.params.headers == null || instance.params.headers.length == 0" class="disabled">还没有自定义Header</span>
|
||||
<div v-if="instance.params.headers != null && instance.params.headers.length > 0">
|
||||
<span class="ui label small" v-for="header in instance.params.headers">{{header.name}}:{{header.value}}</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="instance.params.contentType != null && instance.params.contentType.length > 0">
|
||||
<td class="color-border">
|
||||
<span v-if="instance.params.contentType == 'params'">自定义参数</span>
|
||||
<span v-if="instance.params.contentType == 'body'">自定义内容</span>
|
||||
</td>
|
||||
<td class="color-border">
|
||||
<div v-if="instance.params.contentType == 'params'">
|
||||
<span v-if="instance.params.params == null || instance.params.params.length == 0" class="disabled">还没有自定义参数</span>
|
||||
<div v-if="instance.params.params != null && instance.params.params.length > 0">
|
||||
<span class="ui label small" v-for="param in instance.params.params">{{param.name}}:{{param.value}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="instance.params.contentType == 'body'">
|
||||
<xmp style="margin-top:0;margin-bottom:0">{{instance.params.body}}</xmp>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 脚本 -->
|
||||
<tbody v-if="instance.media.type == 'script'">
|
||||
<tr>
|
||||
<td class="color-border">脚本</td>
|
||||
<td>
|
||||
<span v-if="instance.params.scriptType == 'path'">{{instance.params.path}}</span>
|
||||
<div id="script-code-editor" v-show="instance.params.scriptType == 'code'"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">当前工作目录<em>(CWD)</em></td>
|
||||
<td>
|
||||
<span v-if="instance.params.cwd.length > 0">{{instance.params.cwd}}</span>
|
||||
<span v-if="instance.params.cwd.length == 0" class="disabled">没有设置</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">环境变量<em>(ENV)</em></td>
|
||||
<td>
|
||||
<span v-if="instance.params.env == null || instance.params.env.length == 0" class="disabled">没有设置</span>
|
||||
<div v-if="instance.params.env != null && instance.params.env.length > 0">
|
||||
<span class="ui label small" v-for="(var1, index) in instance.params.env">
|
||||
<em>{{var1.name}}</em>: {{var1.value}}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody v-if="instance.media.type == 'dingTalk'">
|
||||
<tr>
|
||||
<td class="color-border">Hook地址</td>
|
||||
<td>{{instance.params.webHookURL}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 企业微信 -->
|
||||
<tbody v-if="instance.media.type == 'qyWeixin'">
|
||||
<tr>
|
||||
<td class="color-border">企业ID</td>
|
||||
<td>
|
||||
{{instance.params.corporateId}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">应用AgentId</td>
|
||||
<td>
|
||||
{{instance.params.agentId}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">应用Secret</td>
|
||||
<td>
|
||||
{{instance.params.appSecret}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">内容文本格式</td>
|
||||
<td>
|
||||
<span v-if="instance.params.textFormat == null">text</span>
|
||||
{{instance.params.textFormat}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 企业微信群机器人 -->
|
||||
<tbody v-if="instance.media.type == 'qyWeixinRobot'">
|
||||
<tr>
|
||||
<td class="color-border">WebHook地址</td>
|
||||
<td>{{instance.params.webHookURL}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">内容文本格式</td>
|
||||
<td>
|
||||
<span v-if="instance.params.textFormat == null">text</span>
|
||||
{{instance.params.textFormat}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 阿里云短信 -->
|
||||
<tbody v-show="instance.media.type == 'aliyunSms'">
|
||||
<tr>
|
||||
<td class="color-border">签名名称</td>
|
||||
<td>
|
||||
{{instance.params.sign}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">模板CODE</td>
|
||||
<td>
|
||||
{{instance.params.templateCode}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">模板变量</td>
|
||||
<td>
|
||||
<div v-if="instance.params.variables != null">
|
||||
<span class="ui label small" v-for="(var1, index) in instance.params.variables">
|
||||
<em>{{var1.name}}</em>: {{var1.value}}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">AccessKey ID</td>
|
||||
<td>
|
||||
{{instance.params.accessKeyId}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">AccessKey Secret</td>
|
||||
<td>
|
||||
{{instance.params.accessKeySecret}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- Telegram机器人 -->
|
||||
<tbody v-show="instance.media.type == 'telegram'">
|
||||
<tr>
|
||||
<td class="color-border">机器人Token</td>
|
||||
<td>{{instance.params.token}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- TeaOS云短信 -->
|
||||
<tbody v-show="instance.media.type == 'teaSms'">
|
||||
<tr>
|
||||
<td class="color-border">AccessId</td>
|
||||
<td>{{instance.params.accessId}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">AccessSecret</td>
|
||||
<td>{{instance.params.accessSecret}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tr>
|
||||
<td>备注</td>
|
||||
<td>
|
||||
<span v-if="instance.description.length > 0">{{instance.description}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
48
web/views/@default/admins/recipients/instances/instance.js
Normal file
48
web/views/@default/admins/recipients/instances/instance.js
Normal file
@@ -0,0 +1,48 @@
|
||||
Tea.context(function () {
|
||||
let scriptEditor = null
|
||||
|
||||
this.from = encodeURIComponent(window.location.toString())
|
||||
|
||||
if (this.instance.media.type == "script" && this.instance.params.scriptType == "code") {
|
||||
this.$delay(function () {
|
||||
this.loadEditor()
|
||||
})
|
||||
}
|
||||
|
||||
this.loadEditor = function () {
|
||||
if (scriptEditor == null) {
|
||||
scriptEditor = CodeMirror(document.getElementById("script-code-editor"), {
|
||||
theme: "idea",
|
||||
lineNumbers: false,
|
||||
value: "",
|
||||
readOnly: true,
|
||||
showCursorWhenSelecting: true,
|
||||
height: "auto",
|
||||
//scrollbarStyle: null,
|
||||
viewportMargin: Infinity,
|
||||
lineWrapping: true,
|
||||
highlightFormatting: false,
|
||||
indentUnit: 4,
|
||||
indentWithTabs: true
|
||||
})
|
||||
}
|
||||
scriptEditor.setValue(this.instance.params.script)
|
||||
|
||||
let lang = "shell"
|
||||
if (this.instance.params.scriptLang != null && this.instance.params.scriptLang.length > 0) {
|
||||
lang = this.instance.params.scriptLang
|
||||
}
|
||||
let mimeType = "text/x-" + lang
|
||||
if (lang == "nodejs") {
|
||||
mimeType = "text/javascript"
|
||||
} else if (lang == "shell") {
|
||||
mimeType = "text/x-sh"
|
||||
}
|
||||
let info = CodeMirror.findModeByMIME(mimeType)
|
||||
if (info != null) {
|
||||
scriptEditor.setOption("mode", info.mode)
|
||||
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js"
|
||||
CodeMirror.autoLoadMode(scriptEditor, info.mode)
|
||||
}
|
||||
}
|
||||
})
|
||||
14
web/views/@default/admins/recipients/instances/instance.less
Normal file
14
web/views/@default/admins/recipients/instances/instance.less
Normal file
@@ -0,0 +1,14 @@
|
||||
// codemirror
|
||||
.CodeMirror {
|
||||
border: 1px solid #eee;
|
||||
height: auto!important;
|
||||
}
|
||||
|
||||
.CodeMirror-vscrollbar {
|
||||
width: 6px;
|
||||
border-radius: 3px!important;
|
||||
}
|
||||
|
||||
.CodeMirror-vscrollbar::-webkit-scrollbar-thumb {
|
||||
border-radius: 2px;
|
||||
}
|
||||
44
web/views/@default/admins/recipients/instances/test.html
Normal file
44
web/views/@default/admins/recipients/instances/test.html
Normal file
@@ -0,0 +1,44 @@
|
||||
{$layout}
|
||||
{$template "instance_menu"}
|
||||
|
||||
<form class="ui form" data-tea-action="$" data-tea-timeout="30" data-tea-before="submitBefore" data-tea-success="submitSuccess" data-tea-error="submitError" data-tea-fail="submitFail" style="margin-top:1em">
|
||||
<csrf-token></csrf-token>
|
||||
<input type="hidden" name="instanceId" :value="instance.id"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">媒介名称</td>
|
||||
<td>{{instance.media.name}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>通知标题</td>
|
||||
<td>
|
||||
<input type="text" name="subject" value="这是通知标题" maxlength="100"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>通知内容</td>
|
||||
<td>
|
||||
<textarea name="body" rows="2" maxlength="100">这是通知内容</textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>接收人标识</td>
|
||||
<td>
|
||||
<input type="text" name="user" maxlength="500"/>
|
||||
<p class="comment" v-html="instance.media.userDescription"></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="ui segment response-box" :class="{green:error.length == 0, red:error.length > 0}" v-if="isFinished">
|
||||
<div v-if="response.length > 0"><span v-if="error.length == 0">成功</span>返回结果:
|
||||
<div v-for="line in responseLines">{{line}}</div>
|
||||
</div>
|
||||
<div v-if="error.length > 0">错误信息:
|
||||
<div v-for="line in errorLines">{{line}}</div>
|
||||
</div>
|
||||
<span class="disabled" v-if="response.length == 0 && error.length == 0">成功执行,没有返回结果</span>
|
||||
</div>
|
||||
|
||||
<button class="ui button primary" type="submit" v-if="!isRunning">提交测试</button>
|
||||
<span v-if="isRunning">提交测试中,请耐心等待...</span>
|
||||
</form>
|
||||
71
web/views/@default/admins/recipients/instances/test.js
Normal file
71
web/views/@default/admins/recipients/instances/test.js
Normal file
@@ -0,0 +1,71 @@
|
||||
Tea.context(function () {
|
||||
this.isRunning = false
|
||||
this.isFinished = false
|
||||
this.response = ""
|
||||
this.error = ""
|
||||
|
||||
this.submitBefore = function () {
|
||||
this.isRunning = true
|
||||
this.isFinished = false
|
||||
this.response = ""
|
||||
this.error = ""
|
||||
}
|
||||
|
||||
this.submitSuccess = function (resp) {
|
||||
this.reloadStatus(resp.data.taskId)
|
||||
}
|
||||
|
||||
this.submitFail = function (resp) {
|
||||
this.isRunning = false
|
||||
this.isFinished = true
|
||||
this.response = ""
|
||||
this.error = resp.errors[0].messages[0]
|
||||
this.errorLines = []
|
||||
}
|
||||
|
||||
this.submitError = function () {
|
||||
this.isRunning = false
|
||||
this.isFinished = true
|
||||
this.response = ""
|
||||
this.errorLines = []
|
||||
this.error = "请求超时"
|
||||
}
|
||||
|
||||
// 更新状态
|
||||
this.reloadStatus = function (taskId) {
|
||||
let isDone = false
|
||||
this.$post("/admins/recipients/tasks/taskInfo")
|
||||
.params({
|
||||
taskId: taskId
|
||||
})
|
||||
.success(function (resp) {
|
||||
if (resp.data.status == 2 || resp.data.status == 3) {
|
||||
isDone = true
|
||||
this.updateStatus(resp.data.result)
|
||||
}
|
||||
})
|
||||
.done(function () {
|
||||
this.$delay(function () {
|
||||
if (isDone) {
|
||||
return
|
||||
}
|
||||
this.reloadStatus(taskId)
|
||||
}, 3000)
|
||||
})
|
||||
}
|
||||
|
||||
this.updateStatus = function (result) {
|
||||
this.isRunning = false
|
||||
this.isFinished = true
|
||||
this.response = result.response
|
||||
this.responseLines = []
|
||||
if (this.response != null) {
|
||||
this.responseLines = this.response.split("\n")
|
||||
}
|
||||
this.error = result.error
|
||||
this.errorLines = []
|
||||
if (this.error.length > 0) {
|
||||
this.errorLines = this.error.split("\n")
|
||||
}
|
||||
}
|
||||
})
|
||||
12
web/views/@default/admins/recipients/instances/update.css
Normal file
12
web/views/@default/admins/recipients/instances/update.css
Normal file
@@ -0,0 +1,12 @@
|
||||
.CodeMirror {
|
||||
border: 1px solid #eee;
|
||||
height: auto !important;
|
||||
}
|
||||
.CodeMirror-vscrollbar {
|
||||
width: 6px;
|
||||
border-radius: 3px !important;
|
||||
}
|
||||
.CodeMirror-vscrollbar::-webkit-scrollbar-thumb {
|
||||
border-radius: 2px;
|
||||
}
|
||||
/*# sourceMappingURL=update.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["update.less"],"names":[],"mappings":"AACA;EACC,sBAAA;EACA,uBAAA;;AAGD;EACC,UAAA;EACA,6BAAA;;AAGD,sBAAsB;EACrB,kBAAA","file":"update.css"}
|
||||
360
web/views/@default/admins/recipients/instances/update.html
Normal file
360
web/views/@default/admins/recipients/instances/update.html
Normal file
@@ -0,0 +1,360 @@
|
||||
{$layout}
|
||||
{$template "instance_menu"}
|
||||
{$template "/code_editor"}
|
||||
|
||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
<input type="hidden" name="instanceId" :value="instance.id"/>
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td>媒介名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="name" ref="focus" maxlength="100" v-model="instance.name"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border title">媒介类型 *</td>
|
||||
<td>
|
||||
<message-media-selector :v-media-type="instance.media.type" @change="changeMediaType"></message-media-selector>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- E-mail -->
|
||||
<tbody v-show="mediaType == 'email'">
|
||||
<tr>
|
||||
<td class="color-border">SMTP *</td>
|
||||
<td>
|
||||
<input type="text" name="emailSmtp" v-model="instance.params.smtp" maxlength="500" placeholder="类似于 smtp.xxx.com:465"/>
|
||||
<p class="comment">只支持SSL(或TLS)连接,端口通常为:465或587。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">账号 *</td>
|
||||
<td>
|
||||
<input type="text" name="emailUsername" v-model="instance.params.username" maxlength="500" placeholder="类似于 xxx@xxx.com" @input="changeEmailUsername"/>
|
||||
<p class="comment">邮箱账号,比如 123456@qq.com<span v-html="emailUsernameHelp"></span>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">密码 *</td>
|
||||
<td>
|
||||
<input type="text" name="emailPassword" v-model="instance.params.password" maxlength="100"/>
|
||||
<p class="comment">账号对应的密码或者授权码(比如QQ邮箱就需要授权码)。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">发送者Email</td>
|
||||
<td>
|
||||
<input type="text" name="emailFrom" v-model="instance.params.from" maxlength="500" placeholder="类似于 xxx@xxx.com"/>
|
||||
<p class="comment">默认和账号一致</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- WebHook -->
|
||||
<tbody v-show="mediaType == 'webHook'">
|
||||
<tr>
|
||||
<td class="color-border">URL *</td>
|
||||
<td>
|
||||
<input type="text" name="webHookURL" v-model="instance.params.url" maxlength="500" placeholder="http://..."/>
|
||||
<p class="comment">可以在URL中使用<span class="ui label tiny">${NoticeUser}</span>、<span class="ui label tiny">${NoticeSubject}</span>和<span class="ui label tiny">${NoticeBody}</span>来代表接收人标识、标题和内容。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">请求方法 *</td>
|
||||
<td>
|
||||
<select name="webHookMethod" v-model="webHookMethod" class="ui dropdown" style="width:10em">
|
||||
<option v-for="method in methods" :value="method">{{method}}</option>
|
||||
</select>
|
||||
<p class="comment" v-if="webHookMethod == 'POST'">将以POST方式发送<span class="ui label tiny">NoticeUser</span>、<span class="ui label tiny">NoticeSubject</span>和<span class="ui label tiny">NoticeBody</span>参数,分别代表接收人标识、标题和内容</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="advancedOptionsVisible">
|
||||
<td class="color-border">自定义Header</td>
|
||||
<td>
|
||||
<div class="webHook-headers-box">
|
||||
<span class="ui label tiny" v-for="(header,index) in webHookHeaders">{{header.name}}:{{header.value}}
|
||||
<input type="hidden" name="webHookHeaderNames" :value="header.name"/>
|
||||
<input type="hidden" name="webHookHeaderValues" :value="header.value"/>
|
||||
<a href="" title="删除" @click.prevent="removeWebHookHeader(index)"><i class="icon remove"></i></a>
|
||||
</span>
|
||||
</div>
|
||||
<button class="ui button tiny" type="button" @click.prevent="addWebHookHeader()" v-if="!webHookHeadersAdding">+</button>
|
||||
<div v-if="webHookHeadersAdding">
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="webHookHeaderName" v-model="webHookHeadersAddingName" placeholder="名称" maxlength="100" @keyup.enter="confirmWebHookHeadersAdding" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">:</div>
|
||||
<div class="ui field">
|
||||
<input type="text" placeholder="值" v-model="webHookHeadersAddingValue" size="50" maxlength="256" @keyup.enter="confirmWebHookHeadersAdding" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui button tiny" type="button" @click.prevent="confirmWebHookHeadersAdding()">确认添加</button>
|
||||
<a href="" @click.prevent="cancelWebHookHeadersAdding()">取消</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="webHookMethod == 'POST' && advancedOptionsVisible">
|
||||
<td class="color-border">自定义内容</td>
|
||||
<td>
|
||||
<div class="ui menu tabular small attached">
|
||||
<a href="" class="item" :class="{active:webHookContentType == 'params'}" @click.prevent="selectWebHookContentType('params')">参数对</a>
|
||||
<a href="" class="item" :class="{active:webHookContentType == 'body'}" @click.prevent="selectWebHookContentType('body')">文本内容</a>
|
||||
</div>
|
||||
<div class="ui segment attached" v-if="webHookContentType == 'params'">
|
||||
<input type="hidden" name="webHookContentType" value="params"/>
|
||||
<div class="webHook-headers-box">
|
||||
<span class="ui label tiny" v-for="(param,index) in webHookParams">{{param.name}}:{{param.value}}
|
||||
<input type="hidden" name="webHookParamNames" :value="param.name"/>
|
||||
<input type="hidden" name="webHookParamValues" :value="param.value"/>
|
||||
<a href="" title="删除" @click.prevent="removeWebHookParam(index)"><i class="icon remove"></i></a>
|
||||
</span>
|
||||
</div>
|
||||
<button class="ui button tiny" type="button" @click.prevent="addWebHookParam()" v-if="!webHookParamsAdding">+</button>
|
||||
<div v-if="webHookParamsAdding">
|
||||
<input type="hidden" name="webHookContentType" value="params"/>
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="webHookParamName" v-model="webHookParamsAddingName" placeholder="名称" maxlength="100" @keyup.enter="confirmWebHookParamsAdding" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">:</div>
|
||||
<div class="ui field">
|
||||
<textarea type="text" placeholder="值" v-model="webHookParamsAddingValue" cols="50" maxlength="1024" rows="2"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui button tiny" type="button" @click.prevent="confirmWebHookParamsAdding()">确认添加</button>
|
||||
<a href="" @click.prevent="cancelWebHookParamsAdding()">取消</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui segment attached" v-if="webHookContentType == 'body'">
|
||||
<input type="hidden" name="webHookContentType" value="body"/>
|
||||
<textarea name="webHookBody" v-model="webHookBody" rows="5" placeholder="发送的内容"></textarea>
|
||||
<p class="comment">
|
||||
内容中可以使用三个变量:<span class="ui label tiny">${NoticeUser}</span>、<span class="ui label tiny">${NoticeSubject}</span>和<span class="ui label tiny">${NoticeBody}</span>参数,分别代表接收人标识、标题和内容
|
||||
</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- Script -->
|
||||
<tbody v-show="mediaType == 'script'">
|
||||
<tr>
|
||||
<td class="color-border">脚本 *</td>
|
||||
<td>
|
||||
<input type="hidden" name="scriptType" :value="scriptTab"/>
|
||||
<input type="hidden" name="scriptLang" :value="scriptLang"/>
|
||||
<div class="ui tabular menu attached small">
|
||||
<a class="item" :class="{active:scriptTab == 'path'}" @click.prevent="selectScriptTab('path')">脚本文件</a>
|
||||
<a class="item" :class="{active:scriptTab == 'code'}" @click.prevent="selectScriptTab('code')">脚本代码</a>
|
||||
</div>
|
||||
<div class="ui bottom segment attached" v-show="scriptTab == 'path'">
|
||||
<input type="text" name="scriptPath" v-model="instance.params.path" maxlength="500"/>
|
||||
<p class="comment">如果是Shell脚本,请不要忘记在头部添加 <em>#!脚本解释工具</em>,比如 <em>#!/bin/bash</em><br/>
|
||||
执行此脚本时,在脚本中可以使用<span class="ui label tiny">${NoticeUser}</span>、<span class="ui label tiny">${NoticeSubject}</span>和<span class="ui label tiny">${NoticeBody}</span>三个环境变量分别代表通知的接收人标识、标题和内容。
|
||||
</p>
|
||||
</div>
|
||||
<div class="ui bottom segment attached" v-show="scriptTab == 'code'" style="padding-top:0">
|
||||
<div class="ui menu text small">
|
||||
<a class="item" v-for="lang in scriptLangs" :class="{active:lang.code == scriptLang}" @click.prevent="selectScriptLang(lang.code)">{{lang.name}}</a>
|
||||
</div>
|
||||
<textarea name="scriptCode" id="script-code-editor" rows="1"></textarea>
|
||||
<p class="comment">如果是Shell脚本,请不要忘记在头部添加 <em>#!脚本解释工具</em>,比如 <em>#!/bin/bash</em><br/>
|
||||
执行此脚本时,在脚本中可以使用<span class="ui label tiny">${NoticeUser}</span>、<span class="ui label tiny">${NoticeSubject}</span>和<span class="ui label tiny">${NoticeBody}</span>三个环境变量分别代表通知的接收人标识、标题和内容。
|
||||
</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="advancedOptionsVisible">
|
||||
<td class="color-border">当前工作目录<em>(CWD)</em></td>
|
||||
<td>
|
||||
<input type="text" name="scriptCwd" v-model="instance.params.cwd" maxlength="500"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="advancedOptionsVisible">
|
||||
<td class="color-border">环境变量<em>(ENV)</em></td>
|
||||
<td>
|
||||
<div class="ui field">
|
||||
<span class="ui label small" v-for="(var1, index) in env">
|
||||
<input type="hidden" name="scriptEnvNames" :value="var1.name"/>
|
||||
<input type="hidden" name="scriptEnvValues" :value="var1.value"/>
|
||||
<em>{{var1.name}}</em>: {{var1.value}}
|
||||
<a href="" @click.prevent="removeEnv(index)"><i class="icon remove"></i></a>
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="envAdding" class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="envAddingName" v-model="envAddingName" placeholder="变量名" style="width:9em" @keyup.enter="confirmAddEnv" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<input type="text" name="envAddingValue" v-model="envAddingValue" placeholder="变量值" style="width:15em" @keyup.enter="confirmAddEnv" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button" type="button" @click="confirmAddEnv()">添加</button>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<a href="" @click.prevent="cancelEnv()"><i class="icon remove"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button small" type="button" @click="addEnv()">+</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 钉钉 -->
|
||||
<tbody v-show="mediaType == 'dingTalk'">
|
||||
<tr>
|
||||
<td class="color-border">Hook地址 *</td>
|
||||
<td>
|
||||
<textarea name="dingTalkWebHookURL" maxlength="500" placeholder="https://oapi.dingtalk.com/robot/send?access_token=xxx" v-model="instance.params.webHookURL" rows="2"></textarea>
|
||||
<p class="comment">填入自定义群机器人的Hook地址,<a href="https://developers.dingtalk.com/document/app/custom-robot-access" target="_blank">获取方法»</a></p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 企业微信 -->
|
||||
<tbody v-show="mediaType == 'qyWeixin'">
|
||||
<tr>
|
||||
<td class="color-border">企业ID *</td>
|
||||
<td>
|
||||
<input type="text" name="qyWeixinCorporateId" maxlength="100" v-model="instance.params.corporateId" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">应用AgentId *</td>
|
||||
<td>
|
||||
<input type="text" name="qyWeixinAgentId" maxlength="100" v-model="instance.params.agentId"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">应用Secret *</td>
|
||||
<td>
|
||||
<input type="text" name="qyWeixinAppSecret" maxlength="100" v-model="instance.params.appSecret"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">内容文本格式</td>
|
||||
<td>
|
||||
<select name="qyWeixinTextFormat" v-model="instance.params.textFormat" class="ui dropdown" style="width:10em">
|
||||
<option value="text">普通文本</option>
|
||||
<option value="markdown">Markdown</option>
|
||||
</select>
|
||||
<p class="comment" v-if="instance.params.textFormat == 'markdown'">企业微信目前只支持少数的Markdown语法,<a href="https://work.weixin.qq.com/api/doc#90000/90135/90236/%E6%94%AF%E6%8C%81%E7%9A%84markdown%E8%AF%AD%E6%B3%95" target="_blank">点击这里了解»</a> </p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 企业微信群机器人 -->
|
||||
<tbody v-show="mediaType == 'qyWeixinRobot'">
|
||||
<tr>
|
||||
<td class="color-border">WebHook地址 *</td>
|
||||
<td>
|
||||
<textarea name="qyWeixinRobotWebHookURL" v-model="instance.params.webHookURL" maxlength="500" placeholder="https://qyapi.weixin.qq.com/cgi-bin/webHook/send?key=xxx" rows="2"></textarea>
|
||||
<p class="comment">填入自定义群机器人的WebHook地址</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">内容文本格式</td>
|
||||
<td>
|
||||
<select name="qyWeixinRobotTextFormat" v-model="instance.params.textFormat" class="ui dropdown" style="width:10em">
|
||||
<option value="text">普通文本</option>
|
||||
<option value="markdown">Markdown</option>
|
||||
</select>
|
||||
<p class="comment" v-if="instance.params.textFormat == 'markdown'">企业微信目前只支持少数的Markdown语法,<a href="https://work.weixin.qq.com/api/doc#90000/90135/91760/markdown%E7%B1%BB%E5%9E%8B" target="_blank">点击这里了解»</a> </p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 阿里云短信 -->
|
||||
<tbody v-show="mediaType == 'aliyunSms'">
|
||||
<tr>
|
||||
<td class="color-border">签名名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="aliyunSmsSign" maxlength="100" v-model="instance.params.sign"/>
|
||||
<p class="comment">已经审核通过的短信签名名称</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">模板CODE *</td>
|
||||
<td>
|
||||
<input type="text" name="aliyunSmsTemplateCode" maxlength="100" v-model="instance.params.templateCode" placeholder="类似于SMS_12345"/>
|
||||
<p class="comment">已经审核通过的模板CODE</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">模板变量 *</td>
|
||||
<td>
|
||||
<div class="ui field">
|
||||
<span class="ui label small" v-for="(var1, index) in aliyunSmsTemplateVars">
|
||||
<input type="hidden" name="aliyunSmsTemplateVarNames" :value="var1.name"/>
|
||||
<input type="hidden" name="aliyunSmsTemplateVarValues" :value="var1.value"/>
|
||||
<em>{{var1.name}}</em>: {{var1.value}}
|
||||
<a href="" @click.prevent="removeAliyunSmsTemplateVar(index)"><i class="icon remove"></i></a>
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="aliyunSmsTemplateVarAdding" class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="aliyunSmsTemplateVarAddingName" v-model="aliyunSmsTemplateVarAddingName" placeholder="变量名" style="width:9em" @keyup.enter="confirmAddAliyunSmsTemplateVar" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<input type="text" name="aliyunSmsTemplateVarAddingValue" v-model="aliyunSmsTemplateVarAddingValue" placeholder="变量值" style="width:15em" @keyup.enter="confirmAddAliyunSmsTemplateVar" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button" type="button" @click="confirmAddAliyunSmsTemplateVar()">添加</button>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<a href="" @click.prevent="cancelAliyunSmsTemplateVar()"><i class="icon remove"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button small" type="button" @click="addAliyunSmsTemplateVar()">+</button>
|
||||
</div>
|
||||
<p class="comment">模板中使用的变量,在变量中可以使用<span class="ui label tiny">${NoticeUser}</span>、<span class="ui label tiny">${NoticeSubject}</span>和<span class="ui label tiny">${NoticeBody}</span>来代表接收人标识、标题和内容。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">AccessKey ID *</td>
|
||||
<td>
|
||||
<input type="text" name="aliyunSmsAccessKeyId" maxlength="100" v-model="instance.params.accessKeyId"/>
|
||||
<p class="comment">在阿里云控制台中的访问控制中某个用户的AccessKey ID</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">AccessKey Secret *</td>
|
||||
<td>
|
||||
<input type="text" name="aliyunSmsAccessKeySecret" maxlength="100" v-model="instance.params.accessKeySecret"/>
|
||||
<p class="comment">在阿里云控制台中的访问控制中某个用户的AccessKey Secret,和上面的AccessKey ID匹配</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- Telegram -->
|
||||
<tbody v-if="mediaType == 'telegram'">
|
||||
<tr>
|
||||
<td class="color-border">机器人Token</td>
|
||||
<td>
|
||||
<input type="text" name="telegramToken" v-model="instance.params.token"/>
|
||||
<p class="comment">在创建机器人的时候可以获得,类似于 123456:AAAA-AAAAAAAAAAAAAAAAAAAA</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tr>
|
||||
<td>备注</td>
|
||||
<td>
|
||||
<textarea rows="3" name="description" maxlength="100" v-model="instance.description"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>是否启用</td>
|
||||
<td>
|
||||
<checkbox name="isOn" value="1" v-model="instance.isOn"></checkbox>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
460
web/views/@default/admins/recipients/instances/update.js
Normal file
460
web/views/@default/admins/recipients/instances/update.js
Normal file
@@ -0,0 +1,460 @@
|
||||
Tea.context(function () {
|
||||
let scriptEditor = null
|
||||
let isLoaded = false;
|
||||
|
||||
this.$delay(function () {
|
||||
isLoaded = true;
|
||||
|
||||
if (this.instance.media.type == "email") {
|
||||
this.changeEmailUsername()
|
||||
}
|
||||
})
|
||||
|
||||
this.success = function () {
|
||||
let that = this
|
||||
teaweb.success("保存成功", function () {
|
||||
window.location = "/admins/recipients/instances/instance?instanceId=" + that.instance.id
|
||||
})
|
||||
};
|
||||
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
this.rateNoticeVisible = false
|
||||
|
||||
this.changeName = function (name) {
|
||||
if (name.indexOf("短信") > -1 || name.indexOf("钉钉") > -1 || name.indexOf("微信") > -1) {
|
||||
this.rateNoticeVisible = true
|
||||
} else {
|
||||
this.rateNoticeVisible = false
|
||||
}
|
||||
};
|
||||
this.changeName(this.instance.media.name)
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
this.mediaType = this.instance.media.type;
|
||||
|
||||
this.changeMediaType = function (media) {
|
||||
this.mediaType = media.type
|
||||
if (!isLoaded) {
|
||||
return;
|
||||
}
|
||||
if (this.mediaType == "email") {
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='emailSmtp']").focus();
|
||||
});
|
||||
} else if (this.mediaType == "webHook") {
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='webHookURL']").focus();
|
||||
});
|
||||
} else if (this.mediaType == "script") {
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='scriptPath']").focus();
|
||||
});
|
||||
} else if (this.mediaType == "dingTalk") {
|
||||
this.$delay(function () {
|
||||
this.$find("form textarea[name='dingTalkWebHookURL']").focus();
|
||||
});
|
||||
} else if (this.mediaType == "qyWeixin") {
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='qyWeixinCorporateId']").focus();
|
||||
});
|
||||
} else if (this.mediaType == "qyWeixinRobot") {
|
||||
this.$delay(function () {
|
||||
this.$find("form textarea[name='qyWeixinRobotWebHookURL']").focus();
|
||||
});
|
||||
}
|
||||
};
|
||||
this.changeMediaType(this.instance.media);
|
||||
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
this.emailUsernameHelp = "";
|
||||
|
||||
this.changeEmailUsername = function () {
|
||||
this.emailUsernameHelp = "";
|
||||
if (this.instance.params.username.indexOf("qq.com") > 0) {
|
||||
this.emailUsernameHelp = ",<a href=\"https://service.mail.qq.com/cgi-bin/help?id=28\" target='_blank'>QQ邮箱相关设置帮助</a>";
|
||||
} else if (this.instance.params.username.indexOf("163.com") > 0) {
|
||||
this.emailUsernameHelp = ",<a href=\"https://help.mail.163.com/faqDetail.do?code=d7a5dc8471cd0c0e8b4b8f4f8e49998b374173cfe9171305fa1ce630d7f67ac22dc0e9af8168582a\" target='_blank'>网易邮箱相关设置帮助</a>";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* webHook
|
||||
*/
|
||||
this.methods = ["GET", "POST"]
|
||||
this.webHookMethod = "GET";
|
||||
this.webHookHeadersAdding = false;
|
||||
this.webHookHeaders = [];
|
||||
this.webHookHeadersAddingName = "";
|
||||
this.webHookHeadersAddingValue = "";
|
||||
|
||||
this.addWebHookHeader = function () {
|
||||
this.webHookHeadersAdding = true;
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='webHookHeaderName']").focus();
|
||||
});
|
||||
};
|
||||
|
||||
this.cancelWebHookHeadersAdding = function () {
|
||||
this.webHookHeadersAdding = false;
|
||||
};
|
||||
|
||||
this.confirmWebHookHeadersAdding = function () {
|
||||
this.webHookHeaders.push({
|
||||
"name": this.webHookHeadersAddingName,
|
||||
"value": this.webHookHeadersAddingValue
|
||||
});
|
||||
this.webHookHeadersAddingName = "";
|
||||
this.webHookHeadersAddingValue = "";
|
||||
this.webHookHeadersAdding = false;
|
||||
};
|
||||
|
||||
this.removeWebHookHeader = function (index) {
|
||||
if (!window.confirm("确定要删除此Header吗?")) {
|
||||
return;
|
||||
}
|
||||
this.webHookHeaders.$remove(index);
|
||||
};
|
||||
|
||||
this.webHookContentType = "params";
|
||||
|
||||
this.selectWebHookContentType = function (contentType) {
|
||||
this.webHookContentType = contentType;
|
||||
this.$delay(function () {
|
||||
if (contentType == "params") {
|
||||
|
||||
} else if (contentType == "body") {
|
||||
this.$find("form textarea[name='webHookBody']").focus();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.webHookParamsAdding = false;
|
||||
this.webHookParams = [];
|
||||
this.webHookParamsAddingName = "";
|
||||
this.webHookParamsAddingValue = "";
|
||||
|
||||
this.addWebHookParam = function () {
|
||||
this.webHookParamsAdding = true;
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='webHookParamName']").focus();
|
||||
});
|
||||
};
|
||||
|
||||
this.cancelWebHookParamsAdding = function () {
|
||||
this.webHookParamsAdding = false;
|
||||
};
|
||||
|
||||
this.confirmWebHookParamsAdding = function () {
|
||||
this.webHookParams.push({
|
||||
"name": this.webHookParamsAddingName,
|
||||
"value": this.webHookParamsAddingValue
|
||||
});
|
||||
this.webHookParamsAddingName = "";
|
||||
this.webHookParamsAddingValue = "";
|
||||
this.webHookParamsAdding = false;
|
||||
};
|
||||
|
||||
this.removeWebHookParam = function (index) {
|
||||
if (!window.confirm("确定要删除此参数吗?")) {
|
||||
return;
|
||||
}
|
||||
this.webHookParams.$remove(index);
|
||||
};
|
||||
|
||||
this.webHookBody = "";
|
||||
|
||||
if (this.instance.media.type == "webHook") {
|
||||
this.webHookMethod = this.instance.params.method;
|
||||
if (this.instance.params.headers != null) {
|
||||
this.webHookHeaders = this.instance.params.headers;
|
||||
}
|
||||
|
||||
if (this.instance.params.contentType == "params") {
|
||||
this.webHookContentType = "params";
|
||||
if (this.instance.params.params != null) {
|
||||
this.webHookParams = this.instance.params.params;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.instance.params.contentType == "body") {
|
||||
this.webHookContentType = "body";
|
||||
this.webHookBody = this.instance.params.body;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 脚本
|
||||
*/
|
||||
this.scriptTab = "path";
|
||||
this.scriptLang = "shell";
|
||||
|
||||
if (this.instance.media.type == "script") {
|
||||
if (this.instance.params.scriptType == "path") {
|
||||
this.scriptTab = "path";
|
||||
} else {
|
||||
this.scriptTab = "code";
|
||||
this.scriptLang = this.instance.params.scriptLang;
|
||||
this.$delay(function () {
|
||||
this.loadEditor();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.scriptLangs = [
|
||||
{
|
||||
"name": "Shell",
|
||||
"code": "shell"
|
||||
},
|
||||
{
|
||||
"name": "批处理(bat)",
|
||||
"code": "bat"
|
||||
},
|
||||
{
|
||||
"name": "PHP",
|
||||
"code": "php"
|
||||
},
|
||||
{
|
||||
"name": "Python",
|
||||
"code": "python"
|
||||
},
|
||||
{
|
||||
"name": "Ruby",
|
||||
"code": "ruby"
|
||||
},
|
||||
{
|
||||
"name": "NodeJS",
|
||||
"code": "nodejs"
|
||||
}
|
||||
]
|
||||
|
||||
this.selectScriptTab = function (tab) {
|
||||
this.scriptTab = tab
|
||||
|
||||
if (tab == "path") {
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='scriptPath']").focus()
|
||||
})
|
||||
} else if (tab == "code") {
|
||||
this.$delay(function () {
|
||||
this.loadEditor()
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
this.selectScriptLang = function (lang) {
|
||||
this.scriptLang = lang;
|
||||
switch (lang) {
|
||||
case "shell":
|
||||
if (this.instance.media.type == "script" && this.instance.params.scriptType == "code" && this.instance.params.scriptLang == "shell") {
|
||||
scriptEditor.setValue(this.instance.params.script);
|
||||
} else {
|
||||
scriptEditor.setValue("#!/usr/bin/env bash\n\n# your commands here\n");
|
||||
}
|
||||
var info = CodeMirror.findModeByMIME("text/x-sh");
|
||||
if (info != null) {
|
||||
scriptEditor.setOption("mode", info.mode);
|
||||
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
|
||||
CodeMirror.autoLoadMode(scriptEditor, info.mode);
|
||||
}
|
||||
break;
|
||||
case "bat":
|
||||
if (this.instance.media.type == "script" && this.instance.params.scriptType == "code" && this.instance.params.scriptLang == "bat") {
|
||||
scriptEditor.setValue(this.instance.params.script);
|
||||
} else {
|
||||
scriptEditor.setValue("");
|
||||
}
|
||||
break;
|
||||
case "php":
|
||||
if (this.instance.media.type == "script" && this.instance.params.scriptType == "code" && this.instance.params.scriptLang == "php") {
|
||||
scriptEditor.setValue(this.instance.params.script);
|
||||
} else {
|
||||
scriptEditor.setValue("#!/usr/bin/env php\n\n<?php\n// your PHP codes here");
|
||||
}
|
||||
var info = CodeMirror.findModeByMIME("text/x-php");
|
||||
if (info != null) {
|
||||
scriptEditor.setOption("mode", info.mode);
|
||||
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
|
||||
CodeMirror.autoLoadMode(scriptEditor, info.mode);
|
||||
}
|
||||
break;
|
||||
case "python":
|
||||
if (this.instance.media.type == "script" && this.instance.params.scriptType == "code" && this.instance.params.scriptLang == "python") {
|
||||
|
||||
scriptEditor.setValue(this.instance.params.script);
|
||||
} else {
|
||||
scriptEditor.setValue("#!/usr/bin/env python\n\n''' your Python codes here '''");
|
||||
}
|
||||
var info = CodeMirror.findModeByMIME("text/x-python");
|
||||
if (info != null) {
|
||||
scriptEditor.setOption("mode", info.mode);
|
||||
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
|
||||
CodeMirror.autoLoadMode(scriptEditor, info.mode);
|
||||
}
|
||||
break;
|
||||
case "ruby":
|
||||
if (this.instance.media.type == "script" && this.instance.params.scriptType == "code" && this.instance.params.scriptLang == "ruby") {
|
||||
scriptEditor.setValue(this.instance.params.script);
|
||||
} else {
|
||||
scriptEditor.setValue("#!/usr/bin/env ruby\n\n# your Ruby codes here");
|
||||
}
|
||||
var info = CodeMirror.findModeByMIME("text/x-ruby");
|
||||
if (info != null) {
|
||||
scriptEditor.setOption("mode", info.mode);
|
||||
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
|
||||
CodeMirror.autoLoadMode(scriptEditor, info.mode);
|
||||
}
|
||||
break;
|
||||
case "nodejs":
|
||||
if (this.instance.media.type == "script" && this.instance.params.scriptType == "code" && this.instance.params.scriptLang == "nodejs") {
|
||||
scriptEditor.setValue(this.instance.params.script);
|
||||
} else {
|
||||
scriptEditor.setValue("#!/usr/bin/env node\n\n// your javascript codes here");
|
||||
}
|
||||
var info = CodeMirror.findModeByMIME("text/javascript");
|
||||
if (info != null) {
|
||||
scriptEditor.setOption("mode", info.mode);
|
||||
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
|
||||
CodeMirror.autoLoadMode(scriptEditor, info.mode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
scriptEditor.save();
|
||||
scriptEditor.focus();
|
||||
};
|
||||
|
||||
this.loadEditor = function () {
|
||||
if (scriptEditor == null) {
|
||||
scriptEditor = CodeMirror.fromTextArea(document.getElementById("script-code-editor"), {
|
||||
theme: "idea",
|
||||
lineNumbers: true,
|
||||
value: "",
|
||||
readOnly: false,
|
||||
showCursorWhenSelecting: true,
|
||||
height: "auto",
|
||||
//scrollbarStyle: null,
|
||||
viewportMargin: Infinity,
|
||||
lineWrapping: true,
|
||||
highlightFormatting: false,
|
||||
indentUnit: 4,
|
||||
indentWithTabs: true
|
||||
});
|
||||
}
|
||||
if (this.instance.params.script != null && this.instance.params.script.length > 0) {
|
||||
scriptEditor.setValue(this.instance.params.script);
|
||||
} else {
|
||||
scriptEditor.setValue("#!/usr/bin/env bash\n\n# your commands here\n");
|
||||
}
|
||||
scriptEditor.save();
|
||||
scriptEditor.focus();
|
||||
|
||||
var info = CodeMirror.findModeByMIME("text/x-sh");
|
||||
if (info != null) {
|
||||
scriptEditor.setOption("mode", info.mode);
|
||||
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
|
||||
CodeMirror.autoLoadMode(scriptEditor, info.mode);
|
||||
}
|
||||
|
||||
scriptEditor.on("change", function () {
|
||||
scriptEditor.save();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 环境变量
|
||||
*/
|
||||
this.env = [];
|
||||
if (this.instance.media.type == "script" && this.instance.params.env != null) {
|
||||
this.env = this.instance.params.env;
|
||||
}
|
||||
|
||||
this.envAdding = false;
|
||||
this.envAddingName = "";
|
||||
this.envAddingValue = "";
|
||||
|
||||
this.addEnv = function () {
|
||||
this.envAdding = !this.envAdding;
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='envAddingName']").focus();
|
||||
});
|
||||
};
|
||||
|
||||
this.confirmAddEnv = function () {
|
||||
if (this.envAddingName.length == 0) {
|
||||
alert("请输入变量名");
|
||||
this.$find("form input[name='envAddingName']").focus();
|
||||
return;
|
||||
}
|
||||
this.env.push({
|
||||
"name": this.envAddingName,
|
||||
"value": this.envAddingValue
|
||||
});
|
||||
this.envAdding = false;
|
||||
this.envAddingName = "";
|
||||
this.envAddingValue = "";
|
||||
};
|
||||
|
||||
this.removeEnv = function (index) {
|
||||
this.env.$remove(index);
|
||||
};
|
||||
|
||||
this.cancelEnv = function () {
|
||||
this.envAdding = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* 阿里云短信模板
|
||||
*/
|
||||
this.aliyunSmsTemplateVars = [];
|
||||
if (this.instance.params.variables != null) {
|
||||
this.aliyunSmsTemplateVars = this.instance.params.variables;
|
||||
}
|
||||
this.aliyunSmsTemplateVarAdding = false;
|
||||
this.aliyunSmsTemplateVarAddingName = "";
|
||||
this.aliyunSmsTemplateVarAddingValue = "";
|
||||
|
||||
this.addAliyunSmsTemplateVar = function () {
|
||||
this.aliyunSmsTemplateVarAdding = !this.aliyunSmsTemplateVarAdding;
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='aliyunSmsTemplateVarAddingName']").focus();
|
||||
});
|
||||
};
|
||||
|
||||
this.confirmAddAliyunSmsTemplateVar = function () {
|
||||
if (this.aliyunSmsTemplateVarAddingName.length == 0) {
|
||||
alert("请输入变量名");
|
||||
this.$find("form input[name='aliyunSmsTemplateVarAddingName']").focus();
|
||||
return;
|
||||
}
|
||||
this.aliyunSmsTemplateVars.push({
|
||||
"name": this.aliyunSmsTemplateVarAddingName,
|
||||
"value": this.aliyunSmsTemplateVarAddingValue
|
||||
});
|
||||
this.aliyunSmsTemplateVarAdding = false;
|
||||
this.aliyunSmsTemplateVarAddingName = "";
|
||||
this.aliyunSmsTemplateVarAddingValue = "";
|
||||
};
|
||||
|
||||
this.removeAliyunSmsTemplateVar = function (index) {
|
||||
this.aliyunSmsTemplateVars.$remove(index);
|
||||
};
|
||||
|
||||
this.cancelAliyunSmsTemplateVar = function () {
|
||||
this.aliyunSmsTemplateVarAdding = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* 更多选项
|
||||
*/
|
||||
this.advancedOptionsVisible = true;
|
||||
|
||||
this.showAdvancedOptions = function () {
|
||||
this.advancedOptionsVisible = !this.advancedOptionsVisible;
|
||||
};
|
||||
});
|
||||
14
web/views/@default/admins/recipients/instances/update.less
Normal file
14
web/views/@default/admins/recipients/instances/update.less
Normal file
@@ -0,0 +1,14 @@
|
||||
// code mirror
|
||||
.CodeMirror {
|
||||
border: 1px solid #eee;
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
.CodeMirror-vscrollbar {
|
||||
width: 6px;
|
||||
border-radius: 3px !important;
|
||||
}
|
||||
|
||||
.CodeMirror-vscrollbar::-webkit-scrollbar-thumb {
|
||||
border-radius: 2px;
|
||||
}
|
||||
34
web/views/@default/admins/recipients/logs/index.html
Normal file
34
web/views/@default/admins/recipients/logs/index.html
Normal file
@@ -0,0 +1,34 @@
|
||||
{$layout}
|
||||
{$template "../menu"}
|
||||
|
||||
<p class="comment" v-if="logs.length == 0">暂时还没有发送记录。</p>
|
||||
|
||||
<div v-if="logs.length > 0">
|
||||
<div class="margin"></div>
|
||||
<table class="ui table selectable definition" v-for="log in logs" :class="{red: !log.isOk}">
|
||||
<tr>
|
||||
<td class="title">简介</td>
|
||||
<td>接收人:{{log.task.user}} <span class="disabled"> | </span> 媒介:{{log.task.instance.name}}<link-icon :href="'/admins/recipients/instances/instance?instanceId=' + log.task.instance.id"></link-icon>
|
||||
<span class="disabled"> | </span> 时间:{{log.createdTime}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="log.task.subject.length > 0">
|
||||
<td>标题</td>
|
||||
<td>{{log.task.subject}}</td>
|
||||
</tr>
|
||||
<tr v-if="log.task.body.length > 0">
|
||||
<td>内容</td>
|
||||
<td>{{log.task.body}}</td>
|
||||
</tr>
|
||||
<tr v-if="log.error.length > 0" class="error">
|
||||
<td>错误信息</td>
|
||||
<td>{{log.error}}</td>
|
||||
</tr>
|
||||
<tr v-if="log.response.length > 0">
|
||||
<td>响应信息</td>
|
||||
<td>{{log.response}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
50
web/views/@default/admins/recipients/recipient.html
Normal file
50
web/views/@default/admins/recipients/recipient.html
Normal file
@@ -0,0 +1,50 @@
|
||||
{$layout}
|
||||
{$template "recipient_menu"}
|
||||
{$template "/code_editor"}
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">状态</td>
|
||||
<td>
|
||||
<label-on :v-is-on="recipient.isOn"></label-on>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="title">系统用户</td>
|
||||
<td>
|
||||
{{recipient.admin.fullname}} <span class="small grey">({{recipient.admin.username}})</span> <link-icon :href="'/admins/admin?adminId=' + recipient.admin.id"></link-icon>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>媒介</td>
|
||||
<td>
|
||||
{{recipient.instance.name}}
|
||||
<p class="comment">{{recipient.instance.description}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>接收人标识</td>
|
||||
<td>
|
||||
<span v-if="recipient.user.length > 0">{{recipient.user}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>所属分组</td>
|
||||
<td>
|
||||
<div v-if="recipient.groups != null && recipient.groups.length > 0">
|
||||
<div v-for="group in recipient.groups" class="ui label small basic">{{group.name}}</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<span class="disabled">-</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>备注</td>
|
||||
<td>
|
||||
<span v-if="recipient.description.length > 0">{{recipient.description}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
46
web/views/@default/admins/recipients/test.html
Normal file
46
web/views/@default/admins/recipients/test.html
Normal file
@@ -0,0 +1,46 @@
|
||||
{$layout}
|
||||
{$template "recipient_menu"}
|
||||
{$template "/code_editor"}
|
||||
|
||||
|
||||
<form class="ui form" data-tea-action="$" data-tea-timeout="30" data-tea-before="submitBefore" data-tea-success="submitSuccess" data-tea-error="submitError" data-tea-fail="submitFail" style="margin-top:1em">
|
||||
<csrf-token></csrf-token>
|
||||
<input type="hidden" name="instanceId" :value="instance.id"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">媒介名称</td>
|
||||
<td>{{instance.media.name}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>通知标题</td>
|
||||
<td>
|
||||
<input type="text" name="subject" value="这是通知标题" maxlength="100"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>通知内容</td>
|
||||
<td>
|
||||
<textarea name="body" rows="2" maxlength="100">这是通知内容</textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>接收人标识</td>
|
||||
<td>
|
||||
<input type="text" name="user" maxlength="500" v-model="recipient.user"/>
|
||||
<p class="comment" v-html="instance.media.userDescription"></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="ui segment response-box" :class="{green:error.length == 0, red:error.length > 0}" v-if="isFinished">
|
||||
<div v-if="response.length > 0"><span v-if="error.length == 0">成功</span>返回结果:
|
||||
<div v-for="line in responseLines">{{line}}</div>
|
||||
</div>
|
||||
<div v-if="error.length > 0">错误信息:
|
||||
<div v-for="line in errorLines">{{line}}</div>
|
||||
</div>
|
||||
<span class="disabled" v-if="response.length == 0 && error.length == 0">成功执行,没有返回结果</span>
|
||||
</div>
|
||||
|
||||
<button class="ui button primary" type="submit" v-if="!isRunning">提交测试</button>
|
||||
<span v-if="isRunning">提交测试中,请耐心等待...</span>
|
||||
</form>
|
||||
71
web/views/@default/admins/recipients/test.js
Normal file
71
web/views/@default/admins/recipients/test.js
Normal file
@@ -0,0 +1,71 @@
|
||||
Tea.context(function () {
|
||||
this.isRunning = false
|
||||
this.isFinished = false
|
||||
this.response = ""
|
||||
this.error = ""
|
||||
|
||||
this.submitBefore = function () {
|
||||
this.isRunning = true
|
||||
this.isFinished = false
|
||||
this.response = ""
|
||||
this.error = ""
|
||||
}
|
||||
|
||||
this.submitSuccess = function (resp) {
|
||||
this.reloadStatus(resp.data.taskId)
|
||||
}
|
||||
|
||||
this.submitFail = function (resp) {
|
||||
this.isRunning = false
|
||||
this.isFinished = true
|
||||
this.response = ""
|
||||
this.error = resp.errors[0].messages[0]
|
||||
this.errorLines = []
|
||||
}
|
||||
|
||||
this.submitError = function () {
|
||||
this.isRunning = false
|
||||
this.isFinished = true
|
||||
this.response = ""
|
||||
this.errorLines = []
|
||||
this.error = "请求超时"
|
||||
}
|
||||
|
||||
// 更新状态
|
||||
this.reloadStatus = function (taskId) {
|
||||
let isDone = false
|
||||
this.$post("/admins/recipients/tasks/taskInfo")
|
||||
.params({
|
||||
taskId: taskId
|
||||
})
|
||||
.success(function (resp) {
|
||||
if (resp.data.status == 2 || resp.data.status == 3) {
|
||||
isDone = true
|
||||
this.updateStatus(resp.data.result)
|
||||
}
|
||||
})
|
||||
.done(function () {
|
||||
this.$delay(function () {
|
||||
if (isDone) {
|
||||
return
|
||||
}
|
||||
this.reloadStatus(taskId)
|
||||
}, 3000)
|
||||
})
|
||||
}
|
||||
|
||||
this.updateStatus = function (result) {
|
||||
this.isRunning = false
|
||||
this.isFinished = true
|
||||
this.response = result.response
|
||||
this.responseLines = []
|
||||
if (this.response != null) {
|
||||
this.responseLines = this.response.split("\n")
|
||||
}
|
||||
this.error = result.error
|
||||
this.errorLines = []
|
||||
if (this.error.length > 0) {
|
||||
this.errorLines = this.error.split("\n")
|
||||
}
|
||||
}
|
||||
})
|
||||
52
web/views/@default/admins/recipients/update.html
Normal file
52
web/views/@default/admins/recipients/update.html
Normal file
@@ -0,0 +1,52 @@
|
||||
{$layout}
|
||||
{$template "recipient_menu"}
|
||||
{$template "/code_editor"}
|
||||
|
||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
<input type="hidden" name="recipientId" :value="recipient.id"/>
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">系统用户 *</td>
|
||||
<td>
|
||||
<admin-selector :v-admin-id="recipient.admin.id"></admin-selector>
|
||||
<p class="comment">选择关联的系统用户。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>媒介 *</td>
|
||||
<td>
|
||||
<message-media-instance-selector :v-instance-id="recipient.instance.id" @change="changeInstance"></message-media-instance-selector>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>接收人标识</td>
|
||||
<td>
|
||||
<input type="text" name="user" maxlength="300" v-model="recipient.user"/>
|
||||
<p class="comment">{{userDescription}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>分组</td>
|
||||
<td>
|
||||
<message-recipient-group-selector :v-groups="recipient.groups"></message-recipient-group-selector>
|
||||
<p class="comment">选择当前接收人所属分组。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>备注</td>
|
||||
<td>
|
||||
<textarea rows="3" name="description" maxlength="100" v-model="recipient.description"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>是否启用</td>
|
||||
<td>
|
||||
<checkbox name="isOn" value="1" v-model="recipient.isOn"></checkbox>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
20
web/views/@default/admins/recipients/update.js
Normal file
20
web/views/@default/admins/recipients/update.js
Normal file
@@ -0,0 +1,20 @@
|
||||
Tea.context(function () {
|
||||
this.userDescription = ""
|
||||
|
||||
this.changeInstance = function (instance) {
|
||||
if (instance != null) {
|
||||
this.userDescription = instance.media.userDescription
|
||||
} else {
|
||||
this.userDescription = ""
|
||||
}
|
||||
}
|
||||
|
||||
this.success = function () {
|
||||
let that = this
|
||||
teaweb.success("保存成功", function () {
|
||||
window.location = Tea.url(".recipient", {
|
||||
recipientId: that.recipient.id
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user