1.4.5.2
This commit is contained in:
@@ -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="/servers/certs/acme/accounts" code="account">服务商账号</menu-item>
|
||||
</first-menu>
|
||||
@@ -0,0 +1,42 @@
|
||||
{$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"/>
|
||||
<p class="comment">为当前账号起一个容易识别的名称。</p>
|
||||
</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
EdgeAdmin/web/views/@default/servers/certs/acme/create.css
Normal file
15
EdgeAdmin/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"}
|
||||
170
EdgeAdmin/web/views/@default/servers/certs/acme/create.html
Normal file
170
EdgeAdmin/web/views/@default/servers/certs/acme/create.html
Normal file
@@ -0,0 +1,170 @@
|
||||
{$layout}
|
||||
{$template "/left_menu_top"}
|
||||
|
||||
<div class="right-box without-tabbar">
|
||||
{$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>选择平台用户</td>
|
||||
<td>
|
||||
<user-selector @change="changePlatformUser"></user-selector>
|
||||
<p class="comment">可选项,选择证书所属用户,如果没有选择,则视为管理员所有。</p>
|
||||
</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">选择ACME用户 *</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" 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"><span v-if="platformUserId > 0">当前平台用户下</span>暂时还没有ACME用户,点此创建</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>
|
||||
</div>
|
||||
165
EdgeAdmin/web/views/@default/servers/certs/acme/create.js
Normal file
165
EdgeAdmin/web/views/@default/servers/certs/acme/create.js
Normal file
@@ -0,0 +1,165 @@
|
||||
Tea.context(function () {
|
||||
this.step = "prepare"
|
||||
|
||||
/**
|
||||
* 选择平台用户
|
||||
*/
|
||||
this.platformUserId = 0
|
||||
|
||||
this.changePlatformUser = function (platformUserId) {
|
||||
this.platformUserId = platformUserId
|
||||
}
|
||||
|
||||
/**
|
||||
* 准备工作
|
||||
*/
|
||||
this.authType = "http"
|
||||
this.users = []
|
||||
|
||||
this.doPrepare = function () {
|
||||
this.step = "user"
|
||||
|
||||
this.$post(".userOptions")
|
||||
.params({
|
||||
platformUserId: this.platformUserId
|
||||
})
|
||||
.success(function (resp) {
|
||||
this.users = resp.data.users
|
||||
})
|
||||
}
|
||||
|
||||
this.prepareMoreOptionsVisible = false
|
||||
this.authURL = ""
|
||||
this.showPrepareMoreOptionsVisible = function () {
|
||||
this.prepareMoreOptionsVisible = !this.prepareMoreOptionsVisible
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择ACME用户
|
||||
*/
|
||||
this.userId = 0
|
||||
|
||||
this.goPrepare = function () {
|
||||
this.step = "prepare"
|
||||
}
|
||||
|
||||
this.createUser = function () {
|
||||
let that = this
|
||||
teaweb.popup("/servers/certs/acme/users/createPopup?providerCode=" + this.providerCode + "&platformUserId=" + this.platformUserId, {
|
||||
height: "30em",
|
||||
width: "44em",
|
||||
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,
|
||||
providerCode: acmeUser.providerCode
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.providerCode = ""
|
||||
this.changeProvider = function () {
|
||||
this.userId = 0
|
||||
}
|
||||
|
||||
this.doUser = function () {
|
||||
if (this.providerCode.length == 0) {
|
||||
teaweb.warn("请选择一个证书服务商")
|
||||
return
|
||||
}
|
||||
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({
|
||||
platformUserId: this.platformUserId,
|
||||
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"
|
||||
})
|
||||
}
|
||||
})
|
||||
17
EdgeAdmin/web/views/@default/servers/certs/acme/create.less
Normal file
17
EdgeAdmin/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;
|
||||
}
|
||||
}
|
||||
108
EdgeAdmin/web/views/@default/servers/certs/acme/index.html
Normal file
108
EdgeAdmin/web/views/@default/servers/certs/acme/index.html
Normal file
@@ -0,0 +1,108 @@
|
||||
{$layout}
|
||||
{$template "/left_menu_top"}
|
||||
|
||||
<div class="right-box without-tabbar">
|
||||
{$template "menu"}
|
||||
|
||||
<second-menu>
|
||||
<menu-item :href="'/servers/certs/acme?userType=' + userType + '&keyword=' + keyword + '&userId=' + searchingUserId" :active="type == ''">所有任务({{countAll}})</menu-item>
|
||||
<menu-item :href="'/servers/certs/acme?userType=' + userType + '&type=available&keyword=' + keyword + '&userId=' + searchingUserId" :active="type == 'available'">有效证书({{countAvailable}})</menu-item>
|
||||
<menu-item :href="'/servers/certs/acme?userType=' + userType + '&type=expired&keyword=' + keyword + '&userId=' + searchingUserId" :active="type == 'expired'">过期证书<span :class="{red: countExpired > 0}">({{countExpired}})</span></menu-item>
|
||||
<menu-item :href="'/servers/certs/acme?userType=' + userType + '&type=7days&keyword=' + keyword + '&userId=' + searchingUserId" :active="type == '7days'">7天内过期<span :class="{red: count7Days > 0}">({{count7Days}})</span></menu-item>
|
||||
<menu-item :href="'/servers/certs/acme?userType=' + userType + '&type=30days&keyword=' + keyword + '&userId=' + searchingUserId" :active="type == '30days'">30天内过期({{count30Days}})</menu-item>
|
||||
</second-menu>
|
||||
|
||||
<form class="ui form">
|
||||
<input type="hidden" name="userType" :value="userType"/>
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="keyword" placeholder="域名等关键词" style="width:12em" v-model="keyword"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<user-selector :v-user-id="searchingUserId"></user-selector>
|
||||
</div>
|
||||
<div class="ui field"></div>
|
||||
<div class="ui field">
|
||||
<button type="submit" class="ui button">搜索</button>
|
||||
|
||||
<a :href="Tea.url('.', {userType:userType})" v-if="keyword.length > 0 || searchingUserId > 0">[清除条件]</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div v-if="searchingUserId == 0">
|
||||
<div class="ui menu text basic tiny blue" style="margin-bottom:0">
|
||||
<a :href="'/servers/certs/acme?userType=&type=' + type + '&keyword=' + keyword + '&userId=' + searchingUserId" class="item" :class="{active: userType == ''}">管理员证书</a>
|
||||
<a :href="'/servers/certs/acme?userType=user&type=' + type + '&keyword=' + keyword + '&userId=' + searchingUserId" class="item" :class="{active: userType == 'user'}">用户证书</a>
|
||||
</div>
|
||||
<div class="ui divider" style="margin-top:0"></div>
|
||||
</div>
|
||||
|
||||
<p class="comment" v-if="tasks.length == 0"><span v-if="searchingUserId > 0">当前用户下</span>暂时还没有证书申请任务。</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>所属用户</th>
|
||||
<th class="three op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="(task, index) in tasks" :class="{warning: runningIndex == index}">
|
||||
<td>{{task.acmeUser.email}}
|
||||
<div>
|
||||
<grey-label class="olive" v-if="task.authType == 'dns'">DNS</grey-label>
|
||||
<grey-label class="olive" v-if="task.authType == 'http'">HTTP</grey-label>
|
||||
<grey-label v-if="task.acmeUser.provider != null">{{task.acmeUser.provider.name}}</grey-label>
|
||||
<grey-label v-if="task.acmeUser.account != null">{{task.acmeUser.account.name}}</grey-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>
|
||||
<span v-if="task.user != null && task.user.id > 0"><user-link :v-user="task.user"></user-link></span>
|
||||
<span v-else class="disabled">管理员</span>
|
||||
</td>
|
||||
<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>
|
||||
</div>
|
||||
63
EdgeAdmin/web/views/@default/servers/certs/acme/index.js
Normal file
63
EdgeAdmin/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,59 @@
|
||||
{$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 class="title">顶级域名 *</td>
|
||||
<td>
|
||||
<input type="text" maxlength="100" name="dnsDomain" v-model="task.dnsDomain"/>
|
||||
<p class="comment">用于在DNS服务商账号中操作解析记录的域名,比如 example.com,不要输入二级或别的多级域名。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="title">证书域名列表 *</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>
|
||||
<tr>
|
||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||
</tr>
|
||||
<tbody v-show="moreOptionsVisible">
|
||||
<tr>
|
||||
<td>回调URL</td>
|
||||
<td>
|
||||
<input type="text" name="authURL" v-model="task.authURL" maxlength="200"/>
|
||||
<p class="comment">将认证数据以JSON的方式POST到此URL上,可以依此生成认证文件或者设置DNS域名解析;仅适用于未绑定当前CDN系统的域名。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,52 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>创建ACME用户</h3>
|
||||
<form method="post" class="ui form" data-tea-success="success" data-tea-action="$">
|
||||
<csrf-token></csrf-token>
|
||||
<input type="hidden" name="platformUserId" :value="platformUserId"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr v-if="platformUser != null">
|
||||
<td>所属平台用户</td>
|
||||
<td><user-link :v-user="platformUser"></user-link></td>
|
||||
</tr>
|
||||
<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,57 @@
|
||||
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
|
||||
})
|
||||
}
|
||||
|
||||
if (this.providerCode.length > 0) {
|
||||
this.changeProvider()
|
||||
}
|
||||
|
||||
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,42 @@
|
||||
{$layout}
|
||||
{$template "/left_menu_top"}
|
||||
|
||||
<div class="right-box without-tabbar">
|
||||
{$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>
|
||||
</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>修改ACME用户</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
EdgeAdmin/web/views/@default/servers/certs/certPopup.css
Normal file
15
EdgeAdmin/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
EdgeAdmin/web/views/@default/servers/certs/certPopup.html
Normal file
74
EdgeAdmin/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 basic" 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/settings/https?serverId=' + server.id" target="_blank" class="ui label small basic">{{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
EdgeAdmin/web/views/@default/servers/certs/certPopup.js
Normal file
10
EdgeAdmin/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
EdgeAdmin/web/views/@default/servers/certs/certPopup.less
Normal file
15
EdgeAdmin/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;
|
||||
}
|
||||
99
EdgeAdmin/web/views/@default/servers/certs/index.html
Normal file
99
EdgeAdmin/web/views/@default/servers/certs/index.html
Normal file
@@ -0,0 +1,99 @@
|
||||
{$layout}
|
||||
{$template "/left_menu_top"}
|
||||
|
||||
<div class="right-box without-tabbar">
|
||||
<second-menu>
|
||||
<menu-item :href="'/servers/certs?userType=' + userType + '&keyword=' + keyword + '&userId=' + searchingUserId" :active="type == ''">所有证书({{countAll}})</menu-item>
|
||||
<menu-item :href="'/servers/certs?userType=' + userType + '&type=ca&keyword=' + keyword + '&userId=' + searchingUserId" :active="type == 'ca'">CA证书({{countCA}})</menu-item>
|
||||
<menu-item :href="'/servers/certs?userType=' + userType + '&type=available&keyword=' + keyword + '&userId=' + searchingUserId" :active="type == 'available'">有效证书({{countAvailable}})</menu-item>
|
||||
<menu-item :href="'/servers/certs?userType=' + userType + '&type=expired&keyword=' + keyword + '&userId=' + searchingUserId" :active="type == 'expired'">过期证书<span :class="{red: countExpired > 0}">({{countExpired}})</span></menu-item>
|
||||
<menu-item :href="'/servers/certs?userType=' + userType + '&type=7days&keyword=' + keyword + '&userId=' + searchingUserId" :active="type == '7days'">7天内过期<span :class="{red: count7Days > 0}">({{count7Days}})</span></menu-item>
|
||||
<menu-item :href="'/servers/certs?userType=' + userType + '&type=30days&keyword=' + keyword + '&userId=' + searchingUserId" :active="type == '30days'">30天内过期({{count30Days}})</menu-item>
|
||||
<span class="item disabled">|</span>
|
||||
<a href="" class="item" @click.prevent="uploadCert">[上传证书]</a>
|
||||
<a href="" class="item" @click.prevent="uploadBatch">[批量上传]</a>
|
||||
</second-menu>
|
||||
|
||||
<form class="ui form">
|
||||
<input type="hidden" name="type" :value="type"/>
|
||||
<input type="hidden" name="userType" :value="userType"/>
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="keyword" placeholder="域名、说明等关键词" style="width:12em" v-model="keyword"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<user-selector :v-user-id="searchingUserId"></user-selector>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button type="submit" class="ui button">搜索</button>
|
||||
|
||||
<a :href="Tea.url('.', { 'userType':userType, 'type':type })" v-if="keyword.length > 0 || searchingUserId > 0">[清除条件]</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div v-if="searchingUserId == 0">
|
||||
<div class="ui menu text basic tiny blue" style="margin-bottom:0">
|
||||
<a :href="'/servers/certs?userType=&type=' + type + '&keyword=' + keyword + '&userId=' + searchingUserId" class="item" :class="{active: userType == ''}">管理员证书</a>
|
||||
<a :href="'/servers/certs?userType=user&type=' + type + '&keyword=' + keyword + '&userId=' + searchingUserId" class="item" :class="{active: userType == 'user'}">用户证书</a>
|
||||
</div>
|
||||
<div class="ui divider" style="margin-top:0"></div>
|
||||
</div>
|
||||
|
||||
<p class="comment" v-if="certs.length == 0"><span v-if="searchingUserId > 0">当前用户下</span>暂时还没有相关的证书。</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>所属用户</th>
|
||||
<th class="center">状态</th>
|
||||
<th class="three op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="(cert, index) in certs">
|
||||
<td><keyword :v-word="keyword">{{cert.name}}</keyword>
|
||||
<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"><keyword :v-word="keyword">{{dnsName}}</keyword></span>
|
||||
</div>
|
||||
</td>
|
||||
<td>{{certInfos[index].beginDay}}</td>
|
||||
<td>{{certInfos[index].endDay}}</td>
|
||||
<td class="center">{{certInfos[index].countServers}}</td>
|
||||
<td>
|
||||
<span v-if="certInfos[index].user != null && certInfos[index].user.id > 0"><user-link :v-user="certInfos[index].user"></user-link></span>
|
||||
<span v-else class="disabled">管理员</span>
|
||||
</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
EdgeAdmin/web/views/@default/servers/certs/index.js
Normal file
54
EdgeAdmin/web/views/@default/servers/certs/index.js
Normal file
@@ -0,0 +1,54 @@
|
||||
Tea.context(function () {
|
||||
// 上传证书
|
||||
this.uploadCert = function () {
|
||||
teaweb.popup("/servers/certs/uploadPopup?userId=" + this.searchingUserId, {
|
||||
height: "30em",
|
||||
callback: function () {
|
||||
teaweb.success("上传成功", function () {
|
||||
window.location.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 批量上传证书
|
||||
this.uploadBatch = function () {
|
||||
teaweb.popup("/servers/certs/uploadBatchPopup?userId=" + this.searchingUserId, {
|
||||
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: "30em",
|
||||
callback: function () {
|
||||
teaweb.success("修改成功", function () {
|
||||
window.location.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
84
EdgeAdmin/web/views/@default/servers/certs/ocsp/index.html
Normal file
84
EdgeAdmin/web/views/@default/servers/certs/ocsp/index.html
Normal file
@@ -0,0 +1,84 @@
|
||||
{$layout}
|
||||
{$template "/left_menu_top"}
|
||||
|
||||
<div class="right-box without-tabbar">
|
||||
<div class="margin"></div>
|
||||
|
||||
<form class="ui form" method="get" action="/servers/certs/ocsp">
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" placeholder="关键词" style="width: 10em" name="keyword" v-model="keyword"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button small">搜索</button>
|
||||
<a href="/servers/certs/ocsp" v-if="keyword.length > 0">[清除条件]</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="margin"></div>
|
||||
|
||||
<form class="ui form" v-if="certs.length > 0">
|
||||
<div class="ui divider"></div>
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field" v-if="certIds.length == 0" @click.prevent="resetAllCerts">
|
||||
<button class="ui button small basic">重试所有证书</button>
|
||||
</div>
|
||||
<div class="ui field" v-if="certIds.length > 0">
|
||||
<button class="ui button small basic" @click.prevent="resetCerts">重试选中证书</button>
|
||||
</div>
|
||||
<div class="ui field" v-if="certIds.length > 0">
|
||||
<button class="ui button small basic" @click.prevent="ignoreCerts">忽略选中证书</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<p class="comment" v-if="certs.length == 0">暂时没有OCSP日志。</p>
|
||||
|
||||
<table class="ui table selectable celled" v-if="certs.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 1em"><checkbox v-model="allChecked"></checkbox></th>
|
||||
<th>证书说明</th>
|
||||
<th>顶级发行组织</th>
|
||||
<th>域名</th>
|
||||
<th class="six wide">更新错误信息</th>
|
||||
<th class="center">状态</th>
|
||||
<th class="one op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody v-for="(cert, index) in certs">
|
||||
<tr>
|
||||
<td><checkbox :id="'cert_' + cert.id" ref="certCheckboxes" @input="changeCerts"></checkbox></td>
|
||||
<td><keyword :v-word="keyword">{{cert.name}}</keyword>
|
||||
<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"><keyword :v-word="keyword">{{dnsName}}</keyword></span>
|
||||
</div>
|
||||
</td>
|
||||
<td style="word-break: break-all">
|
||||
<span class="red">{{cert.ocspError}}</span>
|
||||
</td>
|
||||
<td nowrap="" class="center">
|
||||
<span class="ui label red tiny basic" v-if="!cert.isOn">未启用</span>
|
||||
<span class="ui label red tiny basic" v-else-if="cert.isExpired">已过期</span>
|
||||
<span class="ui label green tiny basic" v-else>有效中</span>
|
||||
</td>
|
||||
<td>
|
||||
<a href="" @click.prevent="viewCert(cert.id)">详情</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
</div>
|
||||
62
EdgeAdmin/web/views/@default/servers/certs/ocsp/index.js
Normal file
62
EdgeAdmin/web/views/@default/servers/certs/ocsp/index.js
Normal file
@@ -0,0 +1,62 @@
|
||||
Tea.context(function () {
|
||||
this.certIds = []
|
||||
this.allChecked = false
|
||||
|
||||
this.$delay(function () {
|
||||
let that = this
|
||||
this.$watch("allChecked", function (b) {
|
||||
let boxes = that.$refs.certCheckboxes
|
||||
boxes.forEach(function (box) {
|
||||
if (b) {
|
||||
box.check()
|
||||
} else {
|
||||
box.uncheck()
|
||||
}
|
||||
that.changeCerts()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
this.changeCerts = function () {
|
||||
let boxes = this.$refs.certCheckboxes
|
||||
let that = this
|
||||
this.certIds = []
|
||||
boxes.forEach(function (box) {
|
||||
if (box.isChecked()) {
|
||||
let boxId = box.id
|
||||
that.certIds.push(parseInt(boxId.split("_")[1]))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.resetAllCerts = function () {
|
||||
this.$post(".resetAll")
|
||||
.success(function () {
|
||||
teaweb.successRefresh("操作成功,将很快开始重试")
|
||||
})
|
||||
}
|
||||
|
||||
this.resetCerts = function () {
|
||||
this.$post(".reset")
|
||||
.params({ certIds: this.certIds })
|
||||
.success(function () {
|
||||
teaweb.successRefresh("操作成功,将很快开始重试")
|
||||
})
|
||||
}
|
||||
|
||||
this.ignoreCerts = function () {
|
||||
this.$post(".ignore")
|
||||
.params({ certIds: this.certIds })
|
||||
.success(function () {
|
||||
teaweb.successRefresh("忽略成功")
|
||||
})
|
||||
}
|
||||
|
||||
// 查看证书详情
|
||||
this.viewCert = function (certId) {
|
||||
teaweb.popup("/servers/certs/certPopup?certId=" + certId, {
|
||||
height: "28em",
|
||||
width: "48em"
|
||||
})
|
||||
}
|
||||
})
|
||||
92
EdgeAdmin/web/views/@default/servers/certs/selectPopup.html
Normal file
92
EdgeAdmin/web/views/@default/servers/certs/selectPopup.html
Normal file
@@ -0,0 +1,92 @@
|
||||
{$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" ref="searchForm">
|
||||
<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">
|
||||
<user-selector :v-user-id="userId" ref="userSelector"></user-selector>
|
||||
</div>
|
||||
<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>
|
||||
<span class="item"><span v-if="searchingUserId > 0">当前用户</span><span v-else>未指定用户</span></span>
|
||||
<raquo-item></raquo-item>
|
||||
<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="searchingUserId > 0">当前用户下</span>暂时还没有<span v-if="searchingType == 'match'">跟所添加域名匹配的</span>相关证书<span v-if="searchingUserId > 0">,<a href="" @click.prevent="searchNoneUserCerts">[尝试搜索管理员上传和申请的证书]</a></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>
|
||||
84
EdgeAdmin/web/views/@default/servers/certs/selectPopup.js
Normal file
84
EdgeAdmin/web/views/@default/servers/certs/selectPopup.js
Normal file
@@ -0,0 +1,84 @@
|
||||
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
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.searchNoneUserCerts = function () {
|
||||
this.$refs.userSelector.clear()
|
||||
this.$delay(function () {
|
||||
this.$refs.searchForm.submit()
|
||||
}, 10)
|
||||
}
|
||||
})
|
||||
63
EdgeAdmin/web/views/@default/servers/certs/updatePopup.html
Normal file
63
EdgeAdmin/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, .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" 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
EdgeAdmin/web/views/@default/servers/certs/updatePopup.js
Normal file
14
EdgeAdmin/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,25 @@
|
||||
{$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">点击后在弹出的文件选择框中支持多选;不用担心文件名和顺序问题,系统会自动匹配<span v-if="!teaIsPlus">;免费版本限制每次最多上传{{maxFiles}}个文件</span>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>所属用户</td>
|
||||
<td>
|
||||
<user-selector @change="changeUserId" :v-user-id="userId"></user-selector>
|
||||
<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,25 @@
|
||||
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 + "个证书"
|
||||
if (this.userId > 0) {
|
||||
msg += "<br/>由于你选择了证书用户,所以只有此用户才能在用户系统中查看到这些证书。"
|
||||
}
|
||||
teaweb.success(msg, function () {
|
||||
NotifyPopup(resp)
|
||||
})
|
||||
}
|
||||
|
||||
this.changeUserId = function (userId) {
|
||||
this.userId = userId
|
||||
}
|
||||
})
|
||||
69
EdgeAdmin/web/views/@default/servers/certs/uploadPopup.html
Normal file
69
EdgeAdmin/web/views/@default/servers/certs/uploadPopup.html
Normal file
@@ -0,0 +1,69 @@
|
||||
{$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>
|
||||
<user-selector :v-user-id="userId"></user-selector>
|
||||
<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"></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
EdgeAdmin/web/views/@default/servers/certs/uploadPopup.js
Normal file
14
EdgeAdmin/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()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user