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,5 @@
<first-menu>
<menu-item href="/lb" code="index">网站列表</menu-item>
<span class="item disabled">|</span>
<menu-item href="/lb/create" code="create">添加网站</menu-item>
</first-menu>

View File

@@ -0,0 +1,78 @@
{$layout}
{$template "menu"}
<div class="margin"></div>
<form class="ui form" method="post" data-tea-success="success" data-tea-action="$">
<csrf-token></csrf-token>
<table class="ui table definition selectable">
<tr>
<td class="title">网站名称 *</td>
<td>
<input type="text" name="name" maxlength="50" ref="focus"/>
<p class="comment">请设置一个容易识别的网站名称。</p>
</td>
</tr>
<tr>
<td>网站类型 *</td>
<td>
<select class="ui dropdown auto-width" name="serverType" v-model="serverType" @change="changeServerType">
<option v-for="serverType in serverTypes" :value="serverType.code">{{serverType.name}}</option>
</select>
</td>
</tr>
<tr>
<td>监听协议 *</td>
<td>
<span v-if="serverType == 'tcpProxy'">
<checkbox name="protocols" :key="'tcp'" :v-value="'tcp'" v-model="enableTCP">TCP</checkbox> &nbsp; &nbsp; &nbsp;
<checkbox name="protocols" :key="'tls'" :v-value="'tls'" v-model="enableTLS">TLS</checkbox>
</span>
<span v-if="serverType == 'udpProxy'">
<checkbox name="protocols" :key="'udp'" :v-value="'udp'" v-model="enableUDP">UDP</checkbox>
</span>
</td>
</tr>
<tr v-show="enableTLS">
<td>HTTPS证书 *</td>
<td>
<ssl-certs-box></ssl-certs-box>
</td>
</tr>
<tr v-if="canSpecifyTCPPort && enableTCP">
<td>TCP监听端口 *</td>
<td>
<values-box size="5" maxlength="5" placeholder="端口" name="tcpPorts"></values-box>
<p class="comment">添加服务器监听用户网络连接的端口需要在1024-65534之间。TCP和TLS端口之间不能重复。</p>
</td>
</tr>
<tr v-if="canSpecifyTCPPort && enableTLS">
<td>TLS监听端口 *</td>
<td>
<values-box size="5" maxlength="5" placeholder="端口" name="tlsPorts"></values-box>
<p class="comment">添加服务器监听用户网络连接的端口需要在1024-65534之间。TCP和TLS端口之间不能重复。</p>
</td>
</tr>
<tr v-if="!canSpecifyTCPPort && serverType == 'tcpProxy'">
<td>TCP/TLS监听端口</td>
<td>保存后自动生成</td>
</tr>
<tr v-if="canSpecifyUDPPort && enableUDP">
<td>UDP监听端口 *</td>
<td>
<values-box size="5" maxlength="5" placeholder="端口" name="udpPorts"></values-box>
<p class="comment">添加服务器监听用户网络连接的端口需要在1024-65534之间。</p>
</td>
</tr>
<tr v-if="!canSpecifyUDPPort && serverType == 'udpProxy'">
<td>UDP监听端口</td>
<td>保存后自动生成</td>
</tr>
<tr>
<td>源站信息 *</td>
<td>
<origin-input-box :v-family="family" ref="originInputBox"></origin-input-box>
</td>
</tr>
</table>
<submit-btn></submit-btn>
</form>

View File

@@ -0,0 +1,27 @@
Tea.context(function () {
this.serverType = this.serverTypes[0].code
this.enableTCP = false
this.enableTLS = false
this.enableUDP = false
this.family = ""
this.changeServerType = function () {
switch (this.serverType) {
case "tcpProxy":
this.family = "tcp"
break
case "udpProxy":
this.family = "udp"
break
}
if (this.$refs != null) {
this.$refs.originInputBox.changeFamily(this.family)
}
}
this.changeServerType()
this.success = NotifySuccess("保存成功", "/lb")
})

View File

