Initial commit (code only without large binaries)

This commit is contained in:
robin
2026-02-15 18:58:44 +08:00
commit 35df75498f
9442 changed files with 1495866 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
<first-menu>
<menu-item href="/users/setting" code="index">注册设置</menu-item>
<menu-item href="/users/setting/server" code="server">服务设置</menu-item>
<menu-item href="/users/setting/email" code="email">邮件设置</menu-item>
<menu-item href="/users/setting/sms" code="sms">短信设置</menu-item>
<span class="item disabled">|</span>
<menu-item href="/finance/fee">计费设置 &nbsp; <i class="icon external small"></i></menu-item>
<menu-item href="/settings/user-ui">界面设置 &nbsp; <i class="icon external small"></i></menu-item>
</first-menu>

View File

@@ -0,0 +1,14 @@
{$layout}
{$template "menu"}
<form class="ui form" data-tea-action="$" data-tea-success="success">
<csrf-token></csrf-token>
<h4>激活邮件</h4>
<email-sender v-model="config.verifyEmail" name="verifyEmailJSON"></email-sender>
<h4>通知邮件</h4>
<email-sender v-model="config.notifyEmail" name="notifyEmailJSON"></email-sender>
<submit-btn></submit-btn>
</form>

View File

@@ -0,0 +1,3 @@
Tea.context(function () {
this.success = NotifyReloadSuccess("保存成功")
})

View File

@@ -0,0 +1,74 @@
{$layout "layout_popup"}
<h3>邮件发送测试</h3>
<form class="ui form" data-tea-action="$" data-tea-success="successSend" data-tea-before="before" data-tea-done="done">
<csrf-token></csrf-token>
<input type="hidden" name="configJSON" :value="JSON.stringify(config)"/>
<table class="ui table selectable definition">
<tr>
<td>SMTP地址 *</td>
<td>
<span v-if="config.smtpHost.length > 0">{{config.smtpHost}}</span>
<span v-else class="red">没有设置。</span>
</td>
</tr>
<tr>
<td>SMTP端口 *</td>
<td>
<span v-if="config.smtpPort > 0">{{config.smtpPort}}</span>
<span v-else class="red">没有设置。</span>
</td>
</tr>
<tr>
<td>用户名 *</td>
<td>
<span v-if="config.username.length > 0">{{config.username}}</span>
<span v-else class="red">没有设置。</span>
</td>
</tr>
<tr>
<td>密码 *</td>
<td>
<span v-if="config.password.length > 0"><span v-for="i in config.password.length">*</span></span>
<span v-else class="red">没有设置。</span>
</td>
</tr>
<tr>
<td>发件人Email *</td>
<td>
<span v-if="config.fromEmail.length > 0">{{config.fromEmail}}</span>
<span v-else class="red">没有设置。</span>
</td>
</tr>
<tr>
<td>发件人名称</td>
<td>
<span v-if="config.fromName.length > 0">{{config.fromName}}</span>
<span v-else class="disabled">使用默认。</span>
</td>
</tr>
<tr>
<td class="color-border">收件人Email *</td>
<td>
<input type="text" name="toEmail" placeholder="test@example.com" ref="focus"/>
</td>
</tr>
<tr>
<td class="color-border">测试标题 *</td>
<td>
<input type="text" maxlength="100" name="subject" value="这是一封测试邮件"/>
</td>
</tr>
<tr>
<td class="color-border">测试内容 *</td>
<td>
<textarea name="body" rows="3">&lt;p&gt;测试邮件内容 1&lt;/p&gt;
&lt;p&gt;测试邮件内容 2&lt;/p&gt;</textarea>
<p class="comment">通常支持HTML。</p>
</td>
</tr>
</table>
<submit-btn v-show="!isSending">发送测试邮件</submit-btn>
<button class="ui button disabled" type="button" v-show="isSending">发送中...</button>
</form>

View File

@@ -0,0 +1,17 @@
Tea.context(function () {
this.config = window.parent.TESTING_EMAIL_CONFIG
this.isSending = false
this.before = function () {
this.isSending = true
}
this.done = function () {
this.isSending = false
}
this.successSend = function () {
teaweb.success("发送成功")
}
})

View File

@@ -0,0 +1,9 @@
.feature-boxes .feature-box {
margin-bottom: 1em;
width: 24em;
float: left;
}
.feature-boxes .feature-box:hover label {
font-weight: bold;
}
/*# sourceMappingURL=index.css.map */

