1.4.5.2
This commit is contained in:
6
EdgeUser/web/views/@default/servers/@menu.html
Normal file
6
EdgeUser/web/views/@default/servers/@menu.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<first-menu>
|
||||
<menu-item href="/servers" code="index">网站管理</menu-item>
|
||||
<span class="disabled item">|</span>
|
||||
<menu-item href="/servers/create" code="create">添加网站</menu-item>
|
||||
<menu-item href="/servers/groups" code="group">分组管理</menu-item>
|
||||
</first-menu>
|
||||
24
EdgeUser/web/views/@default/servers/addPortPopup.html
Normal file
24
EdgeUser/web/views/@default/servers/addPortPopup.html
Normal file
@@ -0,0 +1,24 @@
|
||||
{$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">
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td>网络协议</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" name="protocol">
|
||||
<option v-for="protocol in protocols" :value="protocol.code">{{protocol.name}}</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="title">端口 *</td>
|
||||
<td>
|
||||
<input type="text" name="address" ref="focus" v-model="address" maxlength="5" style="width:5.2em"/>
|
||||
<p class="comment">需要在1024-65534之间。TCP和TLS端口之间不能重复。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
19
EdgeUser/web/views/@default/servers/addPortPopup.js
Normal file
19
EdgeUser/web/views/@default/servers/addPortPopup.js
Normal file
@@ -0,0 +1,19 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifyPopup;
|
||||
|
||||
this.isUpdating = false
|
||||
|
||||
this.address = ""
|
||||
this.protocol = this.protocols[0].code
|
||||
|
||||
if (window.parent.UPDATING_ADDR != null) {
|
||||
this.isUpdating = true
|
||||
let addr = window.parent.UPDATING_ADDR
|
||||
this.protocol = addr.protocol
|
||||
if (addr.host.length == 0) {
|
||||
this.address = addr.portRange
|
||||
} else {
|
||||
this.address = addr.host.quoteIP() + ":" + addr.portRange
|
||||
}
|
||||
}
|
||||
})
|
||||
25
EdgeUser/web/views/@default/servers/addServerNamePopup.html
Normal file
25
EdgeUser/web/views/@default/servers/addServerNamePopup.html
Normal file
@@ -0,0 +1,25 @@
|
||||
{$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">
|
||||
<csrf-token></csrf-token>
|
||||
<input type="hidden" name="mode" :value="mode"/>
|
||||
<table class="ui table selectable definition">
|
||||
<tr v-if="mode == 'single'">
|
||||
<td class="title">单个域名 *</td>
|
||||
<td>
|
||||
<input type="text" name="serverName" ref="focus" maxlength="1024" v-model="serverName.name"/>
|
||||
<p class="comment">请输入单个域名,比如<code-label>example.com</code-label>、<code-label>www.example.com</code-label>,<strong>不要</strong>包含<code-label>http://</code-label>或<code-label>https://</code-label>或端口号;也可以使用泛域名,比如<code-label>*.example.com</code-label>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="mode == 'multiple'">
|
||||
<td class="title">多个域名 *</td>
|
||||
<td>
|
||||
<textarea name="serverNames" ref="serverNames" v-model="multipleServerNames"></textarea>
|
||||
<p class="comment">每行一个域名,比如<code-label>example.com</code-label>、<code-label>www.example.com</code-label>,<strong>不要</strong>包含<code-label>http://</code-label>或<code-label>https://</code-label>或端口号;也可以使用泛域名,比如<code-label>*.example.com</code-label>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn></submit-btn> <a href="" v-if="mode == 'single'" @click.prevent="switchMode('multiple')">批量添加</a><a href="" v-if="mode == 'multiple'" @click.prevent="switchMode('single')">单个添加</a>
|
||||
</form>
|
||||
29
EdgeUser/web/views/@default/servers/addServerNamePopup.js
Normal file
29
EdgeUser/web/views/@default/servers/addServerNamePopup.js
Normal file
@@ -0,0 +1,29 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifyPopup;
|
||||
this.isUpdating = false
|
||||
this.mode = "single" // single|multiple
|
||||
this.serverName = {
|
||||
name: "",
|
||||
subNames: []
|
||||
}
|
||||
this.multipleServerNames = ""
|
||||
if (window.parent.UPDATING_SERVER_NAME != null) {
|
||||
this.isUpdating = true
|
||||
this.serverName = window.parent.UPDATING_SERVER_NAME
|
||||
if (this.serverName.subNames != null && this.serverName.subNames.length > 0) {
|
||||
this.mode = "multiple"
|
||||
this.multipleServerNames = this.serverName.subNames.join("\n")
|
||||
}
|
||||
}
|
||||
|
||||
this.switchMode = function (mode) {
|
||||
this.mode = mode
|
||||
this.$delay(function () {
|
||||
if (mode == "single") {
|
||||
this.$refs.focus.focus()
|
||||
} else {
|
||||
this.$refs.serverNames.focus()
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
6
EdgeUser/web/views/@default/servers/cache/@menu.html
vendored
Normal file
6
EdgeUser/web/views/@default/servers/cache/@menu.html
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
<first-menu>
|
||||
<menu-item href="/servers/cache" code="purge">刷新缓存</menu-item>
|
||||
<menu-item href="/servers/cache/fetch" code="fetch">预热缓存</menu-item>
|
||||
<span class="disabled item">|</span>
|
||||
<menu-item href="/servers/cache/tasks" code="task">所有任务<span v-if="countDoingTasks > 0" class="grey">({{countDoingTasks}})</span></menu-item>
|
||||
</first-menu>
|
||||
22
EdgeUser/web/views/@default/servers/cache/fetch.html
vendored
Normal file
22
EdgeUser/web/views/@default/servers/cache/fetch.html
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{$layout}
|
||||
{$template "menu"}
|
||||
|
||||
<div class="margin"></div>
|
||||
<div><span class="grey">预热缓存指的是预先从源站读取最新内容,当用户访问预热后的URL时直接从缓存中返回内容,不需要再次回源。</span></div>
|
||||
|
||||
<form class="ui form" method="post" data-tea-action="$" data-tea-success="success" data-tea-done="done" data-tea-timeout="600" data-tea-before="before">
|
||||
<csrf-token></csrf-token>
|
||||
<table class="ui table selectable definition">
|
||||
<tr>
|
||||
<td class="title">
|
||||
URL列表 *
|
||||
</td>
|
||||
<td>
|
||||
<textarea rows="20" name="urlList" ref="focus"></textarea>
|
||||
<p class="comment">每行一条,每次最多提交{{maxKeysPerTask}}个URL,每天最多提交{{maxKeysPerDay}}个<span v-if="quotaKeysToday > 0">,今日剩余{{quotaKeysToday}}个</span>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn v-if="!isRequesting">预热缓存</submit-btn>
|
||||
<button class="ui button disabled" type="button" v-if="isRequesting">处理中...</button>
|
||||
</form>
|
||||
12
EdgeUser/web/views/@default/servers/cache/fetch.js
vendored
Normal file
12
EdgeUser/web/views/@default/servers/cache/fetch.js
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifyReloadSuccess("任务提交成功")
|
||||
|
||||
this.isRequesting = false
|
||||
this.before = function () {
|
||||
this.isRequesting = true
|
||||
}
|
||||
|
||||
this.done = function () {
|
||||
this.isRequesting = false
|
||||
}
|
||||
})
|
||||
32
EdgeUser/web/views/@default/servers/cache/index.html
vendored
Normal file
32
EdgeUser/web/views/@default/servers/cache/index.html
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
{$layout}
|
||||
{$template "menu"}
|
||||
|
||||
<div class="margin"></div>
|
||||
<div><span class="grey">刷新缓存指的是标记URL列表或目录为失效状态,当有新的用户请求这些URL时,会再次从源站读取最新的内容。</span></div>
|
||||
|
||||
<form class="ui form" method="post" data-tea-action="$" data-tea-success="success" data-tea-before="before" data-tea-done="done">
|
||||
<csrf-token></csrf-token>
|
||||
<table class="ui table selectable definition">
|
||||
<tr>
|
||||
<td class="title">刷新类型 *</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" name="keyType" v-model="keyType">
|
||||
<option value="key">URL</option>
|
||||
<option value="prefix">目录</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span v-if="keyType == 'key'">URL列表 *</span>
|
||||
<span v-if="keyType == 'prefix'">目录列表 *</span>
|
||||
</td>
|
||||
<td>
|
||||
<textarea rows="20" name="urlList" ref="keysBox"></textarea>
|
||||
<p class="comment">每行一条,每次最多提交{{maxKeysPerTask}}个URL,每天最多提交{{maxKeysPerDay}}个<span v-if="quotaKeysToday > 0">,今日剩余{{quotaKeysToday}}个</span>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn v-if="!isRequesting">刷新缓存</submit-btn>
|
||||
<button class="ui button disabled" type="button" v-if="isRequesting">处理中...</button>
|
||||
</form>
|
||||
21
EdgeUser/web/views/@default/servers/cache/index.js
vendored
Normal file
21
EdgeUser/web/views/@default/servers/cache/index.js
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
Tea.context(function () {
|
||||
this.keyType = "key"
|
||||
|
||||
this.success = NotifyReloadSuccess("任务提交成功")
|
||||
|
||||
this.$delay(function () {
|
||||
this.$refs.keysBox.focus()
|
||||
this.$watch("keyType", function () {
|
||||
this.$refs.keysBox.focus()
|
||||
})
|
||||
})
|
||||
|
||||
this.isRequesting = false
|
||||
this.before = function () {
|
||||
this.isRequesting = true
|
||||
}
|
||||
|
||||
this.done = function () {
|
||||
this.isRequesting = false
|
||||
}
|
||||
})
|
||||
87
EdgeUser/web/views/@default/servers/cache/task.html
vendored
Normal file
87
EdgeUser/web/views/@default/servers/cache/task.html
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
{$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>Key类型</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.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>
|
||||
</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="width5">状态</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.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
EdgeUser/web/views/@default/servers/cache/task.js
vendored
Normal file
42
EdgeUser/web/views/@default/servers/cache/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)
|
||||
})
|
||||
}
|
||||
})
|
||||
42
EdgeUser/web/views/@default/servers/cache/tasks.html
vendored
Normal file
42
EdgeUser/web/views/@default/servers/cache/tasks.html
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
{$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>Key类型</th>
|
||||
<th>创建时间</th>
|
||||
<th class="two wide">任务状态</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody v-for="task in tasks">
|
||||
<tr>
|
||||
<td><a :href="'/servers/cache/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.isOk" class="green">已完成</span>
|
||||
<a :href="'/servers/cache/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/cache/task?taskId=' + task.id">详情</a>
|
||||
<a href="" @click.prevent="deleteTask(task.id)">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<page-box></page-box>
|
||||
11
EdgeUser/web/views/@default/servers/cache/tasks.js
vendored
Normal file
11
EdgeUser/web/views/@default/servers/cache/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()
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,8 @@
|
||||
<first-menu>
|
||||
<menu-item href="/servers/certs/acme" code="task">所有任务</menu-item>
|
||||
<span class="disabled item">|</span>
|
||||
<menu-item href="/servers/certs/acme/create" code="create">[新申请]</menu-item>
|
||||
<span class="disabled item">|</span>
|
||||
<menu-item href="/servers/certs/acme/users" code="user">ACME用户</menu-item>
|
||||
<menu-item href="/dns/providers" code="dns">DNS服务商</menu-item>
|
||||
</first-menu>
|
||||
@@ -0,0 +1,41 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>添加账号</h3>
|
||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td>账号名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="name" maxlength="50" ref="focus" tabindex="1"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="title">证书服务商 *</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" name="providerCode" v-model="providerCode" @change="changeProvider" tabindex="2">
|
||||
<option value="">[选择服务商]</option>
|
||||
<option v-for="provider in providers" :value="provider.code">{{provider.name}}</option>
|
||||
</select>
|
||||
<p class="comment" v-if="selectedProvider != null" v-html="selectedProvider.description"></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tbody v-show="selectedProvider != null && selectedProvider.requireEAB">
|
||||
<tr>
|
||||
<td>EAB Kid *</td>
|
||||
<td>
|
||||
<input type="text" name="eabKid" maxlength="100" tabindex="3"/>
|
||||
<p class="comment" v-if="selectedProvider != null" v-html="selectedProvider.eabDescription"></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>EAB HMAC Key *</td>
|
||||
<td>
|
||||
<input type="text" name="eabKey" maxlength="300" tabindex="4"/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,16 @@
|
||||
Tea.context(function () {
|
||||
this.selectedProvider = null
|
||||
this.changeProvider = function () {
|
||||
if (this.providerCode.length == 0) {
|
||||
this.selectedProvider = null
|
||||
return
|
||||
}
|
||||
|
||||
let that = this
|
||||
this.selectedProvider = this.providers.$find(function (k, v) {
|
||||
return v.code == that.providerCode
|
||||
})
|
||||
}
|
||||
|
||||
this.changeProvider()
|
||||
})
|
||||
@@ -0,0 +1,46 @@
|
||||
{$layout}
|
||||
{$template "/left_menu_top"}
|
||||
|
||||
<div class="right-box without-tabbar">
|
||||
{$template "../menu"}
|
||||
|
||||
<second-menu>
|
||||
<menu-item @click.prevent="createAccount">[创建账号]</menu-item>
|
||||
</second-menu>
|
||||
|
||||
<p class="comment" v-if="accounts.length == 0">暂时还没有服务商账号。</p>
|
||||
|
||||
<table class="ui table selectable celled" v-if="accounts.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>名称</th>
|
||||
<th>服务商</th>
|
||||
<th class="four wide">EAB Kid</th>
|
||||
<th class="four wide">EBA HMAC Key</th>
|
||||
<th class="two wide">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="account in accounts">
|
||||
<td>
|
||||
<a href="" @click.prevent="updateAccount(account.id)">{{account.name}} <i class="icon expand small"></i></a>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="account.provider != null">{{account.provider.name}}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="account.eabKid.length > 0">{{account.eabKid}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="account.eabKey.length > 0">{{account.eabKey}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td>
|
||||
<a href="" @click.prevent="updateAccount(account.id)">修改</a>
|
||||
<a href="" @click.prevent="deleteAccount(account.id)">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
</div>
|
||||
@@ -0,0 +1,33 @@
|
||||
Tea.context(function () {
|
||||
this.createAccount = function () {
|
||||
teaweb.popup(".createPopup", {
|
||||
height: "24em",
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.updateAccount = function (accountId) {
|
||||
teaweb.popup(".updatePopup?accountId=" + accountId, {
|
||||
height: "24em",
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.deleteAccount = function (accountId) {
|
||||
teaweb.confirm("确定要删除此账号吗?", function () {
|
||||
this.$post(".delete")
|
||||
.params({
|
||||
accountId: accountId
|
||||
})
|
||||
.refresh()
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,41 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>修改账号</h3>
|
||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
|
||||
<input type="hidden" name="accountId" :value="account.id"/>
|
||||
<input type="hidden" name="providerCode" :value="account.providerCode"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td>账号名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="name" maxlength="50" ref="focus" v-model="account.name" tabindex="1"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="title">服务商 *</td>
|
||||
<td>
|
||||
<span v-if="account.provider != null">{{account.provider.name}}</span>
|
||||
<span v-else class="disabled">服务商已失效</span>
|
||||
<p class="comment" v-if="account.provider != null" v-html="account.provider.description"></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tbody v-show="account.provider != null && account.provider.requireEAB">
|
||||
<tr>
|
||||
<td>EAB Kid *</td>
|
||||
<td>
|
||||
<input type="text" name="eabKid" maxlength="100" v-model="account.eabKid" tabindex="3"/>
|
||||
<p class="comment" v-if="account.provider != null" v-html="account.provider.eabDescription"></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>EAB HMAC Key *</td>
|
||||
<td>
|
||||
<input type="text" name="eabKey" maxlength="300" v-model="account.eabKey" tabindex="4"/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,3 @@
|
||||
Tea.context(function () {
|
||||
|
||||
})
|
||||
15
EdgeUser/web/views/@default/servers/certs/acme/create.css
Normal file
15
EdgeUser/web/views/@default/servers/certs/acme/create.css
Normal file
@@ -0,0 +1,15 @@
|
||||
.button-group {
|
||||
margin-top: 4em;
|
||||
z-index: 1;
|
||||
}
|
||||
.button-group .button.primary {
|
||||
float: right;
|
||||
}
|
||||
.success-box {
|
||||
text-align: center;
|
||||
padding-top: 2em;
|
||||
}
|
||||
.success-box p {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
/*# sourceMappingURL=create.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["create.less"],"names":[],"mappings":"AAAA;EACC,eAAA;EACA,UAAA;;AAFD,aAIC,QAAO;EACN,YAAA;;AAIF;EACC,kBAAA;EACA,gBAAA;;AAFD,YAIC;EACC,gBAAA","file":"create.css"}
|
||||
161
EdgeUser/web/views/@default/servers/certs/acme/create.html
Normal file
161
EdgeUser/web/views/@default/servers/certs/acme/create.html
Normal file
@@ -0,0 +1,161 @@
|
||||
{$layout}
|
||||
|
||||
{$template "menu"}
|
||||
|
||||
<div class="margin"></div>
|
||||
|
||||
<form class="ui form">
|
||||
<div class="ui steps fluid small">
|
||||
<div class="ui step" :class="{active:step == 'prepare'}">
|
||||
选择申请方式
|
||||
</div>
|
||||
<div class="ui step" :class="{active:step == 'user'}">
|
||||
选择ACME用户
|
||||
</div>
|
||||
<div class="ui step" :class="{active:step == 'dns'}">
|
||||
填写域名信息
|
||||
</div>
|
||||
<div class="ui step" :class="{active:step == 'finish'}">
|
||||
完成
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 准备工作 -->
|
||||
<div v-show="step == 'prepare'">
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">认证方式 *</td>
|
||||
<td>
|
||||
<div style="margin-bottom: 1em">
|
||||
<radio name="authType" :v-value="'http'" v-model="authType">使用HTTP认证</radio>
|
||||
<radio name="authType" :v-value="'dns'" v-model="authType">使用DNS认证</radio>
|
||||
</div>
|
||||
<div v-if="authType == 'http'">
|
||||
<p class="comment">使用HTTP认证的方式请求网址<code-label>/.well-known/acme-challenge/令牌</code-label>校验,该方式要求需要实现将域名解析到集群上,之后系统会自动生成网址信息;这种方式不支持泛域名证书的申请。</p>
|
||||
</div>
|
||||
<div v-if="authType == 'dns'">
|
||||
<p class="comment">我们在申请免费证书的过程中需要自动增加或修改相关域名的TXT记录,请先确保你已经在"域名解析" -- <a href="/dns/providers" target="_blank">"DNS服务商"</a> 中已经添加了对应的DNS服务商账号。</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<a href="" @click.prevent="showPrepareMoreOptionsVisible">更多选项<i class="icon angle" :class="{up: prepareMoreOptionsVisible, down: !prepareMoreOptionsVisible}"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
<tbody v-show="prepareMoreOptionsVisible">
|
||||
<tr>
|
||||
<td>回调URL</td>
|
||||
<td>
|
||||
<input type="text" name="authURL" v-model="authURL" maxlength="200"/>
|
||||
<p class="comment">将认证数据以JSON的方式POST到此URL上,可以依此生成认证文件或者设置DNS域名解析;仅适用于未绑定当前CDN系统的域名。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="button-group">
|
||||
<button type="button" class="ui button primary" @click.prevent="doPrepare">下一步</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 选择用户 -->
|
||||
<div v-show="step == 'user'">
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">选择证书服务商 *</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" v-model="providerCode" @change="changeProvider">
|
||||
<option value="">[选择服务商]</option>
|
||||
<option v-for="provider in providers" :value="provider.code">{{provider.name}}</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="providerCode.length > 0">
|
||||
<td class="title">选择用户</td>
|
||||
<td>
|
||||
<div v-if="users.length > 0">
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<select class="ui dropdown" v-model="userId">
|
||||
<option value="0">[请选择]</option>
|
||||
<option v-for="user in users" :value="user.id" :data-user-providerCode="user.providerCode" v-if="user.providerCode == providerCode">{{user.email}}{{user.description}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<a href="" @click.prevent="createUser">[新创建]</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else><a href="" @click.prevent="createUser">暂时还没有用户,点此创建</a></div>
|
||||
<p class="comment">选择一个作为申请证书的用户。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="button-group">
|
||||
<button type="button" class="ui button" @click.prevent="goPrepare">上一步</button>
|
||||
<button type="button" class="ui button primary" @click.prevent="doUser">下一步</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 设置域名解析 -->
|
||||
<div v-show="step == 'dns'">
|
||||
<table class="ui table definition selectable">
|
||||
<tr v-show="authType == 'dns'">
|
||||
<td class="title">选择DNS服务商 *</td>
|
||||
<td>
|
||||
<div v-if="dnsProviders.length > 0">
|
||||
<select class="ui dropdown auto-width" v-model="dnsProviderId">
|
||||
<option value="0">[请选择]</option>
|
||||
<option v-for="provider in dnsProviders" :value="provider.id">{{provider.name}}({{provider.typeName}})</option>
|
||||
</select>
|
||||
</div>
|
||||
<div v-else>
|
||||
<span>暂时没有DNS服务商,<a href="/dns/providers">[去添加]</a>。</span>
|
||||
</div>
|
||||
<p class="comment">用于自动创建域名解析记录。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="authType == 'dns'">
|
||||
<td>顶级域名 *</td>
|
||||
<td>
|
||||
<input type="text" maxlength="100" v-model="dnsDomain"/>
|
||||
<p class="comment">用于在DNS服务商账号中操作解析记录的域名,比如 example.com,不要输入二级或别的多级域名。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="title">证书域名列表 *</td>
|
||||
<td>
|
||||
<domains-box :v-support-wildcard="authType == 'dns'" @change="changeDomains"></domains-box>
|
||||
<p class="comment">需要申请的证书中包含的域名列表<span v-if="authType == 'dns'">,所有域名必须是同一个顶级域名</span><span v-if="authType == 'http'">使用HTTP认证方式时,域名中不能含有通配符</span>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>自动续期</td>
|
||||
<td>
|
||||
<checkbox v-model="autoRenew"></checkbox>
|
||||
<p class="comment">选中后,表示在免费证书临近到期之前尝试自动续期。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="button-group">
|
||||
<button type="button" class="ui button" @click.prevent="goUser">上一步</button>
|
||||
<button type="button" class="ui button primary" @click.prevent="doDNS" v-if="!isRequesting">下一步</button>
|
||||
<button type="button" class="ui button primary disabled" v-if="isRequesting">提交中,要花费的时间较长,请耐心等待...</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 完成 -->
|
||||
<div v-show="step == 'finish'">
|
||||
<div class="success-box">
|
||||
<p><span class="green">恭喜,证书申请成功!</span>你可以在证书列表里看到刚申请的证书,也可以 <a href="" @click.prevent="viewCert">点击这里</a> 查看证书详情。</p>
|
||||
</div>
|
||||
|
||||
<div class="button-group">
|
||||
<button type="button" class="ui button primary" @click.prevent="doFinish">返回</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
138
EdgeUser/web/views/@default/servers/certs/acme/create.js
Normal file
138
EdgeUser/web/views/@default/servers/certs/acme/create.js
Normal file
@@ -0,0 +1,138 @@
|
||||
Tea.context(function () {
|
||||
this.step = "prepare"
|
||||
|
||||
/**
|
||||
* 准备工作
|
||||
*/
|
||||
this.authType = "http"
|
||||
|
||||
this.doPrepare = function () {
|
||||
this.step = "user"
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择用户
|
||||
*/
|
||||
this.userId = 0
|
||||
|
||||
this.goPrepare = function () {
|
||||
this.step = "prepare"
|
||||
}
|
||||
|
||||
this.createUser = function () {
|
||||
let that = this
|
||||
teaweb.popup("/servers/certs/acme/users/createPopup", {
|
||||
callback: function (resp) {
|
||||
teaweb.successToast("创建成功")
|
||||
|
||||
let acmeUser = resp.data.acmeUser
|
||||
let description = acmeUser.description
|
||||
if (description.length > 0) {
|
||||
description = "(" + description + ")"
|
||||
}
|
||||
that.userId = acmeUser.id
|
||||
that.users.unshift({
|
||||
id: acmeUser.id,
|
||||
description: description,
|
||||
email: acmeUser.email
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.doUser = function () {
|
||||
if (this.userId == 0) {
|
||||
teaweb.warn("请选择一个申请证书的用户")
|
||||
return
|
||||
}
|
||||
this.step = "dns"
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置DNS解析
|
||||
*/
|
||||
this.dnsProviderId = 0
|
||||
this.dnsDomain = ""
|
||||
this.autoRenew = true
|
||||
this.domains = []
|
||||
this.taskId = 0
|
||||
this.isRequesting = false
|
||||
|
||||
this.goUser = function () {
|
||||
this.step = "user"
|
||||
}
|
||||
|
||||
this.changeDomains = function (v) {
|
||||
this.domains = v
|
||||
}
|
||||
|
||||
this.doDNS = function () {
|
||||
this.isRequesting = true
|
||||
let that = this
|
||||
let taskCreated = false
|
||||
this.$post("$")
|
||||
.params({
|
||||
authType: this.authType,
|
||||
acmeUserId: this.userId,
|
||||
dnsProviderId: this.dnsProviderId,
|
||||
dnsDomain: this.dnsDomain,
|
||||
domains: this.domains,
|
||||
autoRenew: this.autoRenew ? 1 : 0,
|
||||
taskId: this.taskId,
|
||||
authURL: this.authURL
|
||||
})
|
||||
.success(function (resp) {
|
||||
this.taskId = resp.data.taskId
|
||||
taskCreated = true
|
||||
|
||||
this.isRequesting = true
|
||||
this.$post(".run")
|
||||
.timeout(300)
|
||||
.params({
|
||||
taskId: this.taskId
|
||||
})
|
||||
.success(function (resp) {
|
||||
that.certId = resp.data.certId
|
||||
that.step = "finish"
|
||||
})
|
||||
.done(function () {
|
||||
that.isRequesting = false
|
||||
})
|
||||
})
|
||||
.done(function () {
|
||||
if (!taskCreated) {
|
||||
this.isRequesting = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 完成
|
||||
*/
|
||||
this.certId = 0
|
||||
|
||||
this.goDNS = function () {
|
||||
this.step = "dns"
|
||||
}
|
||||
|
||||
this.doFinish = function () {
|
||||
window.location = "/servers/certs/acme"
|
||||
}
|
||||
|
||||
this.viewCert = function () {
|
||||
teaweb.popup("/servers/certs/certPopup?certId=" + this.certId, {
|
||||
height: "28em",
|
||||
width: "48em"
|
||||
})
|
||||
}
|
||||
|
||||
this.prepareMoreOptionsVisible = false
|
||||
this.authURL = ""
|
||||
this.showPrepareMoreOptionsVisible = function () {
|
||||
this.prepareMoreOptionsVisible = !this.prepareMoreOptionsVisible
|
||||
}
|
||||
this.providerCode = ""
|
||||
this.changeProvider = function () {
|
||||
this.userId = 0
|
||||
}
|
||||
})
|
||||
17
EdgeUser/web/views/@default/servers/certs/acme/create.less
Normal file
17
EdgeUser/web/views/@default/servers/certs/acme/create.less
Normal file
@@ -0,0 +1,17 @@
|
||||
.button-group {
|
||||
margin-top: 4em;
|
||||
z-index: 1;
|
||||
|
||||
.button.primary {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.success-box {
|
||||
text-align: center;
|
||||
padding-top: 2em;
|
||||
|
||||
p {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
}
|
||||
64
EdgeUser/web/views/@default/servers/certs/acme/index.html
Normal file
64
EdgeUser/web/views/@default/servers/certs/acme/index.html
Normal file
@@ -0,0 +1,64 @@
|
||||
{$layout}
|
||||
|
||||
{$template "menu"}
|
||||
|
||||
<p class="comment" v-if="tasks.length == 0">暂时还没有证书申请任务。</p>
|
||||
|
||||
<div class="ui message blue" v-if="isRunning">有任务在执行中,可能需要的时间较长,请耐心等待。</div>
|
||||
|
||||
<table class="ui table selectable celled" v-if="tasks.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ACME用户</th>
|
||||
<th>证书域名</th>
|
||||
<th>到期时间</th>
|
||||
<th>更新时间</th>
|
||||
<th class="center" style="width:6em">自动续期</th>
|
||||
<th class="center" style="width:6em">关联证书</th>
|
||||
<th class="three op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="(task, index) in tasks" :class="{warning: runningIndex == index}">
|
||||
<td>{{task.acmeUser.email}}
|
||||
<div style="margin-top: 1em">
|
||||
<tiny-basic-label class="olive" v-if="task.authType == 'dns'">DNS</tiny-basic-label>
|
||||
<tiny-basic-label class="olive" v-if="task.authType == 'http'">HTTP</tiny-basic-label>
|
||||
</div>
|
||||
</td>
|
||||
<td nowrap="">
|
||||
<div v-for="domain in task.domains">
|
||||
<span class="ui label small basic">{{domain}}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td nowrap="">
|
||||
<div v-if="task.cert != null">
|
||||
{{task.cert.endTime}}
|
||||
</div>
|
||||
<span class="disabled" v-else>-</span>
|
||||
</td>
|
||||
<td nowrap="">
|
||||
<div v-if="task.log != null">
|
||||
<span class="green" v-if="task.log.isOk">{{task.log.createdTime}}</span>
|
||||
<link-red v-if="!task.log.isOk" title="任务执行失败,点击查看详情" @click.prevent="showError(task.log.error)">{{task.log.createdTime}}</link-red>
|
||||
</div>
|
||||
<span v-else class="disabled">尚未执行</span>
|
||||
</td>
|
||||
<td class="center">
|
||||
<span class="green" v-if="task.autoRenew">Y</span>
|
||||
<span v-else class="disabled">N</span>
|
||||
</td>
|
||||
<td class="center">
|
||||
<div v-if="task.cert != null">
|
||||
<a href="" @click.prevent="viewCert(task.cert.id)"><link-icon title="查看关联证书"></link-icon></a>
|
||||
</div>
|
||||
<span class="disabled" v-else="">-</span>
|
||||
</td>
|
||||
<td>
|
||||
<a href="" @click.prevent="updateTask(task.id)" :class="{disabled: isRunning}">修改</a>
|
||||
<a href="" @click.prevent="runTask(index, task)" :class="{disabled: isRunning}">执行</a>
|
||||
<a href="" @click.prevent="deleteTask(task.id)" :class="{disabled: isRunning}">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
63
EdgeUser/web/views/@default/servers/certs/acme/index.js
Normal file
63
EdgeUser/web/views/@default/servers/certs/acme/index.js
Normal file
@@ -0,0 +1,63 @@
|
||||
Tea.context(function () {
|
||||
this.viewCert = function (certId) {
|
||||
teaweb.popup("/servers/certs/certPopup?certId=" + certId, {
|
||||
height: "28em",
|
||||
width: "48em"
|
||||
})
|
||||
}
|
||||
|
||||
this.updateTask = function (taskId) {
|
||||
teaweb.popup("/servers/certs/acme/updateTaskPopup?taskId=" + taskId, {
|
||||
width: "45em",
|
||||
height: "26em",
|
||||
callback: function () {
|
||||
teaweb.success("保存成功,如果证书域名发生了改变,请重新执行生成新证书", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.deleteTask = function (taskId) {
|
||||
let that = this
|
||||
teaweb.confirm("确定要删除此任务吗?", function () {
|
||||
that.$post("/servers/certs/acme/deleteTask")
|
||||
.params({
|
||||
taskId: taskId
|
||||
})
|
||||
.refresh()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
this.isRunning = false
|
||||
this.runningIndex = -1
|
||||
|
||||
this.runTask = function (index, task) {
|
||||
let that = this
|
||||
|
||||
teaweb.confirm("html:确定要立即执行此任务吗?<br/>将会重新发起证书申请。", function () {
|
||||
that.isRunning = true
|
||||
that.runningIndex = index
|
||||
|
||||
that.$post(".run")
|
||||
.timeout(300)
|
||||
.params({
|
||||
taskId: task.id
|
||||
})
|
||||
.success(function (resp) {
|
||||
teaweb.success("任务执行成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
})
|
||||
.done(function () {
|
||||
that.isRunning = false
|
||||
that.runningIndex = -1
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
this.showError = function (err) {
|
||||
teaweb.popupTip("任务执行失败:" + err)
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,47 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>修改申请任务</h3>
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
<input type="hidden" name="taskId" :value="task.id"/>
|
||||
<input type="hidden" name="acmeUserId" :value="task.acmeUser.id"/>
|
||||
<input type="hidden" name="authType" :value="task.authType"/>
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr v-if="task.authType == 'dns'">
|
||||
<td class="title">选择DNS服务商 *</td>
|
||||
<td>
|
||||
<div v-if="providers.length > 0">
|
||||
<select class="ui dropdown auto-width" name="dnsProviderId" v-model="task.dnsProvider.id">
|
||||
<option value="0">[请选择]</option>
|
||||
<option v-for="provider in providers" :value="provider.id">{{provider.name}}({{provider.typeName}})</option>
|
||||
</select>
|
||||
</div>
|
||||
<p class="comment">用于自动创建域名解析记录。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="task.authType == 'dns'">
|
||||
<td>顶级域名 *</td>
|
||||
<td>
|
||||
<input type="text" maxlength="100" name="dnsDomain" v-model="task.dnsDomain"/>
|
||||
<p class="comment">用于在DNS服务商账号中操作解析记录的域名,比如 example.com,不要输入二级或别的多级域名。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>证书域名列表 *</td>
|
||||
<td>
|
||||
<domains-box name="domainsJSON" :v-domains="task.domains" :v-support-wildcard="task.authType == 'dns'"></domains-box>
|
||||
<p class="comment">需要申请的证书中包含的域名列表<span v-if="task.authType == 'dns'">,所有域名必须是同一个顶级域名</span><span v-if="task.authType == 'http'">使用HTTP认证方式时,域名中不能含有通配符</span>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>自动续期</td>
|
||||
<td>
|
||||
<checkbox name="autoRenew" v-model="task.autoRenew"></checkbox>
|
||||
<p class="comment">选中后,表示在免费证书临近到期之前尝试自动续期。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,47 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>创建用户</h3>
|
||||
<form method="post" class="ui form" data-tea-success="success" data-tea-action="$">
|
||||
<csrf-token></csrf-token>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">用户邮箱 *</td>
|
||||
<td>
|
||||
<input type="text" name="email" maxlength="100" ref="focus"/>
|
||||
<p class="comment">用于自动注册用户的邮箱。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>所属证书服务商 *</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" name="providerCode" v-model="providerCode" @change="changeProvider">
|
||||
<option value="">[选择服务商]</option>
|
||||
<option v-for="provider in providers" :value="provider.code">{{provider.name}}</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="selectedProvider != null">
|
||||
<td>所属服务商账号 <span v-if="selectedProvider.requireEAB">*</span><em v-else>(可选)</em></td>
|
||||
<td>
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field" v-if="accounts.length > 0">
|
||||
<select class="ui dropdown auto-width" name="accountId" v-model="accountId">
|
||||
<option value="0">[选择账号]</option>
|
||||
<option v-for="account in accounts" :value="account.id">{{account.name}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<a href="" @click.prevent="addAccount">[添加]</a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>备注</td>
|
||||
<td>
|
||||
<textarea name="description" rows="3" maxlength="100"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,53 @@
|
||||
Tea.context(function () {
|
||||
this.selectedProvider = null
|
||||
this.accounts = []
|
||||
this.accountId = 0
|
||||
|
||||
this.changeProvider = function () {
|
||||
this.accountId = 0
|
||||
|
||||
if (this.providerCode.length == 0) {
|
||||
return
|
||||
}
|
||||
|
||||
let that = this
|
||||
let provider = this.providers.$find(function (k, v) {
|
||||
return v.code == that.providerCode
|
||||
})
|
||||
if (provider == null) {
|
||||
return
|
||||
}
|
||||
|
||||
this.selectedProvider = provider
|
||||
|
||||
this.$post(".accountsWithCode")
|
||||
.params({
|
||||
code: provider.code
|
||||
})
|
||||
.success(function (resp) {
|
||||
this.accounts = resp.data.accounts
|
||||
})
|
||||
}
|
||||
|
||||
this.addAccount = function () {
|
||||
let that = this
|
||||
teaweb.popup("/servers/certs/acme/accounts/createPopup?providerCode=" + this.providerCode, {
|
||||
height: "24em",
|
||||
callback: function () {
|
||||
teaweb.successToast("创建成功,已自动选中", 1500, function () {
|
||||
that.$post(".accountsWithCode")
|
||||
.params({
|
||||
code: that.providerCode
|
||||
})
|
||||
.success(function (resp) {
|
||||
that.accounts = resp.data.accounts
|
||||
|
||||
if (that.accounts.length > 0) {
|
||||
that.accountId = that.accounts[0].id
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,39 @@
|
||||
{$layout}
|
||||
|
||||
{$template "../menu"}
|
||||
|
||||
<second-menu>
|
||||
<menu-item @click.prevent="createUser">[创建用户]</menu-item>
|
||||
<menu-item><tip-icon content="这里管理用于申请免费证书的用户信息"></tip-icon></menu-item>
|
||||
</second-menu>
|
||||
|
||||
<p class="comment" v-if="users.length == 0">暂时还没有用户。</p>
|
||||
|
||||
<table class="ui table selectable" v-if="users.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>用户Email</th>
|
||||
<th>备注</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="user in users">
|
||||
<td>
|
||||
<a href="" @click.prevent="updateUser(user.id)">{{user.email}} <i class="icon expand small"></i></a>
|
||||
<div>
|
||||
<grey-label v-if="user.provider != null">{{user.provider.name}}</grey-label>
|
||||
<grey-label v-if="user.account != null">{{user.account.name}}</grey-label>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="user.description.length > 0">{{user.description}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td>
|
||||
<a href="" @click.prevent="updateUser(user.id)">修改</a>
|
||||
<a href="" @click.prevent="deleteUser(user.id)">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
@@ -0,0 +1,36 @@
|
||||
Tea.context(function () {
|
||||
this.createUser = function () {
|
||||
teaweb.popup(Tea.url(".createPopup"), {
|
||||
height: "27em",
|
||||
width: "44em",
|
||||
callback: function () {
|
||||
teaweb.success("创建成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.updateUser = function (userId) {
|
||||
teaweb.popup("/servers/certs/acme/users/updatePopup?userId=" + userId, {
|
||||
height: "27em",
|
||||
width: "44em",
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.deleteUser = function (userId) {
|
||||
let that = this
|
||||
teaweb.confirm("确定要删除此用户吗?", function () {
|
||||
that.$post(".delete")
|
||||
.params({
|
||||
userId: userId
|
||||
})
|
||||
.refresh()
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,31 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>修改用户</h3>
|
||||
<form method="post" class="ui form" data-tea-success="success" data-tea-action="$">
|
||||
<csrf-token></csrf-token>
|
||||
<input type="hidden" name="userId" :value="user.id"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">用户邮箱 *</td>
|
||||
<td>
|
||||
{{user.email}}
|
||||
<p class="comment">用于自动注册用户的邮箱,不允许修改。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="user.provider != null">
|
||||
<td>所属服务商</td>
|
||||
<td>{{user.provider.name}}</td>
|
||||
</tr>
|
||||
<tr v-if="user.account != null">
|
||||
<td>所属服务商账号</td>
|
||||
<td>{{user.account.name}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>备注</td>
|
||||
<td>
|
||||
<textarea name="description" rows="3" maxlength="100" v-model="user.description" ref="focus"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
15
EdgeUser/web/views/@default/servers/certs/certPopup.css
Normal file
15
EdgeUser/web/views/@default/servers/certs/certPopup.css
Normal file
@@ -0,0 +1,15 @@
|
||||
.pre-box {
|
||||
padding: 1em;
|
||||
margin: 0;
|
||||
line-height: 1.7;
|
||||
-ms-word-break: break-all;
|
||||
word-break: break-all;
|
||||
font-size: 0.9em;
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
overflow-y: auto;
|
||||
max-height: 20em;
|
||||
}
|
||||
.pre-box::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
/*# sourceMappingURL=certPopup.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["certPopup.less"],"names":[],"mappings":"AAAA;EACC,YAAA;EACA,SAAA;EACA,gBAAA;EACA,yBAAA;EACA,qBAAA;EACA,gBAAA;EACA,+BAAA;EACA,gBAAA;EACA,gBAAA;;AAGD,QAAQ;EACP,UAAA","file":"certPopup.css"}
|
||||
74
EdgeUser/web/views/@default/servers/certs/certPopup.html
Normal file
74
EdgeUser/web/views/@default/servers/certs/certPopup.html
Normal file
@@ -0,0 +1,74 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>证书详情</h3>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">证书说明</td>
|
||||
<td>{{info.name}}</td>
|
||||
</tr>
|
||||
<tr v-if="info.description.length > 0">
|
||||
<td>详细说明</td>
|
||||
<td>{{info.description}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>证书状态</td>
|
||||
<td>
|
||||
<span class="ui label small green basic" v-if="info.isAvailable">有效中</span>
|
||||
<span class="ui label small red basic" v-else>已过期</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>发行信息</td>
|
||||
<td>
|
||||
<div v-if="info.commonNames != null">
|
||||
<div v-for="(commonName, index) in info.commonNames">
|
||||
<span v-html="indent(index)"></span>{{commonName}}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>域名</td>
|
||||
<td>
|
||||
<span class="ui label small" v-for="dnsName in info.dnsNames">{{dnsName}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>有效期</td>
|
||||
<td>{{info.beginTime}} - {{info.endTime}}</td>
|
||||
</tr>
|
||||
<!--<tr>
|
||||
<td>引用网站</td>
|
||||
<td>
|
||||
<span class="disabled" v-if="servers.length == 0">暂时没有引用此证书的服务。</span>
|
||||
<div v-if="servers.length > 0">
|
||||
<a v-for="server in servers" :href="'/servers/server?serverId=' + server.id" target="_blank" class="ui label small">{{server.name}}</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>-->
|
||||
<tr>
|
||||
<td>证书文件下载</td>
|
||||
<td>
|
||||
<a :href="'/servers/certs/downloadZip?certId=' + info.id" target="_blank">[ZIP下载]</a>
|
||||
<a :href="'/servers/certs/downloadCert?certId=' + info.id" target="_blank">[证书下载]</a>
|
||||
<a :href="'/servers/certs/downloadKey?certId=' + info.id" v-if="!info.isCA" target="_blank">[私钥下载]</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>证书预览</td>
|
||||
<td>
|
||||
<pre class="pre-box" style="font-family: Menlo, Monaco, 'Courier New', monospace !important">{{info.certString}}</pre>
|
||||
<div style="margin-top:1em">
|
||||
<a :href="'/servers/certs/viewCert?certId=' + info.id" target="_blank">[浏览器新窗口打开]</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="!info.isCA">
|
||||
<td>私钥预览</td>
|
||||
<td><pre class="pre-box" style="font-family: Menlo, Monaco, 'Courier New', monospace !important">{{info.keyString}}</pre>
|
||||
<div style="margin-top: 1em">
|
||||
<a :href="'/servers/certs/viewKey?certId=' + info.id" target="_blank">[浏览器新窗口打开]</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
10
EdgeUser/web/views/@default/servers/certs/certPopup.js
Normal file
10
EdgeUser/web/views/@default/servers/certs/certPopup.js
Normal file
@@ -0,0 +1,10 @@
|
||||
Tea.context(function () {
|
||||
// 打印缩进
|
||||
this.indent = function (index) {
|
||||
let indent = ""
|
||||
for (let i = 0; i < index; i++) {
|
||||
indent += " "
|
||||
}
|
||||
return indent
|
||||
}
|
||||
})
|
||||
15
EdgeUser/web/views/@default/servers/certs/certPopup.less
Normal file
15
EdgeUser/web/views/@default/servers/certs/certPopup.less
Normal file
@@ -0,0 +1,15 @@
|
||||
.pre-box {
|
||||
padding: 1em;
|
||||
margin: 0;
|
||||
line-height: 1.7;
|
||||
-ms-word-break: break-all;
|
||||
word-break: break-all;
|
||||
font-size: 0.9em;
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
overflow-y: auto;
|
||||
max-height: 20em;
|
||||
}
|
||||
|
||||
.pre-box::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
76
EdgeUser/web/views/@default/servers/certs/index.html
Normal file
76
EdgeUser/web/views/@default/servers/certs/index.html
Normal file
@@ -0,0 +1,76 @@
|
||||
{$layout}
|
||||
<!--{$template "/left_menu_top"}-->
|
||||
|
||||
<!--<div class="right-box without-tabbar">-->
|
||||
<second-menu>
|
||||
<menu-item :href="'/servers/certs?keyword=' + keyword" :active="type == ''">所有证书({{countAll}})</menu-item>
|
||||
<menu-item :href="'/servers/certs?type=ca&keyword=' + keyword" :active="type == 'ca'">CA证书({{countCA}})</menu-item>
|
||||
<menu-item :href="'/servers/certs?type=available&keyword=' + keyword" :active="type == 'available'">有效证书({{countAvailable}})</menu-item>
|
||||
<menu-item :href="'/servers/certs?type=expired&keyword=' + keyword" :active="type == 'expired'">过期证书<span :class="{red: countExpired > 0}">({{countExpired}})</span></menu-item>
|
||||
<menu-item :href="'/servers/certs?type=7days&keyword=' + keyword" :active="type == '7days'">7天内过期<span :class="{red: count7Days > 0}">({{count7Days}})</span></menu-item>
|
||||
<menu-item :href="'/servers/certs?type=30days&keyword=' + keyword" :active="type == '30days'">30天过期({{count30Days}})</menu-item>
|
||||
<span class="item">|</span>
|
||||
<a href="" class="item" @click.prevent="uploadCert">[上传证书]</a>
|
||||
<a href="" class="item" @click.prevent="uploadBatch">[批量上传]</a>
|
||||
</second-menu>
|
||||
|
||||
<form class="ui form">
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="keyword" placeholder="关键词" style="width:10em" v-model="keyword"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button type="submit" class="ui button">搜索</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<p class="comment" v-if="certs.length == 0">暂时还没有相关的证书。</p>
|
||||
<table class="ui table selectable celled" v-if="certs.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>证书说明</th>
|
||||
<th>顶级发行组织</th>
|
||||
<th>域名</th>
|
||||
<th>生效日期</th>
|
||||
<th>过期日期</th>
|
||||
<th class="center">引用网站</th>
|
||||
<th class="center">状态</th>
|
||||
<th class="three op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="(cert, index) in certs">
|
||||
<td>{{cert.name}}
|
||||
<div v-if="cert.isCA" style="margin-top:0.5em">
|
||||
<micro-basic-label :class="olive">CA</micro-basic-label>
|
||||
</div>
|
||||
<div v-if="cert.isACME" style="margin-top: 0.5em">
|
||||
<micro-basic-label class="olive" title="通过ACME协议免费申请">ACME</micro-basic-label>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="cert.commonNames != null && cert.commonNames.length > 0">{{cert.commonNames[cert.commonNames.length-1]}}</span>
|
||||
</td>
|
||||
<td>
|
||||
<div v-for="dnsName in cert.dnsNames" style="margin-bottom:0.4em">
|
||||
<span class="ui label tiny basic">{{dnsName}}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>{{certInfos[index].beginDay}}</td>
|
||||
<td>{{certInfos[index].endDay}}</td>
|
||||
<td class="center">{{certInfos[index].countServers}}</td>
|
||||
<td nowrap="" class="center">
|
||||
<span class="ui label red tiny basic" v-if="!certInfos[index].isOn">未启用</span>
|
||||
<span class="ui label red tiny basic" v-else-if="certInfos[index].isExpired">已过期</span>
|
||||
<span class="ui label green tiny basic" v-else>有效中</span>
|
||||
</td>
|
||||
<td>
|
||||
<a href="" @click.prevent="viewCert(cert.id)">详情</a>
|
||||
<a href="" @click.prevent="updateCert(cert.id)">修改</a>
|
||||
<a href="" @click.prevent="deleteCert(cert.id)">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
<!--</div>-->
|
||||
54
EdgeUser/web/views/@default/servers/certs/index.js
Normal file
54
EdgeUser/web/views/@default/servers/certs/index.js
Normal file
@@ -0,0 +1,54 @@
|
||||
Tea.context(function () {
|
||||
// 上传证书
|
||||
this.uploadCert = function () {
|
||||
teaweb.popup("/servers/certs/uploadPopup", {
|
||||
height: "28em",
|
||||
callback: function () {
|
||||
teaweb.success("上传成功", function () {
|
||||
window.location.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 批量上传证书
|
||||
this.uploadBatch = function () {
|
||||
teaweb.popup("/servers/certs/uploadBatchPopup", {
|
||||
callback: function () {
|
||||
window.location.reload()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 删除证书
|
||||
this.deleteCert = function (certId) {
|
||||
let that = this
|
||||
teaweb.confirm("确定要删除此证书吗?", function () {
|
||||
that.$post("/servers/certs/delete")
|
||||
.params({
|
||||
certId: certId
|
||||
})
|
||||
.refresh()
|
||||
})
|
||||
}
|
||||
|
||||
// 查看证书
|
||||
this.viewCert = function (certId) {
|
||||
teaweb.popup("/servers/certs/certPopup?certId=" + certId, {
|
||||
height: "28em",
|
||||
width: "48em"
|
||||
})
|
||||
}
|
||||
|
||||
// 修改证书
|
||||
this.updateCert = function (certId) {
|
||||
teaweb.popup("/servers/certs/updatePopup?certId=" + certId, {
|
||||
height: "28em",
|
||||
callback: function () {
|
||||
teaweb.success("修改成功", function () {
|
||||
window.location.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
85
EdgeUser/web/views/@default/servers/certs/selectPopup.html
Normal file
85
EdgeUser/web/views/@default/servers/certs/selectPopup.html
Normal file
@@ -0,0 +1,85 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>选择证书 <span v-if="searchingDomains.length > 0">(当前服务域名:{{searchingDomains[0]}}<var style="font-style: normal" v-if="searchingDomains.length > 1">等{{searchingDomains.length}}个域名</var>)</span></h3>
|
||||
|
||||
<!-- 搜索表单 -->
|
||||
<form class="ui form" action="/servers/certs/selectPopup">
|
||||
<input type="hidden" name="selectedCertIds" :value="selectedCertIds"/>
|
||||
<input type="hidden" name="searchingType" :value="searchingType"/>
|
||||
<input type="hidden" name="searchingDomains" :value="searchingDomains.join(',')"/>
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="keyword" v-model="keyword" placeholder="域名、说明文字等" size="30"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button" type="submit">搜索</button>
|
||||
<a :href="'/servers/certs/selectPopup?selectedCertIds=' + selectedCertIds + '&searchingType=' + searchingType + '&searchingDomains=' + encodeURL(searchingDomains.join(','))" v-if="keyword.length > 0">[清除条件]</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- 选项卡 -->
|
||||
<div v-if="searchingDomains.length > 0">
|
||||
<div class="ui divider" style="margin-bottom: 0"></div>
|
||||
<second-menu>
|
||||
<menu-item :active="searchingType == 'all'" :href="baseURL + '&searchingType=all'">所有证书 <span class="small">({{totalAll}})</span></menu-item>
|
||||
<span class="disabled item">|</span>
|
||||
<menu-item :active="searchingType == 'match'" :href="baseURL + '&searchingType=match'">域名匹配证书 <span class="small"> ({{totalMatch}})</span></menu-item>
|
||||
</second-menu>
|
||||
</div>
|
||||
|
||||
<!-- 全选 -->
|
||||
<div v-if="countChecked > 0">
|
||||
<div class="margin"></div>
|
||||
<button class="ui button small basic" type="button" @click.prevent="confirmChecked">使用选中的{{countChecked}}个证书</button>
|
||||
</div>
|
||||
|
||||
<!-- 证书列表 -->
|
||||
<p class="comment" v-if="certs.length == 0">暂时还没有<span v-if="searchingType == 'match'">跟所添加域名匹配的</span>相关证书。</p>
|
||||
<table class="ui table selectable celled" v-if="certs.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:1em"><checkbox @input="changeAll"></checkbox></th>
|
||||
<th>证书说明</th>
|
||||
<th>域名</th>
|
||||
<th>过期日期</th>
|
||||
<th v-if="viewSize == 'normal'">引用网站</th>
|
||||
<th>状态</th>
|
||||
<th class="one op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="(cert, index) in certs">
|
||||
<td>
|
||||
<checkbox v-model="cert.isChecked" ref="certCheckboxes" @input="changeCertChecked" v-if="!certInfos[index].isSelected"></checkbox>
|
||||
</td>
|
||||
<td>
|
||||
<a href="" @click.prevent="selectCert(cert)" v-if="!certInfos[index].isSelected"><keyword :v-word="keyword">{{cert.name}}</keyword></a>
|
||||
<span v-if="certInfos[index].isSelected">{{cert.name}}</span>
|
||||
|
||||
<div v-if="cert.commonNames != null && cert.commonNames.length > 0" style="margin-top:0.5em">
|
||||
<span class="grey small">{{cert.commonNames[cert.commonNames.length-1]}}</span>
|
||||
</div>
|
||||
|
||||
<div v-if="cert.isCA" style="margin-top:0.5em">
|
||||
<span class="ui label olive tiny">CA</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div v-for="dnsName in cert.dnsNames" style="margin-bottom:0.4em">
|
||||
<span class="ui label tiny basic"><keyword :v-word="keyword">{{dnsName}}</keyword></span>
|
||||
</div>
|
||||
</td>
|
||||
<td>{{certInfos[index].endDay}}</td>
|
||||
<td v-if="viewSize == 'normal'">{{certInfos[index].countServers}}</td>
|
||||
<td nowrap="">
|
||||
<span class="ui label red tiny basic" v-if="certInfos[index].isExpired">已过期</span>
|
||||
<span class="ui label green tiny basic" v-else>有效中</span>
|
||||
</td>
|
||||
<td>
|
||||
<a href="" @click.prevent="selectCert(cert)" v-if="!certInfos[index].isSelected">选择</a>
|
||||
<span v-else>已选</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
77
EdgeUser/web/views/@default/servers/certs/selectPopup.js
Normal file
77
EdgeUser/web/views/@default/servers/certs/selectPopup.js
Normal file
@@ -0,0 +1,77 @@
|
||||
Tea.context(function () {
|
||||
this.selectCert = function (cert) {
|
||||
NotifyPopup({
|
||||
code: 200,
|
||||
data: {
|
||||
cert: cert,
|
||||
certRef: {
|
||||
isOn: true,
|
||||
certId: cert.id
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.encodeURL = function (arg) {
|
||||
return window.encodeURIComponent(arg)
|
||||
}
|
||||
|
||||
/**
|
||||
* 复选框
|
||||
*/
|
||||
this.countChecked = 0
|
||||
|
||||
this.certs.forEach(function (cert) {
|
||||
cert.isChecked = false
|
||||
})
|
||||
|
||||
this.changeAll = function (b) {
|
||||
let that = this
|
||||
this.certs.forEach(function (cert) {
|
||||
cert.isChecked = b
|
||||
})
|
||||
|
||||
if (b) {
|
||||
let countChecked = 0
|
||||
this.certs.forEach(function (cert, index) {
|
||||
if (cert.isChecked && !that.certInfos[index].isSelected) {
|
||||
countChecked++
|
||||
}
|
||||
})
|
||||
this.countChecked = countChecked
|
||||
} else {
|
||||
this.countChecked = 0
|
||||
}
|
||||
}
|
||||
|
||||
this.changeCertChecked = function () {
|
||||
let countChecked = 0
|
||||
this.certs.forEach(function (cert) {
|
||||
if (cert.isChecked) {
|
||||
countChecked++
|
||||
}
|
||||
})
|
||||
this.countChecked = countChecked
|
||||
}
|
||||
|
||||
this.confirmChecked = function () {
|
||||
let resultCerts = []
|
||||
let resultCertRefs = []
|
||||
this.certs.forEach(function (cert) {
|
||||
if (cert.isChecked) {
|
||||
resultCerts.push(cert)
|
||||
resultCertRefs.push({
|
||||
isOn: true,
|
||||
certId: cert.id
|
||||
})
|
||||
}
|
||||
})
|
||||
NotifyPopup({
|
||||
code: 200,
|
||||
data: {
|
||||
certs: resultCerts,
|
||||
certRefs: resultCertRefs
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
63
EdgeUser/web/views/@default/servers/certs/updatePopup.html
Normal file
63
EdgeUser/web/views/@default/servers/certs/updatePopup.html
Normal file
@@ -0,0 +1,63 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>修改证书<span><span v-if="certConfig.dnsNames != null && certConfig.dnsNames.length > 0"> (包含{{certConfig.dnsNames[0]}}<var v-if="certConfig.dnsNames.length > 1" style="font-style: normal">等{{certConfig.dnsNames.length}}个</var>域名)</span></span></h3>
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="certId" :value="certConfig.id"/>
|
||||
<input type="hidden" name="textMode" :value="textMode ? 1 : 0"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">证书说明 *</td>
|
||||
<td>
|
||||
<input type="text" name="name" maxlength="100" ref="focus" v-model="certConfig.name"/>
|
||||
<p class="comment">可以简单说明证书的用途。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>证书类型</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" name="isCA" v-model="isCA">
|
||||
<option value="0">加密证书</option>
|
||||
<option value="1">CA证书</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span v-if="textMode">输入证书内容</span><span v-else>选择证书文件</span></td>
|
||||
<td>
|
||||
<input type="file" name="certFile" accept="application/x-pem-file, application/pkcs10, application/x-pkcs12, application/x-x509-user-cert, application/x-x509-ca-cert, application/pkix-cert, .pem" v-if="!textMode"/>
|
||||
<file-textarea class="wide-code" ref="certTextField" spellcheck="false" name="certText" placeholder="-----BEGIN CERTIFICATE-----" v-if="textMode" style="font-size: 0.7em"></file-textarea>
|
||||
<p class="comment"><a href="" @click.prevent="switchTextMode">[<span v-if="!textMode">输入内容</span><span v-else>上传文件</span>]</a>。文件内容中通常含有"-----BEGIN CERTIFICATE-----"类似的信息<span v-if="textMode">,可以直接拖动证书文件到输入框,留空表示不修改</span>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="isCA == 0">
|
||||
<td><span v-if="textMode">输入私钥内容</span><span v-else>选择私钥文件</span></td>
|
||||
<td>
|
||||
<input type="file" name="keyFile" accept="application/pkcs8, application/x-pem-file, .key, .pem" v-if="!textMode"/>
|
||||
<file-textarea class="wide-code" spellcheck="false" name="keyText" placeholder="-----BEGIN RSA PRIVATE KEY-----" v-if="textMode" style="font-size: 0.7em"></file-textarea>
|
||||
<p class="comment"><a href="" @click.prevent="switchTextMode">[<span v-if="!textMode">输入内容</span><span v-else>上传文件</span>]</a>。文件内容中通常含有"-----BEGIN RSA PRIVATE KEY-----"类似的信息<span v-if="textMode">,可以直接拖动证书文件到输入框,留空表示不修改</span>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||
</tr>
|
||||
<tbody v-show="moreOptionsVisible">
|
||||
<tr>
|
||||
<td>详细说明</td>
|
||||
<td>
|
||||
<textarea rows="3" name="description" maxlength="200" v-model="certConfig.description"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>启用当前证书</td>
|
||||
<td>
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" name="isOn" value="1" v-model="certConfig.isOn"/>
|
||||
<label></label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
14
EdgeUser/web/views/@default/servers/certs/updatePopup.js
Normal file
14
EdgeUser/web/views/@default/servers/certs/updatePopup.js
Normal file
@@ -0,0 +1,14 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifyPopup
|
||||
this.isCA = this.certConfig.isCA ? 1 : 0
|
||||
this.textMode = false
|
||||
|
||||
this.switchTextMode = function () {
|
||||
this.textMode = !this.textMode
|
||||
if (this.textMode) {
|
||||
this.$delay(function () {
|
||||
this.$refs.certTextField.focus()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,18 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>批量上传证书</h3>
|
||||
|
||||
<form class="ui form" data-tea-success="successUpload" data-tea-action="$" data-tea-before="before" data-tea-done="done" data-tea-timeout="600">
|
||||
<csrf-token></csrf-token>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">选择要上传的证书和私钥文件 *</td>
|
||||
<td>
|
||||
<input type="file" name="certFiles" accept="application/x-pem-file, application/pkcs10, application/x-pkcs12, application/x-x509-user-cert, application/x-x509-ca-cert, application/pkix-cert, application/pkcs8, .key, .pem" multiple="multiple"/>
|
||||
<p class="comment">点击后在弹出的文件选择框中支持多选;不用担心文件名和顺序问题,系统会自动匹配。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn v-show="!isRequesting">上传</submit-btn>
|
||||
<button class="ui button disabled " type="button" v-if="isRequesting">上传中...</button>
|
||||
</form>
|
||||
@@ -0,0 +1,18 @@
|
||||
Tea.context(function () {
|
||||
this.isRequesting = false
|
||||
|
||||
this.before = function () {
|
||||
this.isRequesting = true
|
||||
}
|
||||
|
||||
this.done = function () {
|
||||
this.isRequesting = false
|
||||
}
|
||||
|
||||
this.successUpload = function (resp) {
|
||||
let msg = "html:成功上传" + resp.data.count + "个证书"
|
||||
teaweb.success(msg, function () {
|
||||
NotifyPopup(resp)
|
||||
})
|
||||
}
|
||||
})
|
||||
62
EdgeUser/web/views/@default/servers/certs/uploadPopup.html
Normal file
62
EdgeUser/web/views/@default/servers/certs/uploadPopup.html
Normal file
@@ -0,0 +1,62 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>上传证书</h3>
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="textMode" :value="textMode ? 1 : 0"/>
|
||||
<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>
|
||||
<select class="ui dropdown auto-width" name="isCA" v-model="isCA">
|
||||
<option value="0">加密证书</option>
|
||||
<option value="1">CA证书</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span v-if="textMode">输入证书内容</span><span v-else>选择证书文件</span> *</td>
|
||||
<td>
|
||||
<input type="file" name="certFile" accept="application/x-pem-file, application/pkcs10, application/x-pkcs12, application/x-x509-user-cert, application/x-x509-ca-cert, application/pkix-cert, .pem" v-if="!textMode"/>
|
||||
<file-textarea class="wide-code" ref="certTextField" spellcheck="false" name="certText" placeholder="-----BEGIN CERTIFICATE-----" v-if="textMode" style="font-size: 0.7em"></file-textarea>
|
||||
<p class="comment"><a href="" @click.prevent="switchTextMode">[<span v-if="!textMode">输入内容</span><span v-else>上传文件</span>]</a>。文件内容中通常含有"-----BEGIN CERTIFICATE-----"类似的信息<span v-if="textMode">,可以直接拖动证书文件到输入框</span>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="isCA == 0">
|
||||
<td><span v-if="textMode">输入私钥内容</span><span v-else>选择私钥文件</span> *</td>
|
||||
<td>
|
||||
<input type="file" name="keyFile" accept="application/pkcs8, .key" v-if="!textMode"/>
|
||||
<file-textarea class="wide-code" spellcheck="false" name="keyText" placeholder="-----BEGIN RSA PRIVATE KEY-----" v-if="textMode" style="font-size: 0.7em"></file-textarea>
|
||||
<p class="comment"><a href="" @click.prevent="switchTextMode">[<span v-if="!textMode">输入内容</span><span v-else>上传文件</span>]</a>。文件内容中通常含有"-----BEGIN RSA PRIVATE KEY-----"类似的信息<span v-if="textMode">,可以直接拖动私钥文件到输入框</span>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||
</tr>
|
||||
<tbody v-show="moreOptionsVisible">
|
||||
<tr>
|
||||
<td>详细说明</td>
|
||||
<td>
|
||||
<textarea rows="3" name="description" maxlength="200"></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>
|
||||
14
EdgeUser/web/views/@default/servers/certs/uploadPopup.js
Normal file
14
EdgeUser/web/views/@default/servers/certs/uploadPopup.js
Normal file
@@ -0,0 +1,14 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifyPopup
|
||||
this.isCA = 0
|
||||
this.textMode = false
|
||||
|
||||
this.switchTextMode = function () {
|
||||
this.textMode = !this.textMode
|
||||
if (this.textMode) {
|
||||
this.$delay(function () {
|
||||
this.$refs.certTextField.focus()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,39 @@
|
||||
{$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 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,52 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>添加规则集</h3>
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="groupId" :value="groupId"/>
|
||||
<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>
|
||||
<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>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,43 @@
|
||||
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
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,53 @@
|
||||
{$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>
|
||||
<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>阻止动作配置</td>
|
||||
<td>
|
||||
<http-firewall-block-options :v-block-options="firewallPolicy.blockOptions"></http-firewall-block-options>
|
||||
</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" 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,3 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifySuccess("保存成功", "/servers/components/waf/policy?firewallPolicyId=" + this.firewallPolicyId)
|
||||
})
|
||||
@@ -0,0 +1,38 @@
|
||||
{$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 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>
|
||||
<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
|
||||
}
|
||||
})
|
||||
82
EdgeUser/web/views/@default/servers/create.html
Normal file
82
EdgeUser/web/views/@default/servers/create.html
Normal file
@@ -0,0 +1,82 @@
|
||||
{$layout}
|
||||
{$template "menu"}
|
||||
|
||||
<p class="ui message warning" v-show="clusterId == 0">
|
||||
需要管理员在后台设置当前用户所属集群后才能继续操作。
|
||||
</p>
|
||||
|
||||
<form class="ui form" method="post" data-tea-action="$" data-tea-success="success" data-tea-fail="fail" v-show="clusterId > 0">
|
||||
<csrf-token></csrf-token>
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">加速域名 *</td>
|
||||
<td>
|
||||
<server-name-box ref="serverNameBox" ref="serverNameBox"></server-name-box>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>域名协议 *</td>
|
||||
<td>
|
||||
<checkbox name="protocols" :v-value="'http'">HTTP</checkbox>
|
||||
<checkbox name="protocols" :v-value="'https'" v-model="supportHTTPS">HTTPS</checkbox>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="supportHTTPS">
|
||||
<td>HTTPS证书 *</td>
|
||||
<td>
|
||||
<ssl-certs-box :v-domains="findServerNames"></ssl-certs-box>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>源站信息 *</td>
|
||||
<td>
|
||||
<origin-input-box :v-oss-types="ossTypes"></origin-input-box>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>回源主机名 *</td>
|
||||
<td>
|
||||
<radio name="requestHostType" :v-value="0" v-model="requestHostType">跟随CDN服务</radio>
|
||||
<radio name="requestHostType" :v-value="1" v-model="requestHostType">跟随源站</radio>
|
||||
<radio name="requestHostType" :v-value="2" v-model="requestHostType">自定义</radio>
|
||||
<div v-show="requestHostType == 2" style="margin-top: 0.8em">
|
||||
<input type="text" name="requestHost" placeholder="比如example.com" v-model="requestHost"/>
|
||||
</div>
|
||||
<p class="comment">请求源站时的Host,用于设置访问源站的站点域名
|
||||
<span v-if="requestHostType == 0">,"跟随CDN服务"是指访问源站的站点域名和当前CDN服务保持一致</span>
|
||||
<span v-if="requestHostType == 1">,"跟随源站"是指访问源站的站点域名仍然是填写的源站地址中的信息,不随CDN服务域名改变而改变</span>
|
||||
<span v-if="requestHostType == 2">,自定义Host内容中支持请求变量</span>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>缓存设置</td>
|
||||
<td>
|
||||
<cache-cond-box></cache-cond-box>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="requirePlan || userPlans.length > 0">
|
||||
<td>绑定套餐 <span v-if="requirePlan">*</span></td>
|
||||
<td>
|
||||
<input type="hidden" name="isChanged" value="1"/>
|
||||
<span v-if="userPlans.length == 0 && !requirePlan" class="disabled">当前还没有可以使用的套餐。</span>
|
||||
<span v-if="userPlans.length == 0 && requirePlan" class="red"><a href="/plans"><span class="red">当前还没有可以使用的套餐,请先购买套餐</span></a> 。</span>
|
||||
<div v-else>
|
||||
<select class="ui dropdown auto-width" name="userPlanId">
|
||||
<option value="0" v-if="!requirePlan">[不使用套餐]</option>
|
||||
<option value="0" v-if="requirePlan">[选择套餐]</option>
|
||||
<option v-for="userPlan in userPlans" :value="userPlan.id">{{userPlan.name}}({{userPlan.dayTo}})</option>
|
||||
</select>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>所属分组</td>
|
||||
<td>
|
||||
<server-group-selector></server-group-selector>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
29
EdgeUser/web/views/@default/servers/create.js
Normal file
29
EdgeUser/web/views/@default/servers/create.js
Normal file
@@ -0,0 +1,29 @@
|
||||
Tea.context(function () {
|
||||
this.supportHTTPS = false
|
||||
this.requestHostType = 0
|
||||
this.requestHost = ""
|
||||
|
||||
this.success = function (resp) {
|
||||
if (resp.data.hasOSS) {
|
||||
NotifySuccess("保存成功", "/servers/server/settings/reverseProxy?serverId=" + resp.data.serverId)()
|
||||
} else {
|
||||
NotifySuccess("保存成功", "/servers")()
|
||||
}
|
||||
}
|
||||
|
||||
this.fail = function (resp) {
|
||||
let that = this
|
||||
teaweb.warn(resp.message, function () {
|
||||
if (resp.data.requireServerNames) {
|
||||
that.$refs.serverNameBox.addServerName()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 证书相关
|
||||
*/
|
||||
this.findServerNames = function () {
|
||||
return this.$refs.serverNameBox.allServerNames()
|
||||
}
|
||||
})
|
||||
5
EdgeUser/web/views/@default/servers/fee/@menu.html
Normal file
5
EdgeUser/web/views/@default/servers/fee/@menu.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<first-menu>
|
||||
<menu-item href="." code="index">计费方式</menu-item>
|
||||
<menu-item href=".prices" v-if="showPrices" code="price">价格</menu-item>
|
||||
<menu-item href=".calculator" v-if="showPrices" code="calculator">价格计算器</menu-item>
|
||||
</first-menu>
|
||||
80
EdgeUser/web/views/@default/servers/fee/calculator.html
Normal file
80
EdgeUser/web/views/@default/servers/fee/calculator.html
Normal file
@@ -0,0 +1,80 @@
|
||||
{$layout}
|
||||
{$template "menu"}
|
||||
|
||||
<div class="margin"></div>
|
||||
|
||||
<form class="ui form" data-tea-action="$" data-tea-success="success" ref="calculatorForm">
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">计费类型</td>
|
||||
<td>
|
||||
<div v-if="config.canChangePriceType">
|
||||
<radio name="priceType" :v-value="'bandwidth'" v-model="config.priceType">按带宽计费</radio>
|
||||
 
|
||||
<radio name="priceType" :v-value="'traffic'" v-model="config.priceType">按流量计费</radio>
|
||||
</div>
|
||||
<div v-else-if="config.priceType == 'bandwidth'">
|
||||
<radio name="priceType" :v-value="'bandwidth'" v-model="config.priceType">按带宽计费</radio>
|
||||
</div>
|
||||
<div v-else-if="config.priceType == 'traffic'">
|
||||
<radio name="priceType" :v-value="'traffic'" v-model="config.priceType">按流量计费</radio>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="config.priceType == 'bandwidth'">
|
||||
<td>所需带宽</td>
|
||||
<td>
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="bandwidth" size="10" maxlength="10" @input="change" ref="bandwidthInput"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<select class="ui dropdown auto-width" name="bandwidthUnit" @change="change">
|
||||
<option value="mb">Mbps</option>
|
||||
<option value="gb">Gbps</option>
|
||||
<option value="tb">Tbps</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="config.priceType == 'traffic'">
|
||||
<td>所需流量</td>
|
||||
<td>
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="traffic" size="10" maxlength="10" @input="change" ref="trafficInput"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<select class="ui dropdown auto-width" name="trafficUnit" @change="change">
|
||||
<option value="gb">GiB</option>
|
||||
<option value="tb">TiB</option>
|
||||
<option value="eb">EiB</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="regions.length > 0">
|
||||
<td>所在区域</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" name="regionId" @change="change">
|
||||
<option value="0">[不区分区域]</option>
|
||||
<option v-for="region in regions" :value="region.id">{{region.name}}</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>价格</td>
|
||||
<td>
|
||||
<strong v-if="formattedAmount.length > 0">
|
||||
¥{{formattedAmount}}元
|
||||
<span v-if="hasRegionPrice" class="small grey" style="font-weight: normal">(基于区域价格设定)</span>
|
||||
</strong>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<submit-btn>计算价格</submit-btn>
|
||||
</form>
|
||||
46
EdgeUser/web/views/@default/servers/fee/calculator.js
Normal file
46
EdgeUser/web/views/@default/servers/fee/calculator.js
Normal file
@@ -0,0 +1,46 @@
|
||||
Tea.context(function () {
|
||||
this.formattedAmount = ""
|
||||
this.hasRegionPrice = false
|
||||
|
||||
this.$delay(function () {
|
||||
this.changePriceType(this.config.priceType)
|
||||
|
||||
this.$watch("config.priceType", function (priceType) {
|
||||
this.formattedAmount = ""
|
||||
this.changePriceType(priceType)
|
||||
})
|
||||
})
|
||||
|
||||
this.success = function (resp) {
|
||||
this.formattedAmount = resp.data.amountFormatted
|
||||
this.hasRegionPrice = resp.data.hasRegionPrice
|
||||
}
|
||||
|
||||
this.changePriceType = function (priceType) {
|
||||
switch (priceType) {
|
||||
case "traffic":
|
||||
this.$refs.trafficInput.focus()
|
||||
break
|
||||
case "bandwidth":
|
||||
this.$refs.bandwidthInput.focus()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
this.requestId = ""
|
||||
this.change = function () {
|
||||
this.formattedAmount = ""
|
||||
this.hasRegionPrice = false
|
||||
|
||||
let requestId = Math.random().toString()
|
||||
this.requestId = requestId
|
||||
|
||||
this.$post("$")
|
||||
.form(this.$refs.calculatorForm)
|
||||
.success(function (resp) {
|
||||
if (requestId == this.requestId) {
|
||||
this.success(resp)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
21
EdgeUser/web/views/@default/servers/fee/index.html
Normal file
21
EdgeUser/web/views/@default/servers/fee/index.html
Normal file
@@ -0,0 +1,21 @@
|
||||
{$layout}
|
||||
{$template "menu"}
|
||||
|
||||
<div class="margin"></div>
|
||||
|
||||
<form class="ui form">
|
||||
<table class="ui table definition">
|
||||
<tr>
|
||||
<td class="title">计费方式</td>
|
||||
<td>{{config.priceTypeName}}
|
||||
<a href="" v-if="config.canChangeType" @click.prevent="updatePriceType">[修改]</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>计费周期</td>
|
||||
<td>{{config.pricePeriodName}}
|
||||
<a href="" v-if="config.canChangePeriod" @click.prevent="updatePricePeriod">[修改]</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
21
EdgeUser/web/views/@default/servers/fee/index.js
Normal file
21
EdgeUser/web/views/@default/servers/fee/index.js
Normal file
@@ -0,0 +1,21 @@
|
||||
Tea.context(function () {
|
||||
this.updatePriceType = function () {
|
||||
teaweb.popup("/servers/fee/updatePriceTypePopup", {
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
window.location.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.updatePricePeriod = function () {
|
||||
teaweb.popup("/servers/fee/updatePricePeriodPopup", {
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
window.location.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
120
EdgeUser/web/views/@default/servers/fee/prices.html
Normal file
120
EdgeUser/web/views/@default/servers/fee/prices.html
Normal file
@@ -0,0 +1,120 @@
|
||||
{$layout}
|
||||
{$template "menu"}
|
||||
|
||||
<second-menu>
|
||||
<menu-item v-if="supportBandwidth" :class="{active: priceType == 'bandwidth'}" @click.prevent="setPriceType('bandwidth')">带宽价格</menu-item>
|
||||
<menu-item v-if="supportTraffic" :class="{active: priceType == 'traffic'}" @click.prevent="setPriceType('traffic')">流量价格</menu-item>
|
||||
</second-menu>
|
||||
|
||||
<!-- 带宽 -->
|
||||
<div v-if="supportBandwidth && priceType == 'bandwidth'">
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">带宽基础价格</td>
|
||||
<td>{{bandwidthPrices.base}}元/Mbps</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>带宽百分位</td>
|
||||
<td> {{bandwidthPrices.percentile}}th
|
||||
<p class="comment" v-if="bandwidthPrices.percentile < 100">采用计费周期内第{{bandwidthPrices.percentile}}%个计费点作为计费依据。</p>
|
||||
<p class="comment" v-else>采用计费周期内最大峰值带宽作为计费依据。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="bandwidthPrices.ranges != null && bandwidthPrices.ranges.length > 0">
|
||||
<td>基础阶梯价格</td>
|
||||
<td>
|
||||
<table class="ui table selectable celled" style="width: 20em">
|
||||
<thead class="full-width">
|
||||
<tr>
|
||||
<th>带宽区间</th>
|
||||
<th>单价</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="range in bandwidthPrices.ranges">
|
||||
<td><span v-if="range.minMB == 0">0bps</span><span v-else>{{formatMB(range.minMB)}}</span>-{{formatMB(range.maxMB)}}</td>
|
||||
<td>{{range.pricePerMB}}元/Mbps</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div v-if="bandwidthPrices.supportRegions && regions.length > 0 && bandwidthItems.length > 0">
|
||||
<h4>区域带宽价格</h4>
|
||||
|
||||
<table class="ui table selectable small definition celled">
|
||||
<thead class="full-width">
|
||||
<tr>
|
||||
<th class="two wide">区域\带宽区间</th>
|
||||
<th v-for="item in bandwidthItems" class="center">
|
||||
{{item.name}}
|
||||
<br/>
|
||||
<span>{{item.minSize}}-{{item.maxSize}}</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="region in regions" v-show="region.supportBandwidth">
|
||||
<td class="">{{region.name}}</td>
|
||||
<td v-for="item in bandwidthItems" class="center">
|
||||
<div>
|
||||
<span v-if="region.prices[item.id.toString()] != null">¥{{region.prices[item.id.toString()]}}元/Mbps </span>
|
||||
<span v-else class="disabled">[基础阶梯价格]</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 流量 -->
|
||||
<div v-if="supportTraffic && priceType == 'traffic'">
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">流量基础价格</td>
|
||||
<td>{{trafficPrices.base}}元/GiB</td>
|
||||
</tr>
|
||||
<tr v-if="trafficPrices.ranges != null && trafficPrices.ranges.length > 0">
|
||||
<td>基础阶梯价格</td>
|
||||
<td>
|
||||
<table class="ui table selectable celled" style="width: 20em">
|
||||
<thead class="full-width">
|
||||
<tr>
|
||||
<th>流量区间</th>
|
||||
<th>单价</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="range in trafficPrices.ranges">
|
||||
<td><span v-if="range.minGB == 0">0B</span><span v-else>{{formatGB(range.minGB)}}</span>-{{formatGB(range.maxGB)}}</td>
|
||||
<td>{{range.pricePerGB}}元/GiB</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div v-if="trafficPrices.supportRegions && regions.length > 0 && trafficItems.length > 0">
|
||||
<h4>区域流量价格</h4>
|
||||
|
||||
<table class="ui table selectable small definition celled">
|
||||
<thead class="full-width">
|
||||
<tr>
|
||||
<th class="two wide">区域\流量区间</th>
|
||||
<th v-for="item in trafficItems" class="center">
|
||||
{{item.name}}
|
||||
<br/>
|
||||
<span>{{item.minSize}}-{{item.maxSize}}</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="region in regions" v-show="region.supportTraffic">
|
||||
<td class="">{{region.name}}</td>
|
||||
<td v-for="item in trafficItems" class="center">
|
||||
<div>
|
||||
<span v-if="region.prices[item.id.toString()] != null">¥{{region.prices[item.id.toString()]}}元/GiB </span>
|
||||
<span v-else class="disabled">[基础阶梯价格]</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
19
EdgeUser/web/views/@default/servers/fee/prices.js
Normal file
19
EdgeUser/web/views/@default/servers/fee/prices.js
Normal file
@@ -0,0 +1,19 @@
|
||||
Tea.context(function () {
|
||||
this.setPriceType = function (priceType) {
|
||||
this.priceType = priceType
|
||||
}
|
||||
|
||||
this.formatGB = function (gb) {
|
||||
if (gb == 0) {
|
||||
return "∞"
|
||||
}
|
||||
return teaweb.formatBytes(gb * 1024 * 1024 * 1024)
|
||||
}
|
||||
|
||||
this.formatMB = function (mb) {
|
||||
if (mb == 0) {
|
||||
return "∞"
|
||||
}
|
||||
return teaweb.formatBits(mb * 1024 * 1024)
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,20 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>修改支付周期</h3>
|
||||
|
||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">新支付周期 *</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" name="pricePeriod" v-model="pricePeriod">
|
||||
<option v-for="p in pricePeriods" :value="p.code">{{p.name}}</option>
|
||||
</select>
|
||||
<p class="comment" v-for="p in pricePeriods" v-if="pricePeriod == p.code">{{p.description}}如果当前计费周期内已经生成账单,则支付周期变更将在下个计费周期内生效。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,20 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>修改支付方式</h3>
|
||||
|
||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">新支付方式 *</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" name="priceType" v-model="priceType">
|
||||
<option v-for="p in priceTypes" :value="p.code">{{p.name}}</option>
|
||||
</select>
|
||||
<p class="comment" v-for="p in priceTypes" v-if="priceType == p.code">{{p.description}}如果当前计费周期内已经生成账单,则支付方式变更将在下个计费周期内生效。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
14
EdgeUser/web/views/@default/servers/groups/createPopup.html
Normal file
14
EdgeUser/web/views/@default/servers/groups/createPopup.html
Normal file
@@ -0,0 +1,14 @@
|
||||
{$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="50" ref="focus"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,7 @@
|
||||
<first-menu>
|
||||
<menu-item href="/servers/groups">分组列表</menu-item>
|
||||
<span class="item disabled">|</span>
|
||||
<menu-item :href="'/servers/groups/group?groupId=' + group.id" code="group.index">"{{group.name}}"详情</menu-item>
|
||||
<!--<menu-item :href="'/servers/groups/group/settings?groupId=' + group.id" :active="!firstMenuItem.startsWith('group.')">全局设置 <tip-icon content="这里添加的设置将会自动应用到当前分组下的所有服务。"></tip-icon></menu-item>-->
|
||||
<menu-item :href="'/servers/groups/group/update?groupId=' + group.id" code="group.update">修改</menu-item>
|
||||
</first-menu>
|
||||
11
EdgeUser/web/views/@default/servers/groups/group/index.html
Normal file
11
EdgeUser/web/views/@default/servers/groups/group/index.html
Normal file
@@ -0,0 +1,11 @@
|
||||
{$layout}
|
||||
{$template "menu"}
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">分组名称</td>
|
||||
<td>
|
||||
{{group.name}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -0,0 +1,3 @@
|
||||
Tea.context(function () {
|
||||
this.checkDNS = false
|
||||
})
|
||||
15
EdgeUser/web/views/@default/servers/groups/group/update.html
Normal file
15
EdgeUser/web/views/@default/servers/groups/group/update.html
Normal file
@@ -0,0 +1,15 @@
|
||||
{$layout "layout"}
|
||||
{$template "menu"}
|
||||
|
||||
<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="50" ref="focus" v-model="group.name"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,5 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifySuccess("保存成功", ".", {
|
||||
groupId: this.group.id
|
||||
})
|
||||
})
|
||||
38
EdgeUser/web/views/@default/servers/groups/index.html
Normal file
38
EdgeUser/web/views/@default/servers/groups/index.html
Normal file
@@ -0,0 +1,38 @@
|
||||
{$layout}
|
||||
{$template "../menu"}
|
||||
|
||||
<second-menu>
|
||||
<menu-item @click.prevent="createGroup">[创建新分组]</menu-item>
|
||||
</second-menu>
|
||||
|
||||
<p class="comment" v-if="groups.length == 0">暂时还没有分组。</p>
|
||||
<div v-show="groups.length > 0">
|
||||
<div class="margin"></div>
|
||||
<table class="ui table selectable celled" id="sortable-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:3em"></th>
|
||||
<th>分组名称</th>
|
||||
<th class="center width10">服务数量</th>
|
||||
<th class="two 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"></i> </td>
|
||||
<td>
|
||||
<a :href="'/servers/groups/group?groupId=' + group.id">{{group.name}}</a>
|
||||
</td>
|
||||
<td class="center">
|
||||
<a :href="'/servers?groupId=' + group.id" v-if="group.countServers > 0">{{group.countServers}}</a>
|
||||
<span v-else class="disabled">0</span>
|
||||
</td>
|
||||
<td>
|
||||
<a :href="'/servers/groups/group?groupId=' + group.id">详情</a> <a href="" @click.prevent="deleteGroup(group.id)">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p v-if="groups.length > 0" class="comment">可以拖动左侧的<i class="icon bars"></i>排序。</p>
|
||||
</div>
|
||||
43
EdgeUser/web/views/@default/servers/groups/index.js
Normal file
43
EdgeUser/web/views/@default/servers/groups/index.js
Normal file
@@ -0,0 +1,43 @@
|
||||
Tea.context(function () {
|
||||
this.$delay(function () {
|
||||
let that = this
|
||||
sortTable(function () {
|
||||
let groupIds = []
|
||||
document.querySelectorAll("*[data-group-id]").forEach(function (element) {
|
||||
groupIds.push(element.getAttribute("data-group-id"))
|
||||
})
|
||||
that.$post("/servers/groups/sort")
|
||||
.params({
|
||||
groupIds: groupIds
|
||||
})
|
||||
.success(function () {
|
||||
teaweb.successToast("保存成功")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
this.createGroup = function () {
|
||||
teaweb.popup("/servers/groups/createPopup", {
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.deleteGroup = function (groupId) {
|
||||
let that = this
|
||||
teaweb.confirm("确定要删除这个分组吗?", function () {
|
||||
that.$post("/servers/groups/group/delete")
|
||||
.params({
|
||||
groupId: groupId
|
||||
})
|
||||
.success(function () {
|
||||
teaweb.success("删除成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
22
EdgeUser/web/views/@default/servers/groups/selectPopup.html
Normal file
22
EdgeUser/web/views/@default/servers/groups/selectPopup.html
Normal file
@@ -0,0 +1,22 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>选择分组</h3>
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="groupId" :value="groupId"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">选择分组</td>
|
||||
<td>
|
||||
<div v-if="groups.length > 0">
|
||||
<a href="" class="ui label small basic" v-for="group in groups" :class="{blue:group.id == groupId}" style="margin-bottom:0.5em" @click.prevent="selectGroup(group)">{{group.name}}</a>
|
||||
<p class="comment">点击可已选中要使用的分组。</p>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p class="comment">暂时还没有可以使用的分组。</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn>确定</submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,8 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifyPopup
|
||||
this.groupId = 0
|
||||
|
||||
this.selectGroup = function (group) {
|
||||
this.groupId = group.id
|
||||
}
|
||||
})
|
||||
18
EdgeUser/web/views/@default/servers/index.css
Normal file
18
EdgeUser/web/views/@default/servers/index.css
Normal file
@@ -0,0 +1,18 @@
|
||||
.server-checkbox-td .checkbox {
|
||||
opacity: 50%;
|
||||
}
|
||||
.server-checkbox-td .checkbox:hover {
|
||||
opacity: 100%;
|
||||
}
|
||||
.server-td .server-name-box a {
|
||||
display: none;
|
||||
}
|
||||
.server-td:hover .server-name-box a {
|
||||
display: inline;
|
||||
}
|
||||
@media screen and (max-width: 1300px) {
|
||||
.server-td .server-name-box {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
/*# sourceMappingURL=index.css.map */
|
||||
1
EdgeUser/web/views/@default/servers/index.css.map
Normal file
1
EdgeUser/web/views/@default/servers/index.css.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA,mBACC;EACC,YAAA;;AAFF,mBAKC,UAAS;EACR,aAAA;;AAIF,UAAW,iBACV;EACC,aAAA;;AAIF,UAAU,MAAO,iBAChB;EACC,eAAA;;AAIF,mBAAqC;EACpC,UAAW;IACV,aAAA","file":"index.css"}
|
||||
104
EdgeUser/web/views/@default/servers/index.html
Normal file
104
EdgeUser/web/views/@default/servers/index.html
Normal file
@@ -0,0 +1,104 @@
|
||||
{$layout}
|
||||
{$template "menu"}
|
||||
|
||||
<div class="ui message error" v-if="!serversIsEnabled">
|
||||
当前账号下的网站不可用,请检查账号状态以及是否有逾期未支付的账单。
|
||||
</div>
|
||||
|
||||
<div class="ui message warning" v-if="serversIsEnabled && countUnpaidBills > 0">
|
||||
<a href="/finance/bills?paidFlag=0">有逾期未支付的账单,可能会影响你的CDN服务正常运行,请尽快完成支付。</a>
|
||||
</div>
|
||||
|
||||
<div class="margin"></div>
|
||||
<form class="ui form" action="/servers">
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="keyword" v-model="keyword" placeholder="域名"/>
|
||||
</div>
|
||||
<div class="ui field" v-if="groups.length > 0">
|
||||
<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="ui field">
|
||||
<button type="submit" class="ui button">搜索</button>
|
||||
|
||||
<a href="/servers" v-if="keyword.length > 0 || groupId > 0">[清除条件]</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<p class="comment" v-if="servers.length == 0">暂时还没有任何域名。</p>
|
||||
|
||||
<div v-if="checkedServerIds.length > 0">
|
||||
<div class="ui divider"></div>
|
||||
<button class="ui button basic" @click.prevent="resetCheckedServers">取消所选</button>
|
||||
<button class="ui button basic" @click.prevent="deleteServers">删除所选{{checkedServerIds.length}}网站</button>
|
||||
</div>
|
||||
|
||||
<table class="ui table selectable" v-if="servers.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 1em" class="server-checkbox-td"><checkbox ref="allCheckedCheckboxes" @input="changeAllChecked"></checkbox></th>
|
||||
<th>域名</th>
|
||||
<th class="three wide">CNAME</th>
|
||||
<th class="three wide">状态</th>
|
||||
<th class="two wide">HTTP</th>
|
||||
<th class="two wide">HTTPS</th>
|
||||
<th class="three op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="server in servers">
|
||||
<td class="server-checkbox-td"><checkbox ref="serverCheckboxes" :v-value="server.id" @input="changeServerChecked"></checkbox></td>
|
||||
<td class="server-td">
|
||||
<a :href="'/servers/server?serverId=' + server.id">
|
||||
<span v-if="server.serverNames.length > 0">
|
||||
<span v-if="server.serverNames[0].subNames == null || server.serverNames[0].subNames.length == 0"><keyword :v-word="keyword">{{server.serverNames[0].name}}</keyword></span>
|
||||
<span v-else>{{server.serverNames[0].subNames[0]}}</span>
|
||||
<span v-if="server.countServerNames > 1">等{{server.countServerNames}}个域名 <popup-icon :href="'/servers/serverNamesPopup?serverId=' + server.id" height="20em"></popup-icon></span>
|
||||
</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</a>
|
||||
|
||||
<!-- name -->
|
||||
<span class="server-name-box">
|
||||
<span class="grey small"> <i class="icon tag small"></i>{{server.name}}
|
||||
<a href="" @click.prevent="updateServerName(server.id)">[修改]</a>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<div v-if="server.userPlan != null && server.userPlan.id > 0">
|
||||
<span style="margin-top: 1em" class="small" :class="{grey: !server.userPlan.isExpired, red: server.userPlan.isExpired}">套餐:{{server.userPlan.name}} / {{server.userPlan.dayTo}} <span v-if="server.userPlan.isExpired">已过期</span></span>
|
||||
</div>
|
||||
<div v-if="server.trafficLimitStatus != null">
|
||||
<server-traffic-limit-status-viewer v-model="server.trafficLimitStatus"></server-traffic-limit-status-viewer>
|
||||
</div>
|
||||
<div v-if="server.groups.length > 0">
|
||||
<span style="margin-top: 1em" class="small grey" v-for="serverGroup in server.groups">[{{serverGroup.name}}] </span>
|
||||
</div>
|
||||
</td>
|
||||
<td>{{server.cname}}</td>
|
||||
<td>
|
||||
<span v-if="!server.isOn" class="grey">停用中</span>
|
||||
<span v-else-if="server.status.isOk" class="green">正常</span>
|
||||
<span v-else-if="server.status.message.length == 0">检查中</span>
|
||||
<span v-else class="red">{{server.status.message}}
|
||||
<tip-icon :content="server.status.todo"></tip-icon>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="server.httpIsOn" class="green">Y</span>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="server.httpsIsOn" class="green">Y</span>
|
||||
</td>
|
||||
<td>
|
||||
<a :href="'/servers/server?serverId=' + server.id">管理</a>
|
||||
<a href="" v-if="server.isOn" @click.prevent="updateServerOff(server.id)">停用</a><a href="" v-if="!server.isOn" @click.prevent="updateServerOn(server.id)"><span class="red">启用</span></a>
|
||||
<a href="" @click.prevent="deleteServer(server.id)">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
119
EdgeUser/web/views/@default/servers/index.js
Normal file
119
EdgeUser/web/views/@default/servers/index.js
Normal file
@@ -0,0 +1,119 @@
|
||||
Tea.context(function () {
|
||||
this.$delay(function () {
|
||||
this.loadStatus()
|
||||
})
|
||||
|
||||
this.loadStatus = function () {
|
||||
let serverIds = this.servers.map(function (v) {
|
||||
return v.id
|
||||
})
|
||||
this.$post(".status")
|
||||
.params({
|
||||
serverIds: serverIds
|
||||
})
|
||||
.timeout(300)
|
||||
.success(function (resp) {
|
||||
let status = resp.data.status
|
||||
this.servers.forEach(function (server) {
|
||||
if (typeof status[server.id] === "object") {
|
||||
server.status = status[server.id]
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
this.deleteServer = function (serverId) {
|
||||
let that = this
|
||||
teaweb.confirm("确定要删除此域名吗?", function () {
|
||||
that.$post(".delete")
|
||||
.params({
|
||||
serverId: serverId
|
||||
})
|
||||
.refresh()
|
||||
})
|
||||
}
|
||||
|
||||
this.updateServerOn = function (serverId) {
|
||||
let that = this
|
||||
teaweb.confirm("确定要启用此域名吗?", function () {
|
||||
that.$post(".updateOn")
|
||||
.params({
|
||||
serverId: serverId,
|
||||
isOn: true
|
||||
})
|
||||
.refresh()
|
||||
})
|
||||
}
|
||||
|
||||
this.updateServerOff = function (serverId) {
|
||||
let that = this
|
||||
teaweb.confirm("确定要停用此域名吗?", function () {
|
||||
that.$post(".updateOn")
|
||||
.params({
|
||||
serverId: serverId,
|
||||
isOn: false
|
||||
})
|
||||
.refresh()
|
||||
})
|
||||
}
|
||||
|
||||
this.updateServerName = function (serverId) {
|
||||
teaweb.popup("/servers/updateNamePopup?serverId=" + serverId, {
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 全选
|
||||
*/
|
||||
this.checkedServerIds = []
|
||||
this.changeAllChecked = function (checked) {
|
||||
for (let checkbox of this.$refs.serverCheckboxes) {
|
||||
if (checked) {
|
||||
checkbox.check()
|
||||
} else {
|
||||
checkbox.uncheck()
|
||||
}
|
||||
}
|
||||
this.updateCheckedServers()
|
||||
}
|
||||
|
||||
this.changeServerChecked = function () {
|
||||
this.updateCheckedServers()
|
||||
}
|
||||
|
||||
this.updateCheckedServers = function () {
|
||||
let serverIds = []
|
||||
for (let checkbox of this.$refs.serverCheckboxes) {
|
||||
if (checkbox.isChecked()) {
|
||||
serverIds.push(checkbox.vValue)
|
||||
}
|
||||
}
|
||||
this.checkedServerIds = serverIds
|
||||
}
|
||||
|
||||
this.resetCheckedServers = function () {
|
||||
this.$refs.allCheckedCheckboxes.uncheck()
|
||||
for (let checkbox of this.$refs.serverCheckboxes) {
|
||||
checkbox.uncheck()
|
||||
}
|
||||
this.updateCheckedServers()
|
||||
}
|
||||
|
||||
this.deleteServers = function () {
|
||||
let that = this
|
||||
teaweb.confirm("确定要删除所选的" + (this.checkedServerIds.length) + "个网站吗?", function () {
|
||||
that.$post(".deleteServers")
|
||||
.params({
|
||||
serverIds: this.checkedServerIds
|
||||
})
|
||||
.success(function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
27
EdgeUser/web/views/@default/servers/index.less
Normal file
27
EdgeUser/web/views/@default/servers/index.less
Normal file
@@ -0,0 +1,27 @@
|
||||
.server-checkbox-td {
|
||||
.checkbox {
|
||||
opacity: 50%;
|
||||
}
|
||||
|
||||
.checkbox:hover {
|
||||
opacity: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.server-td .server-name-box {
|
||||
a {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.server-td:hover .server-name-box {
|
||||
a {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1300px){
|
||||
.server-td .server-name-box {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
5
EdgeUser/web/views/@default/servers/packages/@menu.html
Normal file
5
EdgeUser/web/views/@default/servers/packages/@menu.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<first-menu>
|
||||
<menu-item href="." code="index">我的流量包</menu-item>
|
||||
<span class="disabled item">|</span>
|
||||
<menu-item href=".buy" code="buy">购买流量包</menu-item>
|
||||
</first-menu>
|
||||
52
EdgeUser/web/views/@default/servers/packages/buy.html
Normal file
52
EdgeUser/web/views/@default/servers/packages/buy.html
Normal file
@@ -0,0 +1,52 @@
|
||||
{$layout}
|
||||
{$template "menu"}
|
||||
|
||||
<form class="ui form">
|
||||
<csrf-token></csrf-token>
|
||||
|
||||
<input type="hidden" name="packageId" :value="packageId"/>
|
||||
<input type="hidden" name="regionId" :value="regionId"/>
|
||||
<input type="hidden" name="periodId" :value="periodId"/>
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">选择流量包规格 *</td>
|
||||
<td>
|
||||
<span v-if="packages.length > 0"><a v-for="p in packages" class="ui label basic" :class="{blue: p.id == packageId}" @click.prevent="selectPackage(p.id)">{{p.size}}{{p.unit.toUpperCase().replace(/(.)B/, "$1iB")}}</a></span>
|
||||
<span v-else="" class="red">没有流量包可供选择</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>选择区域 *</td>
|
||||
<td>
|
||||
<span v-if="regions.length > 0"><a v-for="region in regions" class="ui label basic" :class="{blue: region.id == regionId && hasRegionPrice(region.id), disabled: !hasRegionPrice(region.id)}" @click.prevent="selectRegion(region.id)">{{region.name}}</a></span>
|
||||
<span v-else="" class="red">没有区域可供选择</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>选择有效期 *</td>
|
||||
<td>
|
||||
<span v-if="periods.length > 0"><a v-for="period in periods" class="ui label basic" :class="{blue: period.id == periodId && hasPeriodPrice(period.id), disabled: !hasPeriodPrice(period.id)}" @click.prevent="selectPeriod(period.id)">{{period.count}}{{period.unitName}}</a></span>
|
||||
<span v-else="" class="red">没有有效期可供选择</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>流量包数量 *</td>
|
||||
<td>
|
||||
<div class="ui input">
|
||||
<select class="ui dropdown" name="count" v-model="count" @change="changeCount">
|
||||
<option v-for="i in 20" :value="i">{{i}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>价格</td>
|
||||
<td>
|
||||
<span v-if="amount == 0" class="disabled">没有找到对应价格</span>
|
||||
<span v-if="amount > 0">{{amount}}元</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<button class="ui button primary" :class="{disabled: amount <= 0}" type="button" @click.prevent="goNext()">下一步</button>
|
||||
</form>
|
||||
76
EdgeUser/web/views/@default/servers/packages/buy.js
Normal file
76
EdgeUser/web/views/@default/servers/packages/buy.js
Normal file
@@ -0,0 +1,76 @@
|
||||
Tea.context(function () {
|
||||
this.packageId = 0
|
||||
this.regionId = 0
|
||||
this.periodId = 0
|
||||
this.amount = -1
|
||||
this.count = 1
|
||||
|
||||
this.selectPackage = function (packageId) {
|
||||
this.packageId = packageId
|
||||
this.regionId = 0
|
||||
this.periodId = 0
|
||||
this.reloadPrice()
|
||||
}
|
||||
|
||||
this.selectRegion = function (regionId) {
|
||||
this.regionId = regionId
|
||||
this.periodId = 0
|
||||
this.reloadPrice()
|
||||
}
|
||||
|
||||
this.selectPeriod = function (periodId) {
|
||||
this.periodId = periodId
|
||||
this.reloadPrice()
|
||||
}
|
||||
|
||||
this.changeCount = function () {
|
||||
this.reloadPrice()
|
||||
}
|
||||
|
||||
var requestId = 0
|
||||
this.reloadPrice = function () {
|
||||
var newRequestId = (++requestId)
|
||||
this.$post(".price")
|
||||
.params({
|
||||
packageId: this.packageId,
|
||||
regionId: this.regionId,
|
||||
periodId: this.periodId,
|
||||
count: this.count
|
||||
})
|
||||
.success(function (resp) {
|
||||
if (newRequestId == requestId) {
|
||||
this.amount = resp.data.amount
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.hasRegionPrice = function (regionId) {
|
||||
if (this.packageId <= 0) {
|
||||
return false
|
||||
}
|
||||
for (let k in this.prices) {
|
||||
if (k.startsWith(this.packageId + "@" + regionId + "@")) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
this.hasPeriodPrice = function (periodId) {
|
||||
if (this.packageId <= 0 || this.regionId <= 0) {
|
||||
return false
|
||||
}
|
||||
for (let k in this.prices) {
|
||||
if (k == this.packageId + "@" + this.regionId + "@" + periodId) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
this.goNext = function () {
|
||||
if (this.packageId > 0 && this.regionId > 0 && this.periodId > 0 && this.count > 0) {
|
||||
window.location = "/servers/packages/confirm?packageId=" + this.packageId + "®ionId=" + this.regionId + "&periodId=" + this.periodId + "&count=" + this.count
|
||||
}
|
||||
}
|
||||
})
|
||||
30
EdgeUser/web/views/@default/servers/packages/confirm.html
Normal file
30
EdgeUser/web/views/@default/servers/packages/confirm.html
Normal file
@@ -0,0 +1,30 @@
|
||||
{$layout}
|
||||
{$template "menu"}
|
||||
|
||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
|
||||
<input type="hidden" name="packageId" :value="packageId"/>
|
||||
<input type="hidden" name="regionId" :value="regionId"/>
|
||||
<input type="hidden" name="periodId" :value="periodId"/>
|
||||
<input type="hidden" name="count" :value="count"/>
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">流量包</td>
|
||||
<td>[{{packageName}} / {{regionName}} / {{periodName}}] x {{count}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>价格</td>
|
||||
<td>¥{{amount}}元</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>支付方式</td>
|
||||
<td>
|
||||
<pay-method-selector></pay-method-selector>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<submit-btn>确定购买</submit-btn> <a href="/servers/packages/buy" @click.prevent="goBack()">上一步</a>
|
||||
</form>
|
||||
23
EdgeUser/web/views/@default/servers/packages/confirm.js
Normal file
23
EdgeUser/web/views/@default/servers/packages/confirm.js
Normal file
@@ -0,0 +1,23 @@
|
||||
Tea.context(function () {
|
||||
this.goBack = function () {
|
||||
window.history.back()
|
||||
}
|
||||
|
||||
this.success = function (resp) {
|
||||
if (resp.data.success) {
|
||||
teaweb.success("流量包购买成功", function () {
|
||||
window.location = "/servers/packages"
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (resp.data.orderCode.length > 0) {
|
||||
window.location = "/finance/pay?code=" + resp.data.orderCode + "&from=" + window.escape(window.location.toString()) + "&returnURL=/servers/packages"
|
||||
}
|
||||
}
|
||||
|
||||
this.methodCode = "@balance"
|
||||
this.changePayMethod = function (methodCode) {
|
||||
this.methodCode = methodCode
|
||||
}
|
||||
})
|
||||
53
EdgeUser/web/views/@default/servers/packages/index.html
Normal file
53
EdgeUser/web/views/@default/servers/packages/index.html
Normal file
@@ -0,0 +1,53 @@
|
||||
{$layout}
|
||||
{$template "menu"}
|
||||
|
||||
<second-menu>
|
||||
<menu-item href="/servers/packages" :class="{active: type == ''}">可用流量包</menu-item>
|
||||
<menu-item href="/servers/packages?type=all" :class="{active: type == 'all'}">所有流量包</menu-item>
|
||||
</second-menu>
|
||||
|
||||
<p class="comment" v-if="userPackages.length == 0">
|
||||
<span v-if="type == ''">暂时还没有可用的流量包。</span>
|
||||
<span v-if="type == 'all'">暂时还没有流量包。</span>
|
||||
</p>
|
||||
|
||||
<div v-if="userPackages.length > 0">
|
||||
<div class="margin"></div>
|
||||
<table class="ui table selectable celled">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>流量包</th>
|
||||
<th style="width: 7em">区域</th>
|
||||
<th style="width: 7em">有效期</th>
|
||||
<th style="width: 7em">开始日期</th>
|
||||
<th style="width: 7em">结束日期</th>
|
||||
<th style="width: 7em">已用流量</th>
|
||||
<th style="width: 7em">剩余流量</th>
|
||||
<th style="width: 12em">购买时间</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="up in userPackages">
|
||||
<td>
|
||||
<span v-if="up.package != null">{{up.package.size}}{{up.package.unit.toUpperCase().replace(/(.)B/, "$1iB")}}</span>
|
||||
<span v-else class="disabled">[已删除]</span>
|
||||
|
||||
<div v-if="up.isUsedAll || up.isExpired">
|
||||
<span v-if="up.isUsedAll" class="small red">已用尽</span>
|
||||
<span v-else-if="up.isExpired" class="small red">已过期</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="up.region != null">{{up.region.name}}</span>
|
||||
<span v-else="" class="disabled">[已删除]</span>
|
||||
</td>
|
||||
<td>{{up.periodCount}}{{up.periodUnitName}}</td>
|
||||
<td>{{up.dayFrom}}</td>
|
||||
<td>{{up.dayTo}}</td>
|
||||
<td><span :class="{disabled: up.usedSize == '0B'}">{{up.usedSize}}</span></td>
|
||||
<td><span :class="{disabled: up.availableSize == '0B'}">{{up.availableSize}}</span></td>
|
||||
<td>{{up.createdTime}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<page-box></page-box>
|
||||
</div>
|
||||
1
EdgeUser/web/views/@default/servers/server.html
Normal file
1
EdgeUser/web/views/@default/servers/server.html
Normal file
@@ -0,0 +1 @@
|
||||
{$layout}
|
||||
56
EdgeUser/web/views/@default/servers/server/log/history.html
Normal file
56
EdgeUser/web/views/@default/servers/server/log/history.html
Normal file
@@ -0,0 +1,56 @@
|
||||
{$layout}
|
||||
|
||||
{$var "header"}
|
||||
<!-- datepicker -->
|
||||
<script type="text/javascript" src="/js/moment.min.js"></script>
|
||||
<script type="text/javascript" src="/js/pikaday.js"></script>
|
||||
<link rel="stylesheet" href="/js/pikaday.css"/>
|
||||
<link rel="stylesheet" href="/js/pikaday.theme.css"/>
|
||||
<link rel="stylesheet" href="/js/pikaday.triangle.css"/>
|
||||
{$end}
|
||||
|
||||
{$template "/left_menu"}
|
||||
|
||||
<div class="right-box">
|
||||
{$ if eq .featureIsOn false }
|
||||
<server-feature-required></server-feature-required>
|
||||
{$ else }
|
||||
<first-menu>
|
||||
<menu-item :href="path + '?serverId=' + serverId + '&day=' + day" :active="hasError == 0">所有日志</menu-item>
|
||||
<menu-item :href="path + '?serverId=' + serverId + '&day=' + day + '&hasError=1'" :active="hasError > 0">错误日志</menu-item>
|
||||
<div class="item right">
|
||||
<form method="get" class="ui form small" :action="path" autocomplete="off">
|
||||
<input type="hidden" name="serverId" :value="serverId"/>
|
||||
<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>
|
||||
</form>
|
||||
</div>
|
||||
</first-menu>
|
||||
<form method="get" class="ui form small" :action="path" autocomplete="off">
|
||||
<input type="hidden" name="serverId" :value="serverId"/>
|
||||
<http-access-log-search-box :v-ip="ip" :v-domain="domain" :v-keyword="keyword" :v-cluster-id="clusterId" :v-node-id="nodeId"></http-access-log-search-box>
|
||||
</form>
|
||||
<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 + '?serverId=' + serverId + '&requestId=' + lastRequestId + '&day=' + day + '&hasError=' + hasError+'&ip='+ip+'&domain='+domain+'&keyword='+keyword+'&clusterId='+clusterId+'&nodeId='+nodeId" v-if="hasPrev">上一页</a>
|
||||
<span v-else class="disabled">上一页</span>
|
||||
<span class="disabled"> | </span>
|
||||
<a :href="path + '?serverId=' + serverId + '&requestId=' + nextRequestId + '&day=' + day + '&hasError=' + hasError+'&ip='+ip+'&domain='+domain+'&keyword='+keyword+'&clusterId='+clusterId+'&nodeId='+nodeId" v-if="hasMore">下一页</a>
|
||||
<span v-else class="disabled">下一页</span>
|
||||
</div>
|
||||
{$end}
|
||||
</div>
|
||||
21
EdgeUser/web/views/@default/servers/server/log/history.js
Normal file
21
EdgeUser/web/views/@default/servers/server/log/history.js
Normal file
@@ -0,0 +1,21 @@
|
||||
Tea.context(function () {
|
||||
this.$delay(function () {
|
||||
let that = this
|
||||
if (this.featureIsOn) {
|
||||
teaweb.datepicker("day-input", function (day) {
|
||||
that.day = day
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
let that = this
|
||||
if (this.featureIsOn) {
|
||||
this.accessLogs.forEach(function (accessLog) {
|
||||
if (typeof (that.regions[accessLog.remoteAddr]) == "string") {
|
||||
accessLog.region = that.regions[accessLog.remoteAddr]
|
||||
} else {
|
||||
accessLog.region = ""
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
20
EdgeUser/web/views/@default/servers/server/log/index.html
Normal file
20
EdgeUser/web/views/@default/servers/server/log/index.html
Normal file
@@ -0,0 +1,20 @@
|
||||
{$layout}
|
||||
|
||||
{$template "/left_menu"}
|
||||
<div class="right-box">
|
||||
{$ if eq .featureIsOn false }
|
||||
<server-feature-required></server-feature-required>
|
||||
{$ else }
|
||||
<form method="get" class="ui form small" :action="path" autocomplete="off">
|
||||
<input type="hidden" name="serverId" :value="serverId"/>
|
||||
<http-access-log-search-box :v-ip="ip" :v-domain="domain" :v-keyword="keyword" :v-cluster-id="clusterId" :v-node-id="nodeId"></http-access-log-search-box>
|
||||
</form>
|
||||
<p class="comment" v-if="isLoaded && 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>
|
||||
{$end}
|
||||
</div>
|
||||
61
EdgeUser/web/views/@default/servers/server/log/index.js
Normal file
61
EdgeUser/web/views/@default/servers/server/log/index.js
Normal file
@@ -0,0 +1,61 @@
|
||||
Tea.context(function () {
|
||||
this.$delay(function () {
|
||||
this.load()
|
||||
})
|
||||
|
||||
this.hasMore = false
|
||||
this.accessLogs = []
|
||||
this.isLoaded = false
|
||||
|
||||
this.load = function () {
|
||||
// 如果有弹窗时,暂时不更新
|
||||
if (teaweb.hasPopup()) {
|
||||
this.$delay(function () {
|
||||
this.load()
|
||||
}, 5000)
|
||||
return
|
||||
}
|
||||
|
||||
this.$post("$")
|
||||
.params({
|
||||
serverId: this.serverId,
|
||||
requestId: this.requestId,
|
||||
keyword: this.keyword,
|
||||
ip: this.ip,
|
||||
domain: this.domain,
|
||||
clusterId: this.clusterId,
|
||||
nodeId: this.nodeId
|
||||
})
|
||||
.success(function (resp) {
|
||||
this.accessLogs = resp.data.accessLogs.concat(this.accessLogs)
|
||||
|
||||
// 添加区域信息
|
||||
this.accessLogs.forEach(function (accessLog) {
|
||||
if (typeof (resp.data.regions[accessLog.remoteAddr]) == "string") {
|
||||
accessLog.region = resp.data.regions[accessLog.remoteAddr]
|
||||
} else {
|
||||
accessLog.region = ""
|
||||
}
|
||||
})
|
||||
|
||||
let max = 100
|
||||
if (this.accessLogs.length > max) {
|
||||
this.accessLogs = this.accessLogs.slice(0, max)
|
||||
}
|
||||
this.hasMore = resp.data.hasMore
|
||||
this.requestId = resp.data.requestId
|
||||
})
|
||||
.done(function () {
|
||||
if (!this.isLoaded) {
|
||||
this.$delay(function () {
|
||||
this.isLoaded = true
|
||||
})
|
||||
}
|
||||
|
||||
// 自动刷新
|
||||
this.$delay(function () {
|
||||
this.load()
|
||||
}, 5000)
|
||||
})
|
||||
}
|
||||
})
|
||||
33
EdgeUser/web/views/@default/servers/server/log/today.html
Normal file
33
EdgeUser/web/views/@default/servers/server/log/today.html
Normal file
@@ -0,0 +1,33 @@
|
||||
{$layout}
|
||||
|
||||
{$template "/left_menu"}
|
||||
<div class="right-box">
|
||||
{$ if eq .featureIsOn false }
|
||||
<server-feature-required></server-feature-required>
|
||||
{$ else }
|
||||
<first-menu>
|
||||
<menu-item :href="path + '?serverId=' + serverId" :active="hasError == 0">所有日志</menu-item>
|
||||
<menu-item :href="path + '?serverId=' + serverId + '&hasError=1'" :active="hasError > 0">错误日志</menu-item>
|
||||
</first-menu>
|
||||
|
||||
<form method="get" class="ui form small" :action="path" autocomplete="off">
|
||||
<input type="hidden" name="serverId" :value="serverId"/>
|
||||
<http-access-log-search-box :v-ip="ip" :v-domain="domain" :v-keyword="keyword" :v-cluster-id="clusterId" :v-node-id="nodeId"></http-access-log-search-box>
|
||||
</form>
|
||||
<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 + '?serverId=' + serverId + '&requestId=' + lastRequestId + '&hasError=' + hasError+'&ip='+ip+'&domain='+domain+'&keyword='+keyword+'&clusterId='+clusterId+'&nodeId='+nodeId" v-if="hasPrev">上一页</a>
|
||||
<span v-else class="disabled">上一页</span>
|
||||
<span class="disabled"> | </span>
|
||||
<a :href="path + '?serverId=' + serverId + '&requestId=' + nextRequestId + '&hasError=' + hasError+'&ip='+ip+'&domain='+domain+'&keyword='+keyword+'&clusterId='+clusterId+'&nodeId='+nodeId" v-if="hasMore">下一页</a>
|
||||
<span v-else class="disabled">下一页</span>
|
||||
</div>
|
||||
{$end}
|
||||
</div>
|
||||
12
EdgeUser/web/views/@default/servers/server/log/today.js
Normal file
12
EdgeUser/web/views/@default/servers/server/log/today.js
Normal file
@@ -0,0 +1,12 @@
|
||||
Tea.context(function () {
|
||||
let that = this
|
||||
if (this.featureIsOn) {
|
||||
this.accessLogs.forEach(function (accessLog) {
|
||||
if (typeof (that.regions[accessLog.remoteAddr]) == "string") {
|
||||
accessLog.region = that.regions[accessLog.remoteAddr]
|
||||
} else {
|
||||
accessLog.region = ""
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,7 @@
|
||||
table td {
|
||||
word-break: break-all;
|
||||
}
|
||||
table td.title {
|
||||
width: 12em !important;
|
||||
}
|
||||
/*# sourceMappingURL=viewPopup.css.map */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user