@@ -0,0 +1,67 @@
{$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>
<p class="comment" v-if="servers.length == 0">暂时还没有任何负载均衡服务。</p>
<table class="ui table selectable" v-if="servers.length > 0">
<thead>
<tr>
<th>网站名称</th>
<th>CNAME</th>
<th v-if="supportTCP">TCP</th>
<th v-if="supportTCP">TLS</th>
<th v-if="supportUDP">UDP</th>
<th>状态</th>
<th class="three op">操作</th>
</tr>
</thead>
<tr v-for="server in servers">
<td><a :href="'/lb/server?serverId=' + server.id">{{server.name}}</a>
<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>
</td>
<td>{{server.cname}}</td>
<td v-if="supportTCP">
<div v-if="server.tcpPorts.length > 0">
<span v-for="port in server.tcpPorts" class="ui label basic small">{{port}}</span>
</div>
<span v-else class="disabled">-</span>
</td>
<td v-if="supportTCP">
<div v-if="server.tlsPorts.length > 0">
<span v-for="port in server.tlsPorts" class="ui label basic small">{{port}}</span>
</div>
<span v-else class="disabled">-</span>
</td>
<td v-if="supportUDP">
<div v-if="server.udpPorts.length > 0">
<span v-for="port in server.udpPorts" class="ui label basic small">{{port}}</span>
</div>
<span v-else class="disabled">-</span>
</td>
<td>
<span v-if="!server.isOn" class="grey">停用中</span>
<span v-else class="green">正常</span>
</td>
<td>
<a :href="'/lb/server?serverId=' + server.id">管理</a> &nbsp;
<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> &nbsp;
<a href="" @click.prevent="deleteServer(server.id)">删除</a>
</td>
</tr>
</table>
<div class="page" v-html="page"></div>

View File

@@ -0,0 +1,36 @@
Tea.context(function () {
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()
})
}
})

View File

@@ -0,0 +1,19 @@
{$layout}
{$template "/left_menu"}
<div class="right-box">
<form class="ui form" method="post" data-tea-action="$" data-tea-success="success">
<csrf-token></csrf-token>
<input type="hidden" name="serverId" :value="serverId"/>
<table class="ui table definition selectable">
<tr>
<td class="title">网站名称 *</td>
<td>
<input type="text" name="name" maxlength="50" v-model="name" ref="focus"/>
</td>
</tr>
</table>
<submit-btn></submit-btn>
</form>
</div>

View File

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

View File

@@ -0,0 +1,15 @@
{$layout}
{$template "/left_menu"}
<div class="right-box">
<table class="ui table selectable definition">
<tr>
<td class="title">当前网站CNAME</td>
<td>
<span id="cname-text">{{dnsName}}.<span v-if="dnsDomain.length > 0">{{dnsDomain}}.</span><span v-else>根域名</span></span> &nbsp; <copy-to-clipboard :v-target="'cname-text'"></copy-to-clipboard>
<p class="comment">可以在DNS设置一个CNAME记录名字为你自己的域名值为上面这个值。</p>
</td>
</tr>
</table>
</div>

View File