View File

@@ -0,0 +1 @@
{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA,cACC;EACC,kBAAA;EACA,WAAA;EACA,WAAA;;AAJF,cAOC,aAAY,MACX;EACC,iBAAA","file":"index.css"}

View File

@@ -0,0 +1,260 @@
{$layout}
{$template "menu"}
<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>
<checkbox name="isOn" v-model="config.isOn"></checkbox>
<p class="comment">选中表示允许用户自行注册。</p>
</td>
</tr>
<tbody v-show="config.isOn">
<tr>
<td>必须使用复杂密码</td>
<td>
<checkbox name="complexPassword" v-model="config.complexPassword"></checkbox>
<p class="comment">选中表示用户注册时必须使用复杂密码即长度不能低于6位且必须包含大小写字母。</p>
</td>
</tr>
<tr>
<td>需要审核</td>
<td>
<checkbox name="requireVerification" v-model="config.requireVerification"></checkbox>
<p class="comment">选中后,表示用户注册后需要审核才能创建服务。</p>
</td>
</tr>
<tr>
<td>需要实名认证</td>
<td>
<checkbox name="requireIdentity" v-model="config.requireIdentity"></checkbox>
<p class="comment">选中后,表示用户注册后需要实名认证后才能创建服务。</p>
</td>
</tr>
</tbody>
</table>
<h4>登录设置</h4>
<table class="ui table definition selectable">
<tr>
<td class="title">检查客户端区域</td>
<td>
<checkbox name="checkClientRegion" v-model="config.checkClientRegion"></checkbox>
<p class="comment">选中后,表示每次用户访问时都检查客户端所在地理区域是否和登录时一致,以提升安全性;如果当前系统下游有反向代理设置,请在<a href="/settings/user-ui#client-ip-header-names" target="_blank">[用户界面设置]</a>中设置“自定义客户端IP报头”选项。</p>
</td>
</tr>
</table>
<h4>电子邮箱相关</h4>
<table class="ui table definition selectable">
<tr>
<td class="title">启用电子邮箱绑定功能</td>
<td>
<checkbox name="emailVerificationIsOn" v-model="config.emailVerification.isOn"></checkbox>
<p class="comment">选中后,电子邮箱需要激活之后可以使用邮箱登录、找回密码等。此功能需要事先设置 <a href="/users/setting/email" target="_blank">[激活邮件设置]</a></p>
</td>
</tr>
<tbody v-show="config.emailVerification.isOn">
<tr>
<td>提示用户未绑定</td>
<td>
<checkbox name="emailVerificationShowNotice" v-model="config.emailVerification.showNotice"></checkbox>
<p class="comment">选中后,将在页面上提示用户尚未绑定电子邮箱.</p>
</td>
</tr>
<tr>
<td>允许使用电子邮箱登录</td>
<td>
<checkbox name="emailVerificationCanLogin" v-model="config.emailVerification.canLogin"></checkbox>
<p class="comment">选中后,表示允许用户使用激活后的邮箱登录。</p>
</td>
</tr>
<tr>
<td colspan="2"><more-options-indicator v-model="emailVerificationMoreOptions"></more-options-indicator></td>
</tr>
<tr v-show="emailVerificationMoreOptions">
<td>激活邮件标题</td>
<td>
<input type="text" name="emailVerificationSubject" v-model="config.emailVerification.subject"/>
<p class="comment">其中<code-label>${product.name}</code-label>为当前设置的<a href="/settings/ui" target="_blank">产品名称</a></p>
</td>
</tr>
<tr v-show="emailVerificationMoreOptions">
<td>激活邮件内容</td>
<td>
<textarea name="emailVerificationBody" rows="8" v-model="config.emailVerification.body"></textarea>
<p class="comment">可以使用简单的HTML其中<code-label>${product.name}</code-label>为当前设置的<a href="/settings/ui" target="_blank">产品名称</a><code-label>${url.verify}</code-label>为生成的激活地址,<code-label>${url.home}</code-label>为用户平台主页地址,由<a href="/settings/userNodes" target="_blank">用户节点</a>访问地址组合而成。</p>
</td>
</tr>
</tbody>
</table>
<p class="comment" v-if="config.emailVerification.isOn">修改邮箱相关设置后,请记得自行注册新用户测试。</p>
<div class="margin"></div>
<div v-show="config.emailVerification.isOn">
<h4>通过邮箱找回密码</h4>
<table class="ui table definition selectable">
<tr>
<td class="title">启用找回密码功能</td>
<td>
<checkbox name="emailResetPasswordIsOn" v-model="config.emailResetPassword.isOn"></checkbox>
<p class="comment">选中后,用户可以通过已绑定的电子邮箱找回密码;此功能需要同时开启电子邮箱绑定功能。</p>
</td>
</tr>
<tbody v-show="config.emailResetPassword.isOn">
<tr>
<td colspan="2"><more-options-indicator v-model="emailResetPasswordMoreOptions"></more-options-indicator></td>
</tr>
<tr v-show="emailResetPasswordMoreOptions">
<td>找回密码邮件标题</td>
<td>
<input type="text" name="emailResetPasswordSubject" v-model="config.emailResetPassword.subject" maxlength="100"/>
<p class="comment">其中<code-label>${product.name}</code-label>为当前设置的<a href="/settings/ui" target="_blank">产品名称</a></p>
</td>
</tr>
<tr v-show="emailResetPasswordMoreOptions">
<td>找回密码邮件内容</td>
<td>
<textarea name="emailResetPasswordBody" v-model="config.emailResetPassword.body" rows="5"></textarea>
<p class="comment">可以使用简单的HTML其中<code-label>${product.name}</code-label>为当前设置的<a href="/settings/ui" target="_blank">产品名称</a><code-label>${code}</code-label>为找回密码时用到的验证码,<code-label>${url.home}</code-label>为用户平台主页地址,由<a href="/settings/userNodes" target="_blank">用户节点</a>访问地址组合而成。</p>
</td>
</tr>
</tbody>
</table>
<div class="margin"></div>
</div>
<h4>手机号码相关</h4>
<table class="ui table definition selectable">
<tr>
<td class="title">启用手机号码绑定功能</td>
<td>
<checkbox name="mobileVerificationIsOn" v-model="config.mobileVerification.isOn"></checkbox>
<p class="comment">选中后,手机号码需要激活之后可以使用手机号码、找回密码等。此功能需要事先设置 <a href="/users/setting/sms" target="_blank">[激活短信设置]</a></p>
</td>
</tr>
<tbody v-show="config.mobileVerification.isOn">
<tr>
<td>提示用户未绑定</td>
<td>
<checkbox name="mobileVerificationShowNotice" v-model="config.mobileVerification.showNotice"></checkbox>
<p class="comment">选中后,将在页面上提示用户尚未绑定手机号码.</p>
</td>
</tr>
<tr>
<td>允许使用手机号码登录</td>
<td>
<checkbox name="mobileVerificationCanLogin" v-model="config.mobileVerification.canLogin"></checkbox>
<p class="comment">选中后,表示允许用户使用激活后的手机号码登录。</p>
</td>
</tr>
<tr>
<td>强制绑定手机号</td>
<td>
<checkbox name="mobileVerificationForce" v-model="config.mobileVerification.force"></checkbox>
<p class="comment">选中后,表示强制用户必须绑定手机号后才能使用其他功能。</p>
</td>
</tr>
<tr>
<td colspan="2"><more-options-indicator v-model="mobileVerificationMoreOptions"></more-options-indicator></td>
</tr>
<tr v-show="mobileVerificationMoreOptions">
<td>激活短信内容</td>
<td>
<textarea name="mobileVerificationBody" rows="8" v-model="config.mobileVerification.body"></textarea>
<p class="comment">其中使用<code-label>${code}</code-label>表示验证码。</p>
</td>
</tr>
</tbody>
</table>
<p class="comment" v-if="config.mobileVerification.isOn">修改手机号码相关设置后,请记得自行注册新用户测试。</p>
<div class="margin"></div>
<h4>CDN服务</h4>
<table class="ui table definition selectable">
<tr>
<td class="title">开通CDN服务</td>
<td>
<checkbox name="cdnIsOn" v-model="config.cdnIsOn"></checkbox>
<p class="comment">选中表示自动为用户开通CDN服务。 </p>
</td>
</tr>
<tbody v-show="config.cdnIsOn">
<tr>
<td>CDN集群分配 *</td>
<td>
<cluster-selector :v-cluster-id="config.clusterId"></cluster-selector>
<p class="comment">选择用户新创建服务自动分配的集群。</p>
</td>
</tr>
<tr>
<td>默认开通功能</td>
<td>
<!-- 已选中功能 -->
<div>
<div v-if="selectedFeatureNames().length > 0">
<span>{{selectedFeatureNames()}}</span>
</div>
<span v-else class="grey">暂时还没有开通任何功能。</span>
<div style="margin-top: 0.1em">
<a href="" @click.prevent="showFeatures">修改<i class="icon angle" :class="{up: featuresVisible, down: !featuresVisible}"></i></a>
</div>
</div>
<div class="feature-boxes" v-show="featuresVisible" style="margin-top: 1em">
<div class="feature-box" v-for="feature in features">
<checkbox name="features" :v-value="feature.code" v-model="feature.isChecked">{{feature.name}}</checkbox>
<p class="comment">{{feature.description}}</p>
</div>
</div>
</td>
</tr>
<tr>
<td>对已有用户功能操作</td>
<td>
<select class="ui dropdown auto-width" name="featureOp" v-model="featureOp">
<option value="overwrite">覆盖</option>
<option value="append">追加</option>
<option value="keep">保持</option>
</select>
<p class="comment" v-if="featureOp == 'overwrite'">覆盖用户已经有的功能设置。</p>
<p class="comment" v-if="featureOp == 'append'">只追加用户功能,不减少。</p>
<p class="comment" v-if="featureOp == 'keep'">保持原有用户功能不变,功能修改只对新用户生效。</p>
</td>
</tr>
</tbody>
</table>
<div v-show="adIsVisible">
<div class="margin"></div>
<h4>DDoS高防</h4>
<table class="ui table definition selectable">
<tr>
<td class="title">开通DDoS高防管理</td>
<td><checkbox name="adIsOn" v-model="config.adIsOn"></checkbox>
<p class="comment">选中表示自动为用户开通DDoS高防IP使用服务。</p>
</td>
</tr>
</table>
<div class="margin"></div>
</div>
<div v-show="nsIsVisible">
<div class="margin"></div>
<h4>智能DNS服务</h4>
<table class="ui table definition selectable">
<tr>
<td class="title">开通智能DNS服务</td>
<td><checkbox name="nsIsOn" v-model="config.nsIsOn"></checkbox>
<p class="comment">选中表示自动为用户开通智能DNS服务。</p>
</td>
</tr>
</table>
<p class="comment" v-show="config.nsIsOn"><a href="/ns/settings/user">智能DNS相关功能设置</a></p>
<div class="margin"></div>
</div>
<submit-btn></submit-btn>
</form>

View File

@@ -0,0 +1,30 @@
Tea.context(function () {
this.success = NotifyReloadSuccess("保存成功")
this.emailVerificationMoreOptions = false
this.emailResetPasswordMoreOptions = false
this.mobileVerificationMoreOptions = false
this.mobileResetPasswordMoreOptions = false
this.featureOp = "overwrite"
this.featuresVisible = false
this.showFeatures = function () {
this.featuresVisible = !this.featuresVisible
}
this.selectedFeatureNames = function () {
if (this.features == null) {
return ""
}
let names = []
this.features.forEach(function (v) {
if (v.isChecked) {
names.push(v.name)
}
})
return names.join(" / ")
}
})

View File

@@ -0,0 +1,13 @@
.feature-boxes {
.feature-box {
margin-bottom: 1em;
width: 24em;
float: left;
}
.feature-box:hover {
label {
font-weight: bold;
}
}
}

View File

@@ -0,0 +1,85 @@
{$layout}
{$template "menu"}
<div class="margin"></div>
<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>
<checkbox name="requirePlan" v-model="config.requirePlan"></checkbox>
<p class="comment">选中后,用户在创建网站时,必须选择一个套餐。</p>
</td>
</tr>
<tr>
<td class="title">网站分组<optional-label></optional-label></td>
<td>
<select class="ui dropdown auto-width" name="groupId" v-model="config.groupId">
<option value="0">[选择分组]</option>
<option v-for="group in groups" :value="group.id">{{group.name}}</option>
</select>
<p class="comment">用户创建的新网站自动加入此分组。</p>
</td>
</tr>
<tr>
<td>启用统计</td>
<td>
<checkbox name="enableStat" v-model="config.enableStat"></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>缓存清理任务限制</td>
<td>
<div class="ui fields">
<div class="ui field" style="width: 15em">
<div class="ui input right labeled">
<digit-input name="purgeMaxKeysPerTask" v-model="config.httpCacheTaskPurgeConfig.maxKeysPerTask"></digit-input>
<span class="ui label">个URL/每任务</span>
</div>
<p class="comment">每次能提交的最多URL数量默认{{defaultMaxCacheKeysPerTask}}。</p>
</div>
</div>
<div class="ui fields">
<div class="ui field" style="width: 16em">
<div class="ui input right labeled">
<digit-input name="purgeMaxKeysPerDay" v-model="config.httpCacheTaskPurgeConfig.maxKeysPerDay"></digit-input>
<span class="ui label">个URL/天/每用户</span>
</div>
<p class="comment">每天每个用户能提交的最多URL数量默认{{defaultMaxCacheKeysPerDay}}。</p>
</div>
</div>
</td>
</tr>
<tr>
<td>缓存预热任务限制</td>
<td>
<div class="ui fields">
<div class="ui field" style="width: 15em">
<div class="ui input right labeled">
<digit-input name="fetchMaxKeysPerTask" v-model="config.httpCacheTaskFetchConfig.maxKeysPerTask" style="width: 5em"></digit-input>
<span class="ui label">个URL/每任务</span>
</div>
<p class="comment">每次能提交的最多URL数量默认{{defaultMaxCacheKeysPerTask}}。</p>
</div>
</div>
<div class="ui fields">
<div class="ui field" style="width: 16em">
<div class="ui input right labeled">
<digit-input name="fetchMaxKeysPerDay" v-model="config.httpCacheTaskFetchConfig.maxKeysPerDay" style="width: 5em"></digit-input>
<span class="ui label">个URL/天/每用户</span>
</div>
<p class="comment">每天每个用户能提交的最多URL数量默认{{defaultMaxCacheKeysPerDay}}。</p>
</div>
</div>
</td>
</tr>
</tbody>
</table>
<submit-btn></submit-btn>
</form>

View File

@@ -0,0 +1,3 @@
Tea.context(function () {
this.success = NotifyReloadSuccess("保存成功")
})

View File

@@ -0,0 +1,14 @@
{$layout}
{$template "menu"}
<form class="ui form" data-tea-action="$" data-tea-success="success">
<csrf-token></csrf-token>
<h4>激活短信</h4>
<sms-sender v-model="config.verifySMS" name="verifySMSJSON"></sms-sender>
<h4>通知短信</h4>
<sms-sender v-model="config.notifySMS" name="notifySMSJSON"></sms-sender>
<submit-btn></submit-btn>
</form>

View File

@@ -0,0 +1,3 @@
Tea.context(function () {
this.success = NotifyReloadSuccess("保存成功")
})

View File

@@ -0,0 +1,31 @@
{$layout "layout_popup"}
<h3>短信发送测试</h3>
<form class="ui form" data-tea-action="$" data-tea-success="successSend" data-tea-before="before" data-tea-done="done">
<csrf-token></csrf-token>
<input type="hidden" name="configJSON" :value="JSON.stringify(config)"/>
<table class="ui table selectable definition">
<tr>
<td class="color-border">收信人手机号 *</td>
<td>
<input type="text" name="toMobile" placeholder="138xxxxxxx" ref="focus"/>
</td>
</tr>
<tr>
<td class="color-border">测试内容 *</td>
<td>
<textarea name="body" rows="3" maxlength="50">测试短信内容</textarea>
</td>
</tr>
<tr>
<td class="color-border">验证码</td>
<td>
<input type="text" name="code" maxlength="10" style="width: 10em"/>
<p class="comment">可选参数,仅验证类短信需要填写。</p>
</td>
</tr>
</table>
<submit-btn v-show="!isSending">发送测试短信</submit-btn>
<button class="ui button disabled" type="button" v-show="isSending">发送中...</button>
</form>

View File

@@ -0,0 +1,17 @@
Tea.context(function () {
this.config = window.parent.TESTING_SMS_CONFIG
this.isSending = false
this.before = function () {
this.isSending = true
}
this.done = function () {
this.isSending = false
}
this.successSend = function () {
teaweb.success("发送成功")
}
})