Initial commit (code only without large binaries)
This commit is contained in:
11
EdgeAdmin/web/views/@default/servers/components/cache/@policy_menu.html
vendored
Normal file
11
EdgeAdmin/web/views/@default/servers/components/cache/@policy_menu.html
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
<second-menu>
|
||||
<menu-item href="/servers/components/cache">策略列表</menu-item>
|
||||
<span class="item">|</span>
|
||||
<menu-item :href="'/servers/components/cache/policy?cachePolicyId=' + cachePolicyId" code="index">{{cachePolicyName}}</menu-item>
|
||||
<menu-item :href="'/servers/components/cache/test?cachePolicyId=' + cachePolicyId" code="test">测试</menu-item>
|
||||
<menu-item :href="'/servers/components/cache/stat?cachePolicyId=' + cachePolicyId" code="stat">统计</menu-item>
|
||||
<menu-item :href="'/servers/components/cache/clean?cachePolicyId=' + cachePolicyId" code="clean">清理</menu-item>
|
||||
<menu-item :href="'/servers/components/cache/purge?cachePolicyId=' + cachePolicyId" code="purge">刷新</menu-item>
|
||||
<menu-item :href="'/servers/components/cache/fetch?cachePolicyId=' + cachePolicyId" code="fetch">预热</menu-item>
|
||||
<menu-item :href="'/servers/components/cache/update?cachePolicyId=' + cachePolicyId" code="update">修改</menu-item>
|
||||
</second-menu>
|
||||
6
EdgeAdmin/web/views/@default/servers/components/cache/batch/@menu.html
vendored
Normal file
6
EdgeAdmin/web/views/@default/servers/components/cache/batch/@menu.html
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
<first-menu>
|
||||
<menu-item href="." code="purge">刷新缓存</menu-item>
|
||||
<menu-item href=".fetch" code="fetch">预热缓存</menu-item>
|
||||
<span class="item disabled">|</span>
|
||||
<menu-item href=".tasks" code="task">所有任务<span v-if="countDoingTasks > 0" class="grey">({{countDoingTasks}})</span></menu-item>
|
||||
</first-menu>
|
||||
31
EdgeAdmin/web/views/@default/servers/components/cache/batch/fetch.html
vendored
Normal file
31
EdgeAdmin/web/views/@default/servers/components/cache/batch/fetch.html
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
{$layout}
|
||||
{$template "menu"}
|
||||
|
||||
<div class="margin"></div>
|
||||
<div><span class="grey">预热缓存指的是预先从源站读取最新内容,当用户访问预热后的URL时直接从缓存中返回内容,不需要再次回源。</span></div>
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-before="before" data-tea-success="success" data-tea-fail="fail" data-tea-done="done" data-tea-timeout="3600">
|
||||
<csrf-token></csrf-token>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td>要预热的URL列表</td>
|
||||
<td>
|
||||
<textarea name="keys" rows="20" ref="focus"></textarea>
|
||||
<p class="comment">每行一个URL。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="title">操作结果</td>
|
||||
<td>
|
||||
<div v-if="isRequesting">数据发送中...</div>
|
||||
<span class="red" v-if="!isRequesting && !isOk && message.length > 0">失败:{{message}}</span>
|
||||
<div v-if="!isRequesting && !isOk && failKeys.length > 0" class="fail-keys-box">
|
||||
<div v-for="failKey in failKeys">
|
||||
<span class="red">{{failKey.key}}: {{failKey.reason}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn v-if="!isRequesting">提交</submit-btn>
|
||||
</form>
|
||||
32
EdgeAdmin/web/views/@default/servers/components/cache/batch/fetch.js
vendored
Normal file
32
EdgeAdmin/web/views/@default/servers/components/cache/batch/fetch.js
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
Tea.context(function () {
|
||||
this.isRequesting = false
|
||||
this.isOk = false
|
||||
this.message = ""
|
||||
this.failKeys = []
|
||||
|
||||
this.before = function () {
|
||||
this.isRequesting = true
|
||||
this.isOk = false
|
||||
this.message = ""
|
||||
this.failKeys = []
|
||||
}
|
||||
|
||||
this.success = function (resp) {
|
||||
this.isOk = true
|
||||
|
||||
let f = NotifyReloadSuccess("任务提交成功")
|
||||
f()
|
||||
}
|
||||
|
||||
this.fail = function (resp) {
|
||||
this.message = resp.message
|
||||
|
||||
if (resp.data.failKeys != null) {
|
||||
this.failKeys = resp.data.failKeys
|
||||
}
|
||||
}
|
||||
|
||||
this.done = function () {
|
||||
this.isRequesting = false
|
||||
}
|
||||
});
|
||||
8
EdgeAdmin/web/views/@default/servers/components/cache/batch/index.css
vendored
Normal file
8
EdgeAdmin/web/views/@default/servers/components/cache/batch/index.css
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
.fail-keys-box {
|
||||
max-height: 10em;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.fail-keys-box::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
/*# sourceMappingURL=index.css.map */
|
||||
1
EdgeAdmin/web/views/@default/servers/components/cache/batch/index.css.map
vendored
Normal file
1
EdgeAdmin/web/views/@default/servers/components/cache/batch/index.css.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA;EACC,gBAAA;EACA,gBAAA;;AAGD,cAAc;EACb,UAAA","file":"index.css"}
|
||||
43
EdgeAdmin/web/views/@default/servers/components/cache/batch/index.html
vendored
Normal file
43
EdgeAdmin/web/views/@default/servers/components/cache/batch/index.html
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
{$layout}
|
||||
{$template "menu"}
|
||||
|
||||
<div class="margin"></div>
|
||||
|
||||
<div><span class="grey">刷新缓存指的是标记URL列表或目录为失效状态,当有新的用户请求这些URL时,会再次从源站读取最新的内容。</span></div>
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-before="before" data-tea-success="success" data-tea-fail="fail" data-tea-done="done" data-tea-timeout="300">
|
||||
<csrf-token></csrf-token>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">URL类型</td>
|
||||
<td>
|
||||
<radio name="keyType" :v-value="'key'" v-model="keyType">URL</radio>
|
||||
<radio name="keyType" :v-value="'prefix'" v-model="keyType">目录</radio>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span v-if="keyType == 'key'">要刷新的URL列表</span>
|
||||
<span v-if="keyType == 'prefix'">要刷新的URL目录列表</span>
|
||||
</td>
|
||||
<td>
|
||||
<textarea name="keys" rows="20" ref="keysBox"></textarea>
|
||||
<p class="comment" v-if="keyType == 'key'">每行一个URL,比如<code-label>https://example.com/hello/world.html</code-label>。</p>
|
||||
<p class="comment" v-if="keyType == 'prefix'">每行一个URL目录,比如<code-label>https://example.com/hello/</code-label>;如果只填写域名部分,表示清理全站,比如<code-label>https://example.com/</code-label>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>操作结果</td>
|
||||
<td>
|
||||
<div v-if="isRequesting">数据发送中...</div>
|
||||
<span class="red" v-if="!isRequesting && !isOk && message.length > 0">失败:{{message}}</span>
|
||||
<div v-if="!isRequesting && !isOk && failKeys.length > 0" class="fail-keys-box">
|
||||
<div v-for="failKey in failKeys">
|
||||
<span class="red">{{failKey.key}}: {{failKey.reason}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn v-if="!isRequesting">提交</submit-btn>
|
||||
</form>
|
||||
47
EdgeAdmin/web/views/@default/servers/components/cache/batch/index.js
vendored
Normal file
47
EdgeAdmin/web/views/@default/servers/components/cache/batch/index.js
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
Tea.context(function () {
|
||||
this.isRequesting = false
|
||||
this.isOk = false
|
||||
this.message = ""
|
||||
this.failKeys = []
|
||||
|
||||
this.$delay(function () {
|
||||
this.$refs.keysBox.focus()
|
||||
this.$watch("keyType", function () {
|
||||
this.$refs.keysBox.focus()
|
||||
})
|
||||
})
|
||||
|
||||
this.before = function () {
|
||||
this.isRequesting = true
|
||||
this.isOk = false
|
||||
this.message = ""
|
||||
this.failKeys = []
|
||||
}
|
||||
|
||||
this.success = function () {
|
||||
this.isOk = true
|
||||
let that = this
|
||||
teaweb.success("任务提交成功", function () {
|
||||
window.location = window.location.pathname + "?keyType=" + that.keyType
|
||||
})
|
||||
}
|
||||
|
||||
this.fail = function (resp) {
|
||||
this.message = resp.message
|
||||
|
||||
if (resp.data.failKeys != null) {
|
||||
this.failKeys = resp.data.failKeys
|
||||
}
|
||||
}
|
||||
|
||||
this.done = function () {
|
||||
this.isRequesting = false
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作类型
|
||||
*/
|
||||
if (this.keyType == null || this.keyType.length == 0) {
|
||||
this.keyType = "key" // key | prefix
|
||||
}
|
||||
})
|
||||
8
EdgeAdmin/web/views/@default/servers/components/cache/batch/index.less
vendored
Normal file
8
EdgeAdmin/web/views/@default/servers/components/cache/batch/index.less
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
.fail-keys-box {
|
||||
max-height: 10em;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.fail-keys-box::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
100
EdgeAdmin/web/views/@default/servers/components/cache/batch/task.html
vendored
Normal file
100
EdgeAdmin/web/views/@default/servers/components/cache/batch/task.html
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
{$layout}
|
||||
{$template "menu"}
|
||||
|
||||
<second-menu>
|
||||
<menu-item href=".tasks">所有任务</menu-item>
|
||||
<span class="disabled item" style="padding: 0">»</span>
|
||||
<span class="item">任务详情</span>
|
||||
</second-menu>
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">任务编号</td>
|
||||
<td>{{task.id}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>任务类型</td>
|
||||
<td>
|
||||
<span v-if="task.type == 'purge'">刷新</span>
|
||||
<span v-if="task.type == 'fetch'">预热</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>缓存URL类型</td>
|
||||
<td>
|
||||
<span v-if="task.keyType == 'key'">URL</span>
|
||||
<span v-if="task.keyType == 'prefix'">目录</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>创建时间</td>
|
||||
<td>
|
||||
{{task.createdTime}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>完成时间</td>
|
||||
<td>
|
||||
<span v-if="task.isDone">{{task.doneTime}}</span>
|
||||
<span v-else class="disabled">尚未完成</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>所属用户</td>
|
||||
<td>
|
||||
<span v-if="task.user != null && task.user.id > 0"><user-link :v-user="task.user"></user-link></span>
|
||||
<span v-else="" class="disabled">-</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>任务状态</td>
|
||||
<td>
|
||||
<span v-if="task.isOk" class="green">已完成</span>
|
||||
<a :href="'/servers/components/cache/batch/task?taskId=' + task.id" v-else-if="task.isDone" class="red"><span class="red">失败</span></a>
|
||||
<span v-else-if="!task.isDone" class="grey">等待执行</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>操作</td>
|
||||
<td>
|
||||
<a href="" @click.prevent="deleteTask(task.id)">[删除]</a>
|
||||
<a href="" @click.prevent="resetTask(task.id)">[重置状态]</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h4>要操作的缓存Key</h4>
|
||||
<table class="ui table selectable celled">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<span v-if="task.keyType == 'key'">URL</span>
|
||||
<span v-if="task.keyType == 'prefix'">前缀</span>
|
||||
</th>
|
||||
<th class="two wide">所属集群</th>
|
||||
<th class="width6">状态</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody v-for="key in task.keys">
|
||||
<tr>
|
||||
<td>
|
||||
{{key.key}}
|
||||
<div v-if="key.errors.length > 0" style="margin-top: 0.5em">
|
||||
<a :href="'/clusters/cluster/node?nodeId=' + err.nodeId" v-for="err in key.errors" class="ui label basic tiny red">
|
||||
节点{{err.nodeId}}:{{err.error}}
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="key.cluster != null && key.cluster.id > 0">{{key.cluster.name}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="key.isDone && key.errors.length == 0" class="green">完成</span>
|
||||
<span v-if="key.isDone && key.errors.length > 0" class="red">失败</span>
|
||||
<span v-if="!key.isDone && !key.isDoing" class="grey">未执行</span>
|
||||
<span v-if="!key.isDone && key.isDoing" class="grey">部分完成</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
42
EdgeAdmin/web/views/@default/servers/components/cache/batch/task.js
vendored
Normal file
42
EdgeAdmin/web/views/@default/servers/components/cache/batch/task.js
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
Tea.context(function () {
|
||||
this.$delay(function () {
|
||||
this.reload()
|
||||
})
|
||||
|
||||
this.deleteTask = function (taskId) {
|
||||
teaweb.confirm("确定要删除此任务吗?", function () {
|
||||
this.$post(".deleteTask")
|
||||
.params({
|
||||
taskId: taskId
|
||||
})
|
||||
.success(function () {
|
||||
window.location = Tea.url(".tasks")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
this.resetTask = function (taskId) {
|
||||
teaweb.confirm("确定要重置任务状态吗?", function () {
|
||||
this.$post(".resetTask")
|
||||
.params({
|
||||
taskId: taskId
|
||||
})
|
||||
.refresh()
|
||||
})
|
||||
}
|
||||
|
||||
this.reload = function () {
|
||||
this.$post("$")
|
||||
.params({
|
||||
taskId: this.task.id
|
||||
})
|
||||
.success(function (resp) {
|
||||
this.task = resp.data.task
|
||||
})
|
||||
.done(function () {
|
||||
this.$delay(function () {
|
||||
this.reload()
|
||||
}, 10000)
|
||||
})
|
||||
}
|
||||
})
|
||||
48
EdgeAdmin/web/views/@default/servers/components/cache/batch/tasks.html
vendored
Normal file
48
EdgeAdmin/web/views/@default/servers/components/cache/batch/tasks.html
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
{$layout}
|
||||
{$template "menu"}
|
||||
|
||||
<p class="comment" v-if="tasks.length == 0">暂时还没有任务。</p>
|
||||
|
||||
<table class="ui table selectable celled" v-if="tasks.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 7em">任务编号</th>
|
||||
<th>任务类型</th>
|
||||
<th>URL类型</th>
|
||||
<th>创建时间</th>
|
||||
<th class="four wide">所属用户</th>
|
||||
<th class="two wide">任务状态</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody v-for="task in tasks">
|
||||
<tr>
|
||||
<td><a :href="'/servers/components/cache/batch/task?taskId=' + task.id">{{task.id}}</a></td>
|
||||
<td>
|
||||
<span v-if="task.type == 'purge'">刷新</span>
|
||||
<span v-if="task.type == 'fetch'">预热</span>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="task.keyType == 'key'">URL</span>
|
||||
<span v-if="task.keyType == 'prefix'">目录</span>
|
||||
</td>
|
||||
<td>{{task.createdTime}}</td>
|
||||
<td>
|
||||
<span v-if="task.user != null && task.user.id > 0"><user-link :v-user="task.user"></user-link></span>
|
||||
<span v-if="task.description.length > 0" class="grey">{{task.description}}</span>
|
||||
<span v-else="" class="disabled">-</span>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="task.isOk" class="green">已完成</span>
|
||||
<a :href="'/servers/components/cache/batch/task?taskId=' + task.id" v-else-if="task.isDone" class="red"><span class="red">失败</span></a>
|
||||
<span v-else-if="!task.isDone" class="grey">等待执行</span>
|
||||
</td>
|
||||
<td>
|
||||
<a :href="'/servers/components/cache/batch/task?taskId=' + task.id">详情</a>
|
||||
<a href="" @click.prevent="deleteTask(task.id)">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<page-box></page-box>
|
||||
11
EdgeAdmin/web/views/@default/servers/components/cache/batch/tasks.js
vendored
Normal file
11
EdgeAdmin/web/views/@default/servers/components/cache/batch/tasks.js
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
Tea.context(function () {
|
||||
this.deleteTask = function (taskId) {
|
||||
teaweb.confirm("确定要删除此任务吗?", function () {
|
||||
this.$post(".deleteTask")
|
||||
.params({
|
||||
taskId: taskId
|
||||
})
|
||||
.refresh()
|
||||
})
|
||||
}
|
||||
})
|
||||
74
EdgeAdmin/web/views/@default/servers/components/cache/clean.html
vendored
Normal file
74
EdgeAdmin/web/views/@default/servers/components/cache/clean.html
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
{$layout}
|
||||
|
||||
{$template "policy_menu"}
|
||||
|
||||
<h3>选择集群</h3>
|
||||
<select class="ui dropdown auto-width" v-model="clusterId">
|
||||
<option v-for="cluster in clusters" :value="cluster.id">{{cluster.name}}</option>
|
||||
</select>
|
||||
<div class="ui divider"></div>
|
||||
|
||||
|
||||
<h3>清理</h3>
|
||||
<p class=""><span class="red">严重警告:该操作将清理集群所有节点上的所有当前策略产生的缓存;如果只是想清理单个缓存,请使用“刷新预热”功能。</span></p>
|
||||
<form method="post" data-tea-action="$" data-tea-before="before" data-tea-success="success" data-tea-fail="fail" data-tea-done="done" data-tea-timeout="300">
|
||||
<input type="hidden" name="cachePolicyId" :value="cachePolicyId"/>
|
||||
<input type="hidden" name="clusterId" :value="clusterId"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">操作原因 *</td>
|
||||
<td>
|
||||
<p class="comment">为了防止新手滥用此功能、导致节点崩溃,你需要选择操作原因,才能继续操作:</p>
|
||||
<div>
|
||||
<radio v-model="reason" :v-value="REASON_NEW_PIE">我是一名新手,我不知道怎么清除缓存</radio>
|
||||
</div>
|
||||
<div style="margin-top: 0.6em">
|
||||
<radio v-model="reason" :v-value="REASON_BATCH_DELETE">要清理的域名太多,我比较懒,我不想用“刷新预热”功能</radio>
|
||||
</div>
|
||||
<div style="margin-top: 0.6em">
|
||||
<radio v-model="reason" :v-value="REASON_MAINTAINS">因节点硬盘空间不足或以往缓存设置错误或其他原因,想清除所有缓存,重新开始</radio>
|
||||
</div>
|
||||
<div style="margin-top: 0.6em">
|
||||
<radio v-model="reason" :v-value="REASON_ISSUE_REPORT">我怀疑“刷新预热”功能不起作用</radio>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="!isReasonable()">
|
||||
<td>新手操作建议</td>
|
||||
<td>
|
||||
请使用左侧主菜单中的 <a href="/servers/components/cache/batch?keyType=prefix" target="_blank">[刷新预热]</a> 功能来清理你的缓存。
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="reason == REASON_ISSUE_REPORT">
|
||||
<td>操作建议</td>
|
||||
<td>
|
||||
当前系统提供的 <a href="/servers/components/cache/batch?keyType=prefix" target="_blank">[刷新预热]</a> 功能运行非常可靠,如果你确认发现功能异常,且能100%几率重现问题,请及时报告给软件开发者。
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="reason == REASON_BATCH_DELETE">
|
||||
<td>操作建议</td>
|
||||
<td>
|
||||
请尽可能使用 <a href="/servers/components/cache/batch?keyType=prefix" target="_blank">[刷新预热]</a> 功能,避免影响当前系统上的别的网站。
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="reason == REASON_MAINTAINS">
|
||||
<td>操作建议</td>
|
||||
<td>
|
||||
缓存文件较多时,系统需要消耗更多系统资源和更多时间删除缓存文件,硬盘使用空间会逐渐恢复,操作后,请耐心等待。
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="isReasonable()">
|
||||
<td class="title">操作结果</td>
|
||||
<td>
|
||||
<div v-if="isRequesting">数据发送中...</div>
|
||||
<span class="red" v-if="!isRequesting && !isOk && message.length > 0">失败:{{message}}</span>
|
||||
<div v-if="!isRequesting && isOk">
|
||||
<span v-if="results.length == 0" class="red">此集群下没有任何可用的节点。</span>
|
||||
<div class="ui label tiny" v-for="one in results" :class="{green:one.isOk, red:!one.isOk}" style="margin-bottom: 0.5em">{{one.nodeName}}:{{one.message}}</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn v-if="!isRequesting && isReasonable()">提交</submit-btn>
|
||||
<button class="ui button disabled" type="button" v-if="!isReasonable()">提交</button>
|
||||
</form>
|
||||
45
EdgeAdmin/web/views/@default/servers/components/cache/clean.js
vendored
Normal file
45
EdgeAdmin/web/views/@default/servers/components/cache/clean.js
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
Tea.context(function () {
|
||||
this.reason = 0
|
||||
|
||||
this.REASON_NEW_PIE = 0
|
||||
this.REASON_ISSUE_REPORT = 1
|
||||
this.REASON_BATCH_DELETE = 2
|
||||
this.REASON_MAINTAINS = 3
|
||||
|
||||
this.isReasonable = function () {
|
||||
return this.reason == this.REASON_ISSUE_REPORT || this.reason == this.REASON_BATCH_DELETE || this.reason == this.REASON_MAINTAINS
|
||||
}
|
||||
|
||||
if (this.clusterId == null) {
|
||||
if (this.clusters.length > 0) {
|
||||
this.clusterId = this.clusters[0].id
|
||||
} else {
|
||||
this.clusterId = 0
|
||||
}
|
||||
}
|
||||
|
||||
this.isRequesting = false
|
||||
this.isOk = false
|
||||
this.message = ""
|
||||
this.results = []
|
||||
|
||||
this.before = function () {
|
||||
this.isRequesting = true
|
||||
this.isOk = false
|
||||
this.message = ""
|
||||
this.results = []
|
||||
}
|
||||
|
||||
this.success = function (resp) {
|
||||
this.isOk = true
|
||||
this.results = resp.data.results
|
||||
}
|
||||
|
||||
this.fail = function (resp) {
|
||||
this.message = resp.message
|
||||
}
|
||||
|
||||
this.done = function () {
|
||||
this.isRequesting = false
|
||||
}
|
||||
});
|
||||
135
EdgeAdmin/web/views/@default/servers/components/cache/createPopup.html
vendored
Normal file
135
EdgeAdmin/web/views/@default/servers/components/cache/createPopup.html
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>创建缓存策略</h3>
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">策略名称 *</td>
|
||||
<td><input type="text" name="name" maxlength="100" ref="focus"/> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">缓存类型 *</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" name="type" v-model="policyType">
|
||||
<option v-for="type in types" :value="type.type">{{type.name}}</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- 文件缓存选项 -->
|
||||
<tbody v-if="policyType == 'file'">
|
||||
<tr>
|
||||
<td class="color-border">缓存目录 *</td>
|
||||
<td>
|
||||
<input type="text" name="fileDir" maxlength="500" value="/opt/cache"/>
|
||||
<p class="comment">存放文件缓存的目录,通常填写绝对路径。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">缓存硬盘最大用量 *</td>
|
||||
<td>
|
||||
<size-capacity-box :v-name="'capacityJSON'" :v-count="128" :v-unit="'gb'" :key="'capacityJSON1'"></size-capacity-box>
|
||||
<p class="comment">单个节点上缓存所在硬盘的最大用量,超出此用量或硬盘接近用尽时,将会自动尝试清理旧数据,如果为0表示没有限制。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">内存最大容量</td>
|
||||
<td>
|
||||
<size-capacity-box :v-name="'fileMemoryCapacityJSON'" :v-count="1" :v-unit="'gb'" :key="'fileMemoryCapacityJSON'"></size-capacity-box>
|
||||
<p class="comment">单个节点上作为一级缓存的内存最大容量,可以作为硬盘缓冲区和存储热点缓存内容,如果为0表示不使用内存作为一级缓存。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<tbody v-if="policyType == 'memory'">
|
||||
<tr>
|
||||
<td>内存最大容量</td>
|
||||
<td>
|
||||
<size-capacity-box :key="'a'" :v-name="'capacityJSON'" :v-count="2" :v-unit="'gb'" :key="'capacityJSON2'"></size-capacity-box>
|
||||
<p class="comment">单个节点上允许缓存的最大容量,如果为0表示没有限制。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<tr>
|
||||
<td>最大内容尺寸</td>
|
||||
<td>
|
||||
<size-capacity-box :v-name="'maxSizeJSON'" :v-count="256" :v-unit="'mb'" :key="'maxSizeJSON'"></size-capacity-box>
|
||||
<p class="comment">允许缓存的单个内容最大尺寸,如果为0表示没有限制。</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||
</tr>
|
||||
<tbody v-show="moreOptionsVisible && policyType == 'file'">
|
||||
<tr>
|
||||
<td class="color-border">缓存硬盘最小空余空间</td>
|
||||
<td>
|
||||
<size-capacity-box :v-name="'fileMinFreeSizeJSON'" :v-count="0" :v-unit="'gb'" :key="'minFreeSizeJSON'"></size-capacity-box>
|
||||
<p class="comment">缓存硬盘保留的最小空余空间,如果为0表示自动限制(目前默认保留5GiB)。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">缓存文件句柄缓存</td>
|
||||
<td>
|
||||
<input type="text" name="fileOpenFileCacheMax" maxlength="6" value="0" style="width: 10em"/>
|
||||
<p class="comment"><pro-warning-label></pro-warning-label>保持在内存中的缓存文件句柄的数量,提升缓存文件打开速度,同时也会占用系统更多的内存,建议数量不超过缓存文件数量的百分之一;0表示不启用。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="teaIsPlus">
|
||||
<td class="color-border">开启Sendfile</td>
|
||||
<td>
|
||||
<checkbox name="fileEnableSendfile"></checkbox>
|
||||
<p class="comment"><pro-warning-label></pro-warning-label><plus-label></plus-label>使用sendfile提升发送缓存文件的效率。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">允许读取不完整的Partial Content</td>
|
||||
<td>
|
||||
<checkbox name="enableIncompletePartialContent" checked="checked"></checkbox>
|
||||
<p class="comment">允许在有一部分内容缓存的情况下读取分区内容,剩余的部分将会自动回源读取。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- <tr v-show="moreOptionsVisible && policyType == 'file'">
|
||||
<td class="color-border">启用MMAP</td>
|
||||
<td>
|
||||
<checkbox name="enableMMAP"></checkbox>
|
||||
<p class="comment">选中后,表示允许系统自动利用MMAP提升缓存读取性能。</p>
|
||||
</td>
|
||||
</tr>-->
|
||||
</tbody>
|
||||
<tbody v-show="moreOptionsVisible">
|
||||
<tr>
|
||||
<td>同步写入压缩缓存</td>
|
||||
<td>
|
||||
<checkbox name="syncCompressionCache"></checkbox>
|
||||
<p class="comment">选中后,在压缩设置开启的情况下,在缓存源站内容的同时,也会同步写入压缩缓存;不选中,表示在源站内容缓存后,下一次调用才会缓存压缩内容,防止同一时间内硬盘IO负载过高。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>预热超时时间</td>
|
||||
<td>
|
||||
<time-duration-box :v-name="'fetchTimeoutJSON'" :v-unit="'minute'" maxlength="6"></time-duration-box>
|
||||
<p class="comment">预热读取源站的超时时间,默认20分钟。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>描述</td>
|
||||
<td>
|
||||
<textarea maxlength="200" name="description" rows="3"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>启用当前策略</td>
|
||||
<td>
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" name="isOn" value="1" checked="checked"/>
|
||||
<label></label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
5
EdgeAdmin/web/views/@default/servers/components/cache/createPopup.js
vendored
Normal file
5
EdgeAdmin/web/views/@default/servers/components/cache/createPopup.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifyPopup
|
||||
|
||||
this.policyType = this.types[0].type
|
||||
})
|
||||
28
EdgeAdmin/web/views/@default/servers/components/cache/fetch.html
vendored
Normal file
28
EdgeAdmin/web/views/@default/servers/components/cache/fetch.html
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
{$layout}
|
||||
{$template "policy_menu"}
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-before="before" data-tea-success="success" data-tea-fail="fail" data-tea-done="done" data-tea-timeout="3600">
|
||||
<input type="hidden" name="cachePolicyId" :value="cachePolicyId"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td>URL列表</td>
|
||||
<td>
|
||||
<textarea name="keys" rows="10" ref="focus"></textarea>
|
||||
<p class="comment">每行一个URL。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="title">操作结果</td>
|
||||
<td>
|
||||
<div v-if="isRequesting">数据发送中...</div>
|
||||
<span class="red" v-if="!isRequesting && !isOk && message.length > 0">失败:{{message}}</span>
|
||||
<div v-if="!isRequesting && !isOk && failKeys.length > 0" class="fail-keys-box">
|
||||
<div v-for="failKey in failKeys">
|
||||
<span class="red">{{failKey.key}}: {{failKey.reason}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn v-if="!isRequesting">提交</submit-btn>
|
||||
</form>
|
||||
32
EdgeAdmin/web/views/@default/servers/components/cache/fetch.js
vendored
Normal file
32
EdgeAdmin/web/views/@default/servers/components/cache/fetch.js
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
Tea.context(function () {
|
||||
this.isRequesting = false
|
||||
this.isOk = false
|
||||
this.message = ""
|
||||
this.failKeys = []
|
||||
|
||||
this.before = function () {
|
||||
this.isRequesting = true
|
||||
this.isOk = false
|
||||
this.message = ""
|
||||
this.failKeys = []
|
||||
}
|
||||
|
||||
this.success = function (resp) {
|
||||
this.isOk = true
|
||||
|
||||
let f = NotifyReloadSuccess("任务提交成功")
|
||||
f()
|
||||
}
|
||||
|
||||
this.fail = function (resp) {
|
||||
this.message = resp.message
|
||||
|
||||
if (resp.data.failKeys != null) {
|
||||
this.failKeys = resp.data.failKeys
|
||||
}
|
||||
}
|
||||
|
||||
this.done = function () {
|
||||
this.isRequesting = false
|
||||
}
|
||||
});
|
||||
71
EdgeAdmin/web/views/@default/servers/components/cache/index.html
vendored
Normal file
71
EdgeAdmin/web/views/@default/servers/components/cache/index.html
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
{$layout}
|
||||
|
||||
<first-menu>
|
||||
<menu-item href="/servers/components/cache" code="index">列表</menu-item>
|
||||
<span class="item">|</span>
|
||||
<a href="" class="item" @click.prevent="createPolicy()">[创建]</a>
|
||||
</first-menu>
|
||||
|
||||
<!-- 搜索 -->
|
||||
<div class="margin"></div>
|
||||
<form class="ui form" method="get" action="/servers/components/cache">
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<node-cluster-combo-box :v-cluster-id="clusterId"></node-cluster-combo-box>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<input type="text" name="keyword" v-model="keyword" placeholder="策略名称..."/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<select class="ui dropdown" name="storageType" v-model="storageType">
|
||||
<option value="">[存储类型]</option>
|
||||
<option v-for="storageType in storageTypes" :value="storageType.type">{{storageType.name}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button type="submit" class="ui button">搜索</button>
|
||||
|
||||
<a :href="Tea.url('.')" v-if="keyword.length > 0 || clusterId > 0 || storageType.length > 0">[清除条件]</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- 列表 -->
|
||||
<p class="comment" v-if="cachePolicies == null || cachePolicies.length == 0">暂时还没有缓存策略。</p>
|
||||
<table class="ui table selectable celled" v-if="cachePolicies != null && cachePolicies.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>策略名称</th>
|
||||
<th>策略类型</th>
|
||||
<th>容量</th>
|
||||
<th class="center">集群数</th>
|
||||
<th class="center">状态</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="(policy, index) in cachePolicies">
|
||||
<td>
|
||||
<a :href="'/servers/components/cache/policy?cachePolicyId=' + policy.id"><keyword :v-word="keyword">{{policy.name}}</keyword>
|
||||
|
||||
<i class="icon disk small blue" v-if="policy.type == 'file'" title="硬盘"></i>
|
||||
</a>
|
||||
</td>
|
||||
<td>{{infos[index].typeName}} <span class="small">({{policy.type}})</span></td>
|
||||
<td>
|
||||
<span v-if="policy.capacity != null && policy.capacity.count > 0">
|
||||
{{policy.capacity.count}}{{policy.capacity.unit.toUpperCase().replace(/(.)B/, "$1iB")}}
|
||||
<span v-if="policy.type == 'file' && policy.options.memoryPolicy != null && policy.options.memoryPolicy.capacity != null && policy.options.memoryPolicy.capacity.count > 0" class="small grey" title="内存容量">
|
||||
(内存:{{policy.options.memoryPolicy.capacity.count}}{{policy.options.memoryPolicy.capacity.unit.toUpperCase().replace(/(.)B/, "$1iB")}})
|
||||
</span>
|
||||
</span>
|
||||
<span v-else class="disabled">不限</span>
|
||||
</td>
|
||||
<td class="center">{{infos[index].countClusters}}</td>
|
||||
<td class="center"><label-on :v-is-on="policy.isOn"></label-on></td>
|
||||
<td>
|
||||
<a :href="'/servers/components/cache/policy?cachePolicyId=' + policy.id">详情</a> <a href="" @click.prevent="deletePolicy(policy.id)">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
25
EdgeAdmin/web/views/@default/servers/components/cache/index.js
vendored
Normal file
25
EdgeAdmin/web/views/@default/servers/components/cache/index.js
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
Tea.context(function () {
|
||||
// 创建策略
|
||||
this.createPolicy = function () {
|
||||
teaweb.popup("/servers/components/cache/createPopup", {
|
||||
height: "27em",
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
window.location.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 删除策略
|
||||
this.deletePolicy = function (policyId) {
|
||||
let that = this
|
||||
teaweb.confirm("确定要删除此缓存策略吗?", function () {
|
||||
that.$post("/servers/components/cache/delete")
|
||||
.params({
|
||||
cachePolicyId: policyId
|
||||
})
|
||||
.refresh()
|
||||
})
|
||||
}
|
||||
})
|
||||
128
EdgeAdmin/web/views/@default/servers/components/cache/policy.html
vendored
Normal file
128
EdgeAdmin/web/views/@default/servers/components/cache/policy.html
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
{$layout}
|
||||
{$template "policy_menu"}
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">策略名称</td>
|
||||
<td>{{cachePolicy.name}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>状态</td>
|
||||
<td><label-on :v-is-on="cachePolicy.isOn"></label-on></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">缓存类型</td>
|
||||
<td>
|
||||
{{typeName}}<span class="small">({{cachePolicy.type}})</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- 文件缓存选项 -->
|
||||
<tbody v-if="cachePolicy.type == 'file'">
|
||||
<tr>
|
||||
<td class="color-border">缓存目录</td>
|
||||
<td>
|
||||
{{cachePolicy.options.dir}}
|
||||
<p class="comment">存放文件缓存的目录,通常填写绝对路径。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">缓存硬盘最大用量</td>
|
||||
<td>
|
||||
<size-capacity-view :v-value="cachePolicy.capacity" :v-default-text="'不限'"></size-capacity-view>
|
||||
<p class="comment">单个节点上缓存所在硬盘的最大用量,如果为0表示没有限制。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="cachePolicy.options.memoryPolicy != null && cachePolicy.options.memoryPolicy.capacity != null && cachePolicy.options.memoryPolicy.capacity.count > 0">
|
||||
<td class="color-border">内存最大容量</td>
|
||||
<td>
|
||||
<size-capacity-view :v-value="cachePolicy.options.memoryPolicy.capacity"></size-capacity-view>
|
||||
<p class="comment">作为一级缓存的内存最大容量,可以作为硬盘缓冲区和存储热点缓存内容,如果为0表示不使用内存作为一级缓存。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-else>
|
||||
<td class="color-border">内存最大容量</td>
|
||||
<td>
|
||||
<a :href="Tea.url('.update', {cachePolicyId:cachePolicy.id})"><span class="red">请设置一个内存容量作为缓冲区,以提升缓存写入性能。</span></a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="cachePolicy.options.openFileCache != null && cachePolicy.options.openFileCache.isOn && cachePolicy.options.openFileCache.max > 0">
|
||||
<td class="color-border">缓存文件句柄缓存</td>
|
||||
<td>{{cachePolicy.options.openFileCache.max}}</td>
|
||||
</tr>
|
||||
<tr v-if="cachePolicy.options.enableSendfile">
|
||||
<td class="color-border">开启Sendfile</td>
|
||||
<td><span v-if="cachePolicy.options.enableSendfile" class="green">Y</span><span v-else class="disabled">N</span></td>
|
||||
</tr>
|
||||
<tr v-if="cachePolicy.options.minFreeSize != null && cachePolicy.options.minFreeSize.count > 0">
|
||||
<td class="color-border">缓存硬盘最小空余空间</td>
|
||||
<td><size-capacity-view :v-value="cachePolicy.options.minFreeSize"></size-capacity-view></td>
|
||||
</tr>
|
||||
<tr v-if="cachePolicy.options.enableIncompletePartialContent">
|
||||
<td class="color-border">允许读取不完整的Partial Content</td>
|
||||
<td>
|
||||
<span class="green">Y</span>
|
||||
</td>
|
||||
</tr>
|
||||
<!--<tr v-if="cachePolicy.options.enableMMAP">
|
||||
<td class="color-border">启用MMAP</td>
|
||||
<td>
|
||||
<span>Y</span>
|
||||
</td>
|
||||
</tr>-->
|
||||
</tbody>
|
||||
|
||||
<tbody v-if="cachePolicy.type != 'file'">
|
||||
<tr>
|
||||
<td>缓存最大容量</td>
|
||||
<td>
|
||||
<size-capacity-view :v-value="cachePolicy.capacity" :v-default-text="'不限'"></size-capacity-view>
|
||||
<p class="comment">允许缓存的最大容量,如果为0表示没有限制。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tr>
|
||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||
</tr>
|
||||
<tbody v-show="moreOptionsVisible">
|
||||
<tr>
|
||||
<td>最大内容长度</td>
|
||||
<td>
|
||||
<size-capacity-view :v-value="cachePolicy.maxSize" :v-default-text="'不限'"></size-capacity-view>
|
||||
<p class="comment">允许缓存的单个内容最大尺寸,如果为0表示没有限制。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>同步写入压缩缓存</td>
|
||||
<td>
|
||||
<span v-if="cachePolicy.syncCompressionCache" class="green">Y</span>
|
||||
<span v-else class="disabled">N</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>预热超时时间</td>
|
||||
<td><span v-if="fetchTimeoutString.length > 0">{{fetchTimeoutString}}</span><span v-else class="disabled">使用默认</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>描述</td>
|
||||
<td>
|
||||
<span v-if="cachePolicy.description.length > 0">{{cachePolicy.description}}</span>
|
||||
<span v-else class="disabled">暂时还没有描述。</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<!-- 默认缓存条件 -->
|
||||
<h4>默认缓存条件</h4>
|
||||
<http-cache-refs-box :v-cache-refs="cachePolicy.cacheRefs"></http-cache-refs-box>
|
||||
|
||||
<!-- 使用此策略的集群 -->
|
||||
<h4>使用此策略的集群</h4>
|
||||
<p class="comment" v-if="clusters.length == 0">暂时还没有集群使用此策略。</p>
|
||||
<table class="ui table selectable" v-if="clusters.length > 0">
|
||||
<tr v-for="cluster in clusters">
|
||||
<td>{{cluster.name}}<link-icon :href="'/clusters/cluster?clusterId=' + cluster.id"></link-icon></td>
|
||||
</tr>
|
||||
</table>
|
||||
40
EdgeAdmin/web/views/@default/servers/components/cache/purge.html
vendored
Normal file
40
EdgeAdmin/web/views/@default/servers/components/cache/purge.html
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
{$layout}
|
||||
{$template "policy_menu"}
|
||||
|
||||
<p class="comment">可以在这里批量刷新一组URL。</p>
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-before="before" data-tea-success="success" data-tea-fail="fail" data-tea-done="done" data-tea-timeout="300">
|
||||
<input type="hidden" name="cachePolicyId" :value="cachePolicyId"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">URL类型</td>
|
||||
<td>
|
||||
<radio name="keyType" :v-value="'key'" v-model="keyType">URL</radio>
|
||||
<radio name="keyType" :v-value="'prefix'" v-model="keyType">目录</radio>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span v-if="keyType == 'key'">URL</span>
|
||||
<span v-if="keyType == 'prefix'">目录</span>
|
||||
</td>
|
||||
<td>
|
||||
<textarea name="keys" rows="10" ref="keysBox"></textarea>
|
||||
<p class="comment" v-if="keyType == 'key'">每行一个URL,比如<code-label>https://example.com/hello/world.html</code-label>。</p>
|
||||
<p class="comment" v-if="keyType == 'prefix'">每行一个URL目录,比如<code-label>https://example.com/hello/</code-label>;如果只填写域名部分,表示清理全站,比如<code-label>https://example.com/</code-label>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>操作结果</td>
|
||||
<td>
|
||||
<div v-if="isRequesting">数据发送中...</div>
|
||||
<span class="red" v-if="!isRequesting && !isOk && message.length > 0">失败:{{message}}</span>
|
||||
<div v-if="!isRequesting && !isOk && failKeys.length > 0" class="fail-keys-box">
|
||||
<div v-for="failKey in failKeys">
|
||||
<span class="red">{{failKey.key}}: {{failKey.reason}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn v-if="!isRequesting">提交</submit-btn>
|
||||
</form>
|
||||
43
EdgeAdmin/web/views/@default/servers/components/cache/purge.js
vendored
Normal file
43
EdgeAdmin/web/views/@default/servers/components/cache/purge.js
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
Tea.context(function () {
|
||||
this.isRequesting = false
|
||||
this.isOk = false
|
||||
this.message = ""
|
||||
this.failKeys = []
|
||||
|
||||
this.$delay(function () {
|
||||
this.$refs.keysBox.focus()
|
||||
this.$watch("keyType", function () {
|
||||
this.$refs.keysBox.focus()
|
||||
})
|
||||
})
|
||||
|
||||
this.before = function () {
|
||||
this.isRequesting = true
|
||||
this.isOk = false
|
||||
this.message = ""
|
||||
this.failKeys = []
|
||||
}
|
||||
|
||||
this.success = function () {
|
||||
this.isOk = true
|
||||
let f = NotifyReloadSuccess("任务提交成功")
|
||||
f()
|
||||
}
|
||||
|
||||
this.fail = function (resp) {
|
||||
this.message = resp.message
|
||||
|
||||
if (resp.data.failKeys != null) {
|
||||
this.failKeys = resp.data.failKeys
|
||||
}
|
||||
}
|
||||
|
||||
this.done = function () {
|
||||
this.isRequesting = false
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作类型
|
||||
*/
|
||||
this.keyType = "key" // key | prefix
|
||||
})
|
||||
24
EdgeAdmin/web/views/@default/servers/components/cache/selectPopup.html
vendored
Normal file
24
EdgeAdmin/web/views/@default/servers/components/cache/selectPopup.html
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>选择缓存策略</h3>
|
||||
<table class="ui table selectable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>策略名称</th>
|
||||
<th style="width: 7em">状态</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="cachePolicy in cachePolicies">
|
||||
<td>{{cachePolicy.name}}</td>
|
||||
<td>
|
||||
<label-on :v-is-on="cachePolicy.isOn"></label-on>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="cachePolicy.isOn">
|
||||
<a href="" @click.prevent="selectPolicy(cachePolicy)">选择</a>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="page" v-html="page"></div>
|
||||
11
EdgeAdmin/web/views/@default/servers/components/cache/selectPopup.js
vendored
Normal file
11
EdgeAdmin/web/views/@default/servers/components/cache/selectPopup.js
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
Tea.context(function () {
|
||||
this.selectPolicy = function (cachePolicy) {
|
||||
NotifyPopup({
|
||||
code: 200,
|
||||
data: {
|
||||
cachePolicy: cachePolicy
|
||||
},
|
||||
message: ""
|
||||
})
|
||||
}
|
||||
})
|
||||
31
EdgeAdmin/web/views/@default/servers/components/cache/stat.html
vendored
Normal file
31
EdgeAdmin/web/views/@default/servers/components/cache/stat.html
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
{$layout}
|
||||
|
||||
{$template "policy_menu"}
|
||||
|
||||
<h3>选择集群</h3>
|
||||
<select class="ui dropdown auto-width" v-model="clusterId">
|
||||
<option v-for="cluster in clusters" :value="cluster.id">{{cluster.name}}</option>
|
||||
</select>
|
||||
|
||||
<div class="ui divider"></div>
|
||||
|
||||
<h3>统计</h3>
|
||||
<form method="post" data-tea-action="$" data-tea-before="before" data-tea-success="success" data-tea-fail="fail" data-tea-done="done">
|
||||
<input type="hidden" name="cachePolicyId" :value="cachePolicyId"/>
|
||||
<input type="hidden" name="clusterId" :value="clusterId"/>
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">操作结果</td>
|
||||
<td>
|
||||
<div v-if="isRequesting">数据发送中...</div>
|
||||
<span class="red" v-if="!isRequesting && !isOk && message.length > 0">失败:{{message}}</span>
|
||||
<div v-if="!isRequesting && isOk">
|
||||
<span v-if="results.length == 0" class="red">此集群下没有任何可用的节点。</span>
|
||||
<div class="ui label tiny" v-for="one in results" :class="{green:one.isOk, red:!one.isOk}" style="margin-bottom: 0.5em">{{one.nodeName}}:{{one.message}}</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn v-if="!isRequesting">提交</submit-btn>
|
||||
</form>
|
||||
34
EdgeAdmin/web/views/@default/servers/components/cache/stat.js
vendored
Normal file
34
EdgeAdmin/web/views/@default/servers/components/cache/stat.js
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
Tea.context(function () {
|
||||
if (this.clusterId == null) {
|
||||
if (this.clusters.length > 0) {
|
||||
this.clusterId = this.clusters[0].id
|
||||
} else {
|
||||
this.clusterId = 0
|
||||
}
|
||||
}
|
||||
|
||||
this.isRequesting = false
|
||||
this.isOk = false
|
||||
this.message = ""
|
||||
this.results = []
|
||||
|
||||
this.before = function () {
|
||||
this.isRequesting = true
|
||||
this.isOk = false
|
||||
this.message = ""
|
||||
this.results = []
|
||||
}
|
||||
|
||||
this.success = function (resp) {
|
||||
this.isOk = true
|
||||
this.results = resp.data.results
|
||||
}
|
||||
|
||||
this.fail = function (resp) {
|
||||
this.message = resp.message
|
||||
}
|
||||
|
||||
this.done = function () {
|
||||
this.isRequesting = false
|
||||
}
|
||||
});
|
||||
70
EdgeAdmin/web/views/@default/servers/components/cache/test.html
vendored
Normal file
70
EdgeAdmin/web/views/@default/servers/components/cache/test.html
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
{$layout}
|
||||
|
||||
{$template "policy_menu"}
|
||||
|
||||
<h3>选择集群</h3>
|
||||
<select class="ui dropdown auto-width" v-model="clusterId">
|
||||
<option v-for="cluster in clusters" :value="cluster.id">{{cluster.name}}</option>
|
||||
</select>
|
||||
|
||||
<div class="ui divider"></div>
|
||||
|
||||
<h3>测试写入</h3>
|
||||
<form method="post" class="ui form" data-tea-action=".testWrite" data-tea-before="beforeWrite" data-tea-done="doneWrite" data-tea-success="successWrite" data-tea-fail="failWrite">
|
||||
<input type="hidden" name="clusterId" :value="clusterId"/>
|
||||
<input type="hidden" name="cachePolicyId" :value="cachePolicyId"/>
|
||||
<table class="ui table selectable definition">
|
||||
<tr>
|
||||
<td class="title">Key</td>
|
||||
<td>
|
||||
<input type="text" name="key" value="my-key"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Value</td>
|
||||
<td>
|
||||
<textarea name="value" rows="3">my-value</textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>操作结果</td>
|
||||
<td>
|
||||
<div v-if="isRequestingWrite">数据发送中...</div>
|
||||
<span class="red" v-if="!isRequestingWrite && !writeOk && writeMessage.length > 0">失败:{{writeMessage}}</span>
|
||||
<div v-if="!isRequestingWrite && writeOk">
|
||||
<span v-if="writeResults.length == 0" class="red">此集群下没有任何可用的节点。</span>
|
||||
<div class="ui label tiny" v-for="result in writeResults" :class="{green:result.isOk, red:!result.isOk}" style="margin-bottom:0.5em">节点{{result.nodeName}}:{{result.message}}</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn v-if="!isRequestingWrite">提交</submit-btn>
|
||||
</form>
|
||||
|
||||
<div class="ui divider"></div>
|
||||
|
||||
<h3>测试读取</h3>
|
||||
<form method="post" class="ui form" data-tea-action=".testRead" data-tea-before="beforeRead" data-tea-done="doneRead" data-tea-success="successRead" data-tea-fail="failRead">
|
||||
<input type="hidden" name="clusterId" :value="clusterId"/>
|
||||
<input type="hidden" name="cachePolicyId" :value="cachePolicyId"/>
|
||||
<table class="ui table selectable definition">
|
||||
<tr>
|
||||
<td class="title">Key</td>
|
||||
<td>
|
||||
<input type="text" name="key" value="my-key"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>操作结果</td>
|
||||
<td>
|
||||
<div v-if="isRequestingRead">数据发送中...</div>
|
||||
<span class="red" v-if="!isRequestingRead && !readOk && readMessage.length > 0">失败:{{readMessage}}</span>
|
||||
<div v-if="!isRequestingRead && readOk">
|
||||
<span v-if="readResults.length == 0" class="red">此集群下没有任何可用的节点。</span>
|
||||
<div class="ui label tiny" v-for="result in readResults" :class="{green:result.isOk, red:!result.isOk}" style="margin-bottom: 0.5em">节点{{result.nodeName}}:{{result.message}}</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn v-if="!isRequestingRead">提交</submit-btn>
|
||||
</form>
|
||||
65
EdgeAdmin/web/views/@default/servers/components/cache/test.js
vendored
Normal file
65
EdgeAdmin/web/views/@default/servers/components/cache/test.js
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
Tea.context(function () {
|
||||
if (this.clusterId == null) {
|
||||
if (this.clusters.length > 0) {
|
||||
this.clusterId = this.clusters[0].id
|
||||
} else {
|
||||
this.clusterId = 0
|
||||
}
|
||||
}
|
||||
|
||||
this.isRequestingWrite = false
|
||||
this.writeOk = false
|
||||
this.writeMessage = ""
|
||||
this.writeIsAllOk = false
|
||||
this.writeResults = []
|
||||
|
||||
this.beforeWrite = function () {
|
||||
this.isRequestingWrite = true
|
||||
this.writeOk = false
|
||||
this.writeMessage = ""
|
||||
this.writeResult = {}
|
||||
}
|
||||
|
||||
this.failWrite = function (resp) {
|
||||
this.writeOk = false
|
||||
this.writeMessage = resp.message
|
||||
}
|
||||
|
||||
this.successWrite = function (resp) {
|
||||
this.writeOk = true
|
||||
this.writeIsAllOk = resp.data.isAllOk
|
||||
this.writeResults = resp.data.results
|
||||
}
|
||||
|
||||
this.doneWrite = function () {
|
||||
this.isRequestingWrite = false
|
||||
}
|
||||
|
||||
this.isRequestingRead = false
|
||||
this.readOk = false
|
||||
this.readMessage = ""
|
||||
this.readIsAllOk = false
|
||||
this.readResults = []
|
||||
|
||||
this.beforeRead = function () {
|
||||
this.isRequestingRead = true
|
||||
this.readOk = false
|
||||
this.readMessage = ""
|
||||
this.readResult = {}
|
||||
}
|
||||
|
||||
this.failRead = function (resp) {
|
||||
this.readOk = false
|
||||
this.readMessage = resp.message
|
||||
};
|
||||
|
||||
this.successRead = function (resp) {
|
||||
this.readOk = true;
|
||||
this.readIsAllOk = resp.data.isAllOk
|
||||
this.readResults = resp.data.results
|
||||
}
|
||||
|
||||
this.doneRead = function () {
|
||||
this.isRequestingRead = false
|
||||
}
|
||||
});
|
||||
146
EdgeAdmin/web/views/@default/servers/components/cache/update.html
vendored
Normal file
146
EdgeAdmin/web/views/@default/servers/components/cache/update.html
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
{$layout}
|
||||
|
||||
{$template "policy_menu"}
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="cachePolicyId" :value="cachePolicy.id"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">策略名称 *</td>
|
||||
<td><input type="text" name="name" maxlength="100" ref="focus" v-model="cachePolicy.name"/> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">缓存类型 *</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" name="type" v-model="policyType" @change="changePolicyType">
|
||||
<option v-for="type in types" :value="type.type">{{type.name}}</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- 文件缓存选项 -->
|
||||
<tbody v-if="policyType == 'file'">
|
||||
<tr>
|
||||
<td class="color-border">缓存目录 *</td>
|
||||
<td>
|
||||
<input type="text" name="fileDir" maxlength="500" v-model="cachePolicy.options.dir"/>
|
||||
<p class="comment">存放文件缓存的目录,通常填写绝对路径。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">缓存硬盘最大用量</td>
|
||||
<td>
|
||||
<size-capacity-box :v-name="'capacityJSON'" :v-value="cachePolicy.capacity" :v-count="0" :v-unit="'gb'"></size-capacity-box>
|
||||
<p class="comment">单个节点上缓存所在硬盘的最大用量,超出此用量或硬盘接近用尽时,将会自动尝试清理旧数据,如果为0表示没有限制。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="cachePolicy.options.memoryPolicy != null && cachePolicy.options.memoryPolicy.capacity != null">
|
||||
<td class="color-border">内存最大容量</td>
|
||||
<td>
|
||||
<size-capacity-box :v-name="'fileMemoryCapacityJSON'" :v-value="cachePolicy.options.memoryPolicy.capacity" :v-count="1" :v-unit="'gb'"></size-capacity-box>
|
||||
<p class="comment">单个节点上作为一级缓存的内存最大容量,可以作为硬盘缓冲区和存储热点缓存内容,如果为0表示不使用内存作为一级缓存。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="cachePolicy.options.memoryPolicy == null || cachePolicy.options.memoryPolicy.capacity == null">
|
||||
<td class="color-border">内存最大容量</td>
|
||||
<td>
|
||||
<size-capacity-box :v-name="'fileMemoryCapacityJSON'" :v-count="0" :v-unit="'gb'"></size-capacity-box>
|
||||
<p class="comment">作为一级缓存的内存最大容量,可以作为硬盘缓冲区和存储热点缓存内容,如果为0表示不使用内存作为一级缓存。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<tbody v-if="policyType != 'file'">
|
||||
<tr>
|
||||
<td>缓存最大容量</td>
|
||||
<td>
|
||||
<size-capacity-box :v-name="'capacityJSON'" :v-value="cachePolicy.capacity" :v-count="0" :v-unit="'gb'"></size-capacity-box>
|
||||
<p class="comment">单个节点上允许缓存的最大容量,如果为0表示没有限制。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tr>
|
||||
<td>最大内容长度</td>
|
||||
<td>
|
||||
<size-capacity-box :v-value="cachePolicy.maxSize" :v-name="'maxSizeJSON'" :v-count="32" :v-unit="'mb'"></size-capacity-box>
|
||||
<p class="comment">允许缓存的单个内容最大尺寸,如果为0表示没有限制。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||
</tr>
|
||||
<tbody v-show="moreOptionsVisible && policyType == 'file'">
|
||||
<tr>
|
||||
<td class="color-border">缓存硬盘最小空余空间</td>
|
||||
<td>
|
||||
<size-capacity-box :v-name="'fileMinFreeSizeJSON'" :v-value="cachePolicy.options.minFreeSize" :key="'minFreeSizeJSON'"></size-capacity-box>
|
||||
<p class="comment">缓存硬盘保留的最小空余空间,如果为0表示使用默认(目前默认保留5GiB)。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">缓存文件句柄缓存</td>
|
||||
<td>
|
||||
<input type="text" name="fileOpenFileCacheMax" v-model="fileOpenFileCacheMax" maxlength="6" value="0" style="width: 10em"/>
|
||||
<p class="comment"><pro-warning-label></pro-warning-label>保持在内存中的缓存文件句柄的数量,提升缓存文件打开速度,同时也会占用系统更多的内存,建议数量不超过缓存文件数量的百分之一;0表示不启用。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="teaIsPlus">
|
||||
<td class="color-border">开启Sendfile</td>
|
||||
<td>
|
||||
<checkbox name="fileEnableSendfile" v-model="cachePolicy.options.enableSendfile"></checkbox>
|
||||
<p class="comment"><pro-warning-label></pro-warning-label><plus-label></plus-label>使用sendfile提升发送缓存文件的效率。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">允许读取不完整的Partial Content</td>
|
||||
<td>
|
||||
<checkbox name="enableIncompletePartialContent" v-model="cachePolicy.options.enableIncompletePartialContent"></checkbox>
|
||||
<p class="comment">允许在有一部分内容缓存的情况下读取分区内容,剩余的部分将会自动回源读取。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="false">
|
||||
<td class="color-border">启用MMAP</td>
|
||||
<td>
|
||||
<checkbox name="enableMMAP" v-model="cachePolicy.options.enableMMAP"></checkbox>
|
||||
<p class="comment">选中后,表示允许系统自动利用MMAP提升缓存读取性能。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody v-show="moreOptionsVisible">
|
||||
<tr>
|
||||
<td>同步写入压缩缓存</td>
|
||||
<td>
|
||||
<checkbox name="syncCompressionCache" v-model="cachePolicy.syncCompressionCache"></checkbox>
|
||||
<p class="comment">选中后,在压缩设置开启的情况下,在缓存源站内容的同时,也会同步写入压缩缓存;不选中,表示在源站内容缓存后,下一次调用才会缓存压缩内容,防止同一时间内硬盘IO负载过高。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>预热超时时间</td>
|
||||
<td>
|
||||
<time-duration-box :v-name="'fetchTimeoutJSON'" :v-value="cachePolicy.fetchTimeout" maxlength="6"></time-duration-box>
|
||||
<p class="comment">预热读取源站的超时时间,默认20分钟。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>描述</td>
|
||||
<td>
|
||||
<textarea maxlength="200" name="description" rows="3" v-model="cachePolicy.description"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>启用当前策略</td>
|
||||
<td>
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" name="isOn" value="1" v-model="cachePolicy.isOn"/>
|
||||
<label></label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h4>默认缓存条件</h4>
|
||||
<http-cache-refs-config-box :v-cache-refs="cachePolicy.cacheRefs" :v-cache-policy-id="cachePolicy.id" :v-max-bytes="cachePolicy.maxSize"></http-cache-refs-config-box>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
27
EdgeAdmin/web/views/@default/servers/components/cache/update.js
vendored
Normal file
27
EdgeAdmin/web/views/@default/servers/components/cache/update.js
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifyReloadSuccess("保存成功 ")
|
||||
|
||||
this.policyType = this.cachePolicy.type
|
||||
|
||||
this.fileOpenFileCacheMax = 0
|
||||
if (this.cachePolicy.type == "file" && this.cachePolicy.options.openFileCache != null && this.cachePolicy.options.openFileCache.isOn && this.cachePolicy.options.openFileCache.max > 0) {
|
||||
this.fileOpenFileCacheMax = this.cachePolicy.options.openFileCache.max
|
||||
}
|
||||
|
||||
this.changePolicyType = function () {
|
||||
if (this.policyType == "file") {
|
||||
let options = this.cachePolicy.options
|
||||
if (options != null && typeof options == "object" && typeof options["dir"] === "undefined") {
|
||||
options["enableMMAP"] = false
|
||||
options["enableIncompletePartialContent"] = true
|
||||
options["dir"] = "/opt/cache"
|
||||
options["memoryPolicy"] = {
|
||||
capacity: {
|
||||
unit: "gb",
|
||||
count: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,6 @@
|
||||
{$layout}
|
||||
{$template "/left_menu_top"}
|
||||
|
||||
<div class="right-box without-tabbar">
|
||||
<p class="ui message">此功能暂未开放敬请期待。</p>
|
||||
</div>
|
||||
@@ -0,0 +1,14 @@
|
||||
<second-menu>
|
||||
<menu-item href="/servers/components/waf">列表</menu-item>
|
||||
<span class="item">|</span>
|
||||
<menu-item :href="'/servers/components/waf/policy?firewallPolicyId=' + firewallPolicyId" code="index">{{firewallPolicyName}}</menu-item>
|
||||
<menu-item :href="'/servers/components/waf/groups?firewallPolicyId=' + firewallPolicyId + '&type=inbound'" code="inbound">入站规则({{countInboundGroups}})</menu-item>
|
||||
<menu-item :href="'/servers/components/waf/groups?firewallPolicyId=' + firewallPolicyId + '&type=outbound'" code="outbound">出站规则({{countOutboundGroups}})</menu-item>
|
||||
<menu-item :href="'/servers/components/waf/ipadmin?firewallPolicyId=' + firewallPolicyId" code="ipadmin">IP管理</menu-item>
|
||||
<menu-item :href="'/servers/components/waf/log?firewallPolicyId=' + firewallPolicyId" code="log">拦截日志</menu-item>
|
||||
<!-- TODO -->
|
||||
<!--<menu-item :href="'/servers/components/waf/test?firewallPolicyId=' + firewallPolicyId" code="test">测试</menu-item>-->
|
||||
<menu-item :href="'/servers/components/waf/import?firewallPolicyId=' + firewallPolicyId" code="import">导入</menu-item>
|
||||
<menu-item :href="'/servers/components/waf/export?firewallPolicyId=' + firewallPolicyId" code="export">导出</menu-item>
|
||||
<menu-item :href="'/servers/components/waf/update?firewallPolicyId=' + firewallPolicyId" code="update">修改</menu-item>
|
||||
</second-menu>
|
||||
@@ -0,0 +1,46 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>添加分组</h3>
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="firewallPolicyId" :value="firewallPolicyId"/>
|
||||
<input type="hidden" name="type" :value="type"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">分组名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="name" maxlength="100" ref="focus"/>
|
||||
<p class="comment">给分组起一个容易识别的名称</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>代号</td>
|
||||
<td>
|
||||
<input type="text" name="code" maxlength="100"/>
|
||||
<p class="comment">可选项,在导入时可以合并相同代号的分组。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||
</tr>
|
||||
<tbody v-show="moreOptionsVisible">
|
||||
<tr>
|
||||
<td>分组描述</td>
|
||||
<td>
|
||||
<textarea name="description" maxlength="200" rows="3"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>启用当前分组</td>
|
||||
<td>
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" name="isOn" value="1" checked="checked"/>
|
||||
<label></label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,44 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">策略名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="name" maxlength="100" ref="focus"/>
|
||||
<p class="comment">给策略起一个容易识别的名字。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>启用预置的规则</td>
|
||||
<td>
|
||||
<div class="ui checkbox" v-for="group in groups" style="width:10em;margin-bottom:0.5em">
|
||||
<input type="checkbox" name="groupCodes" :value="group.code" :id="'group-checkbox-' + group.code" v-model="group.isOn"/>
|
||||
<label :for="'group-checkbox-' + group.code">{{group.name}}</label>
|
||||
</div>
|
||||
<p class="comment">可以启用一些我们预置的规则组。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||
</tr>
|
||||
<tbody v-show="moreOptionsVisible">
|
||||
<tr>
|
||||
<td>描述</td>
|
||||
<td>
|
||||
<textarea name="description" rows="3"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>启用当前策略</td>
|
||||
<td>
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" name="isOn" value="1" checked="checked"/>
|
||||
<label></label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,234 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3 v-if="!isUpdating">添加规则</h3>
|
||||
<h3 v-if="isUpdating">修改规则</h3>
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="ruleId" :value="rule.id"/>
|
||||
<input type="hidden" name="optionsJSON" v-if="checkpoint != null && checkpoint.options != null" :value="JSON.stringify(checkpoint.options)"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">参数 *</td>
|
||||
<td>
|
||||
<select name="prefix" class="ui dropdown auto-width" @change="changeCheckpoint()" v-model="rule.checkpointPrefix">
|
||||
<option value="">[选择参数]</option>
|
||||
<optgroup label="特殊参数"></optgroup>
|
||||
<option v-for="cp in checkpoints" v-if="cp.isComposed" :value="cp.prefix">{{cp.name}} - [{{cp.prefix}}]</option>
|
||||
<optgroup label="通用参数"></optgroup>
|
||||
<option v-for="cp in checkpoints" v-if="!cp.isComposed" :value="cp.prefix">{{cp.name}} - [{{cp.prefix}}]</option>
|
||||
</select>
|
||||
<p class="comment" v-if="checkpoint != null"><span class="ui label tiny basic">${<em style="font-style: normal;">{{checkpoint.prefix}}</em>}</span>{{checkpoint.description}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- 参数名 -->
|
||||
<tr v-if="checkpoint != null && checkpoint.hasParams">
|
||||
<td>参数名</td>
|
||||
<td>
|
||||
<select name="param" v-model="rule.checkpointParam" class="ui dropdown auto-width" v-if="checkpoint.params != null">
|
||||
<option v-for="o in checkpoint.params" :value="o.value">{{o.name}}</option>
|
||||
</select>
|
||||
<input type="text" name="param" maxlength="100" v-model="rule.checkpointParam" v-if="checkpoint.params == null"/>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- 组合规则的选项 -->
|
||||
<tbody v-if="checkpoint != null && checkpoint.isComposed">
|
||||
<tr>
|
||||
<td colspan="2">配置选项</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<!-- 通用header -->
|
||||
<http-cond-general-header-length v-if="checkpoint.prefix == 'requestGeneralHeaderLength' || checkpoint.prefix == 'responseGeneralHeaderLength'" :v-checkpoint="checkpoint"></http-cond-general-header-length>
|
||||
|
||||
<!-- 防盗链 -->
|
||||
<http-firewall-checkpoint-referer-block v-if="checkpoint.prefix == 'refererBlock'" :v-checkpoint="checkpoint"></http-firewall-checkpoint-referer-block>
|
||||
|
||||
<!-- CC -->
|
||||
<http-firewall-checkpoint-cc v-if="checkpoint.prefix == 'cc2'" :v-checkpoint="checkpoint"></http-firewall-checkpoint-cc>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 选项 -->
|
||||
<tbody v-if="checkpoint != null && !checkpoint.isComposed && checkpoint.options != null && checkpoint.options.length > 0">
|
||||
<tr v-for="option in checkpoint.options">
|
||||
<td>{{option.name}}</td>
|
||||
<td>
|
||||
<div class="ui fields inline" v-if="option.type == 'field'">
|
||||
<div class="ui field">
|
||||
<input type="text" name="" :placeholder="option.placeholder" :maxlength="(option.maxLength > 0)?option.maxLength:1024" :size="option.size" v-model="option.value"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
{{option.rightLabel}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui fields inline" v-if="option.type == 'options'">
|
||||
<div class="ui field">
|
||||
<select class="ui dropdown" :style="'width:' + option.size + 'em'" name="" v-model="option.value">
|
||||
<option v-for="opt in option.options" :value="opt.value">{{opt.name}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
{{option.rightLabel}}
|
||||
</div>
|
||||
</div>
|
||||
<p class="comment" v-if="option.comment != null && option.comment.length > 0">{{option.comment}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<tbody v-show="checkpoint != null && !checkpoint.isComposed">
|
||||
<tr>
|
||||
<td>操作符 *</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" name="operator" v-model="rule.operator" @change="changeOperator()">
|
||||
<option v-for="op in operators" :value="op.code">{{op.name}}</option>
|
||||
</select>
|
||||
<p class="comment" v-if="operator != null" v-html="operator.description"></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="operator != null && operator.dataType != 'none'">
|
||||
<td>
|
||||
<span v-if="operator != null && operator.dataType == 'regexp'">匹配正则表达式</span>
|
||||
<span v-else-if="operator != null && operator.dataType == 'wildcard'">匹配单个通配符</span>
|
||||
<span v-else-if="operator != null && operator.dataType == 'number'">对比数字</span>
|
||||
<span v-else-if="operator != null && operator.dataType == 'string'">对比单个字符串</span>
|
||||
<span v-else-if="operator != null && operator.dataType == 'strings'">对比一组字符串</span>
|
||||
<span v-else-if="operator != null && operator.dataType == 'string|number'">对比单个字符串或数字</span>
|
||||
<span v-else-if="operator != null && operator.dataType == 'version'">对比单个版本号</span>
|
||||
<span v-else-if="operator != null && operator.dataType == 'versionRange'">对比版本号范围</span>
|
||||
<span v-else-if="operator != null && operator.dataType == 'ip'">对比单个IP</span>
|
||||
<span v-else-if="operator != null && operator.dataType == 'ips'">一组对比IP</span>
|
||||
<span v-else>对比值</span>
|
||||
</td>
|
||||
<td>
|
||||
<!-- 二进制数据 -->
|
||||
<div v-if="rule.operator == 'contains binary'">
|
||||
<textarea rows="3" maxlength="4096" name="value" v-model="rule.value"></textarea>
|
||||
<p class="comment">将二进制进行Base64Encode后放在这里,比如<code-label>Hello</code-label>对应<code-label>SGVsbG8=</code-label>。</p>
|
||||
</div>
|
||||
<div v-else-if="rule.operator == 'not contains binary'">
|
||||
<textarea rows="3" maxlength="4096" name="value" v-model="rule.value"></textarea>
|
||||
<p class="comment">将二进制进行Base64Encode后放在这里,比如<code-label>Hello</code-label>对应<code-label>SGVsbG8=</code-label>。</p>
|
||||
</div>
|
||||
|
||||
<!-- bool数据 -->
|
||||
<div v-else-if="checkpoint != null && checkpoint.dataType == 'bool'">
|
||||
<select name="value" class="ui selectable auto-width" v-model="rule.value" @change="changeRuleValue">
|
||||
<option value="">[请选择]</option>
|
||||
<option value="1">是(1)</option>
|
||||
<option value="0">否(0)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- wildcard -->
|
||||
<div v-else-if="operator != null && operator.dataType == 'wildcard'">
|
||||
<textarea rows="3" maxlength="4096" name="value" v-model="rule.value" @input="changeRuleValue"></textarea>
|
||||
<p class="comment">输入包含通配符的字符串,比如<code-label>Chrome/*</code-label>、<code-label>192.168.*.*</code-label>。</p>
|
||||
</div>
|
||||
|
||||
<!-- number -->
|
||||
<div v-else-if="operator != null && operator.dataType == 'number'">
|
||||
<input type="number" name="value" v-model="rule.value" @input="changeRuleValue" style="width: 16em" maxlength="30" placeholder="对比数字" step="any"/>
|
||||
<p class="comment">输入和参数对比的数字,比如<code-label>123</code-label>、<code-label>123.456</code-label>。</p>
|
||||
</div>
|
||||
|
||||
<!-- string|number -->
|
||||
<div v-else-if="operator != null && operator.dataType == 'string|number'">
|
||||
<input type="text" name="value" v-model="rule.value" @input="changeRuleValue" style="width: 16em" maxlength="30" placeholder="对比字符串或数字"/>
|
||||
<p class="comment">输入和参数对比的字符串或数字,比如<code-label>123</code-label>、<code-label>abc</code-label>。</p>
|
||||
</div>
|
||||
|
||||
<!-- version -->
|
||||
<div v-else-if="operator != null && operator.dataType == 'version'">
|
||||
<input type="text" name="value" v-model="rule.value" @input="changeRuleValue" style="width: 10em" maxlength="100" placeholder="对比版本号"/>
|
||||
<p class="comment">输入和参数对比的版本号,比如<code-label>1.2.7</code-label>。</p>
|
||||
</div>
|
||||
|
||||
<!-- versionRange -->
|
||||
<div v-else-if="operator != null && operator.dataType == 'versionRange'">
|
||||
<input type="text" name="value" v-model="rule.value" @input="changeRuleValue" style="width: 10em" maxlength="100" placeholder="版本号范围"/>
|
||||
<p class="comment">输入和参数对比的版本号范围,比如<code-label>1.2.7,1.3.7</code-label>。</p>
|
||||
</div>
|
||||
|
||||
<!-- IP -->
|
||||
<div v-else-if="operator != null && operator.dataType == 'ip'">
|
||||
<input type="text" name="value" v-model="rule.value" @input="changeRuleValue" style="width: 16em" maxlength="100" placeholder="对比IP"/>
|
||||
<p class="comment">输入和参数对比的IP,比如<code-label>192.168.2.100</code-label>。</p>
|
||||
</div>
|
||||
|
||||
<!-- 其余数据 -->
|
||||
<div v-else>
|
||||
<textarea rows="3" maxlength="4096" name="value" v-model="rule.value" @input="changeRuleValue"></textarea>
|
||||
<p class="comment" v-if="operator != null && operator.dataType == 'strings'">每行一个数据。</p>
|
||||
<p class="comment" v-if="operator != null && operator.dataType == 'regexp'">正则表达式中对于要匹配的内容中的特殊字符需要转义处理(即在字符前面加入反斜杠\),比如<code-label>.?*+()[]{}^$\</code-label>等符号要变成<code-label>\.\?\*\+\(\)\[\]\{\}\^\$\\</code-label>。</p>
|
||||
</div>
|
||||
<p class="comment" v-if="operator != null && operator.dataType == 'regexp' && rule.value.match(/\n/)"><span class="red">警告:发现你填写的正则表达式中包含了换行符,如果你的意图是每行都表示不同的选项,那么请使用竖杠(<code-label>|</code-label>)符号代替换行符,比如把<code-label>a换行b换行c换行</code-label>改成<code-label>a|b|c</code-label>,<a href="" @click.prevent="convertValueLine">[帮我转换]</a>。</span></p>
|
||||
|
||||
<!-- 特殊规则 -->
|
||||
<div style="margin-top: 1em">
|
||||
<!-- geo country name -->
|
||||
<div v-if="checkpoint != null && checkpoint.prefix == 'geoCountryName'" >
|
||||
<combo-box title="已添加" width="14em" data-url="/ui/countryOptions" data-key="countries" placeholder="点这里选择国家/地区" @change="selectGeoCountryName" ref="countryComboBox" key="combo-box-country"></combo-box>
|
||||
</div>
|
||||
|
||||
<!-- geo province name -->
|
||||
<div v-if="checkpoint != null && checkpoint.prefix == 'geoProvinceName'" >
|
||||
<combo-box title="已添加" data-url="/ui/provinceOptions" data-key="provinces" placeholder="点这里选择省份名称" @change="selectGeoProvinceName" ref="provinceComboBox" key="combo-box-province"></combo-box>
|
||||
</div>
|
||||
|
||||
<!-- geo city name -->
|
||||
<div v-if="checkpoint != null && checkpoint.prefix == 'geoCityName'" >
|
||||
<combo-box title="已添加" data-url="/ui/cityOptions" data-key="cities" placeholder="点这里选择城市名称" @change="selectGeoCityName" ref="cityComboBox" key="combo-box-city"></combo-box>
|
||||
</div>
|
||||
|
||||
<!-- ISP Name -->
|
||||
<div v-if="checkpoint != null && checkpoint.prefix == 'ispName'" >
|
||||
<combo-box title="已添加" data-url="/ui/providerOptions" data-key="providers" placeholder="点这里选择ISP名称" @change="selectISPName" ref="ispComboBox" key="combo-box-isp"></combo-box>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="operator != null && operator.dataType == 'regexp'">
|
||||
<td>正则表达式测试</td>
|
||||
<td>
|
||||
<a href="" v-if="!regexpTestIsOn" @click.prevent="changeRegexpTestIsOn">[输入测试字符串]</a>
|
||||
<div v-if="regexpTestIsOn">
|
||||
<textarea placeholder="输入要测试的内容" rows="3" v-model="regexpTestBody" ref="regexpTestBody" @input="changeRegexpTestBody"></textarea>
|
||||
<p class="comment">
|
||||
<span v-if="regexpTestResult.isOk" class="green">{{regexpTestResult.message}}</span>
|
||||
<span v-if="!regexpTestResult.isOk" class="red">{{regexpTestResult.message}}</span>
|
||||
|
||||
<a href="" @click.prevent="changeRegexpTestIsOn">[结束测试]</a>
|
||||
</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="(checkpoint == null || checkpoint.dataType != 'bool') && operator != null && operator.case != 'none'">
|
||||
<td>不区分大小写</td>
|
||||
<td>
|
||||
<div class="ui checkbox">
|
||||
<input name="case" type="checkbox" value="1" v-model="rule.isCaseInsensitive" @change="changeCaseInsensitive"/>
|
||||
<label></label>
|
||||
</div>
|
||||
<p class="comment">开启后忽略英文字母大小写</p>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- 参数过滤器 -->
|
||||
<tr v-if="checkpoint != null && !checkpoint.isComposed">
|
||||
<td>编解码</td>
|
||||
<td>
|
||||
<http-firewall-param-filters-box :v-filters="rule.paramFilters"></http-firewall-param-filters-box>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>备注</td>
|
||||
<td><input type="text" name="description" v-model="rule.description"/></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,231 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifyPopup
|
||||
|
||||
this.isUpdating = (window.parent.UPDATING_RULE != null)
|
||||
this.rule = {
|
||||
id: 0,
|
||||
param: "",
|
||||
paramFilters: [],
|
||||
checkpointPrefix: "",
|
||||
checkpointParam: "",
|
||||
value: "",
|
||||
isCaseInsensitive: false,
|
||||
operator: "match",
|
||||
checkpointOptions: null,
|
||||
description: "",
|
||||
isOn: true
|
||||
}
|
||||
if (window.parent.UPDATING_RULE != null) {
|
||||
this.rule = window.parent.UPDATING_RULE
|
||||
|
||||
let param = this.rule.param.substring(this.rule.param.indexOf("${") + 2, this.rule.param.indexOf("}"))
|
||||
let index = param.indexOf(".")
|
||||
if (index > 0) {
|
||||
this.rule.checkpointPrefix = param.substring(0, index)
|
||||
this.rule.checkpointParam = param.substring(index + 1)
|
||||
} else {
|
||||
this.rule.checkpointPrefix = param
|
||||
}
|
||||
this.$delay(function () {
|
||||
this.loadCheckpoint()
|
||||
if (this.rule.checkpointOptions != null && this.checkpoint != null && this.checkpoint.options != null) {
|
||||
let that = this
|
||||
this.checkpoint.options.forEach(function (option) {
|
||||
if (typeof (that.rule.checkpointOptions[option.code]) != "undefined") {
|
||||
option.value = that.rule.checkpointOptions[option.code]
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* checkpoint
|
||||
*/
|
||||
this.checkpoint = null
|
||||
|
||||
this.loadCheckpoint = function () {
|
||||
if (this.rule.checkpointPrefix.length == 0) {
|
||||
this.checkpoint = null
|
||||
return
|
||||
}
|
||||
let that = this
|
||||
this.checkpoint = this.checkpoints.$find(function (k, v) {
|
||||
return v.prefix == that.rule.checkpointPrefix
|
||||
})
|
||||
}
|
||||
|
||||
this.changeCheckpoint = function () {
|
||||
if (this.rule.checkpointPrefix.length == 0) {
|
||||
this.checkpoint = null
|
||||
return
|
||||
}
|
||||
let that = this
|
||||
this.checkpoint = this.checkpoints.$find(function (k, v) {
|
||||
return v.prefix == that.rule.checkpointPrefix
|
||||
})
|
||||
if (this.checkpoint == null) {
|
||||
return
|
||||
}
|
||||
switch (this.checkpoint.dataType) {
|
||||
case "bool":
|
||||
this.rule.operator = "eq"
|
||||
break
|
||||
case "number":
|
||||
this.rule.operator = "eq"
|
||||
break
|
||||
default:
|
||||
this.rule.operator = "match"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* operator
|
||||
*/
|
||||
this.changeOperator = function () {
|
||||
let that = this;
|
||||
this.operator = this.operators.$find(function (k, v) {
|
||||
return v.code == that.rule.operator
|
||||
})
|
||||
if (this.operator == null) {
|
||||
return
|
||||
}
|
||||
if (!this.isUpdating) {
|
||||
this.rule.isCaseInsensitive = (this.operator.case == "yes")
|
||||
}
|
||||
};
|
||||
this.changeOperator()
|
||||
|
||||
/**
|
||||
* caseInsensitive
|
||||
*/
|
||||
this.changeCaseInsensitive = function () {
|
||||
if (this.rule.operator == "match" || this.rule.operator == "not match") {
|
||||
if (this.regexpTestIsOn) {
|
||||
this.changeRegexpTestBody()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* value
|
||||
*/
|
||||
this.changeRuleValue = function () {
|
||||
if (this.rule.operator == "match" || this.rule.operator == "not match") {
|
||||
if (this.regexpTestIsOn) {
|
||||
this.changeRegexpTestBody()
|
||||
}
|
||||
} else {
|
||||
this.regexpTestIsOn = false
|
||||
this.regexpTestResult = {isOk: false, message: ""}
|
||||
}
|
||||
}
|
||||
|
||||
this.convertValueLine = function () {
|
||||
let value = this.rule.value
|
||||
if (value != null && value.length > 0) {
|
||||
let lines = value.split(/\n/)
|
||||
let resultLines = []
|
||||
lines.forEach(function (line) {
|
||||
line = line.trim()
|
||||
if (line.length > 0) {
|
||||
resultLines.push(line)
|
||||
}
|
||||
})
|
||||
this.rule.value = resultLines.join("|")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 正则测试
|
||||
*/
|
||||
this.regexpTestIsOn = false
|
||||
this.regexpTestBody = ""
|
||||
this.regexpTestResult = {isOk: false, message: ""}
|
||||
|
||||
this.changeRegexpTestIsOn = function () {
|
||||
this.regexpTestIsOn = !this.regexpTestIsOn
|
||||
if (this.regexpTestIsOn) {
|
||||
this.$delay(function () {
|
||||
this.$refs.regexpTestBody.focus()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
this.changeRegexpTestBody = function () {
|
||||
this.$post(".testRegexp")
|
||||
.params({
|
||||
"regexp": this.rule.value,
|
||||
"body": this.regexpTestBody,
|
||||
"isCaseInsensitive": this.rule.isCaseInsensitive
|
||||
})
|
||||
.success(function (resp) {
|
||||
this.regexpTestResult = resp.data.result
|
||||
})
|
||||
}
|
||||
|
||||
// isp
|
||||
this.selectISPName = function (isp) {
|
||||
if (isp == null) {
|
||||
return
|
||||
}
|
||||
|
||||
let ispName = isp.name
|
||||
this.$refs.ispComboBox.clear()
|
||||
|
||||
if (this.rule.value.length == 0) {
|
||||
this.rule.value = ispName
|
||||
} else {
|
||||
this.rule.value += "|" + ispName
|
||||
}
|
||||
}
|
||||
|
||||
// country
|
||||
this.selectGeoCountryName = function (country) {
|
||||
if (country == null) {
|
||||
return
|
||||
}
|
||||
|
||||
let countryName = country.name
|
||||
this.$refs.countryComboBox.clear()
|
||||
|
||||
if (this.rule.value.length == 0) {
|
||||
this.rule.value = countryName
|
||||
} else {
|
||||
this.rule.value += "|" + countryName
|
||||
}
|
||||
}
|
||||
|
||||
// province
|
||||
this.selectGeoProvinceName = function (province) {
|
||||
if (province == null) {
|
||||
return
|
||||
}
|
||||
|
||||
let provinceName = province.name
|
||||
this.$refs.provinceComboBox.clear()
|
||||
|
||||
if (this.rule.value.length == 0) {
|
||||
this.rule.value = provinceName
|
||||
} else {
|
||||
this.rule.value += "|" + provinceName
|
||||
}
|
||||
}
|
||||
|
||||
// city
|
||||
this.selectGeoCityName = function (city) {
|
||||
if (city == null) {
|
||||
return
|
||||
}
|
||||
|
||||
let cityName = city.name
|
||||
this.$refs.cityComboBox.clear()
|
||||
|
||||
if (this.rule.value.length == 0) {
|
||||
this.rule.value = cityName
|
||||
} else {
|
||||
this.rule.value += "|" + cityName
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,69 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>添加规则集</h3>
|
||||
|
||||
<p class="ui message" v-if="isGlobalPolicy">当前设置的规则集为WAF策略的规则集,将会应用于对应集群已经启用WAF的网站;如果你只是想设置某个网站相关的规则集,请到对应网站WAF功能中设置。</p>
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="groupId" :value="groupId"/>
|
||||
<input type="hidden" name="formType" :value="useCode ? 'code' : 'normal'"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">规则集名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="name" maxlength="100" ref="focus"/>
|
||||
<p class="comment">可以用来描述当前规则集用途。<a href="" @click.prevent="switchToCode"><span v-if="!useCode">[使用代码]</span><span v-else>[切换到常规表单]</span></a></p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- usual form -->
|
||||
<tbody v-show="!useCode">
|
||||
<tr>
|
||||
<td>规则 *</td>
|
||||
<td>
|
||||
<http-firewall-rules-box :v-rules="rules" :v-type="type"></http-firewall-rules-box>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="rules.length > 1">
|
||||
<td>规则之间的关系 *</td>
|
||||
<td>
|
||||
<select class="ui dropdown" name="connector" style="width:10em" @change="changeConnector()" v-model="selectedConnector">
|
||||
<option v-for="connector in connectors" :value="connector.value">{{connector.name}}</option>
|
||||
</select>
|
||||
<p class="comment">{{selectedConnectorDescription}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>执行动作 *</td>
|
||||
<td>
|
||||
<http-firewall-actions-box :v-actions="actions" :v-firewall-policy="firewallPolicy" :v-group-type="type"></http-firewall-actions-box>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>允许局域网IP</td>
|
||||
<td>
|
||||
<checkbox name="ignoreLocal"></checkbox>
|
||||
<p class="comment">选中后,表示如果请求来自局域网IP,则直接跳过当前规则集。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>允许搜索引擎</td>
|
||||
<td>
|
||||
<checkbox name="ignoreSearchEngine"></checkbox>
|
||||
<p class="comment">选中后,表示如果请求来自常见搜索引擎的IP,则直接跳过当前规则集。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- code form -->
|
||||
<tbody v-show="useCode">
|
||||
<tr>
|
||||
<td>规则集代码 *</td>
|
||||
<td>
|
||||
<textarea name="code" ref="codeInput" placeholder="{ ... 规则集代码 ... }" rows="20"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,55 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifyPopup
|
||||
|
||||
// rules
|
||||
this.rules = []
|
||||
|
||||
// connector
|
||||
this.selectedConnector = this.connectors[1].value
|
||||
this.selectedConnectorDescription = ""
|
||||
this.changeConnector = function () {
|
||||
let that = this
|
||||
this.selectedConnectorDescription = this.connectors.$find(function (k, v) {
|
||||
return v.value == that.selectedConnector
|
||||
}).description
|
||||
}
|
||||
this.changeConnector()
|
||||
|
||||
// action
|
||||
this.action = "block"
|
||||
|
||||
// action:go_group
|
||||
this.actionGroupId = 0
|
||||
|
||||
// action:go_set
|
||||
this.actionSetId = 0
|
||||
this.groupSets = function (groupId) {
|
||||
let group = null
|
||||
this.firewallPolicy.inbound.groups.forEach(function (v) {
|
||||
if (v.id == groupId) {
|
||||
group = v
|
||||
}
|
||||
})
|
||||
this.firewallPolicy.outbound.groups.forEach(function (v) {
|
||||
if (v.id == groupId) {
|
||||
group = v
|
||||
}
|
||||
})
|
||||
if (group == null) {
|
||||
return []
|
||||
}
|
||||
return group.sets
|
||||
}
|
||||
|
||||
// 使用代码
|
||||
this.useCode = false
|
||||
this.switchToCode = function () {
|
||||
this.useCode = !this.useCode
|
||||
|
||||
if (this.useCode) {
|
||||
this.$delay(function () {
|
||||
this.$refs.codeInput.focus()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,7 @@
|
||||
.groups-box .group-box {
|
||||
float: left;
|
||||
width: 11em;
|
||||
margin-top: 0.1em;
|
||||
margin-bottom: 0.6em;
|
||||
}
|
||||
/*# sourceMappingURL=export.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["export.less"],"names":[],"mappings":"AAAA,WACC;EACC,WAAA;EACA,WAAA;EACA,iBAAA;EACA,oBAAA","file":"export.css"}
|
||||
@@ -0,0 +1,53 @@
|
||||
{$layout}
|
||||
{$template "waf_menu"}
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
<input type="hidden" name="firewallPolicyId" :value="firewallPolicyId"/>
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">启用的入站规则</td>
|
||||
<td>
|
||||
<span v-if="enabledInboundGroups.length == 0" class="disabled">暂时还没有入站规则。</span>
|
||||
<div class="groups-box" v-show="enabledInboundGroups.length > 0">
|
||||
<div v-for="g in enabledInboundGroups" class="group-box">
|
||||
<checkbox name="inboundGroupIds" :value="true" :v-value="g.id">{{g.name}}</checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="disabledInboundGroups.length > 0">
|
||||
<td class="title">停用的入站规则</td>
|
||||
<td>
|
||||
<div class="groups-box" v-show="disabledInboundGroups.length > 0">
|
||||
<div v-for="g in disabledInboundGroups" class="group-box">
|
||||
<checkbox name="inboundGroupIds" :value="false" :v-value="g.id">{{g.name}} <sup><span class="red">停用</span></sup></checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>启用的出站规则</td>
|
||||
<td>
|
||||
<span v-if="enabledOutboundGroups.length == 0" class="disabled">暂时还没有出站规则。</span>
|
||||
<div class="groups-box" v-show="enabledOutboundGroups.length > 0">
|
||||
<div v-for="g in enabledOutboundGroups" class="group-box">
|
||||
<checkbox name="outboundGroupIds" :value="true" :v-value="g.id">{{g.name}}</checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="disabledOutboundGroups.length > 0">
|
||||
<td>停用的出站规则</td>
|
||||
<td>
|
||||
<div class="groups-box" v-show="disabledOutboundGroups.length > 0">
|
||||
<div v-for="g in disabledOutboundGroups" class="group-box">
|
||||
<checkbox name="outboundGroupIds" :value="false" :v-value="g.id">{{g.name}} <sup><span class="red">停用</span></sup></checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn>导出</submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,5 @@
|
||||
Tea.context(function () {
|
||||
this.success = function (resp) {
|
||||
window.location = "/servers/components/waf/exportDownload?key=" + resp.data.key + "&policyId=" + resp.data.id
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,8 @@
|
||||
.groups-box {
|
||||
.group-box {
|
||||
float: left;
|
||||
width: 11em;
|
||||
margin-top: 0.1em;
|
||||
margin-bottom: 0.6em;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
{$layout}
|
||||
|
||||
{$template "waf_menu"}
|
||||
|
||||
<h3>分组<a href="" @click.prevent="updateGroup(group.id)">[修改]</a></h3>
|
||||
<table class="ui table selectable definition">
|
||||
<tr>
|
||||
<td class="title">名称</td>
|
||||
<td>{{group.name}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>代号</td>
|
||||
<td>
|
||||
<span v-if="group.code.length > 0">{{group.code}}</span>
|
||||
<span v-else class="disabled">没有设置。</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>描述</td>
|
||||
<td>
|
||||
<span v-if="group.description.length == 0" class="disabled">暂时还没有描述。</span>
|
||||
<span v-if="group.description.length > 0">{{group.description}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>启用状态</td>
|
||||
<td>
|
||||
<label-on :v-is-on="group.isOn"></label-on>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h3 style="padding-top:0.8em">规则集<a href="" @click.prevent="createSet(group.id)">[添加规则集]</a> </h3>
|
||||
<p class="comment" v-if="sets == null || sets.length == 0">暂时还没有规则。</p>
|
||||
<table class="ui table selectable celled" id="sortable-table" v-if="sets != null && sets.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:3em"></th>
|
||||
<th nowrap="">规则集名称</th>
|
||||
<th nowrap="">规则</th>
|
||||
<th nowrap="" class="center one wide">规则关系</th>
|
||||
<th nowrap="">动作</th>
|
||||
<th class="three op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody v-for="set in sets" :data-set-id="set.id">
|
||||
<tr>
|
||||
<td style="text-align: center;"><i class="icon bars handle grey"></i></td>
|
||||
<td nowrap=""><a :name="'set' + set.id"></a><a href="" @click.prevent="updateSet(set.id)"><span :class="{disabled:!set.isOn}">{{set.name}}</span> <i class="icon expand small"></i> </a>
|
||||
<p style="margin-top:0.5em">
|
||||
<label-on :v-is-on="set.isOn"></label-on>
|
||||
</p>
|
||||
</td>
|
||||
<td class="rules-box">
|
||||
<div v-for="rule in set.rules" style="margin-top: 0.4em;margin-bottom:0.4em">
|
||||
<http-firewall-rule-label :v-rule="rule"></http-firewall-rule-label>
|
||||
</div>
|
||||
<span class="ui disabled" v-if="set.rules.length == 0">暂时还没有规则</span>
|
||||
</td>
|
||||
<td class="center">
|
||||
<span v-if="set.connector.toUpperCase() == 'OR'">或</span><span v-else>和</span>
|
||||
<span class="small grey">({{set.connector.toUpperCase()}})</span>
|
||||
</td>
|
||||
<td nowrap="">
|
||||
<http-firewall-actions-view :v-actions="set.actions"></http-firewall-actions-view>
|
||||
</td>
|
||||
<td>
|
||||
<a href="" @click.prevent="updateSet(set.id)">修改</a> <a href="" @click.prevent="updateSetOn(set.id, false)" v-if="set.isOn">停用</a><a href="" @click.prevent="updateSetOn(set.id, true)" v-if="!set.isOn"><span class="red">启用</span></a> <a href="" @click.prevent="deleteSet(set.id)">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p class="comment" v-if="group.sets != null && group.sets.length > 1">所有规则匹配顺序为从上到下,可以拖动左侧的<i class="icon bars"></i>排序。</p>
|
||||
82
EdgeAdmin/web/views/@default/servers/components/waf/group.js
Normal file
82
EdgeAdmin/web/views/@default/servers/components/waf/group.js
Normal file
@@ -0,0 +1,82 @@
|
||||
Tea.context(function () {
|
||||
this.$delay(function () {
|
||||
let that = this
|
||||
sortTable(function () {
|
||||
let setIds = []
|
||||
document
|
||||
.querySelectorAll("tbody[data-set-id]")
|
||||
.forEach(function (v) {
|
||||
setIds.push(v.getAttribute("data-set-id"))
|
||||
})
|
||||
that.$post(".sortSets")
|
||||
.params({
|
||||
groupId: that.group.id,
|
||||
setIds: setIds
|
||||
})
|
||||
.success(function () {
|
||||
teaweb.successToast("排序保存成功")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// 更改分组
|
||||
this.updateGroup = function (groupId) {
|
||||
teaweb.popup("/servers/components/waf/updateGroupPopup?groupId=" + groupId, {
|
||||
height: "20em",
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
window.location.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 创建规则集
|
||||
this.createSet = function (groupId) {
|
||||
teaweb.popup("/servers/components/waf/createSetPopup?firewallPolicyId=" + this.firewallPolicyId + "&groupId=" + groupId + "&type=" + this.type, {
|
||||
width: "50em",
|
||||
height: "40em",
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
window.location.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 修改规则集
|
||||
this.updateSet = function (setId) {
|
||||
teaweb.popup("/servers/components/waf/updateSetPopup?firewallPolicyId=" + this.firewallPolicyId + "&groupId=" + this.group.id + "&type=" + this.type + "&setId=" + setId, {
|
||||
width: "50em",
|
||||
height: "40em",
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
window.location.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 停用|启用规则集
|
||||
this.updateSetOn = function (setId, isOn) {
|
||||
this.$post(".updateSetOn")
|
||||
.params({
|
||||
setId: setId,
|
||||
isOn: isOn ? 1 : 0
|
||||
})
|
||||
.refresh()
|
||||
}
|
||||
|
||||
// 删除规则集
|
||||
this.deleteSet = function (setId) {
|
||||
let that = this
|
||||
teaweb.confirm("确定要删除此规则集吗?", function () {
|
||||
that.$post(".deleteSet")
|
||||
.params({
|
||||
groupId: this.group.id,
|
||||
setId: setId
|
||||
})
|
||||
.refresh()
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,45 @@
|
||||
{$layout}
|
||||
|
||||
{$template "waf_menu"}
|
||||
|
||||
<second-menu style="margin-top:-1em">
|
||||
<a href="" class="item" @click.prevent="createGroup(type)">[添加分组]</a>
|
||||
</second-menu>
|
||||
|
||||
<p class="comment" v-if="groups.length == 0">暂时还没有规则分组。</p>
|
||||
|
||||
<table class="ui table selectable celled" v-if="groups.length > 0" id="sortable-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:3em"></th>
|
||||
<th>规则分组</th>
|
||||
<th class="center">规则集</th>
|
||||
<th class="three op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody v-for="group in groups" :data-group-id="group.id">
|
||||
<tr>
|
||||
<td style="text-align: center;"><i class="icon bars handle grey" title="拖动排序"></i> </td>
|
||||
<td><a :href="'/servers/components/waf/group?firewallPolicyId=' + firewallPolicyId + '&type=' + type + '&groupId=' + group.id"><span :class="{disabled:!group.isOn}">{{group.name}}</span></a>
|
||||
<p class="comment" v-if="group.description.length > 0" style="padding-bottom:0">{{group.description}}</p>
|
||||
<p style="margin-top: 0.5em">
|
||||
<span v-if="group.isOn" class="ui label tiny basic green">启用</span>
|
||||
<span v-if="!group.isOn" class="ui label tiny basic red">停用</span>
|
||||
<span v-if="group.isTemplate" class="ui label basic tiny">预置</span>
|
||||
<span v-if="!group.isTemplate" class="ui label basic tiny">自定义</span>
|
||||
<span v-if="group.code.length > 0" class="ui label basic tiny">代号:{{group.code}}</span>
|
||||
</p>
|
||||
</td>
|
||||
<td class="center">
|
||||
<a :href="'/servers/components/waf/group?firewallPolicyId=' + firewallPolicyId + '&type=' + type + '&groupId=' + group.id">{{group.countSets}}</a>
|
||||
</td>
|
||||
<td>
|
||||
<a :href="'/servers/components/waf/group?firewallPolicyId=' + firewallPolicyId + '&type=' + type + '&groupId=' + group.id">详情</a>
|
||||
<a href="" v-if="!group.isOn" @click.prevent="enableGroup(group.id)">启用</a><a href="" v-if="group.isOn" @click.prevent="disableGroup(group.id)">停用</a>
|
||||
<a href="" @click.prevent="deleteGroup(group.id)" v-if="group.canDelete">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p class="comment" v-if="groups.length > 0">所有规则匹配顺序为从上到下,可以拖动左侧的<i class="icon bars"></i>排序。</p>
|
||||
@@ -0,0 +1,67 @@
|
||||
Tea.context(function () {
|
||||
// 排序
|
||||
this.$delay(function () {
|
||||
let that = this
|
||||
sortTable(function () {
|
||||
let groupIds = []
|
||||
document.querySelectorAll("tbody[data-group-id]")
|
||||
.forEach(function (v) {
|
||||
groupIds.push(v.getAttribute("data-group-id"))
|
||||
})
|
||||
|
||||
that.$post(".sortGroups")
|
||||
.params({
|
||||
firewallPolicyId: that.firewallPolicyId,
|
||||
type: that.type,
|
||||
groupIds: groupIds
|
||||
})
|
||||
.success(function () {
|
||||
teaweb.successToast("排序保存成功")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// 启用
|
||||
this.enableGroup = function (groupId) {
|
||||
this.$post(".updateGroupOn")
|
||||
.params({
|
||||
groupId: groupId,
|
||||
isOn: 1
|
||||
})
|
||||
.refresh()
|
||||
|
||||
}
|
||||
|
||||
// 停用
|
||||
this.disableGroup = function (groupId) {
|
||||
this.$post(".updateGroupOn")
|
||||
.params({
|
||||
groupId: groupId,
|
||||
isOn: 0
|
||||
})
|
||||
.refresh()
|
||||
}
|
||||
|
||||
// 删除
|
||||
this.deleteGroup = function (groupId) {
|
||||
teaweb.confirm("确定要删除此规则分组吗?", function () {
|
||||
this.$post(".deleteGroup")
|
||||
.params({
|
||||
firewallPolicyId: this.firewallPolicyId,
|
||||
groupId: groupId
|
||||
})
|
||||
.refresh()
|
||||
})
|
||||
}
|
||||
|
||||
// 添加分组
|
||||
this.createGroup = function (type) {
|
||||
teaweb.popup("/servers/components/waf/createGroupPopup?firewallPolicyId=" + this.firewallPolicyId + "&type=" + type, {
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
window.location.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,17 @@
|
||||
{$layout}
|
||||
{$template "waf_menu"}
|
||||
|
||||
<form method="post" class="ui form" data-tea-success="success" data-tea-action="$" data-tea-before="beforeSubmit" data-tea-fail="fail">
|
||||
<csrf-token></csrf-token>
|
||||
<input type="hidden" name="firewallPolicyId" :value="firewallPolicyId"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">选择要导入的规则文件</td>
|
||||
<td>
|
||||
<input type="file" name="file" accept=".json"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn v-if="!isRequesting">导入</submit-btn>
|
||||
<button class="ui button" type="button" v-if="isRequesting">处理中...</button>
|
||||
</form>
|
||||
@@ -0,0 +1,23 @@
|
||||
Tea.context(function () {
|
||||
this.isRequesting = false
|
||||
this.beforeSubmit = function () {
|
||||
this.isRequesting = true
|
||||
}
|
||||
this.success = function (resp) {
|
||||
this.isRequesting = false
|
||||
if(resp.data.key){
|
||||
return teaweb.success("部分规则解析失败,请查阅错误规则表格", function () {
|
||||
window.location = "/servers/components/waf/importErr?key=" + resp.data.key;
|
||||
});
|
||||
}else{
|
||||
return teaweb.success("导入成功", function () {
|
||||
window.location.reload()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.fail = function (resp) {
|
||||
this.isRequesting = false
|
||||
Tea.failResponse(resp)
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,63 @@
|
||||
{$layout}
|
||||
|
||||
<first-menu>
|
||||
<menu-item href="/servers/components/waf" code="index">列表</menu-item>
|
||||
<span class="item">|</span>
|
||||
<a href="" class="item" @click.prevent="createPolicy()">[创建]</a>
|
||||
</first-menu>
|
||||
|
||||
<!-- 搜索 -->
|
||||
<div class="margin"></div>
|
||||
<form class="ui form" method="get" action="/servers/components/waf">
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<node-cluster-combo-box :v-cluster-id="clusterId"></node-cluster-combo-box>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<input type="text" name="keyword" v-model="keyword" placeholder="策略名称..."/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button type="submit" class="ui button">搜索</button>
|
||||
|
||||
<a :href="Tea.url('.')" v-if="keyword.length > 0 || clusterId > 0">[清除条件]</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- 列表 -->
|
||||
<p class="comment" v-if="policies.length == 0">暂时还没有WAF策略。</p>
|
||||
|
||||
<table class="ui table selectable celled" v-if="policies.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>策略名称</th>
|
||||
<th class="center">入站规则分组</th>
|
||||
<th class="center">出站规则分组</th>
|
||||
<th class="center">集群数</th>
|
||||
<th class="two wide center">状态</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="policy in policies">
|
||||
<td><a :href="'/servers/components/waf/policy?firewallPolicyId=' + policy.id"><keyword :v-word="keyword">{{policy.name}}</keyword></a></td>
|
||||
<td class="center">
|
||||
<a :href="'/servers/components/waf/groups?firewallPolicyId=' + policy.id + '&type=inbound'"><span :class="{disabled:policy.countInbound == 0 }">{{policy.countInbound}}</span></a>
|
||||
</td>
|
||||
<td class="center">
|
||||
<a :href="'/servers/components/waf/groups?firewallPolicyId=' + policy.id + '&type=outbound'"><span :class="{disabled:policy.countOutbound == 0 }">{{policy.countOutbound}}</span></a>
|
||||
</td>
|
||||
<td class="center">{{policy.countClusters}}</td>
|
||||
<td class="center">
|
||||
<span v-if="!policy.isOn" class="red">已停用</span>
|
||||
<div v-else-if="policy.modeInfo != null">
|
||||
<span :class="{green: policy.modeInfo.code == 'defend', blue: policy.modeInfo.code == 'observe', grey: policy.modeInfo.code == 'bypass'}">{{policy.modeInfo.name}}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<a :href="'/servers/components/waf/policy?firewallPolicyId=' + policy.id">详情</a>
|
||||
<a href="" @click.prevent="deletePolicy(policy.id)">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
25
EdgeAdmin/web/views/@default/servers/components/waf/index.js
Normal file
25
EdgeAdmin/web/views/@default/servers/components/waf/index.js
Normal file
@@ -0,0 +1,25 @@
|
||||
Tea.context(function () {
|
||||
// 创建策略
|
||||
this.createPolicy = function () {
|
||||
teaweb.popup("/servers/components/waf/createPopup", {
|
||||
height: "27em",
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
window.location.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 删除策略
|
||||
this.deletePolicy = function (policyId) {
|
||||
let that = this
|
||||
teaweb.confirm("确定要删除此WAF策略吗?", function () {
|
||||
that.$post("/servers/components/waf/delete")
|
||||
.params({
|
||||
firewallPolicyId: policyId
|
||||
})
|
||||
.refresh()
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,9 @@
|
||||
<second-menu style="margin-top:-1em">
|
||||
<menu-item :href="'/servers/components/waf/ipadmin?firewallPolicyId=' + firewallPolicyId" :active="subMenuItem == 'region'">国家/地区封禁</menu-item>
|
||||
<menu-item :href="'/servers/components/waf/ipadmin/provinces?firewallPolicyId=' + firewallPolicyId" :active="subMenuItem == 'province'">省份封禁</menu-item>
|
||||
<span class="item disabled">|</span>
|
||||
<menu-item :href="'/servers/components/waf/ipadmin/lists?firewallPolicyId=' + firewallPolicyId + '&type=white'" :active="subMenuItem == 'white'">白名单</menu-item>
|
||||
<menu-item :href="'/servers/components/waf/ipadmin/lists?firewallPolicyId=' + firewallPolicyId + '&type=black'" :active="subMenuItem == 'black'">黑名单</menu-item>
|
||||
<menu-item :href="'/servers/components/waf/ipadmin/lists?firewallPolicyId=' + firewallPolicyId + '&type=grey'" :active="subMenuItem == 'grey'">灰名单</menu-item>
|
||||
<menu-item :href="'/servers/components/waf/ipadmin/test?firewallPolicyId=' + firewallPolicyId" :active="subMenuItem == 'test'">IP检查</menu-item>
|
||||
</second-menu>
|
||||
@@ -0,0 +1,16 @@
|
||||
.region-letter-group .item {
|
||||
padding-left: 1em !important;
|
||||
padding-right: 1em !important;
|
||||
}
|
||||
.country-group {
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
.country-group .country-list .item {
|
||||
float: left;
|
||||
width: 12em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
.country-group .country-list .item .checkbox label {
|
||||
font-size: 12px !important;
|
||||
}
|
||||
/*# sourceMappingURL=index.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA,oBACC;EACC,4BAAA;EACA,6BAAA;;AAIF;EAaC,mBAAA;;AAbD,cACC,cACC;EACC,WAAA;EACA,WAAA;EACA,oBAAA;;AALH,cACC,cACC,MAKC,UAAU;EACT,0BAAA","file":"index.css"}
|
||||
@@ -0,0 +1,53 @@
|
||||
{$layout}
|
||||
|
||||
{$template "../waf_menu"}
|
||||
{$template "menu"}
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="firewallPolicyId" :value="firewallPolicyId"/>
|
||||
<input type="hidden" name="exceptURLPatternsJSON" :value="JSON.stringify(exceptURLPatterns)"/>
|
||||
<input type="hidden" name="onlyURLPatternsJSON" :value="JSON.stringify(onlyURLPatterns)"/>
|
||||
<table class="ui table selectable definition">
|
||||
<tr>
|
||||
<td class="title">仅允许的区域</td>
|
||||
<td>
|
||||
<http-firewall-region-selector :v-countries="allowedCountries" :v-type="'allow'" @change="changeAllowedCountries"></http-firewall-region-selector>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="title">仅封禁的区域</td>
|
||||
<td>
|
||||
<p class="comment" v-if="allowedCountries.length > 0">由于你已设置"仅允许的区域",所以不需要再设置封禁区域。</p>
|
||||
<http-firewall-region-selector :v-countries="deniedCountries" :v-type="'deny'" v-show="allowedCountries.length == 0"></http-firewall-region-selector>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||
</tr>
|
||||
<tbody v-show="moreOptionsVisible">
|
||||
<tr>
|
||||
<td>例外URL <tip-icon content="对这些URL将不做任何限制。"></tip-icon></td>
|
||||
<td><url-patterns-box v-model="exceptURLPatterns"></url-patterns-box></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>限制URL <tip-icon content="只对这些URL做限制。"></tip-icon></td>
|
||||
<td><url-patterns-box v-model="onlyURLPatterns"></url-patterns-box></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>提示内容</td>
|
||||
<td>
|
||||
<textarea v-model="countryHTML" name="countryHTML" rows="3"></textarea>
|
||||
<p class="comment">当客户端所在区域被封禁时提示页面的HTML内容;不填则表示使用默认的提示内容;支持请求变量。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>允许搜索引擎</td>
|
||||
<td>
|
||||
<checkbox name="allowSearchEngine" v-model="allowSearchEngine"></checkbox>
|
||||
<p class="comment">选中后,表示如果请求来自常见搜索引擎的IP,则不受区域限制。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,11 @@
|
||||
Tea.context(function () {
|
||||
this.success = function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
|
||||
this.changeAllowedCountries = function (event) {
|
||||
this.allowedCountries = event.countries
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,22 @@
|
||||
.region-letter-group {
|
||||
.item {
|
||||
padding-left: 1em !important;
|
||||
padding-right: 1em !important;
|
||||
}
|
||||
}
|
||||
|
||||
.country-group {
|
||||
.country-list {
|
||||
.item {
|
||||
float: left;
|
||||
width: 12em;
|
||||
margin-bottom: 0.5em;
|
||||
|
||||
.checkbox label {
|
||||
font-size: 12px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{$layout}
|
||||
{$template "../waf_menu"}
|
||||
{$template "menu"}
|
||||
|
||||
<second-menu style="margin-top: -1em">
|
||||
<a href="" class="item" @click.prevent="createIP">添加IP</a>
|
||||
<span class="item disabled">|</span>
|
||||
<div class="item"><ip-list-bind-box :v-http-firewall-policy-id="firewallPolicyId" :v-type="type"></ip-list-bind-box></div>
|
||||
<span class="item disabled">|</span>
|
||||
<span class="item">ID: {{listId}} <tip-icon content="ID可以用于使用API操作此IP名单"></tip-icon></span>
|
||||
</second-menu>
|
||||
|
||||
<p class="comment" v-if="items.length == 0">暂时还没有IP。</p>
|
||||
|
||||
<ip-list-table v-if="items.length > 0" :v-items="items" @update-item="updateItem" @delete-item="deleteItem"></ip-list-table>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
@@ -0,0 +1,39 @@
|
||||
Tea.context(function () {
|
||||
this.updateItem = function (itemId) {
|
||||
teaweb.popup(Tea.url(".updateIPPopup?firewallPolicyId=" + this.firewallPolicyId, {itemId: itemId}), {
|
||||
height: "30em",
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.deleteItem = function (itemId) {
|
||||
let that = this
|
||||
teaweb.confirm("确定要删除这个IP吗?", function () {
|
||||
that.$post(".deleteIP")
|
||||
.params({
|
||||
"firewallPolicyId": this.firewallPolicyId,
|
||||
"itemId": itemId
|
||||
})
|
||||
.refresh()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加IP名单菜单
|
||||
*/
|
||||
this.createIP = function (type) {
|
||||
let that = this
|
||||
teaweb.popup("/servers/iplists/createIPPopup?listId=" + this.listId + '&type=' + type, {
|
||||
height: "30em",
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,9 @@
|
||||
.province-list .item {
|
||||
float: left;
|
||||
width: 12em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
.province-list .item .checkbox label {
|
||||
font-size: 12px !important;
|
||||
}
|
||||
/*# sourceMappingURL=provinces.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["provinces.less"],"names":[],"mappings":"AAAA,cACC;EACC,WAAA;EACA,WAAA;EACA,oBAAA;;AAJF,cACC,MAKC,UAAU;EACT,0BAAA","file":"provinces.css"}
|
||||
@@ -0,0 +1,46 @@
|
||||
{$layout}
|
||||
|
||||
{$template "../waf_menu"}
|
||||
{$template "menu"}
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="firewallPolicyId" :value="firewallPolicyId"/>
|
||||
<input type="hidden" name="exceptURLPatternsJSON" :value="JSON.stringify(exceptURLPatterns)"/>
|
||||
<input type="hidden" name="onlyURLPatternsJSON" :value="JSON.stringify(onlyURLPatterns)"/>
|
||||
<table class="ui table selectable definition">
|
||||
<tr>
|
||||
<td class="title">仅允许的省份</td>
|
||||
<td>
|
||||
<http-firewall-province-selector :v-provinces="allowedProvinces" :v-type="'allow'" @change="changeAllowedProvinces"></http-firewall-province-selector>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="title">仅封禁的省份</td>
|
||||
<td>
|
||||
<p class="comment" v-if="allowedProvinces.length > 0">由于你已设置"仅允许的省份",所以不需要再设置封禁省份。</p>
|
||||
<http-firewall-province-selector :v-provinces="deniedProvinces" :v-type="'deny'" v-show="allowedProvinces.length == 0"></http-firewall-province-selector>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||
</tr>
|
||||
<tbody v-show="moreOptionsVisible">
|
||||
<tr>
|
||||
<td>例外URL <tip-icon content="对这些URL将不做任何限制。"></tip-icon></td>
|
||||
<td><url-patterns-box v-model="exceptURLPatterns"></url-patterns-box></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>限制URL <tip-icon content="只对这些URL做限制。"></tip-icon></td>
|
||||
<td><url-patterns-box v-model="onlyURLPatterns"></url-patterns-box></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>提示内容</td>
|
||||
<td>
|
||||
<textarea v-model="provinceHTML" name="provinceHTML" rows="3"></textarea>
|
||||
<p class="comment">当客户端所在省份被封禁时提示页面的HTML内容;不填则表示使用默认的提示内容;支持请求变量。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,12 @@
|
||||
Tea.context(function () {
|
||||
this.success = function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
this.changeAllowedProvinces = function (event) {
|
||||
this.allowedProvinces = event.provinces
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,11 @@
|
||||
.province-list {
|
||||
.item {
|
||||
float: left;
|
||||
width: 12em;
|
||||
margin-bottom: 0.5em;
|
||||
|
||||
.checkbox label {
|
||||
font-size: 12px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{$layout}
|
||||
{$template "../waf_menu"}
|
||||
{$template "menu"}
|
||||
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="firewallPolicyId" :value="firewallPolicyId"/>
|
||||
<table class="ui table selectable definition">
|
||||
<tr>
|
||||
<td class="title">IP *</td>
|
||||
<td>
|
||||
<input type="text" name="ip" class="text" maxlength="100" ref="focus" placeholder="x.x.x.x" v-model="ip"/>
|
||||
<p class="comment">要检查的IP</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>检查结果</td>
|
||||
<td>
|
||||
<div v-if="result.isDone">
|
||||
<div v-if="!result.isOk">
|
||||
<span class="red">{{result.error}}</span>
|
||||
</div>
|
||||
<div v-if="result.isFound">
|
||||
<div v-if="result.item != null">
|
||||
<div v-if="result.isAllowed">
|
||||
<span class="green">在 {{result.list.name}} 中 <ip-item-text :v-item="result.item"></ip-item-text> <a href="" @click.prevent="updateItem(result.item.id)" title="查看和修改"><i class="icon pencil small"></i></a></span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<span class="red">在 {{result.list.name}} 中 <ip-item-text :v-item="result.item"></ip-item-text> <a href="" @click.prevent="updateItem( result.item.id)" title="查看和修改"><i class="icon pencil small"></i></a></span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="result.province != null">
|
||||
<span class="red">在省份封禁中 "{{result.province.name}}"</span>
|
||||
</div>
|
||||
<div v-if="result.country != null && result.province == null">
|
||||
<span class="red">在国家/地区封禁中 "{{result.country.name}}"</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!result.isFound">
|
||||
没有找到和{{ip}}匹配的配置。
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn>检查IP状态</submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,50 @@
|
||||
Tea.context(function () {
|
||||
this.ip = ""
|
||||
this.result = {
|
||||
isDone: false,
|
||||
isOk: false,
|
||||
isFound: false,
|
||||
isAllowed: false,
|
||||
error: "",
|
||||
province: null,
|
||||
country: null,
|
||||
ipItem: null,
|
||||
ipList: null
|
||||
}
|
||||
|
||||
this.$delay(function () {
|
||||
this.$watch("ip", function () {
|
||||
this.result.isDone = false
|
||||
})
|
||||
})
|
||||
|
||||
this.success = function (resp) {
|
||||
this.result = resp.data.result
|
||||
}
|
||||
|
||||
this.updateItem = function (itemId) {
|
||||
teaweb.popup(Tea.url(".updateIPPopup?firewallPolicyId=" + this.firewallPolicyId, {itemId: itemId}), {
|
||||
height: "30em",
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加IP名单菜单
|
||||
*/
|
||||
this.createIP = function (type) {
|
||||
let that = this
|
||||
teaweb.popup("/servers/iplists/createIPPopup?listId=" + this.listId + '&type=' + type, {
|
||||
height: "30em",
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
window.location = "/servers/components/waf/ipadmin/lists?firewallPolicyId=" + that.firewallPolicyId + "&type=" + type
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,60 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>修改IP</h3>
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="firewallPolicyId" :value="firewallPolicyId"/>
|
||||
<input type="hidden" name="itemId" :value="item.id"/>
|
||||
<input type="hidden" name="type" :value="item.type"/>
|
||||
<csrf-token></csrf-token>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">类型 *</td>
|
||||
<td>
|
||||
<!-- 类型不允许修改 -->
|
||||
<span v-if="item.type == 'ipv4'">IPv4</span>
|
||||
<span v-if="item.type == 'ipv6'">IPv6</span>
|
||||
<span v-if="item.type == 'all'">所有IP</span>
|
||||
|
||||
<p class="comment" v-if="type == 'ipv4'">单个IPv4或一个IPv4范围。</p>
|
||||
<p class="comment" v-if="type == 'ipv6'">单个IPv6或一个IPv6范围。</p>
|
||||
<p class="comment" v-if="type == 'all'">允许或禁用所有的IP。</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tbody v-if="type != 'all'">
|
||||
<tr>
|
||||
<td>IP或IP段 *</td>
|
||||
<td>
|
||||
<input type="text" name="value" maxlength="64" placeholder="x.x.x.x" ref="focus" v-model="item.value" style="width: 20em"/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<tr>
|
||||
<td>过期时间</td>
|
||||
<td>
|
||||
<datetime-input :v-name="'expiredAt'" :v-timestamp="item.expiredAt"></datetime-input>
|
||||
<p class="comment">在加入名单某一段时间后会失效,留空表示永久有效。</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>级别</td>
|
||||
<td>
|
||||
<firewall-event-level-options :v-value="item.eventLevel"></firewall-event-level-options>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||
</tr>
|
||||
<tbody v-show="moreOptionsVisible">
|
||||
<tr>
|
||||
<td>备注</td>
|
||||
<td><input type="text" name="reason" maxlength="100" v-model="item.reason"/></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
45
EdgeAdmin/web/views/@default/servers/components/waf/log.html
Normal file
45
EdgeAdmin/web/views/@default/servers/components/waf/log.html
Normal file
@@ -0,0 +1,45 @@
|
||||
{$layout}
|
||||
{$template "/datepicker"}
|
||||
|
||||
{$template "waf_menu"}
|
||||
|
||||
<form method="get" class="ui form small" :action="path" autocomplete="off">
|
||||
<first-menu style="margin-top: -1em">
|
||||
<div class="item">
|
||||
<select class="ui dropdown" name="groupId" v-model="groupId">
|
||||
<option value="0">[规则分组]</option>
|
||||
<option v-for="group in groups" :value="group.id">{{group.name}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="item right">
|
||||
<input type="hidden" name="firewallPolicyId" :value="firewallPolicyId"/>
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="day" maxlength="10" placeholder="选择日期" style="width:7.8em" id="day-input" v-model="day"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button small" type="submit">查找</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</first-menu>
|
||||
</form>
|
||||
|
||||
<http-access-log-partitions-box :v-day="day" :v-partition="partition"></http-access-log-partitions-box>
|
||||
|
||||
<p class="comment" v-if="accessLogs.length == 0">暂时还没有日志。</p>
|
||||
|
||||
<table class="ui table selectable" v-if="accessLogs.length > 0">
|
||||
<!-- 这里之所以需要添加 :key,是因为要不然不会刷新显示 -->
|
||||
<tr v-for="accessLog in accessLogs" :key="accessLog.requestId">
|
||||
<td><http-access-log-box :v-access-log="accessLog"></http-access-log-box></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div v-if="accessLogs.length > 0">
|
||||
<a :href="path + '?requestId=' + lastRequestId + '&day=' + day + '&firewallPolicyId=' + firewallPolicyId + '&groupId=' + groupId" v-if="hasPrev">上一页</a>
|
||||
<span v-else class="disabled">上一页</span>
|
||||
<span class="disabled"> | </span>
|
||||
<a :href="path + '?requestId=' + nextRequestId + '&day=' + day + '&firewallPolicyId=' + firewallPolicyId + '&groupId=' + groupId" v-if="hasMore">下一页</a>
|
||||
<span v-else class="disabled">下一页</span>
|
||||
</div>
|
||||
22
EdgeAdmin/web/views/@default/servers/components/waf/log.js
Normal file
22
EdgeAdmin/web/views/@default/servers/components/waf/log.js
Normal file
@@ -0,0 +1,22 @@
|
||||
Tea.context(function () {
|
||||
this.$delay(function () {
|
||||
let that = this
|
||||
teaweb.datepicker("day-input", function (day) {
|
||||
that.day = day
|
||||
})
|
||||
})
|
||||
|
||||
let that = this
|
||||
this.accessLogs.forEach(function (accessLog) {
|
||||
if (typeof (that.regions[accessLog.remoteAddr]) == "string") {
|
||||
accessLog.region = that.regions[accessLog.remoteAddr]
|
||||
} else {
|
||||
accessLog.region = ""
|
||||
}
|
||||
if (accessLog.firewallRuleSetId > 0 && typeof (that.wafInfos[accessLog.firewallRuleSetId]) == "object") {
|
||||
accessLog.wafInfo = that.wafInfos[accessLog.firewallRuleSetId]
|
||||
} else {
|
||||
accessLog.wafInfo = null
|
||||
}
|
||||
})
|
||||
})
|
||||
141
EdgeAdmin/web/views/@default/servers/components/waf/policy.html
Normal file
141
EdgeAdmin/web/views/@default/servers/components/waf/policy.html
Normal file
@@ -0,0 +1,141 @@
|
||||
{$layout}
|
||||
{$template "waf_menu"}
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">策略名称</td>
|
||||
<td>{{firewallPolicy.name}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>状态</td>
|
||||
<td>
|
||||
<span v-if="!firewallPolicy.isOn" class="red">已停用</span>
|
||||
<div v-else-if="firewallPolicy.modeInfo != null">
|
||||
<span :class="{green: firewallPolicy.modeInfo.code == 'defend', blue: firewallPolicy.modeInfo.code == 'observe', grey: firewallPolicy.modeInfo.code == 'bypass'}">{{firewallPolicy.modeInfo.name}}</span>
|
||||
<p class="comment">{{firewallPolicy.modeInfo.description}}</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>预置的规则分组</td>
|
||||
<td>
|
||||
<span class="ui label tiny basic" v-for="group in firewallPolicy.groups" style="margin-bottom:0.5em" :class="{disabled:!group.isOn}">{{group.name}}</span>
|
||||
<div v-if="upgradeItems.length > 0">
|
||||
<div class="ui divider"></div>
|
||||
<a href=""><span class="red">升级提醒:官方提供了新的规则,是否要加入以下规则:<span class="ui label tiny basic" v-for="item in upgradeItems" style="margin-bottom: 0.2em">{{item.name}}<span v-if="!item.isOn" class="small">(默认不启用)</span></span></span></a> <a href="" @click.prevent="upgradeTemplate">[加入]</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h4>动作配置</h4>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">阻止动作设置</td>
|
||||
<td>
|
||||
<http-firewall-block-options-viewer :v-block-options="firewallPolicy.blockOptions"></http-firewall-block-options-viewer>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="title">显示页面动作设置</td>
|
||||
<td>
|
||||
<http-firewall-page-options-viewer :v-page-options="firewallPolicy.pageOptions"></http-firewall-page-options-viewer>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>人机识别动作配置</td>
|
||||
<td>
|
||||
<http-firewall-captcha-options-viewer :v-captcha-options="firewallPolicy.captchaOptions"></http-firewall-captcha-options-viewer>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>JSCookie动作配置</td>
|
||||
<td>
|
||||
<http-firewall-js-cookie-options-viewer :v-js-cookie-options="firewallPolicy.jsCookieOptions"></http-firewall-js-cookie-options-viewer>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>使用系统防火墙</td>
|
||||
<td>
|
||||
<span class="green" v-if="firewallPolicy.useLocalFirewall">启用</span>
|
||||
<span class="disabled" v-if="!firewallPolicy.useLocalFirewall">不启用</span>
|
||||
<p class="comment" v-if="firewallPolicy.useLocalFirewall">可以在合适的时候自动使用系统自带防火墙进行防御。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h4>日志配置</h4>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title" :class="{'color-border':firewallPolicy.log !=null && firewallPolicy.log.isOn}">记录访问日志</td>
|
||||
<td>
|
||||
<span v-if="firewallPolicy.log == null || !firewallPolicy.log.isOn">默认</span>
|
||||
<span v-else class="green">开启</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="firewallPolicy.log != null && firewallPolicy.log.isOn">
|
||||
<td class="color-border">记录请求Body</td>
|
||||
<td>
|
||||
<span class="green" v-if="firewallPolicy.log.requestBody">开启</span>
|
||||
<span v-else>默认</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="firewallPolicy.log != null && firewallPolicy.log.isOn">
|
||||
<td class="color-border">记录区域封禁日志</td>
|
||||
<td>
|
||||
<span class="green" v-if="firewallPolicy.log.regionDenying">开启</span>
|
||||
<span v-else>不记录</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h4>区域封禁设置</h4>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">区域封禁默认提示内容</td>
|
||||
<td>
|
||||
<span v-if="firewallPolicy.denyCountryHTML != null && firewallPolicy.denyCountryHTML.length > 0">自定义</span>
|
||||
<span v-else class="disabled">使用默认</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>省份封禁默认提示内容</td>
|
||||
<td>
|
||||
<span v-if="firewallPolicy.denyProvinceHTML != null && firewallPolicy.denyProvinceHTML.length > 0">自定义</span>
|
||||
<span v-else class="disabled">使用默认</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h4>其他配置</h4>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">SYN Flood防御</td>
|
||||
<td>
|
||||
<span v-if="firewallPolicy.synFlood == null || !firewallPolicy.synFlood.isOn" class="disabled">未启用</span>
|
||||
<firewall-syn-flood-config-viewer v-else :v-syn-flood-config="firewallPolicy.synFlood"></firewall-syn-flood-config-viewer>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>最多检查内容尺寸</td>
|
||||
<td>
|
||||
<span v-if="firewallPolicy.maxRequestBodySize == 0" class="disabled">使用默认</span>
|
||||
<span v-else>{{firewallPolicy.maxRequestBodySizeFormat}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>描述</td>
|
||||
<td>
|
||||
<span v-if="firewallPolicy.description.length > 0">{{firewallPolicy.description}}</span>
|
||||
<span v-else class="disabled">暂时还没有描述。</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h4>使用此策略的集群</h4>
|
||||
<p class="comment" v-if="clusters.length == 0">暂时还没有集群使用此策略。</p>
|
||||
<table class="ui table selectable" v-if="clusters.length > 0">
|
||||
<tr v-for="cluster in clusters">
|
||||
<td>{{cluster.name}}<link-icon :href="'/clusters/cluster?clusterId=' + cluster.id"></link-icon></td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -0,0 +1,11 @@
|
||||
Tea.context(function () {
|
||||
this.upgradeTemplate = function () {
|
||||
teaweb.confirm("确定要加入这些新规则吗?", function () {
|
||||
this.$post(".upgradeTemplate")
|
||||
.params({
|
||||
policyId: this.firewallPolicy.id
|
||||
})
|
||||
.refresh()
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,24 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>选择WAF策略</h3>
|
||||
<table class="ui table selectable celled">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>策略名称</th>
|
||||
<th style="width: 7em">状态</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="policy in policies">
|
||||
<td>{{policy.name}}</td>
|
||||
<td>
|
||||
<label-on :v-is-on="policy.isOn"></label-on>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="policy.isOn">
|
||||
<a href="" @click.prevent="selectPolicy(policy)">选择</a>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="page" v-html="page"></div>
|
||||
@@ -0,0 +1,11 @@
|
||||
Tea.context(function () {
|
||||
this.selectPolicy = function (firewallPolicy) {
|
||||
NotifyPopup({
|
||||
code: 200,
|
||||
data: {
|
||||
firewallPolicy: firewallPolicy
|
||||
},
|
||||
message: ""
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,10 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>规则集 “{{setName}}” 代码</h3>
|
||||
|
||||
<form class="ui form" data-tea-action="$">
|
||||
<textarea rows="13">{{code}}</textarea>
|
||||
<p class="comment">你可以将此段代码复制并在创建规则集的时候使用。</p>
|
||||
|
||||
<button class="ui button" type="button" @click.prevent="closePopup">关闭窗口</button>
|
||||
</form>
|
||||
@@ -0,0 +1,5 @@
|
||||
Tea.context(function () {
|
||||
this.closePopup = function () {
|
||||
teaweb.closePopup()
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,5 @@
|
||||
{$layout}
|
||||
|
||||
{$template "waf_menu"}
|
||||
|
||||
<p class="ui message">此功能暂未开放,敬请期待。</p>
|
||||
156
EdgeAdmin/web/views/@default/servers/components/waf/update.html
Normal file
156
EdgeAdmin/web/views/@default/servers/components/waf/update.html
Normal file
@@ -0,0 +1,156 @@
|
||||
{$layout}
|
||||
|
||||
{$template "waf_menu"}
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="firewallPolicyId" :value="firewallPolicyId"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">策略名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="name" maxlength="100" ref="focus" v-model="firewallPolicy.name"/>
|
||||
<p class="comment">给策略起一个容易识别的名字。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>当前模式</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" name="mode" v-model="firewallPolicy.mode">
|
||||
<option v-for="mode in modes" :value="mode.code">{{mode.name}}</option>
|
||||
</select>
|
||||
<p class="comment" v-for="mode in modes" v-if="mode.code == firewallPolicy.mode">{{mode.description}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>启用预置的规则</td>
|
||||
<td>
|
||||
<div class="ui checkbox" v-for="group in groups" style="width:10em;margin-bottom:0.5em">
|
||||
<input type="checkbox" name="groupCodes" :value="group.code" :id="'group-checkbox-' + group.code" v-model="group.isOn"/>
|
||||
<label :for="'group-checkbox-' + group.code">{{group.name}}</label>
|
||||
</div>
|
||||
<p class="comment">可以启用一些我们预置的规则组。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h4>动作配置</h4>
|
||||
<table class="ui table definition selectable">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="title">阻止动作配置</td>
|
||||
<td>
|
||||
<http-firewall-block-options :v-block-options="firewallPolicy.blockOptions"></http-firewall-block-options>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>显示页面动作配置</td>
|
||||
<td>
|
||||
<http-firewall-page-options :v-page-options="firewallPolicy.pageOptions"></http-firewall-page-options>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>人机识别动作配置</td>
|
||||
<td>
|
||||
<http-firewall-captcha-options :v-captcha-options="firewallPolicy.captchaOptions"></http-firewall-captcha-options>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>JSCookie动作配置</td>
|
||||
<td>
|
||||
<http-firewall-js-cookie-options :v-js-cookie-options="firewallPolicy.jsCookieOptions"></http-firewall-js-cookie-options>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h4>日志配置</h4>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title" :class="{'color-border':firewallPolicy.log.isOn}">记录访问日志</td>
|
||||
<td>
|
||||
<input type="hidden" name="logJSON" :value="JSON.stringify(firewallPolicy.log)"/>
|
||||
<checkbox name="" v-model="firewallPolicy.log.isOn"></checkbox>
|
||||
<p class="comment">选中后,总是记录WAF相关访问日志,即使服务中没有开启访问日志。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="firewallPolicy.log.isOn">
|
||||
<td class="color-border">记录请求Body</td>
|
||||
<td>
|
||||
<checkbox v-model="firewallPolicy.log.requestBody"></checkbox>
|
||||
<p class="comment">选中后,表示在访问日志中记录匹配的请求内容。注意:此选项会明显增加访问日志占用空间,请谨慎开启。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="firewallPolicy.log.isOn">
|
||||
<td class="color-border">记录区域封禁日志</td>
|
||||
<td>
|
||||
<checkbox v-model="firewallPolicy.log.regionDenying"></checkbox>
|
||||
<p class="comment">选中后,表示在访问日志中记录区域封禁(地区和省份)事件。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h4>区域封禁设置</h4>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">区域封禁默认提示内容</td>
|
||||
<td>
|
||||
<textarea v-model="firewallPolicy.denyCountryHTML" name="denyCountryHTML" rows="3"></textarea>
|
||||
<p class="comment">当客户端所在区域被封禁时提示页面的HTML内容;不填则表示使用默认的提示内容;支持请求变量。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>省份封禁默认提示内容</td>
|
||||
<td>
|
||||
<textarea v-model="firewallPolicy.denyProvinceHTML" name="denyProvinceHTML" rows="3"></textarea>
|
||||
<p class="comment">当客户端所在省份被封禁时提示页面的HTML内容;不填则表示使用默认的提示内容;支持请求变量。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h4>其他配置</h4>
|
||||
<table class="ui table definition selectable">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="title">使用系统防火墙</td>
|
||||
<td>
|
||||
<checkbox name="useLocalFirewall" v-model="firewallPolicy.useLocalFirewall"></checkbox>
|
||||
<p class="comment">开启后,可以在合适的时候自动使用系统自带防火墙进行防御;建议在每个边缘节点都安装nftables以提升封禁性能。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SYN Flood防御</td>
|
||||
<td>
|
||||
<firewall-syn-flood-config-box :v-syn-flood-config="firewallPolicy.synFloodConfig"></firewall-syn-flood-config-box>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>最多检查内容尺寸</td>
|
||||
<td>
|
||||
<input type="hidden" name="maxRequestBodySize" v-model="maxRequestBodySize"/>
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" style="width: 10em" maxlength="10" v-model="firewallPolicy.maxRequestBodySize" @input="changeMaxRequestBodySize(firewallPolicy.maxRequestBodySize)"/>
|
||||
<span class="ui label">字节</span>
|
||||
</div>
|
||||
<p class="comment"><span v-if="maxRequestBodySize > 0">当前:{{maxRequestBodySizeFormat}}。</span>WAF能够分析的最大文件内容尺寸,0表示默认,默认为512K;此值越大,对应使用的系统内存越多,除非特殊情况,否则请谨慎修改。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>描述</td>
|
||||
<td>
|
||||
<textarea name="description" rows="3" v-model="firewallPolicy.description"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>启用当前策略</td>
|
||||
<td>
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" name="isOn" value="1" v-model="firewallPolicy.isOn"/>
|
||||
<label></label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,22 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifySuccess("保存成功", "/servers/components/waf/policy?firewallPolicyId=" + this.firewallPolicyId)
|
||||
|
||||
this.maxRequestBodySize = this.firewallPolicy.maxRequestBodySize
|
||||
this.maxRequestBodySizeFormat = teaweb.formatBytes(this.maxRequestBodySize)
|
||||
if (this.maxRequestBodySize == 0) {
|
||||
this.maxRequestBodySizeFormat = ""
|
||||
}
|
||||
|
||||
this.changeMaxRequestBodySize = function (v) {
|
||||
if (v.toString().length == 0) {
|
||||
this.maxRequestBodySize = 0
|
||||
this.maxRequestBodySizeFormat = teaweb.formatBytes(this.maxRequestBodySize)
|
||||
return
|
||||
}
|
||||
let size = parseInt(v)
|
||||
if (!isNaN(size) && size >= 0) {
|
||||
this.maxRequestBodySize = size
|
||||
this.maxRequestBodySizeFormat = teaweb.formatBytes(this.maxRequestBodySize)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,45 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>修改分组</h3>
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<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="100" ref="focus" v-model="group.name"/>
|
||||
<p class="comment">给分组起一个容易识别的名称</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>代号</td>
|
||||
<td>
|
||||
<input type="text" name="code" maxlength="100" v-model="group.code"/>
|
||||
<p class="comment">可选项,在导入时可以合并相同代号的分组。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||
</tr>
|
||||
<tbody v-show="moreOptionsVisible">
|
||||
<tr>
|
||||
<td>分组描述</td>
|
||||
<td>
|
||||
<textarea name="description" maxlength="200" rows="3" v-model="group.description"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>启用当前分组</td>
|
||||
<td>
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" name="isOn" value="1" v-model="group.isOn" />
|
||||
<label></label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,52 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>修改规则集</h3>
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="setId" :value="setConfig.id"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">规则集名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="name" maxlength="100" ref="focus" v-model="setConfig.name"/>
|
||||
<p class="comment">可以用来描述当前规则集用途。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>规则 *</td>
|
||||
<td style="word-break: break-word">
|
||||
<http-firewall-rules-box :v-rules="rules" :v-type="type"></http-firewall-rules-box>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="rules.length > 1">
|
||||
<td>规则之间的关系 *</td>
|
||||
<td>
|
||||
<select class="ui dropdown" name="connector" style="width:10em" @change="changeConnector()" v-model="selectedConnector">
|
||||
<option v-for="connector in connectors" :value="connector.value">{{connector.name}}</option>
|
||||
</select>
|
||||
<p class="comment">{{selectedConnectorDescription}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>执行动作 *</td>
|
||||
<td>
|
||||
<http-firewall-actions-box :v-actions="actions" :v-firewall-policy="firewallPolicy" :v-action-configs="actionConfigs" :v-group-type="type"></http-firewall-actions-box>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>允许局域网IP</td>
|
||||
<td>
|
||||
<checkbox name="ignoreLocal" v-model="setConfig.ignoreLocal"></checkbox>
|
||||
<p class="comment">选中后表示如果请求来自局域网IP,则直接跳过当前规则集。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>允许搜索引擎</td>
|
||||
<td>
|
||||
<checkbox name="ignoreSearchEngine" v-model="setConfig.ignoreSearchEngine"></checkbox>
|
||||
<p class="comment">选中后,表示如果请求来自常见搜索引擎的IP,则直接跳过当前规则集。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,57 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifyPopup
|
||||
|
||||
// rules
|
||||
this.rules = this.setConfig.rules
|
||||
|
||||
// connector
|
||||
this.selectedConnector = this.setConfig.connector
|
||||
this.selectedConnectorDescription = ""
|
||||
this.changeConnector = function () {
|
||||
let that = this
|
||||
this.selectedConnectorDescription = this.connectors.$find(function (k, v) {
|
||||
return v.value == that.selectedConnector
|
||||
}).description
|
||||
}
|
||||
this.changeConnector()
|
||||
|
||||
// action
|
||||
this.action = this.setConfig.action
|
||||
|
||||
// action:go_group
|
||||
this.actionGroupId = 0
|
||||
if (this.action == "go_group" || this.action == "go_set" && this.setConfig.actionOptions != null) {
|
||||
this.$delay(function () {
|
||||
this.actionGroupId = this.setConfig.actionOptions["groupId"]
|
||||
})
|
||||
}
|
||||
|
||||
// action:go_set
|
||||
this.actionSetId = 0
|
||||
if (this.action == "go_set" && this.setConfig.actionOptions != null) {
|
||||
this.$delay(function () {
|
||||
this.actionSetId = this.setConfig.actionOptions["setId"]
|
||||
})
|
||||
}
|
||||
|
||||
this.groupSets = function (groupId) {
|
||||
if (this.firewallPolicy == null) {
|
||||
return
|
||||
}
|
||||
let group = null
|
||||
this.firewallPolicy.inbound.groups.forEach(function (v) {
|
||||
if (v.id == groupId) {
|
||||
group = v
|
||||
}
|
||||
})
|
||||
this.firewallPolicy.outbound.groups.forEach(function (v) {
|
||||
if (v.id == groupId) {
|
||||
group = v
|
||||
}
|
||||
})
|
||||
if (group == null) {
|
||||
return []
|
||||
}
|
||||
return group.sets
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user