@@ -0,0 +1,76 @@
{$layout}
{$template "/left_menu"}
<div class="right-box">
<form class="ui form" data-tea-success="success" data-tea-action="$">
<csrf-token></csrf-token>
<input type="hidden" name="serverId" :value="serverId"/>
<table class="ui table selectable definition">
<tr>
<td class="title">当前绑定套餐</td>
<td>
<span v-if="userPlan.id == 0" class="disabled">暂时还没有绑定套餐。
<a href="" @click.prevent="update()" v-if="!isUpdating">[修改]</a>
<a href="" @click.prevent="update()" v-if="isUpdating">[取消修改]</a>
</span>
<div v-else>
{{userPlan.plan.name}}<span v-if="userPlan.name.length > 0">-{{userPlan.name}}</span> (到期时间:{{userPlan.dayTo}}&nbsp;
<a href="" @click.prevent="update()" v-if="!isUpdating">[修改]</a>
<a href="" @click.prevent="update()" v-if="isUpdating">[取消修改]</a>
<p class="comment" v-if="userPlan.isExpired"><a href="/plans"><span class="red">[已过期,请及时续费]</span></a></p>
</div>
</td>
</tr>
<!-- 注意必须使用v-if -->
<tr v-if="isUpdating">
<td>新套餐 *</td>
<td>
<input type="hidden" name="isChanged" value="1"/>
<span v-if="userPlans.length == 0" class="disabled">当前还没有可以使用的套餐。</span>
<div v-else>
<select class="ui dropdown auto-width" name="userPlanId" v-model="newUserPlanId" @change="changeUserPlan">
<option value="0">[不使用套餐]</option>
<option v-for="userPlan in userPlans" :value="userPlan.id">{{userPlan.name}}{{userPlan.dayTo}}</option>
</select>
<p class="comment" v-if="newUserPlanId > 0 && newUserPlanId == userPlan.id">当前正在使用的套餐。</p>
</div>
</td>
</tr>
<tr v-if="isUpdating && newUserPlan != null">
<td>所选套餐限制</td>
<td>
<div v-if="newUserPlan != null && newUserPlanDescription.length > 0">
{{newUserPlanDescription}}
</div>
<div v-else><span class="disabled">没有限制</span></div>
<div v-if="newUserPlanLimit.length > 0 && newUserPlanId != userPlan.id">
<span class="red">{{newUserPlanLimit}}</span>
</div>
</td>
</tr>
<tbody v-if="!isUpdating && hasTrafficLimit">
<tr v-if="userPlan.plan.trafficLimit.dailySize != null && userPlan.plan.trafficLimit.dailySize.count > 0">
<td>套餐日流量限制</td>
<td>
<size-capacity-view :v-value="userPlan.plan.trafficLimit.dailySize"></size-capacity-view>
<p class="comment">当天流量:{{trafficDailyFormat}}</p>
</td>
</tr>
<tr v-if="userPlan.plan.trafficLimit.monthlySize != null && userPlan.plan.trafficLimit.monthlySize.count > 0">
<td>套餐月流量限制</td>
<td>
<size-capacity-view :v-value="userPlan.plan.trafficLimit.monthlySize"></size-capacity-view>
<p class="comment">当月流量:{{trafficMonthlyFormat}}</p>
</td>
</tr>
</tbody>
</table>
<submit-btn v-show="newUserPlanLimit.length == 0 && newUserPlanId != userPlan.id"></submit-btn>
<button class="ui button disabled" type="button" v-if="newUserPlanLimit.length > 0 || newUserPlanId == userPlan.id">保存</button>
</form>
</div>

View File

@@ -0,0 +1,69 @@
Tea.context(function () {
this.isUpdating = false
this.success = NotifyReloadSuccess("保存成功")
this.update = function () {
this.isUpdating = !this.isUpdating
}
this.newUserPlanId = 0
this.newUserPlan = null
this.newUserPlanDescription = ""
this.newUserPlanLimit = ""
let changePlanRequestId = ""
this.changeUserPlan = function () {
this.newUserPlan = null
this.newUserPlanDescription = ""
this.newUserPlanLimit = ""
if (this.newUserPlanId == 0) {
return
}
let that = this
this.newUserPlan = this.userPlans.find(function (v) {
return v.id == that.newUserPlanId
})
if (this.newUserPlan != null) {
changePlanRequestId = Math.random().toString()
var requestId = changePlanRequestId
this.$post(".data")
.params({
serverId: this.serverId,
userPlanId: this.newUserPlanId
})
.success(function (resp) {
// check request
if (requestId != changePlanRequestId) {
return
}
let quotaInfo = resp.data
let descriptionItems = []
if (quotaInfo.servers.max > 0) {
descriptionItems.push("网站数限制:" + quotaInfo.servers.current + "+1/" + quotaInfo.servers.max)
if (!quotaInfo.servers.isValid) {
this.newUserPlanLimit = "已绑定网站数超出当前套餐限制"
}
}
if (quotaInfo.allServerNames.max > 0) {
descriptionItems.push("域名数限制:" + quotaInfo.allServerNames.current + "+" + quotaInfo.serverNames.current + "/" + quotaInfo.allServerNames.max)
if (!quotaInfo.allServerNames.isValid) {
this.newUserPlanLimit = "已绑定域名数超出当前套餐限制"
}
}
if (quotaInfo.serverNames.max > 0) {
descriptionItems.push("单网站域名数限制:+" + quotaInfo.serverNames.current + "/" + quotaInfo.serverNames.max)
if (!quotaInfo.serverNames.isValid) {
this.newUserPlanLimit = "当前网站域名数超出当前套餐限制"
}
}
if (descriptionItems.length > 0) {
this.newUserPlanDescription = descriptionItems.join("") + "。"
}
})
}
}
})

View File

@@ -0,0 +1,5 @@
<first-menu>
<menu-item :href="'/lb/server/settings/reverseProxy?serverId=' + serverId" code="index">源站列表</menu-item>
<menu-item :href="'/lb/server/settings/reverseProxy/scheduling?serverId=' + serverId" code="scheduling">调度算法</menu-item>
<menu-item :href="'/lb/server/settings/reverseProxy/setting?serverId=' + serverId" code="setting">更多设置</menu-item>
</first-menu>

View File

@@ -0,0 +1,15 @@
{$layout}
{$template "/left_menu"}
<div class="right-box">
{$template "menu"}
<div v-if="!reverseProxyRef.isOn">
<div class="margin"></div>
<p class="ui message warning">当前反向代理服务没有开启,可以通过点击 <a :href="'/lb/server/settings/reverseProxy/setting?serverId=' + serverId">[更多设置]</a> 开启 。</p>
</div>
<origin-list-box :v-primary-origins="primaryOrigins" :v-backup-origins="backupOrigins"
:v-server-type="serverType"
:v-params="'type=server&serverId=' + serverId + '&reverseProxyId=' + reverseProxyConfig.id"></origin-list-box>
</div>

View File

@@ -0,0 +1,8 @@
{$layout}
{$template "/left_menu"}
<div class="right-box">
{$template "menu"}
<origin-scheduling-view-box :v-scheduling="scheduling" :v-params="'type=server&serverId=' + serverId + '&reverseProxyId=' + reverseProxyId"></origin-scheduling-view-box>
</div>

View File

@@ -0,0 +1,14 @@
{$layout}
{$template "/left_menu"}
<div class="right-box">
{$template "menu"}
<div class="margin"></div>
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
<input type="hidden" name="serverId" :value="serverId"/>
<input type="hidden" name="reverseProxyRefJSON" :value="JSON.stringify(reverseProxyRef)"/>
<reverse-proxy-box :v-reverse-proxy-ref="reverseProxyRef" :v-reverse-proxy-config="reverseProxyConfig" :v-family="serverFamily"></reverse-proxy-box>
<submit-btn></submit-btn>
</form>
</div>

View File

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

View File

@@ -0,0 +1,60 @@
{$layout "layout_popup"}
<h3>修改调度算法</h3>
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
<input type="hidden" name="dataType" :value="dataType"/>
<input type="hidden" name="serverId" :value="serverId"/>
<input type="hidden" name="reverseProxyId" :value="reverseProxyId"/>
<table class="ui table selectable definition">
<tr>
<td class="title">选择调度算法</td>
<td>
<select class="ui dropdown auto-width" name="type" v-model="selectedType"
@change="changeSchedulingType()">
<option v-for="schedulingType in schedulingTypes"
:value="schedulingType.code">{{schedulingType.name}}</option>
</select>
<p class="comment">{{schedulingTypeDescription}}</p>
</td>
</tr>
<tr v-if="selectedType == 'hash'">
<td>
Key
</td>
<td>
<input type="text" name="hashKey" v-model="hashKey" maxlength="500"/>
<p class="comment">用来计算Hash的字符串其中可以使用变量。</p>
</td>
</tr>
<tr v-if="selectedType == 'hash'">
<td>常用变量</td>
<td>
<select class="ui dropdown" style="width:12em" v-model="hashVar" @change="changeHashVar()">
<option></option>
<option value="${remoteAddr}">客户端IP</option>
<option value="${host}${requestURI}">请求URL</option>
</select>
</td>
</tr>
<tr v-if="selectedType == 'sticky'">
<td>参数类型</td>
<td>
<select class="ui dropdown" style="width:12em" name="stickyType" v-model="stickyType">
<option value="cookie">Cookie</option>
<option value="header">HTTP Header</option>
<option value="argument">URL参数</option>
</select>
</td>
</tr>
<tr v-if="selectedType == 'sticky'">
<td>参数名</td>
<td>
<input type="text" name="stickyParam" v-model="stickyParam" maxlength="50"/>
<p class="comment">记录或指定源站的参数名只能是英文字母和数字的组合不允许有下划线因为在HTTP Header中下划线是不标准的</p>
</td>
</tr>
</table>
<submit-btn></submit-btn>
</form>

View File

@@ -0,0 +1,39 @@
Tea.context(function () {
var that = this;
this.success = NotifyPopup
this.selectedType = this.scheduling.code;
this.schedulingTypeDescription = null;
this.changeSchedulingType = function () {
this.schedulingTypeDescription = this.schedulingTypes.$find(function (k, v) {
return v.code == that.selectedType;
}).description;
};
this.changeSchedulingType();
// hash
this.hashKey = "";
this.hashVar = "";
if (this.scheduling.code == "hash") {
this.hashKey = this.scheduling.options.key;
} else {
this.hashKey = "${remoteAddr}";
}
this.changeHashVar = function () {
if (this.hashVar.length > 0) {
this.hashKey = this.hashVar;
}
};
// sticky
if (this.scheduling.code == "sticky") {
this.stickyType = this.scheduling.options.type;
this.stickyParam = this.scheduling.options.param;
} else {
this.stickyType = "cookie";
this.stickyParam = "Origin";
}
});

View File

@@ -0,0 +1,27 @@
{$layout}
{$template "/left_menu"}
<div class="right-box">
{$if eq .canSpecifyPort false}
<p class="ui message warning">根据系统管理员设定,你不能修改此网站的端口信息。</p>
{$end}
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
<input type="hidden" name="serverId" :value="serverId"/>
<input type="hidden" name="serverType" :value="serverType"/>
<table class="ui table selectable definition">
<tr>
<td class="title">绑定端口 *</td>
<td>
<div v-show="canSpecifyPort">
<network-addresses-box :v-server-type="serverType" :v-addresses="tcpConfig.listen" :v-protocol="'tcp'"></network-addresses-box>
</div>
<div v-show="!canSpecifyPort" v-if="tcpConfig.listen != null">
<span v-for="listen in tcpConfig.listen" class="ui basic small label">tcp://*:{{listen.portRange}}</span>
</div>
</td>
</tr>
</table>
<submit-btn></submit-btn>
</form>
</div>

View File

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

View File

@@ -0,0 +1,35 @@
{$layout}
{$template "/left_menu"}
{$var "header"}
<script src="/servers/certs/datajs" type="text/javascript"></script>
<script src="/js/sortable.min.js" type="text/javascript"></script>
{$end}
<div class="right-box">
{$if eq .canSpecifyPort false}
<p class="ui message warning">根据管理员设定,你不能修改此服务端口信息。</p>
{$end}
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
<input type="hidden" name="serverId" :value="serverId"/>
<input type="hidden" name="serverType" :value="serverType"/>
<table class="ui table selectable definition">
<tr>
<td class="title">绑定端口 *</td>
<td>
<div v-show="canSpecifyPort">
<network-addresses-box :v-server-type="serverType" :v-addresses="tlsConfig.listen" :v-protocol="'tls'" ></network-addresses-box>
</div>
<div v-show="!canSpecifyPort" v-if="tlsConfig.listen != null">
<span v-for="listen in tlsConfig.listen" class="ui basic small label">tls://*:{{listen.portRange}}</span>
</div>
</td>
</tr>
</table>
<!-- SSL配置 -->
<ssl-config-box :v-ssl-policy="tlsConfig.sslPolicy" :v-protocol="'tls'" v-show="tlsConfig.isOn"></ssl-config-box>
<submit-btn></submit-btn>
</form>
</div>

View File

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

View File

@@ -0,0 +1,26 @@
{$layout}
{$template "/left_menu"}
<div class="right-box">
{$if eq .canSpecifyPort false}
<p class="ui message warning">根据系统管理员设定,你不能修改此网站的端口信息。</p>
{$end}
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
<input type="hidden" name="serverId" :value="serverId"/>
<input type="hidden" name="serverType" :value="serverType"/>
<table class="ui table selectable definition">
<tr>
<td class="title">绑定端口 *</td>
<td>
<div v-show="canSpecifyPort">
<network-addresses-box :v-server-type="serverType" :v-addresses="udpConfig.listen" :v-protocol="'udp'" :v-support-range="true"></network-addresses-box>
</div>
<div v-show="!canSpecifyPort" v-if="udpConfig.listen != null">
<span v-for="listen in udpConfig.listen" class="ui basic small label">udp://*:{{listen.portRange}}</span>
</div>
</td>
</tr>
</table>
<submit-btn></submit-btn>
</form>
</div>

View File

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